prelude-manager/master: Upgrade to libev 3.9
[email protected] Fri, 29 Jan 2010 18:39:22 +0100 (CET)
| Newsgroups | gmane.comp.security.ids.prelude.cvs |
|---|---|
| Message-ID | <[email protected]> |
commit 717fec2d74081e3ec7be40a4395f653575d6eee5 Author: Yoann Vandoorselaere <[email protected]> Date: Wed Jan 20 19:05:15 2010 +0100 Upgrade to libev 3.9 ======================================== libev/Changes | 64 +++++ libev/LICENSE | 2 +- libev/ev.c | 684 +++++++++++++++++++++++++++++++++++++++-------------- libev/ev.h | 86 +++++-- libev/ev_epoll.c | 19 ++- libev/ev_kqueue.c | 4 +- libev/ev_poll.c | 8 +- libev/ev_port.c | 6 +- libev/ev_select.c | 12 +- libev/ev_vars.h | 23 ++- libev/ev_win32.c | 27 +- libev/ev_wrap.h | 28 ++- libev/libev.m4 | 6 +- 13 files changed, 734 insertions(+), 235 deletions(-) ======================================== diff --git a/libev/Changes b/libev/Changes index 25b9adc..a9e0ac4 100644 --- a/libev/Changes +++ b/libev/Changes @@ -1,5 +1,69 @@ Revision history for libev, a high-performance and full-featured event loop. +3.9 Thu Dec 31 07:59:59 CET 2009 + - signalfd is no longer used by default and has to be requested + explicitly - this means that easy to catch bugs become hard to + catch race conditions, but the users have spoken. + - point out the unspecified signal mask in the documentation, and + that this is a race condition regardless of EV_SIGNALFD. + - backport inotify code to C89. + - inotify file descriptors could leak into child processes. + - ev_stat watchers could keep an errornous extra ref on the loop, + preventing exit when unregistering all watchers (testcases + provided by [email protected]). + - implement EV_WIN32_HANDLE_TO_FD and EV_WIN32_CLOSE_FD configuration + symbols to make it easier for apps to do their own fd management. + - support EV_IDLE_ENABLE being disabled in ev++.h + (patch by Didier Spezia). + - take advantage of inotify_init1, if available, to set cloexec/nonblock + on fd creation, to avoid races. + - the signal handling pipe wasn't always initialised under windows + (analysed by lekma). + - changed minimum glibc requirement from glibc 2.9 to 2.7, for + signalfd. + - add missing string.h include (Denis F. Latypoff). + - only replace ev_stat.prev when we detect an actual difference, + so prev is (almost) always different to attr. this might + have caused the probems with 04_stat.t. + - add ev::timer->remaining () method to C++ API. + +3.8 Sun Aug 9 14:30:45 CEST 2009 + - incompatible change: do not necessarily reset signal handler + to SIG_DFL when a sighandler is stopped. + - ev_default_destroy did not properly free or zero some members, + potentially causing crashes and memory corruption on repated + ev_default_destroy/ev_default_loop calls. + - 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. + - take advantage of some GNU/Linux calls to set cloexec/nonblock + on fd creation, to avoid race conditions. + +3.7 Fri Jul 17 16:36:32 CEST 2009 + - ev_unloop and ev_loop wrongly used a global variable to exit loops, + instead of using a per-loop variable (bug caught by accident...). + - the ev_set_io_collect_interval interpretation has changed. + - add new functionality: ev_set_userdata, ev_userdata, + ev_set_invoke_pending_cb, ev_set_loop_release_cb, + ev_invoke_pending, ev_pending_count, together with a long example + about thread locking. + - add ev_timer_remaining (as requested by Denis F. Latypoff). + - add ev_loop_depth. + - calling ev_unloop in fork/prepare watchers will no longer poll + for new events. + - Denis F. Latypoff corrected many typos in example code snippets. + - honor autoconf detection of EV_USE_CLOCK_SYSCALL, also double- + check that the syscall number is available before trying to + use it (reported by ry@tinyclouds). + - use GetSystemTimeAsFileTime instead of _timeb on windows, for + slightly higher accuracy. + - properly declare ev_loop_verify and ev_now_update even when + !EV_MULTIPLICITY. + - do not compile in any priority code when EV_MAXPRI == EV_MINPRI. + - support EV_MINIMAL==2 for a reduced API. + - actually 0-initialise struct sigaction when installing signals. + - add section on hibernate and stopped processes to ev_timer docs. + 3.6 Tue Apr 28 02:49:30 CEST 2009 - multiple timers becoming ready within an event loop iteration will be invoked in the "correct" order now. diff --git a/libev/LICENSE b/libev/LICENSE index df62c4f..7fa0e9f 100644 --- a/libev/LICENSE +++ b/libev/LICENSE @@ -1,4 +1,4 @@ -All files in libev are Copyright (C)2007,2008 Marc Alexander Lehmann. +All files in libev are Copyright (C)2007,2008,2009 Marc Alexander Lehmann. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are diff --git a/libev/ev.c b/libev/ev.c index a1a8ce1..ccd202b 100644 --- a/libev/ev.c +++ b/libev/ev.c @@ -59,6 +59,8 @@ extern "C" { # define EV_USE_MONOTONIC 1 # endif # endif +# elif !defined(EV_USE_CLOCK_SYSCALL) +# define EV_USE_CLOCK_SYSCALL 0 # endif # if HAVE_CLOCK_GETTIME @@ -133,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 @@ -145,6 +155,7 @@ extern "C" { #include <math.h> #include <stdlib.h> +#include <string.h> #include <fcntl.h> #include <stddef.h> @@ -178,6 +189,33 @@ extern "C" { /* this block tries to deduce configuration from header-defined symbols and defaults */ +/* try to deduce the maximum number of signals on this platform */ +#if defined (EV_NSIG) +/* use what's provided */ +#elif defined (NSIG) +# define EV_NSIG (NSIG) +#elif defined(_NSIG) +# define EV_NSIG (_NSIG) +#elif defined (SIGMAX) +# define EV_NSIG (SIGMAX+1) +#elif defined (SIG_MAX) +# define EV_NSIG (SIG_MAX+1) +#elif defined (_SIG_MAX) +# define EV_NSIG (_SIG_MAX+1) +#elif defined (MAXSIG) +# define EV_NSIG (MAXSIG+1) +#elif defined (MAX_SIG) +# define EV_NSIG (MAX_SIG+1) +#elif defined (SIGARRAYSIZE) +# define EV_NSIG SIGARRAYSIZE /* Assume ary[SIGARRAYSIZE] */ +#elif defined (_sys_nsig) +# define EV_NSIG (_sys_nsig) /* Solaris 2.5 */ +#else +# error "unable to find value for NSIG, please report" +/* to make it compile regardless, just remove the above line */ +# define EV_NSIG 65 +#endif + #ifndef EV_USE_CLOCK_SYSCALL # if __linux && __GLIBC__ >= 2 # define EV_USE_CLOCK_SYSCALL 1 @@ -266,6 +304,14 @@ extern "C" { # endif #endif +#ifndef EV_USE_SIGNALFD +# if __linux && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 7)) +# 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 @@ -284,6 +330,20 @@ extern "C" { # define EV_HEAP_CACHE_AT !EV_MINIMAL #endif +/* on linux, we can use a (slow) syscall to avoid a dependency on pthread, */ +/* which makes programs even slower. might work on other unices, too. */ +#if EV_USE_CLOCK_SYSCALL +# include <syscall.h> +# ifdef SYS_clock_gettime +# define clock_gettime(id, ts) syscall (SYS_clock_gettime, (id), (ts)) +# undef EV_USE_MONOTONIC +# define EV_USE_MONOTONIC 1 +# else +# undef EV_USE_CLOCK_SYSCALL +# define EV_USE_CLOCK_SYSCALL 0 +# endif +#endif + /* this block fixes any misconfiguration where we know we run into trouble otherwise */ #ifndef CLOCK_MONOTONIC @@ -322,18 +382,19 @@ extern "C" { # include <winsock.h> #endif -/* on linux, we can use a (slow) syscall to avoid a dependency on pthread, */ -/* which makes programs even slower. might work on other unices, too. */ -#if EV_USE_CLOCK_SYSCALL -# include <syscall.h> -# define clock_gettime(id, ts) syscall (SYS_clock_gettime, (id), (ts)) -# undef EV_USE_MONOTONIC -# define EV_USE_MONOTONIC 1 -#endif - #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 +# ifdef O_CLOEXEC +# define EFD_CLOEXEC O_CLOEXEC +# else +# define EFD_CLOEXEC 02000000 +# endif +# endif # ifdef __cplusplus extern "C" { # endif @@ -343,6 +404,35 @@ int eventfd (unsigned int initval, int flags); # endif #endif +#if EV_USE_SIGNALFD +/* our minimum requirement is glibc 2.7 which has the stub, but not the header */ +# include <stdint.h> +# ifndef SFD_NONBLOCK +# define SFD_NONBLOCK O_NONBLOCK +# endif +# ifndef SFD_CLOEXEC +# ifdef O_CLOEXEC +# define SFD_CLOEXEC O_CLOEXEC +# else +# define SFD_CLOEXEC 02000000 +# endif +# endif +# ifdef __cplusplus +extern "C" { +# endif +int signalfd (int fd, const sigset_t *mask, int flags); + +struct signalfd_siginfo +{ + uint32_t ssi_signo; + char pad[128 - sizeof (uint32_t)]; +}; +# ifdef __cplusplus +} +# endif +#endif + + /**/ #if EV_VERIFY >= 3 @@ -363,7 +453,6 @@ int eventfd (unsigned int initval, int flags); #define MIN_TIMEJUMP 1. /* minimum timejump that gets detected (if monotonic clock available) */ #define MAX_BLOCKTIME 59.743 /* never wait longer than this time (to detect time jumps) */ -/*#define CLEANUP_INTERVAL (MAX_BLOCKTIME * 5.) /* how often to try to free memory and re-check fds, TODO */ #if __GNUC__ >= 4 # define expect(expr,value) __builtin_expect ((expr),(value)) @@ -386,8 +475,13 @@ int eventfd (unsigned int initval, int flags); # define inline_speed static inline #endif -#define NUMPRI (EV_MAXPRI - EV_MINPRI + 1) -#define ABSPRI(w) (((W)w)->priority - EV_MINPRI) +#define NUMPRI (EV_MAXPRI - EV_MINPRI + 1) + +#if EV_MINPRI == EV_MAXPRI +# define ABSPRI(w) (((W)w), 0) +#else +# define ABSPRI(w) (((W)w)->priority - EV_MINPRI) +#endif #define EMPTY /* required for microsofts broken pseudo-c compiler */ #define EMPTY2(a,b) /* used to suppress some warnings */ @@ -409,6 +503,16 @@ static EV_ATOMIC_T have_realtime; /* did clock_gettime (CLOCK_REALTIME) work? */ static EV_ATOMIC_T have_monotonic; /* did clock_gettime (CLOCK_MONOTONIC) work? */ #endif +#ifndef EV_FD_TO_WIN32_HANDLE +# define EV_FD_TO_WIN32_HANDLE(fd) _get_osfhandle (fd) +#endif +#ifndef EV_WIN32_HANDLE_TO_FD +# define EV_WIN32_HANDLE_TO_FD(handle) _open_osfhandle (fd, 0) +#endif +#ifndef EV_WIN32_CLOSE_FD +# define EV_WIN32_CLOSE_FD(fd) close (fd) +#endif + #ifdef _WIN32 # include "ev_win32.c" #endif @@ -480,12 +584,15 @@ ev_realloc (void *ptr, long size) /*****************************************************************************/ +/* set in reify when reification needed */ +#define EV_ANFD_REIFY 1 + /* file descriptor info structure */ typedef struct { WL head; unsigned char events; /* the events watched for */ - unsigned char reify; /* flag set when this ANFD needs reification */ + unsigned char reify; /* flag set when this ANFD needs reification (EV_ANFD_REIFY, EV__IOFDSET) */ unsigned char emask; /* the epoll backend stores the actual kernel mask in here */ unsigned char unused; #if EV_USE_EPOLL @@ -557,8 +664,21 @@ typedef struct #endif +#if EV_MINIMAL < 2 +# define EV_RELEASE_CB if (expect_false (release_cb)) release_cb (EV_A) +# define EV_ACQUIRE_CB if (expect_false (acquire_cb)) acquire_cb (EV_A) +# define EV_INVOKE_PENDING invoke_cb (EV_A) +#else +# define EV_RELEASE_CB (void)0 +# define EV_ACQUIRE_CB (void)0 +# define EV_INVOKE_PENDING ev_invoke_pending (EV_A) +#endif + +#define EVUNLOOP_RECURSE 0x80 + /*****************************************************************************/ +#ifndef EV_HAVE_EV_TIME ev_tstamp ev_time (void) { @@ -575,6 +695,7 @@ ev_time (void) gettimeofday (&tv, 0); return tv.tv_sec + tv.tv_usec * 1e-6; } +#endif inline_size ev_tstamp get_clock (void) @@ -620,7 +741,7 @@ ev_sleep (ev_tstamp delay) tv.tv_usec = (long)((delay - (ev_tstamp)(tv.tv_sec)) * 1e6); /* here we rely on sys/time.h + sys/types.h + unistd.h providing select */ - /* somehting nto guaranteed by newer posix versions, but guaranteed */ + /* something not guaranteed by newer posix versions, but guaranteed */ /* by older ones */ select (0, 0, 0, 0, &tv); #endif @@ -738,7 +859,7 @@ queue_events (EV_P_ W *events, int eventcnt, int type) /*****************************************************************************/ inline_speed void -fd_event (EV_P_ int fd, int revents) +fd_event_nc (EV_P_ int fd, int revents) { ANFD *anfd = anfds + fd; ev_io *w; @@ -752,11 +873,22 @@ fd_event (EV_P_ int fd, int revents) } } +/* do not submit kernel events for fds that have reify set */ +/* because that means they changed while we were polling for new events */ +inline_speed void +fd_event (EV_P_ int fd, int revents) +{ + ANFD *anfd = anfds + fd; + + if (expect_true (!anfd->reify)) + fd_event_nc (EV_A_ fd, revents); +} + void ev_feed_fd_event (EV_P_ int fd, int revents) { if (fd >= 0 && fd < anfdmax) - fd_event (EV_A_ fd, revents); + fd_event_nc (EV_A_ fd, revents); } /* make sure the external fd watch events are in-sync */ @@ -781,11 +913,7 @@ fd_reify (EV_P) if (events) { unsigned long arg; - #ifdef EV_FD_TO_WIN32_HANDLE - anfd->handle = EV_FD_TO_WIN32_HANDLE (fd); - #else - anfd->handle = _get_osfhandle (fd); - #endif + anfd->handle = EV_FD_TO_WIN32_HANDLE (fd); assert (("libev: only socket fds supported in this configuration", ioctlsocket (anfd->handle, FIONREAD, &arg) == 0)); } #endif @@ -866,7 +994,7 @@ fd_enomem (EV_P) if (anfds [fd].events) { fd_kill (EV_A_ fd); - return; + break; } } @@ -881,7 +1009,7 @@ fd_rearm_all (EV_P) { anfds [fd].events = 0; anfds [fd].emask = 0; - fd_change (EV_A_ fd, EV__IOFDSET | 1); + fd_change (EV_A_ fd, EV__IOFDSET | EV_ANFD_REIFY); } } @@ -966,7 +1094,7 @@ downheap (ANHE *heap, int N, int k) { int c = k << 1; - if (c > N + HEAP0 - 1) + if (c >= N + HEAP0) break; c += c + 1 < N + HEAP0 && ANHE_at (heap [c]) > ANHE_at (heap [c + 1]) @@ -1012,7 +1140,7 @@ upheap (ANHE *heap, int k) inline_size void adjustheap (ANHE *heap, int N, int k) { - if (k > HEAP0 && ANHE_at (heap [HPARENT (k)]) >= ANHE_at (heap [k])) + if (k > HEAP0 && ANHE_at (heap [k]) <= ANHE_at (heap [HPARENT (k)])) upheap (heap, k); else downheap (heap, N, k); @@ -1035,14 +1163,14 @@ reheap (ANHE *heap, int N) /* associate signal watchers to a signal signal */ typedef struct { + EV_ATOMIC_T pending; +#if EV_MULTIPLICITY + EV_P; +#endif WL head; - EV_ATOMIC_T gotsig; } ANSIG; -static ANSIG *signals; -static int signalmax; - -static EV_ATOMIC_T gotsig; +static ANSIG signals [EV_NSIG - 1]; /*****************************************************************************/ @@ -1066,10 +1194,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 @@ -1116,6 +1248,8 @@ evpipe_write (EV_P_ EV_ATOMIC_T *flag) static void pipecb (EV_P_ ev_io *iow, int revents) { + int i; + #if EV_USE_EVENTFD if (evfd >= 0) { @@ -1129,21 +1263,19 @@ pipecb (EV_P_ ev_io *iow, int revents) read (evpipe [0], &dummy, 1); } - if (gotsig && ev_is_default_loop (EV_A)) + if (sig_pending) { - int signum; - gotsig = 0; + sig_pending = 0; - for (signum = signalmax; signum--; ) - if (signals [signum].gotsig) - ev_feed_signal_event (EV_A_ signum + 1); + for (i = EV_NSIG - 1; i--; ) + if (expect_false (signals [i].pending)) + ev_feed_signal_event (EV_A_ i + 1); } #if EV_ASYNC_ENABLE - if (gotasync) + if (async_pending) { - int i; - gotasync = 0; + async_pending = 0; for (i = asynccnt; i--; ) if (asyncs [i]->sent) @@ -1161,15 +1293,15 @@ static void ev_sighandler (int signum) { #if EV_MULTIPLICITY - struct ev_loop *loop = &default_loop_struct; + EV_P = signals [signum - 1].loop; #endif #if _WIN32 signal (signum, ev_sighandler); #endif - signals [signum - 1].gotsig = 1; - evpipe_write (EV_A_ &gotsig); + signals [signum - 1].pending = 1; + evpipe_write (EV_A_ &sig_pending); } void noinline @@ -1177,21 +1309,45 @@ ev_feed_signal_event (EV_P_ int signum) { WL w; -#if EV_MULTIPLICITY - assert (("libev: feeding signal events is only supported in the default loop", loop == ev_default_loop_ptr)); -#endif + if (expect_false (signum <= 0 || signum > EV_NSIG)) + return; --signum; - if (signum < 0 || signum >= signalmax) +#if EV_MULTIPLICITY + /* it is permissible to try to feed a signal to the wrong loop */ + /* or, likely more useful, feeding a signal nobody is waiting for */ + + if (expect_false (signals [signum].loop != EV_A)) return; +#endif - signals [signum].gotsig = 0; + signals [signum].pending = 0; for (w = signals [signum].head; w; w = w->next) 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[2], *sip; /* these structs are big */ + + 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]; @@ -1345,12 +1501,19 @@ ev_backend (EV_P) return backend; } +#if EV_MINIMAL < 2 unsigned int ev_loop_count (EV_P) { return loop_count; } +unsigned int +ev_loop_depth (EV_P) +{ + return loop_depth; +} + void ev_set_io_collect_interval (EV_P_ ev_tstamp interval) { @@ -1363,6 +1526,30 @@ ev_set_timeout_collect_interval (EV_P_ ev_tstamp interval) timeout_blocktime = interval; } +void +ev_set_userdata (EV_P_ void *data) +{ + userdata = data; +} + +void * +ev_userdata (EV_P) +{ + return userdata; +} + +void ev_set_invoke_pending_cb (EV_P_ void (*invoke_pending_cb)(EV_P)) +{ + invoke_cb = invoke_pending_cb; +} + +void ev_set_loop_release_cb (EV_P_ void (*release)(EV_P), void (*acquire)(EV_P)) +{ + release_cb = release; + acquire_cb = acquire; +} +#endif + /* initialise a loop structure, must be zero-initialised */ static void noinline loop_init (EV_P_ unsigned int flags) @@ -1389,31 +1576,40 @@ loop_init (EV_P_ unsigned int flags) } #endif + /* pid check not overridable via env */ +#ifndef _WIN32 + if (flags & EVFLAG_FORKCHECK) + curpid = getpid (); +#endif + + if (!(flags & EVFLAG_NOENV) + && !enable_secure () + && getenv ("LIBEV_FLAGS")) + flags = atoi (getenv ("LIBEV_FLAGS")); + ev_rt_now = ev_time (); mn_now = get_clock (); now_floor = mn_now; rtmn_diff = ev_rt_now - mn_now; +#if EV_MINIMAL < 2 + invoke_cb = ev_invoke_pending; +#endif io_blocktime = 0.; timeout_blocktime = 0.; backend = 0; backend_fd = -1; - gotasync = 0; + sig_pending = 0; +#if EV_ASYNC_ENABLE + async_pending = 0; +#endif #if EV_USE_INOTIFY - fs_fd = -2; + fs_fd = flags & EVFLAG_NOINOTIFY ? -1 : -2; #endif - - /* pid check not overridable via env */ -#ifndef _WIN32 - if (flags & EVFLAG_FORKCHECK) - curpid = getpid (); +#if EV_USE_SIGNALFD + sigfd = flags & EVFLAG_SIGNALFD ? -2 : -1; #endif - if (!(flags & EVFLAG_NOENV) - && !enable_secure () - && getenv ("LIBEV_FLAGS")) - flags = atoi (getenv ("LIBEV_FLAGS")); - if (!(flags & 0x0000ffffU)) flags |= ev_recommended_backends (); @@ -1448,8 +1644,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) @@ -1458,11 +1654,16 @@ loop_destroy (EV_P) if (evpipe [0] >= 0) { - close (evpipe [0]); - close (evpipe [1]); + EV_WIN32_CLOSE_FD (evpipe [0]); + EV_WIN32_CLOSE_FD (evpipe [1]); } } +#if EV_USE_SIGNALFD + if (ev_is_active (&sigfd_w)) + close (sigfd); +#endif + #if EV_USE_INOTIFY if (fs_fd >= 0) close (fs_fd); @@ -1495,7 +1696,7 @@ loop_destroy (EV_P) #endif } - ev_free (anfds); anfdmax = 0; + ev_free (anfds); anfds = 0; anfdmax = 0; /* have to use the microsoft-never-gets-it-right macro */ array_free (rfeed, EMPTY); @@ -1540,9 +1741,9 @@ loop_fork (EV_P) { /* this "locks" the handlers against writing to the pipe */ /* while we modify the fd vars */ - gotsig = 1; + sig_pending = 1; #if EV_ASYNC_ENABLE - gotasync = 1; + async_pending = 1; #endif ev_ref (EV_A); @@ -1555,8 +1756,8 @@ loop_fork (EV_P) if (evpipe [0] >= 0) { - close (evpipe [0]); - close (evpipe [1]); + EV_WIN32_CLOSE_FD (evpipe [0]); + EV_WIN32_CLOSE_FD (evpipe [1]); } evpipe_init (EV_A); @@ -1572,14 +1773,13 @@ loop_fork (EV_P) struct ev_loop * 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)); + EV_P = (struct ev_loop *)ev_malloc (sizeof (struct ev_loop)); + memset (EV_A, 0, sizeof (struct ev_loop)); loop_init (EV_A_ flags); if (ev_backend (EV_A)) - return loop; + return EV_A; return 0; } @@ -1596,6 +1796,7 @@ ev_loop_fork (EV_P) { postfork = 1; /* must be in line with ev_default_fork */ } +#endif /* multiplicity */ #if EV_VERIFY static void noinline @@ -1633,6 +1834,7 @@ array_verify (EV_P_ W *ws, int cnt) } #endif +#if EV_MINIMAL < 2 void ev_loop_verify (EV_P) { @@ -1691,12 +1893,11 @@ ev_loop_verify (EV_P) # if 0 for (w = (ev_child *)childs [chain & (EV_PID_HASHSIZE - 1)]; w; w = (ev_child *)((WL)w)->next) - for (signum = signalmax; signum--; ) if (signals [signum].gotsig) + for (signum = EV_NSIG; signum--; ) if (signals [signum].pending) # endif #endif } - -#endif /* multiplicity */ +#endif #if EV_MULTIPLICITY struct ev_loop * @@ -1709,7 +1910,7 @@ ev_default_loop (unsigned int flags) if (!ev_default_loop_ptr) { #if EV_MULTIPLICITY - struct ev_loop *loop = ev_default_loop_ptr = &default_loop_struct; + EV_P = ev_default_loop_ptr = &default_loop_struct; #else ev_default_loop_ptr = 1; #endif @@ -1736,7 +1937,7 @@ void ev_default_destroy (void) { #if EV_MULTIPLICITY - struct ev_loop *loop = ev_default_loop_ptr; + EV_P = ev_default_loop_ptr; #endif ev_default_loop_ptr = 0; @@ -1753,7 +1954,7 @@ void ev_default_fork (void) { #if EV_MULTIPLICITY - struct ev_loop *loop = ev_default_loop_ptr; + EV_P = ev_default_loop_ptr; #endif postfork = 1; /* must be in line with ev_loop_fork */ @@ -1767,8 +1968,20 @@ ev_invoke (EV_P_ void *w, int revents) EV_CB_INVOKE ((W)w, revents); } -inline_speed void -call_pending (EV_P) +unsigned int +ev_pending_count (EV_P) +{ + int pri; + unsigned int count = 0; + + for (pri = NUMPRI; pri--; ) + count += pendingcnt [pri]; + + return count; +} + +void noinline +ev_invoke_pending (EV_P) { int pri; @@ -1950,11 +2163,10 @@ timers_reschedule (EV_P_ ev_tstamp adjust) inline_speed void time_update (EV_P_ ev_tstamp max_block) { - int i; - #if EV_USE_MONOTONIC if (expect_true (have_monotonic)) { + int i; ev_tstamp odiff = rtmn_diff; mn_now = get_clock (); @@ -2014,14 +2226,18 @@ time_update (EV_P_ ev_tstamp max_block) } } -static int loop_done; - void ev_loop (EV_P_ int flags) { +#if EV_MINIMAL < 2 + ++loop_depth; +#endif + + assert (("libev: ev_loop recursion during release detected", loop_done != EVUNLOOP_RECURSE)); + loop_done = EVUNLOOP_CANCEL; - call_pending (EV_A); /* in case we recurse, ensure ordering stays nice and clean */ + EV_INVOKE_PENDING; /* in case we recurse, ensure ordering stays nice and clean */ do { @@ -2044,7 +2260,7 @@ ev_loop (EV_P_ int flags) if (forkcnt) { queue_events (EV_A_ (W *)forks, forkcnt, EV_FORK); - call_pending (EV_A); + EV_INVOKE_PENDING; } #endif @@ -2052,9 +2268,12 @@ ev_loop (EV_P_ int flags) if (expect_false (preparecnt)) { queue_events (EV_A_ (W *)prepares, preparecnt, EV_PREPARE); - call_pending (EV_A); + EV_INVOKE_PENDING; } + if (expect_false (loop_done)) + break; + /* we might have forked, so reify kernel state if necessary */ if (expect_false (postfork)) loop_fork (EV_A); @@ -2069,6 +2288,9 @@ ev_loop (EV_P_ int flags) if (expect_true (!(flags & EVLOOP_NONBLOCK || idleall || !activecnt))) { + /* remember old timestamp for io_blocktime calculation */ + ev_tstamp prev_mn_now = mn_now; + /* update time to cancel out callback processing overhead */ time_update (EV_A_ 1e100); @@ -2088,23 +2310,32 @@ ev_loop (EV_P_ int flags) } #endif + /* don't let timeouts decrease the waittime below timeout_blocktime */ if (expect_false (waittime < timeout_blocktime)) waittime = timeout_blocktime; - sleeptime = waittime - backend_fudge; + /* extra check because io_blocktime is commonly 0 */ + if (expect_false (io_blocktime)) + { + sleeptime = io_blocktime - (mn_now - prev_mn_now); - if (expect_true (sleeptime > io_blocktime)) - sleeptime = io_blocktime; + if (sleeptime > waittime - backend_fudge) + sleeptime = waittime - backend_fudge; - if (sleeptime) - { - ev_sleep (sleeptime); - waittime -= sleeptime; + if (expect_true (sleeptime > 0.)) + { + ev_sleep (sleeptime); + waittime -= sleeptime; + } } } +#if EV_MINIMAL < 2 ++loop_count; +#endif + assert ((loop_done = EVUNLOOP_RECURSE, 1)); /* assert for side effect */ backend_poll (EV_A_ waittime); + assert ((loop_done = EVUNLOOP_CANCEL, 1)); /* assert for side effect */ /* update ev_rt_now, do magic */ time_update (EV_A_ waittime + sleeptime); @@ -2125,7 +2356,7 @@ ev_loop (EV_P_ int flags) if (expect_false (checkcnt)) queue_events (EV_A_ (W *)checks, checkcnt, EV_CHECK); - call_pending (EV_A); + EV_INVOKE_PENDING; } while (expect_true ( activecnt @@ -2135,6 +2366,10 @@ ev_loop (EV_P_ int flags) if (loop_done == EVUNLOOP_ONE) loop_done = EVUNLOOP_CANCEL; + +#if EV_MINIMAL < 2 + --loop_depth; +#endif } void @@ -2195,10 +2430,10 @@ wlist_del (WL *head, WL elem) { while (*head) { - if (*head == elem) + if (expect_true (*head == elem)) { *head = elem->next; - return; + break; } head = &(*head)->next; @@ -2236,10 +2471,10 @@ ev_clear_pending (EV_P_ void *w) inline_size void pri_adjust (EV_P_ W w) { - int pri = w->priority; + int pri = ev_priority (w); pri = pri < EV_MINPRI ? EV_MINPRI : pri; pri = pri > EV_MAXPRI ? EV_MAXPRI : pri; - w->priority = pri; + ev_set_priority (w, pri); } inline_speed void @@ -2276,7 +2511,7 @@ ev_io_start (EV_P_ ev_io *w) array_needsize (ANFD, anfds, anfdmax, fd + 1, array_init_zero); wlist_add (&anfds[fd].head, (WL)w); - fd_change (EV_A_ fd, w->events & EV__IOFDSET | 1); + fd_change (EV_A_ fd, w->events & EV__IOFDSET | EV_ANFD_REIFY); w->events &= ~EV__IOFDSET; EV_FREQUENT_CHECK; @@ -2380,6 +2615,12 @@ ev_timer_again (EV_P_ ev_timer *w) EV_FREQUENT_CHECK; } +ev_tstamp +ev_timer_remaining (EV_P_ ev_timer *w) +{ + return ev_at (w) - (ev_is_active (w) ? mn_now : 0.); +} + #if EV_PERIODIC_ENABLE void noinline ev_periodic_start (EV_P_ ev_periodic *w) @@ -2456,47 +2697,77 @@ ev_periodic_again (EV_P_ ev_periodic *w) void noinline ev_signal_start (EV_P_ ev_signal *w) { -#if EV_MULTIPLICITY - assert (("libev: signal watchers are only supported in the default loop", loop == ev_default_loop_ptr)); -#endif if (expect_false (ev_is_active (w))) return; - assert (("libev: ev_signal_start called with illegal signal number", w->signum > 0)); + assert (("libev: ev_signal_start called with illegal signal number", w->signum > 0 && w->signum < EV_NSIG)); - evpipe_init (EV_A); +#if EV_MULTIPLICITY + assert (("libev: a signal must not be attached to two different loops", + !signals [w->signum - 1].loop || signals [w->signum - 1].loop == loop)); + + signals [w->signum - 1].loop = EV_A; +#endif EV_FREQUENT_CHECK; - { -#ifndef _WIN32 - sigset_t full, prev; - sigfillset (&full); - sigprocmask (SIG_SETMASK, &full, &prev); -#endif +#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 */ - array_needsize (ANSIG, signals, signalmax, w->signum, array_init_zero); + if (sigfd >= 0) + { + fd_intern (sigfd); /* doing it twice will not hurt */ -#ifndef _WIN32 - sigprocmask (SIG_SETMASK, &prev, 0); + 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); + } #endif - } ev_start (EV_A_ (W)w, 1); wlist_add (&signals [w->signum - 1].head, (WL)w); if (!((WL)w)->next) - { -#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 EV_USE_SIGNALFD + if (sigfd < 0) /*TODO*/ +# endif + { +# if _WIN32 + evpipe_init (EV_A); + + signal (w->signum, ev_sighandler); +# else + struct sigaction sa; + + evpipe_init (EV_A); + + 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); + + sigemptyset (&sa.sa_mask); + sigaddset (&sa.sa_mask, w->signum); + sigprocmask (SIG_UNBLOCK, &sa.sa_mask, 0); #endif - } + } EV_FREQUENT_CHECK; } @@ -2514,7 +2785,26 @@ 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_MULTIPLICITY + signals [w->signum - 1].loop = 0; /* unattach from signal */ +#endif +#if EV_USE_SIGNALFD + if (sigfd >= 0) + { + sigset_t ss; + + sigemptyset (&ss); + sigaddset (&ss, w->signum); + sigdelset (&sigfd_set, w->signum); + + signalfd (sigfd, &sigfd_set, 0); + sigprocmask (SIG_UNBLOCK, &ss, 0); + } + else +#endif + signal (w->signum, SIG_DFL); + } EV_FREQUENT_CHECK; } @@ -2572,12 +2862,33 @@ infy_add (EV_P_ ev_stat *w) { w->wd = inotify_add_watch (fs_fd, w->path, IN_ATTRIB | IN_DELETE_SELF | IN_MOVE_SELF | IN_MODIFY | IN_DONT_FOLLOW | IN_MASK_ADD); - if (w->wd < 0) + if (w->wd >= 0) { + struct statfs sfs; + + /* now local changes will be tracked by inotify, but remote changes won't */ + /* unless the filesystem is known to be local, we therefore still poll */ + /* also do poll on <2.6.25, but with normal frequency */ + + if (!fs_2625) + w->timer.repeat = w->interval ? w->interval : DEF_STAT_INTERVAL; + else if (!statfs (w->path, &sfs) + && (sfs.f_type == 0x1373 /* devfs */ + || sfs.f_type == 0xEF53 /* ext2/3 */ + || sfs.f_type == 0x3153464a /* jfs */ + || sfs.f_type == 0x52654973 /* reiser3 */ + || sfs.f_type == 0x01021994 /* tempfs */ + || sfs.f_type == 0x58465342 /* xfs */)) + w->timer.repeat = 0.; /* filesystem is local, kernel new enough */ + else + w->timer.repeat = w->interval ? w->interval : NFS_STAT_INTERVAL; /* remote, use reduced frequency */ + } + else + { + /* can't use inotify, continue to stat */ w->timer.repeat = w->interval ? w->interval : DEF_STAT_INTERVAL; - ev_timer_again (EV_A_ &w->timer); /* this is not race-free, so we still need to recheck periodically */ - /* monitor some parent directory for speedup hints */ + /* if path is not there, monitor some parent directory for speedup hints */ /* note that exceeding the hardcoded path limit is not a correctness issue, */ /* but an efficiency issue only */ if ((errno == ENOENT || errno == EACCES) && strlen (w->path) < 4096) @@ -2603,26 +2914,12 @@ infy_add (EV_P_ ev_stat *w) } if (w->wd >= 0) - { - wlist_add (&fs_hash [w->wd & (EV_INOTIFY_HASHSIZE - 1)].head, (WL)w); - - /* now local changes will be tracked by inotify, but remote changes won't */ - /* unless the filesystem it known to be local, we therefore still poll */ - /* also do poll on <2.6.25, but with normal frequency */ - struct statfs sfs; - - if (fs_2625 && !statfs (w->path, &sfs)) - if (sfs.f_type == 0x1373 /* devfs */ - || sfs.f_type == 0xEF53 /* ext2/3 */ - || sfs.f_type == 0x3153464a /* jfs */ - || sfs.f_type == 0x52654973 /* reiser3 */ - || sfs.f_type == 0x01021994 /* tempfs */ - || sfs.f_type == 0x58465342 /* xfs */) - return; + wlist_add (&fs_hash [w->wd & (EV_INOTIFY_HASHSIZE - 1)].head, (WL)w); - w->timer.repeat = w->interval ? w->interval : fs_2625 ? NFS_STAT_INTERVAL : DEF_STAT_INTERVAL; - ev_timer_again (EV_A_ &w->timer); - } + /* now re-arm timer, if required */ + if (ev_is_active (&w->timer)) ev_ref (EV_A); + ev_timer_again (EV_A_ &w->timer); + if (ev_is_active (&w->timer)) ev_unref (EV_A); } static void noinline @@ -2708,6 +3005,17 @@ check_2625 (EV_P) fs_2625 = 1; } +inline_size int +infy_newfd (void) +{ +#if defined (IN_CLOEXEC) && defined (IN_NONBLOCK) + int fd = inotify_init1 (IN_CLOEXEC | IN_NONBLOCK); + if (fd >= 0) + return fd; +#endif + return inotify_init (); +} + inline_size void infy_init (EV_P) { @@ -2718,13 +3026,15 @@ infy_init (EV_P) check_2625 (EV_A); - fs_fd = inotify_init (); + fs_fd = infy_newfd (); if (fs_fd >= 0) { + fd_intern (fs_fd); ev_io_init (&fs_w, infy_cb, fs_fd, EV_READ); ev_set_priority (&fs_w, EV_MAXPRI); ev_io_start (EV_A_ &fs_w); + ev_unref (EV_A); } } @@ -2736,8 +3046,18 @@ infy_fork (EV_P) if (fs_fd < 0) return; + ev_ref (EV_A); + ev_io_stop (EV_A_ &fs_w); close (fs_fd); - fs_fd = inotify_init (); + fs_fd = infy_newfd (); + + if (fs_fd >= 0) + { + fd_intern (fs_fd); + ev_io_set (&fs_w, fs_fd, EV_READ); + ev_io_start (EV_A_ &fs_w); + ev_unref (EV_A); + } for (slot = 0; slot < EV_INOTIFY_HASHSIZE; ++slot) { @@ -2754,7 +3074,12 @@ infy_fork (EV_P) if (fs_fd >= 0) infy_add (EV_A_ w); /* re-add, no matter what */ else - ev_timer_again (EV_A_ &w->timer); + { + w->timer.repeat = w->interval ? w->interval : DEF_STAT_INTERVAL; + if (ev_is_active (&w->timer)) ev_ref (EV_A); + ev_timer_again (EV_A_ &w->timer); + if (ev_is_active (&w->timer)) ev_unref (EV_A); + } } } } @@ -2781,25 +3106,28 @@ stat_timer_cb (EV_P_ ev_timer *w_, int revents) { ev_stat *w = (ev_stat *)(((char *)w_) - offsetof (ev_stat, timer)); - /* we copy this here each the time so that */ - /* prev has the old value when the callback gets invoked */ - w->prev = w->attr; + ev_statdata prev = w->attr; ev_stat_stat (EV_A_ w); /* memcmp doesn't work on netbsd, they.... do stuff to their struct stat */ if ( - w->prev.st_dev != w->attr.st_dev - || w->prev.st_ino != w->attr.st_ino - || w->prev.st_mode != w->attr.st_mode - || w->prev.st_nlink != w->attr.st_nlink - || w->prev.st_uid != w->attr.st_uid - || w->prev.st_gid != w->attr.st_gid - || w->prev.st_rdev != w->attr.st_rdev - || w->prev.st_size != w->attr.st_size - || w->prev.st_atime != w->attr.st_atime - || w->prev.st_mtime != w->attr.st_mtime - || w->prev.st_ctime != w->attr.st_ctime + prev.st_dev != w->attr.st_dev + || prev.st_ino != w->attr.st_ino + || prev.st_mode != w->attr.st_mode + || prev.st_nlink != w->attr.st_nlink + || prev.st_uid != w->attr.st_uid + || prev.st_gid != w->attr.st_gid + || prev.st_rdev != w->attr.st_rdev + || prev.st_size != w->attr.st_size + || prev.st_atime != w->attr.st_atime + || prev.st_mtime != w->attr.st_mtime + || prev.st_ctime != w->attr.st_ctime ) { + /* we only update w->prev on actual differences */ + /* in case we test more often than invoke the callback, */ + /* to ensure that prev is always different to attr */ + w->prev = prev; + #if EV_USE_INOTIFY if (fs_fd >= 0) { @@ -2834,7 +3162,10 @@ ev_stat_start (EV_P_ ev_stat *w) infy_add (EV_A_ w); else #endif - ev_timer_again (EV_A_ &w->timer); + { + ev_timer_again (EV_A_ &w->timer); + ev_unref (EV_A); + } ev_start (EV_A_ (W)w, 1); @@ -2853,7 +3184,12 @@ ev_stat_stop (EV_P_ ev_stat *w) #if EV_USE_INOTIFY infy_del (EV_A_ w); #endif - ev_timer_stop (EV_A_ &w->timer); + + if (ev_is_active (&w->timer)) + { + ev_ref (EV_A); + ev_timer_stop (EV_A_ &w->timer); + } ev_stop (EV_A_ (W)w); @@ -3004,7 +3340,7 @@ embed_prepare_cb (EV_P_ ev_prepare *prepare, int revents) ev_embed *w = (ev_embed *)(((char *)prepare) - offsetof (ev_embed, prepare)); { - struct ev_loop *loop = w->other; + EV_P = w->other; while (fdchangecnt) { @@ -3022,7 +3358,7 @@ embed_fork_cb (EV_P_ ev_fork *fork_w, int revents) ev_embed_stop (EV_A_ w); { - struct ev_loop *loop = w->other; + EV_P = w->other; ev_loop_fork (EV_A); ev_loop (EV_A_ EVLOOP_NONBLOCK); @@ -3046,7 +3382,7 @@ ev_embed_start (EV_P_ ev_embed *w) return; { - struct ev_loop *loop = w->other; + EV_P = w->other; assert (("libev: loop to be embedded is not embeddable", backend & ev_embeddable_backends ())); ev_io_init (&w->io, embed_io_cb, backend_fd, EV_READ); } @@ -3168,7 +3504,7 @@ void ev_async_send (EV_P_ ev_async *w) { w->sent = 1; - evpipe_write (EV_A_ &gotasync); + evpipe_write (EV_A_ &async_pending); } #endif @@ -3327,7 +3663,7 @@ ev_walk (EV_P_ int types, void (*cb)(EV_P_ int type, void *w)) cb (EV_A_ EV_CHECK, checks [i]); if (types & EV_SIGNAL) - for (i = 0; i < signalmax; ++i) + for (i = 0; i < EV_NSIG - 1; ++i) for (wl = signals [i].head; wl; ) { wn = wl->next; diff --git a/libev/ev.h b/libev/ev.h index 737390f..f8b239e 100644 --- a/libev/ev.h +++ b/libev/ev.h @@ -37,8 +37,8 @@ * either the BSD or the GPL. */ -#ifndef EV_H__ -#define EV_H__ +#ifndef EV_H_ +#define EV_H_ #ifdef __cplusplus extern "C" { @@ -163,7 +163,7 @@ struct ev_loop; #endif #define EV_VERSION_MAJOR 3 -#define EV_VERSION_MINOR 0 +#define EV_VERSION_MINOR 9 #ifndef EV_CB_DECLARE # define EV_CB_DECLARE(type) void (*cb)(EV_P_ struct type *w, int revents); @@ -189,11 +189,17 @@ struct ev_loop; * or the array index + 1 in the pendings array. */ +#if EV_MINPRI == EV_MAXPRI +# define EV_DECL_PRIORITY +#else +# define EV_DECL_PRIORITY int priority; +#endif + /* shared by all watchers */ #define EV_WATCHER(type) \ int active; /* private */ \ int pending; /* private */ \ - int priority; /* private */ \ + EV_DECL_PRIORITY /* private */ \ EV_COMMON /* rw */ \ EV_CB_DECLARE (type) /* private */ @@ -359,7 +365,7 @@ typedef struct ev_async EV_ATOMIC_T sent; /* private */ } ev_async; -# define ev_async_pending(w) ((w)->sent + 0) +# define ev_async_pending(w) (+(w)->sent) #endif /* the presence of this union forces similar struct layout */ @@ -398,6 +404,10 @@ union ev_any_watcher /* flag bits */ #define EVFLAG_NOENV 0x01000000U /* do NOT consult environment */ #define EVFLAG_FORKCHECK 0x02000000U /* check for a fork in each iteration */ +/* debugging/feature disable */ +#define EVFLAG_NOINOTIFY 0x00100000U /* do not attempt to use inotify */ +#define EVFLAG_NOSIGFD 0 /* compatibility to pre-3.9 */ +#define EVFLAG_SIGNALFD 0x00200000U /* attempt to use signalfd */ /* method bits to be ored together */ #define EVBACKEND_SELECT 0x00000001U /* about anywhere */ #define EVBACKEND_POLL 0x00000002U /* !win */ @@ -405,6 +415,7 @@ union ev_any_watcher #define EVBACKEND_KQUEUE 0x00000008U /* bsd */ #define EVBACKEND_DEVPOLL 0x00000010U /* solaris 8 */ /* NYI */ #define EVBACKEND_PORT 0x00000020U /* solaris 10 */ +#define EVBACKEND_ALL 0x0000003FU #if EV_PROTOTYPES int ev_version_major (void); @@ -431,11 +442,11 @@ void ev_set_allocator (void *(*cb)(void *ptr, long size)); */ void ev_set_syserr_cb (void (*cb)(const char *msg)); + #if EV_MULTIPLICITY extern struct ev_loop *ev_default_loop_ptr; extern struct ev_loop *ev_default_loop_init (unsigned int flags); - EV_INLINE struct ev_loop * ev_default_loop_uc (void) { @@ -461,13 +472,12 @@ ev_default_loop (unsigned int flags) struct ev_loop *ev_loop_new (unsigned int flags); void ev_loop_destroy (EV_P); void ev_loop_fork (EV_P); -void ev_loop_verify (EV_P); ev_tstamp ev_now (EV_P); /* time w.r.t. timers and the eventloop, updated after each poll */ -void ev_now_update (EV_P); #else extern ev_tstamp ev_rt_now; + int ev_default_loop (unsigned int flags); /* returns true when successful */ EV_INLINE ev_tstamp @@ -494,6 +504,10 @@ void ev_default_destroy (void); /* destroy the default loop */ /* you can actually call it at any time, anywhere :) */ void ev_default_fork (void); +unsigned int ev_backend (EV_P); /* backend in use by loop */ + +void ev_now_update (EV_P); /* update event loop time */ + #if EV_WALK_ENABLE /* walk (almost) all watchers in the loop of a given type, invoking the */ /* callback on every such watcher. The callback might stop the watcher, */ @@ -501,8 +515,6 @@ void ev_default_fork (void); void ev_walk (EV_P_ int types, void (*cb)(EV_P_ int type, void *w)); #endif -unsigned int ev_backend (EV_P); /* backend in use by loop */ -unsigned int ev_loop_count (EV_P); /* number of loop iterations */ #endif /* prototypes */ #define EVLOOP_NONBLOCK 1 /* do not block/wait */ @@ -515,36 +527,52 @@ unsigned int ev_loop_count (EV_P); /* number of loop iterations */ void ev_loop (EV_P_ int flags); void ev_unloop (EV_P_ int how); /* set to 1 to break out of event loop, set to 2 to break out of all event loops */ -void ev_set_io_collect_interval (EV_P_ ev_tstamp interval); /* sleep at least this time, default 0 */ -void ev_set_timeout_collect_interval (EV_P_ ev_tstamp interval); /* sleep at least this time, default 0 */ - /* * ref/unref can be used to add or remove a refcount on the mainloop. every watcher - * keeps one reference. if you have a long-runing watcher you never unregister that + * keeps one reference. if you have a long-running watcher you never unregister that * should not keep ev_loop from running, unref() after starting, and ref() before stopping. */ void ev_ref (EV_P); void ev_unref (EV_P); /* + * convenience function, wait for a single event, without registering an event watcher + * if timeout is < 0, do wait indefinitely + */ +void ev_once (EV_P_ int fd, int events, ev_tstamp timeout, void (*cb)(int revents, void *arg), void *arg); + +# if EV_MINIMAL < 2 +unsigned int ev_loop_count (EV_P); /* number of loop iterations */ +unsigned int ev_loop_depth (EV_P); /* #ev_loop enters - #ev_loop leaves */ +void ev_loop_verify (EV_P); /* abort if loop data corrupted */ + +void ev_set_io_collect_interval (EV_P_ ev_tstamp interval); /* sleep at least this time, default 0 */ +void ev_set_timeout_collect_interval (EV_P_ ev_tstamp interval); /* sleep at least this time, default 0 */ + +/* advanced stuff for threading etc. support, see docs */ +void ev_set_userdata (EV_P_ void *data); +void *ev_userdata (EV_P); +void ev_set_invoke_pending_cb (EV_P_ void (*invoke_pending_cb)(EV_P)); +void ev_set_loop_release_cb (EV_P_ void (*release)(EV_P), void (*acquire)(EV_P)); + +unsigned int ev_pending_count (EV_P); /* number of pending events, if any */ +void ev_invoke_pending (EV_P); /* invoke all pending watchers */ + +/* * stop/start the timer handling. */ void ev_suspend (EV_P); void ev_resume (EV_P); +#endif -/* - * convenience function, wait for a single event, without registering an event watcher - * if timeout is < 0, do wait indefinitely - */ -void ev_once (EV_P_ int fd, int events, ev_tstamp timeout, void (*cb)(int revents, void *arg), void *arg); #endif /* these may evaluate ev multiple times, and the other arguments at most once */ /* either use ev_init + ev_TYPE_set, or the ev_TYPE_init macro, below, to first initialise a watcher */ #define ev_init(ev,cb_) do { \ - ((ev_watcher *)(void *)(ev))->active = \ - ((ev_watcher *)(void *)(ev))->pending = \ - ((ev_watcher *)(void *)(ev))->priority = 0; \ + ((ev_watcher *)(void *)(ev))->active = \ + ((ev_watcher *)(void *)(ev))->pending = 0; \ + ev_set_priority ((ev), 0); \ ev_set_cb ((ev), cb_); \ } while (0) @@ -577,11 +605,17 @@ void ev_once (EV_P_ int fd, int events, ev_tstamp timeout, void (*cb)(int revent #define ev_is_pending(ev) (0 + ((ev_watcher *)(void *)(ev))->pending) /* ro, true when watcher is waiting for callback invocation */ #define ev_is_active(ev) (0 + ((ev_watcher *)(void *)(ev))->active) /* ro, true when the watcher has been started */ -#define ev_priority(ev) ((((ev_watcher *)(void *)(ev))->priority) + 0) #define ev_cb(ev) (ev)->cb /* rw */ -#define ev_set_priority(ev,pri) ((ev_watcher *)(void *)(ev))->priority = (pri) -#define ev_periodic_at(ev) (((ev_watcher_time *)(ev))->at + 0.) +#if EV_MINPRI == EV_MAXPRI +# define ev_priority(ev) ((ev), EV_MINPRI) +# define ev_set_priority(ev,pri) ((ev), (pri)) +#else +# define ev_priority(ev) (+(((ev_watcher *)(void *)(ev))->priority)) +# define ev_set_priority(ev,pri) ( (ev_watcher *)(void *)(ev))->priority = (pri) +#endif + +#define ev_periodic_at(ev) (+((ev_watcher_time *)(ev))->at) #ifndef ev_set_cb # define ev_set_cb(ev,cb_) ev_cb (ev) = (cb_) @@ -606,6 +640,8 @@ void ev_timer_start (EV_P_ ev_timer *w); void ev_timer_stop (EV_P_ ev_timer *w); /* stops if active and no repeat, restarts if active and repeating, starts if inactive and repeating */ void ev_timer_again (EV_P_ ev_timer *w); +/* return remaining time */ +ev_tstamp ev_timer_remaining (EV_P_ ev_timer *w); #if EV_PERIODIC_ENABLE void ev_periodic_start (EV_P_ ev_periodic *w); diff --git a/libev/ev_epoll.c b/libev/ev_epoll.c index b302e26..f7e3d60 100644 --- a/libev/ev_epoll.c +++ b/libev/ev_epoll.c @@ -1,7 +1,7 @@ /* * libev epoll fd activity backend * - * Copyright (c) 2007,2008 Marc Alexander Lehmann <[email protected]> + * Copyright (c) 2007,2008,2009 Marc Alexander Lehmann <[email protected]> * All rights reserved. * * Redistribution and use in source and binary forms, with or without modifica- @@ -119,7 +119,13 @@ static void epoll_poll (EV_P_ ev_tstamp timeout) { int i; - int eventcnt = epoll_wait (backend_fd, epoll_events, epoll_eventmax, (int)ceil (timeout * 1000.)); + int eventcnt; + + /* epoll wait times cannot be larger than (LONG_MAX - 999UL) / HZ msecs, which is below */ + /* the default libev max wait time, however. */ + EV_RELEASE_CB; + eventcnt = epoll_wait (backend_fd, epoll_events, epoll_eventmax, (int)ceil (timeout * 1000.)); + EV_ACQUIRE_CB; if (expect_false (eventcnt < 0)) { @@ -155,6 +161,8 @@ epoll_poll (EV_P_ ev_tstamp timeout) ev->events = (want & EV_READ ? EPOLLIN : 0) | (want & EV_WRITE ? EPOLLOUT : 0); + /* pre-2.6.9 kernels require a non-null pointer with EPOLL_CTL_DEL, */ + /* which is fortunately easy to do for us. */ if (epoll_ctl (backend_fd, want ? EPOLL_CTL_MOD : EPOLL_CTL_DEL, fd, ev)) { postfork = 1; /* an error occured, recreate kernel state */ @@ -177,7 +185,12 @@ epoll_poll (EV_P_ ev_tstamp timeout) int inline_size epoll_init (EV_P_ int flags) { - backend_fd = epoll_create (256); +#ifdef EPOLL_CLOEXEC + backend_fd = epoll_create1 (EPOLL_CLOEXEC); + + if (backend_fd <= 0) +#endif + backend_fd = epoll_create (256); if (backend_fd < 0) return 0; diff --git a/libev/ev_kqueue.c b/libev/ev_kqueue.c index 63828d6..0fe340b 100644 --- a/libev/ev_kqueue.c +++ b/libev/ev_kqueue.c @@ -1,7 +1,7 @@ /* * libev kqueue backend * - * Copyright (c) 2007,2008 Marc Alexander Lehmann <[email protected]> + * Copyright (c) 2007,2008,2009 Marc Alexander Lehmann <[email protected]> * All rights reserved. * * Redistribution and use in source and binary forms, with or without modifica- @@ -93,9 +93,11 @@ kqueue_poll (EV_P_ ev_tstamp timeout) kqueue_events = (struct kevent *)ev_malloc (sizeof (struct kevent) * kqueue_eventmax); } + EV_RELEASE_CB; ts.tv_sec = (time_t)timeout; ts.tv_nsec = (long)((timeout - (ev_tstamp)ts.tv_sec) * 1e9); res = kevent (backend_fd, kqueue_changes, kqueue_changecnt, kqueue_events, kqueue_eventmax, &ts); + EV_ACQUIRE_CB; kqueue_changecnt = 0; if (expect_false (res < 0)) diff --git a/libev/ev_poll.c b/libev/ev_poll.c index 5b82b29..178e458 100644 --- a/libev/ev_poll.c +++ b/libev/ev_poll.c @@ -1,7 +1,7 @@ /* * libev poll fd activity backend * - * Copyright (c) 2007,2008 Marc Alexander Lehmann <[email protected]> + * Copyright (c) 2007,2008,2009 Marc Alexander Lehmann <[email protected]> * All rights reserved. * * Redistribution and use in source and binary forms, with or without modifica- @@ -89,7 +89,11 @@ static void poll_poll (EV_P_ ev_tstamp timeout) { struct pollfd *p; - int res = poll (polls, pollcnt, (int)ceil (timeout * 1000.)); + int res; + + EV_RELEASE_CB; + res = poll (polls, pollcnt, (int)ceil (timeout * 1000.)); + EV_ACQUIRE_CB; if (expect_false (res < 0)) { diff --git a/libev/ev_port.c b/libev/ev_port.c index c2dde65..47da929 100644 --- a/libev/ev_port.c +++ b/libev/ev_port.c @@ -1,7 +1,7 @@ /* * libev solaris event port backend * - * Copyright (c) 2007,2008 Marc Alexander Lehmann <[email protected]> + * Copyright (c) 2007,2008,2009 Marc Alexander Lehmann <[email protected]> * All rights reserved. * * Redistribution and use in source and binary forms, with or without modifica- @@ -85,14 +85,16 @@ port_poll (EV_P_ ev_tstamp timeout) struct timespec ts; uint_t nget = 1; + EV_RELEASE_CB; ts.tv_sec = (time_t)timeout; ts.tv_nsec = (long)(timeout - (ev_tstamp)ts.tv_sec) * 1e9; res = port_getn (backend_fd, port_events, port_eventmax, &nget, &ts); + EV_ACQUIRE_CB; if (res == -1) { if (errno != EINTR && errno != ETIME) - ev_syserr ("(libev) port_getn"); + ev_syserr ("(libev) port_getn (see http://bugs.opensolaris.org/view_bug.do?bug_id=6268715, try LIBEV_FLAGS=3 env variable)"); return; } diff --git a/libev/ev_select.c b/libev/ev_select.c index 173c286..818a63e 100644 --- a/libev/ev_select.c +++ b/libev/ev_select.c @@ -140,6 +140,7 @@ select_poll (EV_P_ ev_tstamp timeout) int res; int fd_setsize; + EV_RELEASE_CB; tv.tv_sec = (long)timeout; tv.tv_usec = (long)((timeout - (ev_tstamp)tv.tv_sec) * 1e6); @@ -166,6 +167,7 @@ select_poll (EV_P_ ev_tstamp timeout) #else res = select (vec_max * NFDBITS, (fd_set *)vec_ro, (fd_set *)vec_wo, 0, &tv); #endif + EV_ACQUIRE_CB; if (expect_false (res < 0)) { @@ -280,9 +282,12 @@ select_init (EV_P_ int flags) #else vec_max = 0; vec_ri = 0; - vec_ri = 0; - vec_wo = 0; + vec_ro = 0; + vec_wi = 0; vec_wo = 0; + #ifdef _WIN32 + vec_eo = 0; + #endif #endif return EVBACKEND_SELECT; @@ -295,6 +300,9 @@ select_destroy (EV_P) ev_free (vec_ro); ev_free (vec_wi); ev_free (vec_wo); + #ifdef _WIN32 + ev_free (vec_eo); + #endif } diff --git a/libev/ev_vars.h b/libev/ev_vars.h index b91e430..da53ee8 100644 --- a/libev/ev_vars.h +++ b/libev/ev_vars.h @@ -1,7 +1,7 @@ /* * loop member variable declarations * - * Copyright (c) 2007,2008 Marc Alexander Lehmann <[email protected]> + * Copyright (c) 2007,2008,2009 Marc Alexander Lehmann <[email protected]> * All rights reserved. * * Redistribution and use in source and binary forms, with or without modifica- @@ -48,7 +48,7 @@ VARx(ev_tstamp, timeout_blocktime) VARx(int, backend) VARx(int, activecnt) /* total number of active events ("refcount") */ -VARx(unsigned int, loop_count) /* total number of loop iterations/blocks */ +VARx(unsigned char, loop_done) /* signal by ev_unloop */ VARx(int, backend_fd) VARx(ev_tstamp, backend_fudge) /* assumed typical timer resolution */ @@ -152,8 +152,8 @@ VARx(int, forkmax) VARx(int, forkcnt) #endif -VARx(EV_ATOMIC_T, gotasync) #if EV_ASYNC_ENABLE || EV_GENWRAP +VARx(EV_ATOMIC_T, async_pending) VARx(struct ev_async **, asyncs) VARx(int, asyncmax) VARx(int, asynccnt) @@ -166,5 +166,22 @@ 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 +VARx(EV_ATOMIC_T, sig_pending) +#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 */ + +VARx(void *, userdata) +VAR (release_cb, void (*release_cb)(EV_P)) +VAR (acquire_cb, void (*acquire_cb)(EV_P)) +VAR (invoke_cb , void (*invoke_cb) (EV_P)) +#endif + #undef VARx diff --git a/libev/ev_win32.c b/libev/ev_win32.c index 61bff50..ee60ae6 100644 --- a/libev/ev_win32.c +++ b/libev/ev_win32.c @@ -111,8 +111,8 @@ ev_pipe (int filedes [2]) closesocket (listener); #if EV_SELECT_IS_WINSOCKET - filedes [0] = _open_osfhandle (sock [0], 0); - filedes [1] = _open_osfhandle (sock [1], 0); + filedes [0] = EV_WIN32_HANDLE_TO_FD (sock [0]); + filedes [1] = EV_WIN32_HANDLE_TO_FD (sock [1]); #else /* when select isn't winsocket, we also expect socket, connect, accept etc. * to work on fds */ @@ -133,22 +133,21 @@ fail: #undef pipe #define pipe(filedes) ev_pipe (filedes) - -static int -ev_gettimeofday (struct timeval *tv, struct timezone *tz) + +#define EV_HAVE_EV_TIME 1 +ev_tstamp +ev_time (void) { - struct _timeb tb; - - _ftime (&tb); + FILETIME ft; + ULARGE_INTEGER ui; - tv->tv_sec = (long)tb.time; - tv->tv_usec = ((long)tb.millitm) * 1000; + GetSystemTimeAsFileTime (&ft); + ui.u.LowPart = ft.dwLowDateTime; + ui.u.HighPart = ft.dwHighDateTime; - return 0; + /* msvc cannot convert ulonglong to double... yes, it is that sucky */ + return (LONGLONG)(ui.QuadPart - 116444736000000000) * 1e-7; } -#undef gettimeofday -#define gettimeofday(tv,tz) ev_gettimeofday (tv, tz) - #endif diff --git a/libev/ev_wrap.h b/libev/ev_wrap.h index e2c5be6..03b6b87 100644 --- a/libev/ev_wrap.h +++ b/libev/ev_wrap.h @@ -8,7 +8,7 @@ #define timeout_blocktime ((loop)->timeout_blocktime) #define backend ((loop)->backend) #define activecnt ((loop)->activecnt) -#define loop_count ((loop)->loop_count) +#define loop_done ((loop)->loop_done) #define backend_fd ((loop)->backend_fd) #define backend_fudge ((loop)->backend_fudge) #define backend_modify ((loop)->backend_modify) @@ -69,7 +69,7 @@ #define forks ((loop)->forks) #define forkmax ((loop)->forkmax) #define forkcnt ((loop)->forkcnt) -#define gotasync ((loop)->gotasync) +#define async_pending ((loop)->async_pending) #define asyncs ((loop)->asyncs) #define asyncmax ((loop)->asyncmax) #define asynccnt ((loop)->asynccnt) @@ -77,6 +77,16 @@ #define fs_w ((loop)->fs_w) #define fs_2625 ((loop)->fs_2625) #define fs_hash ((loop)->fs_hash) +#define sig_pending ((loop)->sig_pending) +#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) +#define release_cb ((loop)->release_cb) +#define acquire_cb ((loop)->acquire_cb) +#define invoke_cb ((loop)->invoke_cb) #else #undef EV_WRAP_H #undef now_floor @@ -86,7 +96,7 @@ #undef timeout_blocktime #undef backend #undef activecnt -#undef loop_count +#undef loop_done #undef backend_fd #undef backend_fudge #undef backend_modify @@ -147,7 +157,7 @@ #undef forks #undef forkmax #undef forkcnt -#undef gotasync +#undef async_pending #undef asyncs #undef asyncmax #undef asynccnt @@ -155,4 +165,14 @@ #undef fs_w #undef fs_2625 #undef fs_hash +#undef sig_pending +#undef sigfd +#undef sigfd_w +#undef sigfd_set +#undef loop_count +#undef loop_depth +#undef userdata +#undef release_cb +#undef acquire_cb +#undef invoke_cb #endif diff --git a/libev/libev.m4 b/libev/libev.m4 index 2ba20eb..ff4c804 100644 --- a/libev/libev.m4 +++ b/libev/libev.m4 @@ -2,9 +2,9 @@ dnl this file is part of libev, do not make local modifications dnl http://software.schmorp.de/pkg/libev dnl libev support -AC_CHECK_HEADERS(sys/inotify.h sys/epoll.h sys/event.h sys/queue.h port.h poll.h sys/select.h sys/eventfd.h) +AC_CHECK_HEADERS(sys/inotify.h sys/epoll.h sys/event.h sys/queue.h port.h poll.h sys/select.h sys/eventfd.h sys/signalfd.h) -AC_CHECK_FUNCS(inotify_init epoll_ctl kqueue port_create poll select eventfd) +AC_CHECK_FUNCS(inotify_init epoll_ctl kqueue port_create poll select eventfd signalfd) AC_CHECK_FUNC(clock_gettime, [], [ dnl on linux, try syscall wrapper first @@ -36,5 +36,3 @@ AC_CHECK_FUNC(nanosleep, [], [ AC_CHECK_LIB(m, ceil) - - _______________________________________________ Prelude-cvslog site list [email protected] http://lists.prelude-ids.org/mailman/listinfo/prelude-cvslog