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