Browse Source

*** empty log message ***

master
Marc Alexander Lehmann 12 years ago
parent
commit
5373133d94
5 changed files with 160 additions and 25 deletions
  1. +8
    -0
      Changes
  2. +121
    -13
      ev.c
  3. +19
    -12
      ev.pod
  4. +6
    -0
      ev_vars.h
  5. +6
    -0
      ev_wrap.h

+ 8
- 0
Changes View File

@ -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,


+ 121
- 13
ev.c View File

@ -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;
}


+ 19
- 12
ev.pod View File

@ -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


+ 6
- 0
ev_vars.h View File

@ -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 */


+ 6
- 0
ev_wrap.h View File

@ -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


Loading…
Cancel
Save