]> git.llucax.com Git - software/libev.git/commitdiff
implement select method
authorroot <root>
Tue, 30 Oct 2007 23:54:38 +0000 (23:54 +0000)
committerroot <root>
Tue, 30 Oct 2007 23:54:38 +0000 (23:54 +0000)
README
ev.c
ev_epoll.c
ev_select.c

diff --git a/README b/README
index 5895388b2665abd544d45e97c58619db9618e0e9..544055158646a50ac88879ae303d575a18bd3bbe 100644 (file)
--- a/README
+++ b/README
@@ -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)
diff --git a/ev.c b/ev.c
index 67d0368668d0de8e7030801085df660262678564..889dfe63c76b332a70969a581def965a09df23ec 100644 (file)
--- a/ev.c
+++ b/ev.c
@@ -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)
index 42e4a8bd05615c0d1154b16a2362404171fdbeaf..b3b546f4c352d4bedd9d5f2e934ff91a82bf56a8 100644 (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);
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..63612dcc9f31fe0aa78d8085f7fc440d16b7a5ee 100644 (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;
+}
+
+