diff options
-rw-r--r-- | README | 3 | ||||
-rw-r--r-- | ev.c | 35 | ||||
-rw-r--r-- | ev_epoll.c | 53 | ||||
-rw-r--r-- | ev_select.c | 92 |
4 files changed, 146 insertions, 37 deletions
@@ -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) @@ -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,11 +236,38 @@ 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 () { int i; @@ -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) @@ -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); diff --git a/ev_select.c b/ev_select.c index e69de29..63612dc 100644 --- a/ev_select.c +++ b/ev_select.c @@ -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; +} + + |