summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Changes8
-rw-r--r--ev.c134
-rw-r--r--ev.pod31
-rw-r--r--ev_vars.h6
-rw-r--r--ev_wrap.h6
5 files changed, 160 insertions, 25 deletions
diff --git a/Changes b/Changes
index 4fed655..d92940b 100644
--- a/Changes
+++ b/Changes
@@ -2,6 +2,14 @@ Revision history for libev, a high-performance and full-featured event loop.
TODO: ev_walk
TODO: signal handling per loop
+TODO: signalfd
+
+TODO: document signalfd procmask
+ - incompatible change: do not necessarily reset signal handler
+ to SIG_DFL when a sighandler is stopped.
+ - take advantage of signalfd on GNU/Linux systems.
+ - document that the signal mask might be in an unspecified
+ state when using libev's signal handling.
3.7 Fri Jul 17 16:36:32 CEST 2009
- ev_unloop and ev_loop wrongly used a global variable to exit loops,
diff --git a/ev.c b/ev.c
index 3214fba..a20623e 100644
--- a/ev.c
+++ b/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
@@ -268,6 +276,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 +357,12 @@ 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
+# define EFD_CLOEXEC O_CLOEXEC
+# endif
# ifdef __cplusplus
extern "C" {
# endif
@@ -350,6 +372,10 @@ int eventfd (unsigned int initval, int flags);
# endif
#endif
+#if EV_USE_SIGNALFD
+# include <sys/signalfd.h>
+#endif
+
/**/
#if EV_VERIFY >= 3
@@ -1106,10 +1132,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
@@ -1232,6 +1262,26 @@ ev_feed_signal_event (EV_P_ int signum)
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[4], *sip;
+
+ 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];
@@ -1476,6 +1526,9 @@ loop_init (EV_P_ unsigned int flags)
#if EV_USE_INOTIFY
fs_fd = -2;
#endif
+#if EV_USE_SIGNALFD
+ sigfd = -2;
+#endif
/* pid check not overridable via env */
#ifndef _WIN32
@@ -1522,8 +1575,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 +1590,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);
@@ -1649,7 +1712,6 @@ 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));
-
loop_init (EV_A_ flags);
if (ev_backend (EV_A))
@@ -2579,10 +2641,40 @@ ev_signal_start (EV_P_ ev_signal *w)
assert (("libev: ev_signal_start called with illegal signal number", w->signum > 0));
- evpipe_init (EV_A);
-
EV_FREQUENT_CHECK;
+#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 */
+
+ if (sigfd >= 0)
+ {
+ fd_intern (sigfd); /* doing it twice will not hurt */
+
+ 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);
+ }
+ else
+#endif
+ evpipe_init (EV_A);
+
{
#ifndef _WIN32
sigset_t full, prev;
@@ -2593,6 +2685,8 @@ ev_signal_start (EV_P_ ev_signal *w)
array_needsize (ANSIG, signals, signalmax, w->signum, array_init_zero);
#ifndef _WIN32
+ if (sigfd < 0)/*TODO*/
+ sigdelset (&prev, w->signum);
sigprocmask (SIG_SETMASK, &prev, 0);
#endif
}
@@ -2605,11 +2699,14 @@ ev_signal_start (EV_P_ ev_signal *w)
#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 (sigfd < 0) /*TODO*/
+ {
+ 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);
+ }
#endif
}
@@ -2629,7 +2726,18 @@ 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_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;
}
diff --git a/ev.pod b/ev.pod
index 289362b..194b439 100644
--- a/ev.pod
+++ b/ev.pod
@@ -2078,22 +2078,28 @@ signal one or more times. Even though signals are very asynchronous, libev
will try it's best to deliver signals synchronously, i.e. as part of the
normal event processing, like any other event.
+Note that only the default loop supports registering signal watchers
+currently.
+
If you want signals asynchronously, just use C<sigaction> as you would
do without libev and forget about sharing the signal. You can even use
C<ev_async> from a signal handler to synchronously wake up an event loop.
You can configure as many watchers as you like per signal. Only when the
-first watcher gets started will libev actually register a signal handler
-with the kernel (thus it coexists with your own signal handlers as long as
-you don't register any with libev for the same signal). Similarly, when
-the last signal watcher for a signal is stopped, libev will reset the
-signal handler to SIG_DFL (regardless of what it was set to before).
+first watcher gets started will libev actually register something with
+the kernel (thus it coexists with your own signal handlers as long as you
+don't register any with libev for the same signal).
+
+Both the signal mask state (C<sigprocmask>) and the signal handler state
+(C<sigaction>) are unspecified after starting a signal watcher (and after
+sotpping it again), that is, libev might or might not block the signal,
+and might or might not set or restore the installed signal handler.
If possible and supported, libev will install its handlers with
-C<SA_RESTART> behaviour enabled, so system calls should not be unduly
-interrupted. If you have a problem with system calls getting interrupted by
-signals you can block all signals in an C<ev_check> watcher and unblock
-them in an C<ev_prepare> watcher.
+C<SA_RESTART> (or equivalent) behaviour enabled, so system calls should
+not be unduly interrupted. If you have a problem with system calls getting
+interrupted by signals you can block all signals in an C<ev_check> watcher
+and unblock them in an C<ev_prepare> watcher.
=head3 Watcher-Specific Functions and Data Members
@@ -2148,8 +2154,8 @@ libev)
=head3 Process Interaction
Libev grabs C<SIGCHLD> as soon as the default event loop is
-initialised. This is necessary to guarantee proper behaviour even if
-the first child watcher is started after the child exits. The occurrence
+initialised. This is necessary to guarantee proper behaviour even if the
+first child watcher is started after the child exits. The occurrence
of C<SIGCHLD> is recorded asynchronously, but child reaping is done
synchronously as part of the event loop processing. Libev always reaps all
children, even ones not watched.
@@ -2169,7 +2175,8 @@ that, so other libev users can use C<ev_child> watchers freely.
Currently, the child watcher never gets stopped, even when the
child terminates, so normally one needs to stop the watcher in the
callback. Future versions of libev might stop the watcher automatically
-when a child exit is detected.
+when a child exit is detected (calling C<ev_child_stop> twice is not a
+problem).
=head3 Watcher-Specific Functions and Data Members
diff --git a/ev_vars.h b/ev_vars.h
index da73ca2..4e118d7 100644
--- a/ev_vars.h
+++ b/ev_vars.h
@@ -166,6 +166,12 @@ VARx(char, fs_2625) /* whether we are running in linux 2.6.25 or newer */
VAR (fs_hash, ANFS fs_hash [EV_INOTIFY_HASHSIZE])
#endif
+#if EV_USE_SIGNALFD || EV_GENWRAP
+VARx(int, sigfd)
+VARx(ev_io, sigfd_w)
+VARx(sigset_t, sigfd_set)
+#endif
+
#if EV_MINIMAL < 2 || EV_GENWRAP
VARx(unsigned int, loop_count) /* total number of loop iterations/blocks */
VARx(unsigned int, loop_depth) /* #ev_loop enters - #ev_loop leaves */
diff --git a/ev_wrap.h b/ev_wrap.h
index ba99da6..d5b0178 100644
--- a/ev_wrap.h
+++ b/ev_wrap.h
@@ -77,6 +77,9 @@
#define fs_w ((loop)->fs_w)
#define fs_2625 ((loop)->fs_2625)
#define fs_hash ((loop)->fs_hash)
+#define sigfd ((loop)->sigfd)
+#define sigfd_w ((loop)->sigfd_w)
+#define sigfd_set ((loop)->sigfd_set)
#define loop_count ((loop)->loop_count)
#define loop_depth ((loop)->loop_depth)
#define userdata ((loop)->userdata)
@@ -161,6 +164,9 @@
#undef fs_w
#undef fs_2625
#undef fs_hash
+#undef sigfd
+#undef sigfd_w
+#undef sigfd_set
#undef loop_count
#undef loop_depth
#undef userdata