diff options
author | root <root> | 2009-07-19 01:36:34 +0000 |
---|---|---|
committer | root <root> | 2009-07-19 01:36:34 +0000 |
commit | dfa24c077cc325f0e21e169379aa6cac343cdaa2 (patch) | |
tree | 6678a0f6a8036a1467ab0c9d7dee48d47afdb910 | |
parent | c86e19d112a50d0f32e74f6f698f6dc81687da74 (diff) |
*** empty log message ***
-rw-r--r-- | Changes | 8 | ||||
-rw-r--r-- | ev.c | 134 | ||||
-rw-r--r-- | ev.pod | 31 | ||||
-rw-r--r-- | ev_vars.h | 6 | ||||
-rw-r--r-- | ev_wrap.h | 6 |
5 files changed, 160 insertions, 25 deletions
@@ -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, @@ -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; } @@ -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 @@ -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 */ @@ -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 |