diff options
-rw-r--r-- | Changes | 9 | ||||
-rw-r--r-- | EV.pm | 2 | ||||
-rw-r--r-- | META.json | 2 | ||||
-rw-r--r-- | META.yml | 2 | ||||
-rw-r--r-- | Makefile.PL | 17 | ||||
-rw-r--r-- | debian/changelog | 7 | ||||
-rw-r--r-- | debian/copyright | 2 | ||||
-rw-r--r-- | libev/Changes | 8 | ||||
-rw-r--r-- | libev/ev.c | 157 | ||||
-rw-r--r-- | libev/ev.h | 15 | ||||
-rw-r--r-- | libev/ev.pod | 35 | ||||
-rw-r--r-- | libev/ev_vars.h | 5 | ||||
-rw-r--r-- | libev/ev_wrap.h | 4 |
13 files changed, 233 insertions, 32 deletions
@@ -1,8 +1,15 @@ Revision history for Perl extension EV -Changes marked with (libev) are changes in libev, and have more +Changes marked with (libev) are changes in libev, and might have more documentation in the libev Changes file. +4.31 Fri Dec 20 21:57:00 CET 2019 + - (libev) handle backends with minimum wait time a bit better by + not waiting in the presence of already-expired timers + (behaviour reported by Felipe Gasper). + - (libev) use timerfd to detect timejumps. + - (libev) new loop flag: EVFLAG_NOTIMERFD. + 4.30 Fri Nov 22 21:00:00 CET 2019 - (libev) use a different and hopefully even more portable test to disable io_uring when header files are too old, @@ -121,7 +121,7 @@ package EV; use common::sense; BEGIN { - our $VERSION = '4.30'; + our $VERSION = '4.31'; use XSLoader; local $^W = 0; # avoid spurious warning XSLoader::load "EV", $VERSION; @@ -38,5 +38,5 @@ } }, "release_status" : "stable", - "version" : "4.30" + "version" : "4.31" } @@ -20,4 +20,4 @@ no_index: - inc requires: common::sense: '0' -version: '4.30' +version: '4.31' diff --git a/Makefile.PL b/Makefile.PL index e85219e..7d409db 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -341,6 +341,23 @@ print <<EOF; *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** +Linux kernels can notify userspace about realtime clock timejumps +using timerfd. Libev by default will try to take advantage of this if +possible. You can completely disable the detection and use of timerfd for +this purpose by answering 'n' here. Support for timerfd will otherwise be +autodetected at both compile- and runtime. + +EOF + +unless (prompt ("Enable optional support for timerfd to detect timejumps (y/n)?", "y") =~ /[yY]/) { + $DEFINE .= " -DEV_USE_TIMERFD=0"; +} + +print <<EOF; + +*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** + + Libev contains numerous internal assert() invocations to check for consistency and user errors. These are normally enabled, but most perl builds disable this error reporting mechanism by default. You diff --git a/debian/changelog b/debian/changelog index d0b5bd9..941c0a9 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +libev-perl (4.31-1) unstable; urgency=medium + + * Import upstream version 4.31. + * Update years of packaging copyright. + + -- gregor herrmann <gregoa@debian.org> Sun, 22 Dec 2019 15:34:23 +0100 + libev-perl (4.30-1) unstable; urgency=medium * Team upload. diff --git a/debian/copyright b/debian/copyright index f8edab3..2f26610 100644 --- a/debian/copyright +++ b/debian/copyright @@ -24,7 +24,7 @@ Files: debian/* Copyright: 2011, 2011, Dmitry E. Oboukhov <unera@debian.org>, 2011, Nicholas Bamber <nicholas@periapt.co.uk>, 2011, Alessandro Ghedini <ghedo@debian.org> - 2013-2018, gregor herrmann <gregoa@debian.org> + 2013-2019, gregor herrmann <gregoa@debian.org> 2019, Nick Morrott <nickm@debian.org> License: Artistic or GPL-2+ diff --git a/libev/Changes b/libev/Changes index ff97245..48acc12 100644 --- a/libev/Changes +++ b/libev/Changes @@ -4,6 +4,14 @@ TODO: revisit 59.x timer in the light of modern powersaving TODO: maybe use timerfd to detect time jumps on linux TODO: document EV_TSTAMP_T +4.31 Fri Dec 20 21:58:29 CET 2019 + - handle backends with minimum wait time a bit better by not + waiting in the presence of already-expired timers + (behaviour reported by Felipe Gasper). + - new feature: use timerfd to detect timejumps quickly, + can be disabled with the new EVFLAG_NOTIMERFD loop flag. + - document EV_USE_SIGNALFD feature macro. + 4.30 (EV only) - change non-autoconf test for __kernel_rwf_t by testing LINUX_VERSION_CODE, the most direct test I could find. @@ -180,6 +180,15 @@ # define EV_USE_EVENTFD 0 # endif +# if HAVE_SYS_TIMERFD_H +# ifndef EV_USE_TIMERFD +# define EV_USE_TIMERFD EV_FEATURE_OS +# endif +# else +# undef EV_USE_TIMERFD +# define EV_USE_TIMERFD 0 +# endif + #endif /* OS X, in its infinite idiocy, actually HARDCODES @@ -383,6 +392,14 @@ # endif #endif +#ifndef EV_USE_TIMERFD +# if __linux && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8)) +# define EV_USE_TIMERFD EV_FEATURE_OS +# else +# define EV_USE_TIMERFD 0 +# endif +#endif + #if 0 /* debugging */ # define EV_VERIFY 3 # define EV_USE_4HEAP 1 @@ -500,7 +517,7 @@ #endif #if EV_USE_EVENTFD -/* our minimum requirement is glibc 2.7 which has the stub, but not the header */ +/* our minimum requirement is glibc 2.7 which has the stub, but not the full header */ # include <stdint.h> # ifndef EFD_NONBLOCK # define EFD_NONBLOCK O_NONBLOCK @@ -516,7 +533,7 @@ EV_CPP(extern "C") int (eventfd) (unsigned int initval, int flags); #endif #if EV_USE_SIGNALFD -/* our minimum requirement is glibc 2.7 which has the stub, but not the header */ +/* our minimum requirement is glibc 2.7 which has the stub, but not the full header */ # include <stdint.h> # ifndef SFD_NONBLOCK # define SFD_NONBLOCK O_NONBLOCK @@ -528,7 +545,7 @@ EV_CPP(extern "C") int (eventfd) (unsigned int initval, int flags); # define SFD_CLOEXEC 02000000 # endif # endif -EV_CPP (extern "C") int signalfd (int fd, const sigset_t *mask, int flags); +EV_CPP (extern "C") int (signalfd) (int fd, const sigset_t *mask, int flags); struct signalfd_siginfo { @@ -537,6 +554,16 @@ struct signalfd_siginfo }; #endif +/* for timerfd, libev core requires TFD_TIMER_CANCEL_ON_SET &c */ +#if EV_USE_TIMERFD +# include <sys/timerfd.h> +/* timerfd is only used for periodics */ +# if !(defined (TFD_TIMER_CANCEL_ON_SET) && defined (TFD_CLOEXEC) && defined (TFD_NONBLOCK)) || !EV_PERIODIC_ENABLE +# undef EV_USE_TIMERFD +# define EV_USE_TIMERFD 0 +# endif +#endif + /*****************************************************************************/ #if EV_VERIFY >= 3 @@ -2850,6 +2877,58 @@ childcb (EV_P_ ev_signal *sw, int revents) /*****************************************************************************/ +#if EV_USE_TIMERFD + +static void periodics_reschedule (EV_P); + +static void +timerfdcb (EV_P_ ev_io *iow, int revents) +{ + struct itimerspec its = { 0 }; + + /* since we can't easily come zup with a (portable) maximum value of time_t, + * we wake up once per month, which hopefully is rare enough to not + * be a problem. */ + its.it_value.tv_sec = ev_rt_now + 86400 * 30; + timerfd_settime (timerfd, TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, &its, 0); + + ev_rt_now = ev_time (); + /* periodics_reschedule only needs ev_rt_now */ + /* but maybe in the future we want the full treatment. */ + /* + now_floor = EV_TS_CONST (0.); + time_update (EV_A_ EV_TSTAMP_HUGE); + */ + periodics_reschedule (EV_A); +} + +ecb_noinline ecb_cold +static void +evtimerfd_init (EV_P) +{ + if (!ev_is_active (&timerfd_w)) + { + timerfd = timerfd_create (CLOCK_REALTIME, TFD_NONBLOCK | TFD_CLOEXEC); + + if (timerfd >= 0) + { + fd_intern (timerfd); /* just to be sure */ + + ev_io_init (&timerfd_w, timerfdcb, timerfd, EV_READ); + ev_set_priority (&sigfd_w, EV_MINPRI); + ev_io_start (EV_A_ &timerfd_w); + ev_unref (EV_A); /* watcher should not keep loop alive */ + + /* (re-) arm timer */ + timerfdcb (EV_A_ 0, 0); + } + } +} + +#endif + +/*****************************************************************************/ + #if EV_USE_IOCP # include "ev_iocp.c" #endif @@ -3091,6 +3170,9 @@ loop_init (EV_P_ unsigned int flags) EV_NOEXCEPT #if EV_USE_SIGNALFD sigfd = flags & EVFLAG_SIGNALFD ? -2 : -1; #endif +#if EV_USE_TIMERFD + timerfd = flags & EVFLAG_NOTIMERFD ? -1 : -2; +#endif if (!(flags & EVBACKEND_MASK)) flags |= ev_recommended_backends (); @@ -3173,6 +3255,11 @@ ev_loop_destroy (EV_P) close (sigfd); #endif +#if EV_USE_TIMERFD + if (ev_is_active (&timerfd_w)) + close (timerfd); +#endif + #if EV_USE_INOTIFY if (fs_fd >= 0) close (fs_fd); @@ -3273,22 +3360,44 @@ loop_fork (EV_P) infy_fork (EV_A); #endif -#if EV_SIGNAL_ENABLE || EV_ASYNC_ENABLE - if (ev_is_active (&pipe_w) && postfork != 2) + if (postfork != 2) { - /* pipe_write_wanted must be false now, so modifying fd vars should be safe */ - - ev_ref (EV_A); - ev_io_stop (EV_A_ &pipe_w); - - if (evpipe [0] >= 0) - EV_WIN32_CLOSE_FD (evpipe [0]); + #if EV_USE_SIGNALFD + /* surprisingly, nothing needs to be done for signalfd, accoridng to docs, it does the right thing on fork */ + #endif + + #if EV_USE_TIMERFD + if (ev_is_active (&timerfd_w)) + { + ev_ref (EV_A); + ev_io_stop (EV_A_ &timerfd_w); - evpipe_init (EV_A); - /* iterate over everything, in case we missed something before */ - ev_feed_event (EV_A_ &pipe_w, EV_CUSTOM); + close (timerfd); + timerfd = -2; + + evtimerfd_init (EV_A); + /* reschedule periodics, in case we missed something */ + ev_feed_event (EV_A_ &timerfd_w, EV_CUSTOM); + } + #endif + + #if EV_SIGNAL_ENABLE || EV_ASYNC_ENABLE + if (ev_is_active (&pipe_w)) + { + /* pipe_write_wanted must be false now, so modifying fd vars should be safe */ + + ev_ref (EV_A); + ev_io_stop (EV_A_ &pipe_w); + + if (evpipe [0] >= 0) + EV_WIN32_CLOSE_FD (evpipe [0]); + + evpipe_init (EV_A); + /* iterate over everything, in case we missed something before */ + ev_feed_event (EV_A_ &pipe_w, EV_CUSTOM); + } + #endif } -#endif postfork = 0; } @@ -3860,10 +3969,15 @@ ev_run (EV_P_ int flags) if (ecb_expect_false (waittime < timeout_blocktime)) waittime = timeout_blocktime; - /* at this point, we NEED to wait, so we have to ensure */ - /* to pass a minimum nonzero value to the backend */ + /* now there are two more special cases left, either we have + * already-expired timers, so we should not sleep, or we have timers + * that expire very soon, in which case we need to wait for a minimum + * amount of time for some event loop backends. + */ if (ecb_expect_false (waittime < backend_mintime)) - waittime = backend_mintime; + waittime = waittime <= EV_TS_CONST (0.) + ? EV_TS_CONST (0.) + : backend_mintime; /* extra check because io_blocktime is commonly 0 */ if (ecb_expect_false (io_blocktime)) @@ -4209,6 +4323,11 @@ ev_periodic_start (EV_P_ ev_periodic *w) EV_NOEXCEPT if (ecb_expect_false (ev_is_active (w))) return; +#if EV_USE_TIMERFD + if (timerfd == -2) + evtimerfd_init (EV_A); +#endif + if (w->reschedule_cb) ev_at (w) = w->reschedule_cb (w, ev_rt_now); else if (w->interval) @@ -504,17 +504,18 @@ union ev_any_watcher /* flag bits for ev_default_loop and ev_loop_new */ enum { /* the default */ - EVFLAG_AUTO = 0x00000000U, /* not quite a mask */ + EVFLAG_AUTO = 0x00000000U, /* not quite a mask */ /* flag bits */ - EVFLAG_NOENV = 0x01000000U, /* do NOT consult environment */ - EVFLAG_FORKCHECK = 0x02000000U, /* check for a fork in each iteration */ + EVFLAG_NOENV = 0x01000000U, /* do NOT consult environment */ + EVFLAG_FORKCHECK = 0x02000000U, /* check for a fork in each iteration */ /* debugging/feature disable */ - EVFLAG_NOINOTIFY = 0x00100000U, /* do not attempt to use inotify */ + EVFLAG_NOINOTIFY = 0x00100000U, /* do not attempt to use inotify */ #if EV_COMPAT3 - EVFLAG_NOSIGFD = 0, /* compatibility to pre-3.9 */ + EVFLAG_NOSIGFD = 0, /* compatibility to pre-3.9 */ #endif - EVFLAG_SIGNALFD = 0x00200000U, /* attempt to use signalfd */ - EVFLAG_NOSIGMASK = 0x00400000U /* avoid modifying the signal mask */ + EVFLAG_SIGNALFD = 0x00200000U, /* attempt to use signalfd */ + EVFLAG_NOSIGMASK = 0x00400000U, /* avoid modifying the signal mask */ + EVFLAG_NOTIMERFD = 0x00800000U /* avoid creating a timerfd */ }; /* method bits to be ored together */ diff --git a/libev/ev.pod b/libev/ev.pod index fc8cdce..5d60ed2 100644 --- a/libev/ev.pod +++ b/libev/ev.pod @@ -482,7 +482,16 @@ unblocking the signals. It's also required by POSIX in a threaded program, as libev calls C<sigprocmask>, whose behaviour is officially unspecified. -This flag's behaviour will become the default in future versions of libev. +=item C<EVFLAG_NOTIMERFD> + +When this flag is specified, the libev will avoid using a C<timerfd> to +detect time jumps. It will still be able to detect time jumps, but takes +longer and has a lower accuracy in doing so, but saves a file descriptor +per loop. + +The current implementation only tries to use a C<timerfd> when the first +C<ev_periodic> watcher is started and falls back on other methods if it +cannot be created, but this behaviour might change in the future. =item C<EVBACKEND_SELECT> (value 1, portable select backend) @@ -4617,6 +4626,30 @@ C<ev_signal> and C<ev_async> performance and reduce resource consumption. If undefined, it will be enabled if the headers indicate GNU/Linux + Glibc 2.7 or newer, otherwise disabled. +=item EV_USE_SIGNALFD + +If defined to be C<1>, then libev will assume that C<signalfd ()> is +available and will probe for kernel support at runtime. This enables +the use of EVFLAG_SIGNALFD for faster and simpler signal handling. If +undefined, it will be enabled if the headers indicate GNU/Linux + Glibc +2.7 or newer, otherwise disabled. + +=item EV_USE_TIMERFD + +If defined to be C<1>, then libev will assume that C<timerfd ()> is +available and will probe for kernel support at runtime. This allows +libev to detect time jumps accurately. If undefined, it will be enabled +if the headers indicate GNU/Linux + Glibc 2.8 or newer and define +C<TFD_TIMER_CANCEL_ON_SET>, otherwise disabled. + +=item EV_USE_EVENTFD + +If defined to be C<1>, then libev will assume that C<eventfd ()> is +available and will probe for kernel support at runtime. This will improve +C<ev_signal> and C<ev_async> performance and reduce resource consumption. +If undefined, it will be enabled if the headers indicate GNU/Linux + Glibc +2.7 or newer, otherwise disabled. + =item EV_USE_SELECT If undefined or defined to be C<1>, libev will compile in support for the diff --git a/libev/ev_vars.h b/libev/ev_vars.h index 44b5bbd..4a56321 100644 --- a/libev/ev_vars.h +++ b/libev/ev_vars.h @@ -228,6 +228,11 @@ VARx(ev_io, sigfd_w) VARx(sigset_t, sigfd_set) #endif +#if EV_USE_TIMERFD || EV_GENWRAP +VARx(int, timerfd) /* timerfd for time jump detection */ +VARx(ev_io, timerfd_w) +#endif + VARx(unsigned int, origflags) /* original loop flags */ #if EV_FEATURE_API || EV_GENWRAP diff --git a/libev/ev_wrap.h b/libev/ev_wrap.h index e6b7cb3..41bba7a 100644 --- a/libev/ev_wrap.h +++ b/libev/ev_wrap.h @@ -124,6 +124,8 @@ #define sigfd_w ((loop)->sigfd_w) #define timeout_blocktime ((loop)->timeout_blocktime) #define timercnt ((loop)->timercnt) +#define timerfd ((loop)->timerfd) +#define timerfd_w ((loop)->timerfd_w) #define timermax ((loop)->timermax) #define timers ((loop)->timers) #define userdata ((loop)->userdata) @@ -258,6 +260,8 @@ #undef sigfd_w #undef timeout_blocktime #undef timercnt +#undef timerfd +#undef timerfd_w #undef timermax #undef timers #undef userdata |