Hi!

We use libev in our project (tarantool.org) and a problem with how libev 
handles its internal errors.
Periodically we need to create a new thread with libev pool and async. But in 
some cases process can haven't enough file descriptors to create pipe in 
evpipe_init (called by ev_async_start). In case of error libev will call 
ev_syscall and return to pipe creation. 
ev_syscall can abort process (this is unacceptable for us) or can callback if 
installed. But installed callback can't do nothing to break evpipe_init loop.

To fix this i create a patch, that allow early descriptors initialization at 
ev_loop_new, that can return NULL in case of errors. 
diff --git a/third_party/libev/ev.c b/third_party/libev/ev.c
index 4530009..d33b55a 100644
--- a/third_party/libev/ev.c
+++ b/third_party/libev/ev.c
@@ -2250,45 +2250,54 @@ static ANSIG signals [EV_NSIG - 1];
 
 #if EV_SIGNAL_ENABLE || EV_ASYNC_ENABLE
 
-static void noinline ecb_cold
-evpipe_init (EV_P)
+static int evpipe_alloc(EV_P)
 {
-  if (!ev_is_active (&pipe_w))
-    {
-      int fds [2];
+  int fds [2];
 
 # if EV_USE_EVENTFD
-      fds [0] = -1;
-      fds [1] = eventfd (0, EFD_NONBLOCK | EFD_CLOEXEC);
-      if (fds [1] < 0 && errno == EINVAL)
-        fds [1] = eventfd (0, 0);
+  fds [0] = -1;
+  fds [1] = eventfd (0, EFD_NONBLOCK | EFD_CLOEXEC);
+  if (fds [1] < 0 && errno == EINVAL)
+    fds [1] = eventfd (0, 0);
 
-      if (fds [1] < 0)
+  if (fds [1] < 0)
 # endif
-        {
-          while (pipe (fds))
-            ev_syserr ("(libev) error creating signal/async pipe");
+    {
+      if (!pipe (fds))
+         fd_intern (fds [0]);
+    }
+  if (fds [1] < 0)
+    return -1;
 
-          fd_intern (fds [0]);
-        }
+  evpipe [0] = fds [0];
 
-      evpipe [0] = fds [0];
+  if (evpipe [1] < 0)
+    evpipe [1] = fds [1]; /* first call, set write fd */
+  else
+    {
+      /* on subsequent calls, do not change evpipe [1] */
+      /* so that evpipe_write can always rely on its value. */
+      /* this branch does not do anything sensible on windows, */
+      /* so must not be executed on windows */
 
-      if (evpipe [1] < 0)
-        evpipe [1] = fds [1]; /* first call, set write fd */
-      else
-        {
-          /* on subsequent calls, do not change evpipe [1] */
-          /* so that evpipe_write can always rely on its value. */
-          /* this branch does not do anything sensible on windows, */
-          /* so must not be executed on windows */
+      dup2 (fds [1], evpipe [1]);
+      close (fds [1]);
+    }
 
-          dup2 (fds [1], evpipe [1]);
-          close (fds [1]);
-        }
+  fd_intern (evpipe [1]);
+  return 1;
+}
 
-      fd_intern (evpipe [1]);
 
+static void noinline ecb_cold
+evpipe_init (EV_P)
+{
+  if (!ev_is_active (&pipe_w))
+    {
+
+      if (evpipe [0] == -1)
+        while (evpipe_alloc(loop) == -1)
+          ev_syserr("(libev) error creating signal/async pipe");
       ev_io_set (&pipe_w, evpipe [0] < 0 ? evpipe [1] : evpipe [0], EV_READ);
       ev_io_start (EV_A_ &pipe_w);
       ev_unref (EV_A); /* watcher should not keep loop alive */
@@ -2763,6 +2772,9 @@ loop_init (EV_P_ unsigned int flags) EV_THROW
       if (!(flags & EVBACKEND_MASK))
         flags |= ev_recommended_backends ();
 
+      if (flags & EVFLAG_ALLOCFD)
+        if (evpipe_alloc(EV_A) < 0)
+          return;
 #if EV_USE_IOCP
       if (!backend && (flags & EVBACKEND_IOCP  )) backend = iocp_init   (EV_A_ flags);
 #endif
diff --git a/third_party/libev/ev.h b/third_party/libev/ev.h
index 5ecf16a..bcc92f0 100644
--- a/third_party/libev/ev.h
+++ b/third_party/libev/ev.h
@@ -510,7 +510,8 @@ enum {
   EVFLAG_NOSIGFD   = 0, /* compatibility to pre-3.9 */
 #endif
   EVFLAG_SIGNALFD  = 0x00200000U, /* attempt to use signalfd */
-  EVFLAG_NOSIGMASK = 0x00400000U  /* avoid modifying the signal mask */
+  EVFLAG_NOSIGMASK = 0x00400000U,  /* avoid modifying the signal mask */
+  EVFLAG_ALLOCFD   = 0x00800000U /* preallocate event pipe descriptors */
 };
 
 /* method bits to be ored together */
_______________________________________________
libev mailing list
[email protected]
http://lists.schmorp.de/mailman/listinfo/libev

Reply via email to