implement select method

master
Marc Alexander Lehmann 2007-10-30 23:54:38 +00:00
parent 7e9192be63
commit 22a3064bad
4 changed files with 146 additions and 37 deletions

3
README
View File

@ -22,6 +22,9 @@ to be faster and more correct, and also more featureful. Examples:
- can correctly remove timers while executing callbacks
(libevent doesn't handle this reliably and can crash)
- race-free signal processing
(libevent may delay processing signals till after the next event)
- less calls to epoll_ctl
(stopping and starting an io watcher between two loop iterations will now
result in spuriois epoll_ctl calls)

35
ev.c
View File

@ -14,7 +14,7 @@
#define HAVE_EPOLL 1
#define HAVE_REALTIME 1
#define HAVE_SELECT 0
#define HAVE_SELECT 1
#define MIN_TIMEJUMP 1. /* minimum timejump that gets detected (if monotonic clock available) */
#define MAX_BLOCKTIME 60.
@ -36,7 +36,7 @@ int ev_method;
static int have_monotonic; /* runtime */
static ev_tstamp method_fudge; /* stupid epoll-returns-early bug */
static void (*method_reify)(void);
static void (*method_modify)(int fd, int oev, int nev);
static void (*method_poll)(ev_tstamp timeout);
ev_tstamp
@ -236,10 +236,37 @@ void ev_postfork_parent (void)
void ev_postfork_child (void)
{
#if HAVE_EPOLL
epoll_postfork_child ();
if (ev_method == EVMETHOD_EPOLL)
epoll_postfork_child ();
#endif
}
static void
fd_reify (void)
{
int i;
for (i = 0; i < fdchangecnt; ++i)
{
int fd = fdchanges [i];
ANFD *anfd = anfds + fd;
struct ev_io *w;
int wev = 0;
for (w = anfd->head; w; w = w->next)
wev |= w->events;
if (anfd->wev != wev)
{
method_modify (fd, anfd->wev, wev);
anfd->wev = wev;
}
}
fdchangecnt = 0;
}
static void
call_pending ()
{
@ -338,7 +365,7 @@ void ev_loop (int flags)
do
{
/* update fd-related kernel structures */
method_reify (); fdchangecnt = 0;
fd_reify ();
/* calculate blocking time */
if (flags & EVLOOP_NONBLOCK)

View File

@ -3,44 +3,31 @@
static int epoll_fd = -1;
static void
epoll_reify_fd (int fd)
epoll_modify (int fd, int oev, int nev)
{
ANFD *anfd = anfds + fd;
struct ev_io *w;
int mode = nev ? oev ? EPOLL_CTL_MOD : EPOLL_CTL_ADD : EPOLL_CTL_DEL;
int wev = 0;
struct epoll_event ev;
ev.data.fd = fd;
ev.events =
(nev & EV_READ ? EPOLLIN : 0)
| (nev & EV_WRITE ? EPOLLOUT : 0);
for (w = anfd->head; w; w = w->next)
wev |= w->events;
if (anfd->wev != wev)
{
int mode = wev ? anfd->wev ? EPOLL_CTL_MOD : EPOLL_CTL_ADD : EPOLL_CTL_DEL;
struct epoll_event ev;
ev.events = wev;
ev.data.fd = fd;
fprintf (stderr, "reify %d,%d,%d m%d (r=%d)\n", fd, anfd->wev, wev, mode,//D
epoll_ctl (epoll_fd, mode, fd, &ev)
);//D
anfd->wev = wev;
}
fprintf (stderr, "reify %d,%d,%d m%d (r=%d)\n", fd, oev, nev, mode,//D
epoll_ctl (epoll_fd, mode, fd, &ev)
);//D
}
void epoll_postfork_child (void)
{
int i;
int fd;
epoll_fd = epoll_create (256);
for (i = 0; i < anfdmax; ++i)
epoll_reify_fd (i);
}
static void epoll_reify (void)
{
int i;
for (i = 0; i < fdchangecnt; ++i)
epoll_reify_fd (fdchanges [i]);
/* re-register interest in fds */
for (fd = 0; fd < anfdmax; ++fd)
if (anfds [fd].wev)
epoll_modify (fd, EV_NONE, anfds [fd].wev);
}
static struct epoll_event *events;
@ -57,8 +44,8 @@ static void epoll_poll (ev_tstamp timeout)
for (i = 0; i < eventcnt; ++i)
fd_event (
events [i].data.fd,
(events [i].events & (EPOLLOUT | EPOLLERR | EPOLLHUP | EPOLLPRI) ? EV_WRITE : 0)
| (events [i].events & (EPOLLIN | EPOLLERR | EPOLLHUP) ? EV_READ : 0)
(events [i].events & (EPOLLOUT | EPOLLERR | EPOLLHUP) ? EV_WRITE : 0)
| (events [i].events & (EPOLLIN | EPOLLERR | EPOLLHUP) ? EV_READ : 0)
);
/* if the receive array was full, increase its size */
@ -78,9 +65,9 @@ int epoll_init (int flags)
return 0;
ev_method = EVMETHOD_EPOLL;
method_fudge = 1e-3; /* needed to compensate fro epoll returning early */
method_reify = epoll_reify;
method_poll = epoll_poll;
method_fudge = 1e-3; /* needed to compensate for epoll returning early */
method_modify = epoll_modify;
method_poll = epoll_poll;
eventmax = 64; /* intiial number of events receivable per poll */
events = malloc (sizeof (struct epoll_event) * eventmax);

View File

@ -0,0 +1,92 @@
/* for broken bsd's */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
/* for unix systems */
#include <sys/select.h>
#include <string.h>
#include <inttypes.h>
static unsigned char *vec_ri, *vec_ro, *vec_wi, *vec_wo;
static int vec_max;
static void
select_modify (int fd, int oev, int nev)
{
int offs = fd >> 3;
int mask = 1 << (fd & 7);
if (vec_max < (fd >> 5) + 1)
{
vec_max = (fd >> 5) + 1;
vec_ri = (unsigned char *)realloc (vec_ri, vec_max * 4);
vec_ro = (unsigned char *)realloc (vec_ro, vec_max * 4); /* could free/malloc */
vec_wi = (unsigned char *)realloc (vec_wi, vec_max * 4);
vec_wo = (unsigned char *)realloc (vec_wo, vec_max * 4); /* could free/malloc */
}
vec_ri [offs] |= mask;
if (!(nev & EV_READ))
vec_ri [offs] &= ~mask;
vec_wi [offs] |= mask;
if (!(nev & EV_WRITE))
vec_wi [offs] &= ~mask;
}
static void select_poll (ev_tstamp timeout)
{
struct timeval tv;
int res;
memcpy (vec_ro, vec_ri, vec_max * 4);
memcpy (vec_wo, vec_wi, vec_max * 4);
tv.tv_sec = (long)timeout;
tv.tv_usec = (long)((timeout - (ev_tstamp)tv.tv_sec) * 1e6);
res = select (vec_max * 32, (fd_set *)vec_ro, (fd_set *)vec_wo, 0, &tv);
if (res > 0)
{
int word, offs;
for (word = vec_max; word--; )
{
if (((uint32_t *)vec_ro) [word] | ((uint32_t *)vec_wo) [word])
for (offs = 4; offs--; )
{
int idx = word * 4 + offs;
unsigned char byte_r = vec_ro [idx];
unsigned char byte_w = vec_wo [idx];
int bit;
if (byte_r | byte_w)
for (bit = 8; bit--; )
{
int events = 0;
events |= byte_r & (1 << bit) ? EV_READ : 0;
events |= byte_w & (1 << bit) ? EV_WRITE : 0;
if (events)
fd_event (idx * 8 + bit, events);
}
}
}
}
}
int select_init (int flags)
{
ev_method = EVMETHOD_SELECT;
method_fudge = 1e-2; /* needed to compensate for select returning early, very conservative */
method_modify = select_modify;
method_poll = select_poll;
return 1;
}