diff options
-rw-r--r-- | Changes | 4 | ||||
-rw-r--r-- | ev.c | 32 | ||||
-rw-r--r-- | ev.h | 9 | ||||
-rw-r--r-- | ev.pod | 58 | ||||
-rw-r--r-- | ev_vars.h | 3 | ||||
-rw-r--r-- | ev_wrap.h | 4 |
6 files changed, 93 insertions, 17 deletions
@@ -3,13 +3,15 @@ Revision history for libev, a high-performance and full-featured event loop. TODO: move some other examples to common idioms? combining watchers, thread usage, coroutine switch? -TODO: /dev/null epoll breakage, maybe catch EPERM? TODO: frankenpoll 4.03 - support files, /dev/zero etc. the same way as select in the epoll backend, by generating events on our own. - define EV_READ/EV_WRITE as macros in event.h, as some programs use #ifdef to test for them. + - new (experimental) function: ev_feed_signal. + - new (to become default) EVFLAG_NOSIGMASK flag. + - new EVBACKEND_MASK symbol. 4.01 Fri Nov 5 21:51:29 CET 2010 - automake fucked it up, apparently, --add-missing -f is not quite enough @@ -1,7 +1,7 @@ /* * libev event processing core, watcher management * - * Copyright (c) 2007,2008,2009,2010 Marc Alexander Lehmann <libev@schmorp.de> + * Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann <libev@schmorp.de> * All rights reserved. * * Redistribution and use in source and binary forms, with or without modifica- @@ -1371,19 +1371,28 @@ pipecb (EV_P_ ev_io *iow, int revents) /*****************************************************************************/ -static void -ev_sighandler (int signum) +void +ev_feed_signal (int signum) { #if EV_MULTIPLICITY EV_P = signals [signum - 1].loop; + + if (!EV_A) + return; #endif + signals [signum - 1].pending = 1; + evpipe_write (EV_A_ &sig_pending); +} + +static void +ev_sighandler (int signum) +{ #ifdef _WIN32 signal (signum, ev_sighandler); #endif - signals [signum - 1].pending = 1; - evpipe_write (EV_A_ &sig_pending); + ev_feed_signal (signum); } void noinline @@ -1645,6 +1654,8 @@ loop_init (EV_P_ unsigned int flags) { if (!backend) { + origflags = flags; + #if EV_USE_REALTIME if (!have_realtime) { @@ -1699,7 +1710,7 @@ loop_init (EV_P_ unsigned int flags) sigfd = flags & EVFLAG_SIGNALFD ? -2 : -1; #endif - if (!(flags & 0x0000ffffU)) + if (!(flags & EVBACKEND_MASK)) flags |= ev_recommended_backends (); #if EV_USE_IOCP @@ -2881,9 +2892,12 @@ ev_signal_start (EV_P_ ev_signal *w) 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); + if (origflags & EVFLAG_NOSIGMASK) + { + sigemptyset (&sa.sa_mask); + sigaddset (&sa.sa_mask, w->signum); + sigprocmask (SIG_UNBLOCK, &sa.sa_mask, 0); + } #endif } @@ -1,7 +1,7 @@ /* * libev native API header * - * Copyright (c) 2007,2008,2009,2010 Marc Alexander Lehmann <libev@schmorp.de> + * Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann <libev@schmorp.de> * All rights reserved. * * Redistribution and use in source and binary forms, with or without modifica- @@ -491,7 +491,8 @@ enum { #if EV_COMPAT3 EVFLAG_NOSIGFD = 0, /* compatibility to pre-3.9 */ #endif - EVFLAG_SIGNALFD = 0x00200000U /* attempt to use signalfd */ + EVFLAG_SIGNALFD = 0x00200000U, /* attempt to use signalfd */ + EVFLAG_NOSIGMASK = 0x00400000U /* avoid modifying the signal mask */ }; /* method bits to be ored together */ @@ -502,7 +503,8 @@ enum { EVBACKEND_KQUEUE = 0x00000008U, /* bsd */ EVBACKEND_DEVPOLL = 0x00000010U, /* solaris 8 */ /* NYI */ EVBACKEND_PORT = 0x00000020U, /* solaris 10 */ - EVBACKEND_ALL = 0x0000003FU + EVBACKEND_ALL = 0x0000003FU, /* all known backends */ + EVBACKEND_MASK = 0x0000FFFFU /* all future backends */ }; #if EV_PROTOTYPES @@ -720,6 +722,7 @@ void ev_resume (EV_P); void ev_feed_event (EV_P_ void *w, int revents); void ev_feed_fd_event (EV_P_ int fd, int revents); #if EV_SIGNAL_ENABLE +void ev_feed_signal (int signum); void ev_feed_signal_event (EV_P_ int signum); #endif void ev_invoke (EV_P_ void *w, int revents); @@ -301,6 +301,19 @@ Example: This is basically the same thing that libev does internally, too. ... ev_set_syserr_cb (fatal_error); +=item ev_feed_signal (int signum) + +This function can be used to "simulate" a signal receive. It is completely +safe to call this function at any time, from any context, including signal +handlers or random threads. + +It's main use is to customise signal handling in your process, especially +in the presence of threads. For example, you could block signals +by default in all threads (and specifying C<EVFLAG_NOSIGMASK> when +creating any loops), and in one thread, use C<sigwait> or any other +mechanism to wait for signals, then "deliver" them to libev by calling +C<ev_feed_signal>. + =back =head1 FUNCTIONS CONTROLLING EVENT LOOPS @@ -421,6 +434,18 @@ Signalfd will not be used by default as this changes your signal mask, and there are a lot of shoddy libraries and programs (glib's threadpool for example) that can't properly initialise their signal masks. +=item C<EVFLAG_NOSIGMASK> + +When this flag is specified, then libev will avoid to modify the signal +mask. Specifically, this means you ahve to make sure signals are unblocked +when you want to receive them. + +This behaviour is useful when you want to do your own signal handling, or +want to handle signals only in specific threads and want to avoid libev +unblocking the signals. + +This flag's behaviour will become the default in future versions of libev. + =item C<EVBACKEND_SELECT> (value 1, portable select backend) This is your standard select(2) backend. Not I<completely> standard, as @@ -582,7 +607,15 @@ Try all backends (even potentially broken ones that wouldn't be tried with C<EVFLAG_AUTO>). Since this is a mask, you can do stuff such as C<EVBACKEND_ALL & ~EVBACKEND_KQUEUE>. -It is definitely not recommended to use this flag. +It is definitely not recommended to use this flag, use whatever +C<ev_recommended_backends ()> returns, or simply do not specify a backend +at all. + +=item C<EVBACKEND_MASK> + +Not a backend at all, but a mask to select all backend bits from a +C<flags> value, in case you want to mask out any backends from a flags +value (e.g. when modifying the C<LIBEV_FLAGS> environment variable). =back @@ -2322,6 +2355,20 @@ So I can't stress this enough: I<If you do not reset your signal mask when you expect it to be empty, you have a race condition in your code>. This is not a libev-specific thing, this is true for most event libraries. +=head3 The special problem of threads signal handling + +POSIX threads has problematic signal handling semantics, specifically, +a lot of functionality (sigfd, sigwait etc.) only really works if all +threads in a process block signals, which is hard to achieve. + +When you want to use sigwait (or mix libev signal handling with your own +for the same signals), you can tackle this problem by globally blocking +all signals before creating any threads (or creating them with a fully set +sigprocmask) and also specifying the C<EVFLAG_NOSIGMASK> when creating +loops. Then designate one thread as "signal receiver thread" which handles +these signals. You can pass on any signals that libev might be interested +in by calling C<ev_feed_signal>. + =head3 Watcher-Specific Functions and Data Members =over 4 @@ -3177,7 +3224,10 @@ it by calling C<ev_async_send>, which is thread- and signal safe. This functionality is very similar to C<ev_signal> watchers, as signals, too, are asynchronous in nature, and signals, too, will be compressed (i.e. the number of callback invocations may be less than the number of -C<ev_async_sent> calls). +C<ev_async_sent> calls). In fact, you could use signal watchers as a kind +of "global async watchers" by using a watcher on an otherwise unused +signal, and C<ev_feed_signal> to signal this watcher from another thread, +even without knowing which loop owns the signal. Unlike C<ev_signal> watchers, C<ev_async> works with any event loop, not just the default loop. @@ -3363,8 +3413,8 @@ the given events it. =item ev_feed_signal_event (loop, int signum) -Feed an event as if the given signal occurred (C<loop> must be the default -loop!). +Feed an event as if the given signal occurred. See also C<ev_feed_signal>, +which is async-safe. =back @@ -180,12 +180,15 @@ VAR (fs_hash, ANFS fs_hash [EV_INOTIFY_HASHSIZE]) #endif VARx(EV_ATOMIC_T, sig_pending) +VARx(int, nosigmask) #if EV_USE_SIGNALFD || EV_GENWRAP VARx(int, sigfd) VARx(ev_io, sigfd_w) VARx(sigset_t, sigfd_set) #endif +VARx(unsigned int, origflags) /* original loop flags */ + #if EV_FEATURE_API || EV_GENWRAP VARx(unsigned int, loop_count) /* total number of loop iterations/blocks */ VARx(unsigned int, loop_depth) /* #ev_run enters - #ev_run leaves */ @@ -85,9 +85,11 @@ #define fs_2625 ((loop)->fs_2625) #define fs_hash ((loop)->fs_hash) #define sig_pending ((loop)->sig_pending) +#define nosigmask ((loop)->nosigmask) #define sigfd ((loop)->sigfd) #define sigfd_w ((loop)->sigfd_w) #define sigfd_set ((loop)->sigfd_set) +#define origflags ((loop)->origflags) #define loop_count ((loop)->loop_count) #define loop_depth ((loop)->loop_depth) #define userdata ((loop)->userdata) @@ -180,9 +182,11 @@ #undef fs_2625 #undef fs_hash #undef sig_pending +#undef nosigmask #undef sigfd #undef sigfd_w #undef sigfd_set +#undef origflags #undef loop_count #undef loop_depth #undef userdata |