summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorroot <root>2011-01-10 01:58:54 +0000
committerroot <root>2011-01-10 01:58:54 +0000
commitfdf8e637ed5779a72783db49d403f4f8b2e76de0 (patch)
tree4269b403eae4c81717b29963e66ce01eb3b9ec39
parentf1c5ab398807a485aff4f2b412b8974fe7f62d0f (diff)
*** empty log message ***
-rw-r--r--Changes4
-rw-r--r--ev.c32
-rw-r--r--ev.h9
-rw-r--r--ev.pod58
-rw-r--r--ev_vars.h3
-rw-r--r--ev_wrap.h4
6 files changed, 93 insertions, 17 deletions
diff --git a/Changes b/Changes
index cfd1fbd..604f5ff 100644
--- a/Changes
+++ b/Changes
@@ -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
diff --git a/ev.c b/ev.c
index 512e15d..c7e5077 100644
--- a/ev.c
+++ b/ev.c
@@ -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
}
diff --git a/ev.h b/ev.h
index 1f9d8d1..75017f3 100644
--- a/ev.h
+++ b/ev.h
@@ -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);
diff --git a/ev.pod b/ev.pod
index c2652cc..b682667 100644
--- a/ev.pod
+++ b/ev.pod
@@ -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
diff --git a/ev_vars.h b/ev_vars.h
index 5de913d..17d77c8 100644
--- a/ev_vars.h
+++ b/ev_vars.h
@@ -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 */
diff --git a/ev_wrap.h b/ev_wrap.h
index 1c1d37f..2c195c5 100644
--- a/ev_wrap.h
+++ b/ev_wrap.h
@@ -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