summaryrefslogtreecommitdiff
path: root/deps/libev/ev.c
diff options
context:
space:
mode:
Diffstat (limited to 'deps/libev/ev.c')
-rw-r--r--deps/libev/ev.c314
1 files changed, 229 insertions, 85 deletions
diff --git a/deps/libev/ev.c b/deps/libev/ev.c
index 3214fba702..bfb87f29bd 100644
--- a/deps/libev/ev.c
+++ b/deps/libev/ev.c
@@ -135,6 +135,14 @@ extern "C" {
# endif
# endif
+# ifndef EV_USE_SIGNALFD
+# if HAVE_SIGNALFD && HAVE_SYS_SIGNALFD_H
+# define EV_USE_SIGNALFD 1
+# else
+# define EV_USE_SIGNALFD 0
+# endif
+# endif
+
# ifndef EV_USE_EVENTFD
# if HAVE_EVENTFD
# define EV_USE_EVENTFD 1
@@ -180,6 +188,33 @@ extern "C" {
/* this block tries to deduce configuration from header-defined symbols and defaults */
+/* try to deduce the maximum number of signals on this platform */
+#if defined (EV_NSIG)
+/* use what's provided */
+#elif defined (NSIG)
+# define EV_NSIG (NSIG)
+#elif defined(_NSIG)
+# define EV_NSIG (_NSIG)
+#elif defined (SIGMAX)
+# define EV_NSIG (SIGMAX+1)
+#elif defined (SIG_MAX)
+# define EV_NSIG (SIG_MAX+1)
+#elif defined (_SIG_MAX)
+# define EV_NSIG (_SIG_MAX+1)
+#elif defined (MAXSIG)
+# define EV_NSIG (MAXSIG+1)
+#elif defined (MAX_SIG)
+# define EV_NSIG (MAX_SIG+1)
+#elif defined (SIGARRAYSIZE)
+# define EV_NSIG SIGARRAYSIZE /* Assume ary[SIGARRAYSIZE] */
+#elif defined (_sys_nsig)
+# define EV_NSIG (_sys_nsig) /* Solaris 2.5 */
+#else
+# error "unable to find value for NSIG, please report"
+/* to make it compile regardless, just remove the above line */
+# define EV_NSIG 65
+#endif
+
#ifndef EV_USE_CLOCK_SYSCALL
# if __linux && __GLIBC__ >= 2
# define EV_USE_CLOCK_SYSCALL 1
@@ -268,6 +303,14 @@ extern "C" {
# endif
#endif
+#ifndef EV_USE_SIGNALFD
+# if __linux && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 9))
+# define EV_USE_SIGNALFD 1
+# else
+# define EV_USE_SIGNALFD 0
+# endif
+#endif
+
#if 0 /* debugging */
# define EV_VERIFY 3
# define EV_USE_4HEAP 1
@@ -341,6 +384,16 @@ extern "C" {
#if EV_USE_EVENTFD
/* our minimum requirement is glibc 2.7 which has the stub, but not the header */
# include <stdint.h>
+# ifndef EFD_NONBLOCK
+# define EFD_NONBLOCK O_NONBLOCK
+# endif
+# ifndef EFD_CLOEXEC
+# ifdef O_CLOEXEC
+# define EFD_CLOEXEC O_CLOEXEC
+# else
+# define EFD_CLOEXEC 02000000
+# endif
+# endif
# ifdef __cplusplus
extern "C" {
# endif
@@ -350,6 +403,10 @@ int eventfd (unsigned int initval, int flags);
# endif
#endif
+#if EV_USE_SIGNALFD
+# include <sys/signalfd.h>
+#endif
+
/**/
#if EV_VERIFY >= 3
@@ -906,7 +963,7 @@ fd_enomem (EV_P)
if (anfds [fd].events)
{
fd_kill (EV_A_ fd);
- return;
+ break;
}
}
@@ -1006,7 +1063,7 @@ downheap (ANHE *heap, int N, int k)
{
int c = k << 1;
- if (c > N + HEAP0 - 1)
+ if (c >= N + HEAP0)
break;
c += c + 1 < N + HEAP0 && ANHE_at (heap [c]) > ANHE_at (heap [c + 1])
@@ -1052,7 +1109,7 @@ upheap (ANHE *heap, int k)
inline_size void
adjustheap (ANHE *heap, int N, int k)
{
- if (k > HEAP0 && ANHE_at (heap [HPARENT (k)]) >= ANHE_at (heap [k]))
+ if (k > HEAP0 && ANHE_at (heap [k]) <= ANHE_at (heap [HPARENT (k)]))
upheap (heap, k);
else
downheap (heap, N, k);
@@ -1075,14 +1132,14 @@ reheap (ANHE *heap, int N)
/* associate signal watchers to a signal signal */
typedef struct
{
+ EV_ATOMIC_T pending;
+#if EV_MULTIPLICITY
+ EV_P;
+#endif
WL head;
- EV_ATOMIC_T gotsig;
} ANSIG;
-static ANSIG *signals;
-static int signalmax;
-
-static EV_ATOMIC_T gotsig;
+static ANSIG signals [EV_NSIG - 1];
/*****************************************************************************/
@@ -1106,10 +1163,14 @@ evpipe_init (EV_P)
if (!ev_is_active (&pipe_w))
{
#if EV_USE_EVENTFD
- if ((evfd = eventfd (0, 0)) >= 0)
+ evfd = eventfd (0, EFD_NONBLOCK | EFD_CLOEXEC);
+ if (evfd < 0 && errno == EINVAL)
+ evfd = eventfd (0, 0);
+
+ if (evfd >= 0)
{
evpipe [0] = -1;
- fd_intern (evfd);
+ fd_intern (evfd); /* doing it twice doesn't hurt */
ev_io_set (&pipe_w, evfd, EV_READ);
}
else
@@ -1156,6 +1217,8 @@ evpipe_write (EV_P_ EV_ATOMIC_T *flag)
static void
pipecb (EV_P_ ev_io *iow, int revents)
{
+ int i;
+
#if EV_USE_EVENTFD
if (evfd >= 0)
{
@@ -1169,21 +1232,19 @@ pipecb (EV_P_ ev_io *iow, int revents)
read (evpipe [0], &dummy, 1);
}
- if (gotsig && ev_is_default_loop (EV_A))
+ if (sig_pending)
{
- int signum;
- gotsig = 0;
+ sig_pending = 0;
- for (signum = signalmax; signum--; )
- if (signals [signum].gotsig)
- ev_feed_signal_event (EV_A_ signum + 1);
+ for (i = EV_NSIG - 1; i--; )
+ if (expect_false (signals [i].pending))
+ ev_feed_signal_event (EV_A_ i + 1);
}
#if EV_ASYNC_ENABLE
- if (gotasync)
+ if (async_pending)
{
- int i;
- gotasync = 0;
+ async_pending = 0;
for (i = asynccnt; i--; )
if (asyncs [i]->sent)
@@ -1201,15 +1262,15 @@ static void
ev_sighandler (int signum)
{
#if EV_MULTIPLICITY
- struct ev_loop *loop = &default_loop_struct;
+ EV_P = signals [signum - 1].loop;
#endif
#if _WIN32
signal (signum, ev_sighandler);
#endif
- signals [signum - 1].gotsig = 1;
- evpipe_write (EV_A_ &gotsig);
+ signals [signum - 1].pending = 1;
+ evpipe_write (EV_A_ &sig_pending);
}
void noinline
@@ -1217,21 +1278,45 @@ ev_feed_signal_event (EV_P_ int signum)
{
WL w;
-#if EV_MULTIPLICITY
- assert (("libev: feeding signal events is only supported in the default loop", loop == ev_default_loop_ptr));
-#endif
+ if (expect_false (signum <= 0 || signum > EV_NSIG))
+ return;
--signum;
- if (signum < 0 || signum >= signalmax)
+#if EV_MULTIPLICITY
+ /* it is permissible to try to feed a signal to the wrong loop */
+ /* or, likely more useful, feeding a signal nobody is waiting for */
+
+ if (expect_false (signals [signum].loop != EV_A))
return;
+#endif
- signals [signum].gotsig = 0;
+ signals [signum].pending = 0;
for (w = signals [signum].head; w; w = w->next)
ev_feed_event (EV_A_ (W)w, EV_SIGNAL);
}
+#if EV_USE_SIGNALFD
+static void
+sigfdcb (EV_P_ ev_io *iow, int revents)
+{
+ struct signalfd_siginfo si[2], *sip; /* these structs are big */
+
+ for (;;)
+ {
+ ssize_t res = read (sigfd, si, sizeof (si));
+
+ /* not ISO-C, as res might be -1, but works with SuS */
+ for (sip = si; (char *)sip < (char *)si + res; ++sip)
+ ev_feed_signal_event (EV_A_ sip->ssi_signo);
+
+ if (res < (ssize_t)sizeof (si))
+ break;
+ }
+}
+#endif
+
/*****************************************************************************/
static WL childs [EV_PID_HASHSIZE];
@@ -1460,6 +1545,17 @@ loop_init (EV_P_ unsigned int flags)
}
#endif
+ /* pid check not overridable via env */
+#ifndef _WIN32
+ if (flags & EVFLAG_FORKCHECK)
+ curpid = getpid ();
+#endif
+
+ if (!(flags & EVFLAG_NOENV)
+ && !enable_secure ()
+ && getenv ("LIBEV_FLAGS"))
+ flags = atoi (getenv ("LIBEV_FLAGS"));
+
ev_rt_now = ev_time ();
mn_now = get_clock ();
now_floor = mn_now;
@@ -1472,22 +1568,17 @@ loop_init (EV_P_ unsigned int flags)
timeout_blocktime = 0.;
backend = 0;
backend_fd = -1;
- gotasync = 0;
+ sig_pending = 0;
+#if EV_ASYNC_ENABLE
+ async_pending = 0;
+#endif
#if EV_USE_INOTIFY
- fs_fd = -2;
+ fs_fd = flags & EVFLAG_NOINOTIFY ? -1 : -2;
#endif
-
- /* pid check not overridable via env */
-#ifndef _WIN32
- if (flags & EVFLAG_FORKCHECK)
- curpid = getpid ();
+#if EV_USE_SIGNALFD
+ sigfd = flags & EVFLAG_NOSIGFD ? -1 : -2;
#endif
- if (!(flags & EVFLAG_NOENV)
- && !enable_secure ()
- && getenv ("LIBEV_FLAGS"))
- flags = atoi (getenv ("LIBEV_FLAGS"));
-
if (!(flags & 0x0000ffffU))
flags |= ev_recommended_backends ();
@@ -1522,8 +1613,8 @@ loop_destroy (EV_P)
if (ev_is_active (&pipe_w))
{
- ev_ref (EV_A); /* signal watcher */
- ev_io_stop (EV_A_ &pipe_w);
+ /*ev_ref (EV_A);*/
+ /*ev_io_stop (EV_A_ &pipe_w);*/
#if EV_USE_EVENTFD
if (evfd >= 0)
@@ -1537,6 +1628,16 @@ loop_destroy (EV_P)
}
}
+#if EV_USE_SIGNALFD
+ if (ev_is_active (&sigfd_w))
+ {
+ /*ev_ref (EV_A);*/
+ /*ev_io_stop (EV_A_ &sigfd_w);*/
+
+ close (sigfd);
+ }
+#endif
+
#if EV_USE_INOTIFY
if (fs_fd >= 0)
close (fs_fd);
@@ -1569,7 +1670,7 @@ loop_destroy (EV_P)
#endif
}
- ev_free (anfds); anfdmax = 0;
+ ev_free (anfds); anfds = 0; anfdmax = 0;
/* have to use the microsoft-never-gets-it-right macro */
array_free (rfeed, EMPTY);
@@ -1614,9 +1715,9 @@ loop_fork (EV_P)
{
/* this "locks" the handlers against writing to the pipe */
/* while we modify the fd vars */
- gotsig = 1;
+ sig_pending = 1;
#if EV_ASYNC_ENABLE
- gotasync = 1;
+ async_pending = 1;
#endif
ev_ref (EV_A);
@@ -1646,14 +1747,13 @@ loop_fork (EV_P)
struct ev_loop *
ev_loop_new (unsigned int flags)
{
- struct ev_loop *loop = (struct ev_loop *)ev_malloc (sizeof (struct ev_loop));
-
- memset (loop, 0, sizeof (struct ev_loop));
+ EV_P = (struct ev_loop *)ev_malloc (sizeof (struct ev_loop));
+ memset (EV_A, 0, sizeof (struct ev_loop));
loop_init (EV_A_ flags);
if (ev_backend (EV_A))
- return loop;
+ return EV_A;
return 0;
}
@@ -1767,7 +1867,7 @@ ev_loop_verify (EV_P)
# if 0
for (w = (ev_child *)childs [chain & (EV_PID_HASHSIZE - 1)]; w; w = (ev_child *)((WL)w)->next)
- for (signum = signalmax; signum--; ) if (signals [signum].gotsig)
+ for (signum = EV_NSIG; signum--; ) if (signals [signum].pending)
# endif
#endif
}
@@ -1784,7 +1884,7 @@ ev_default_loop (unsigned int flags)
if (!ev_default_loop_ptr)
{
#if EV_MULTIPLICITY
- struct ev_loop *loop = ev_default_loop_ptr = &default_loop_struct;
+ EV_P = ev_default_loop_ptr = &default_loop_struct;
#else
ev_default_loop_ptr = 1;
#endif
@@ -1811,7 +1911,7 @@ void
ev_default_destroy (void)
{
#if EV_MULTIPLICITY
- struct ev_loop *loop = ev_default_loop_ptr;
+ EV_P = ev_default_loop_ptr;
#endif
ev_default_loop_ptr = 0;
@@ -1828,7 +1928,7 @@ void
ev_default_fork (void)
{
#if EV_MULTIPLICITY
- struct ev_loop *loop = ev_default_loop_ptr;
+ EV_P = ev_default_loop_ptr;
#endif
postfork = 1; /* must be in line with ev_loop_fork */
@@ -2304,10 +2404,10 @@ wlist_del (WL *head, WL elem)
{
while (*head)
{
- if (*head == elem)
+ if (expect_true (*head == elem))
{
*head = elem->next;
- return;
+ break;
}
head = &(*head)->next;
@@ -2571,47 +2671,75 @@ ev_periodic_again (EV_P_ ev_periodic *w)
void noinline
ev_signal_start (EV_P_ ev_signal *w)
{
-#if EV_MULTIPLICITY
- assert (("libev: signal watchers are only supported in the default loop", loop == ev_default_loop_ptr));
-#endif
if (expect_false (ev_is_active (w)))
return;
- assert (("libev: ev_signal_start called with illegal signal number", w->signum > 0));
+ assert (("libev: ev_signal_start called with illegal signal number", w->signum > 0 && w->signum < EV_NSIG));
- evpipe_init (EV_A);
+#if EV_MULTIPLICITY
+ assert (("libev: a signal must not be attached to two different loops",
+ !signals [w->signum - 1].loop || signals [w->signum - 1].loop == loop));
+
+ signals [w->signum - 1].loop = EV_A;
+#endif
EV_FREQUENT_CHECK;
- {
-#ifndef _WIN32
- sigset_t full, prev;
- sigfillset (&full);
- sigprocmask (SIG_SETMASK, &full, &prev);
-#endif
+#if EV_USE_SIGNALFD
+ if (sigfd == -2)
+ {
+ sigfd = signalfd (-1, &sigfd_set, SFD_NONBLOCK | SFD_CLOEXEC);
+ if (sigfd < 0 && errno == EINVAL)
+ sigfd = signalfd (-1, &sigfd_set, 0); /* retry without flags */
- array_needsize (ANSIG, signals, signalmax, w->signum, array_init_zero);
+ if (sigfd >= 0)
+ {
+ fd_intern (sigfd); /* doing it twice will not hurt */
-#ifndef _WIN32
- sigprocmask (SIG_SETMASK, &prev, 0);
+ sigemptyset (&sigfd_set);
+
+ ev_io_init (&sigfd_w, sigfdcb, sigfd, EV_READ);
+ ev_set_priority (&sigfd_w, EV_MAXPRI);
+ ev_io_start (EV_A_ &sigfd_w);
+ ev_unref (EV_A); /* signalfd watcher should not keep loop alive */
+ }
+ }
+
+ if (sigfd >= 0)
+ {
+ /* TODO: check .head */
+ sigaddset (&sigfd_set, w->signum);
+ sigprocmask (SIG_BLOCK, &sigfd_set, 0);
+
+ signalfd (sigfd, &sigfd_set, 0);
+ }
#endif
- }
ev_start (EV_A_ (W)w, 1);
wlist_add (&signals [w->signum - 1].head, (WL)w);
if (!((WL)w)->next)
- {
-#if _WIN32
- signal (w->signum, ev_sighandler);
-#else
- struct sigaction sa = { };
- sa.sa_handler = ev_sighandler;
- sigfillset (&sa.sa_mask);
- sa.sa_flags = SA_RESTART; /* if restarting works we save one iteration */
- sigaction (w->signum, &sa, 0);
+# if EV_USE_SIGNALFD
+ if (sigfd < 0) /*TODO*/
+# endif
+ {
+# if _WIN32
+ signal (w->signum, ev_sighandler);
+# else
+ struct sigaction sa;
+
+ evpipe_init (EV_A);
+
+ sa.sa_handler = ev_sighandler;
+ sigfillset (&sa.sa_mask);
+ sa.sa_flags = SA_RESTART; /* if restarting works we save one iteration */
+ sigaction (w->signum, &sa, 0);
+
+ sigemptyset (&sa.sa_mask);
+ sigaddset (&sa.sa_mask, w->signum);
+ sigprocmask (SIG_UNBLOCK, &sa.sa_mask, 0);
#endif
- }
+ }
EV_FREQUENT_CHECK;
}
@@ -2629,7 +2757,23 @@ ev_signal_stop (EV_P_ ev_signal *w)
ev_stop (EV_A_ (W)w);
if (!signals [w->signum - 1].head)
- signal (w->signum, SIG_DFL);
+ {
+#if EV_MULTIPLICITY
+ signals [w->signum - 1].loop = 0; /* unattach from signal */
+#endif
+#if EV_USE_SIGNALFD
+ if (sigfd >= 0)
+ {
+ sigprocmask (SIG_UNBLOCK, &sigfd_set, 0);//D
+ sigdelset (&sigfd_set, w->signum);
+ signalfd (sigfd, &sigfd_set, 0);
+ sigprocmask (SIG_BLOCK, &sigfd_set, 0);//D
+ /*TODO: maybe unblock signal? */
+ }
+ else
+#endif
+ signal (w->signum, SIG_DFL);
+ }
EV_FREQUENT_CHECK;
}
@@ -3119,7 +3263,7 @@ embed_prepare_cb (EV_P_ ev_prepare *prepare, int revents)
ev_embed *w = (ev_embed *)(((char *)prepare) - offsetof (ev_embed, prepare));
{
- struct ev_loop *loop = w->other;
+ EV_P = w->other;
while (fdchangecnt)
{
@@ -3137,7 +3281,7 @@ embed_fork_cb (EV_P_ ev_fork *fork_w, int revents)
ev_embed_stop (EV_A_ w);
{
- struct ev_loop *loop = w->other;
+ EV_P = w->other;
ev_loop_fork (EV_A);
ev_loop (EV_A_ EVLOOP_NONBLOCK);
@@ -3161,7 +3305,7 @@ ev_embed_start (EV_P_ ev_embed *w)
return;
{
- struct ev_loop *loop = w->other;
+ EV_P = w->other;
assert (("libev: loop to be embedded is not embeddable", backend & ev_embeddable_backends ()));
ev_io_init (&w->io, embed_io_cb, backend_fd, EV_READ);
}
@@ -3283,7 +3427,7 @@ void
ev_async_send (EV_P_ ev_async *w)
{
w->sent = 1;
- evpipe_write (EV_A_ &gotasync);
+ evpipe_write (EV_A_ &async_pending);
}
#endif
@@ -3442,7 +3586,7 @@ ev_walk (EV_P_ int types, void (*cb)(EV_P_ int type, void *w))
cb (EV_A_ EV_CHECK, checks [i]);
if (types & EV_SIGNAL)
- for (i = 0; i < signalmax; ++i)
+ for (i = 0; i < EV_NSIG - 1; ++i)
for (wl = signals [i].head; wl; )
{
wn = wl->next;