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; +} + +  | 
