summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Changes9
-rw-r--r--EV.pm2
-rw-r--r--META.json2
-rw-r--r--META.yml2
-rw-r--r--Makefile.PL17
-rw-r--r--debian/changelog7
-rw-r--r--debian/copyright2
-rw-r--r--libev/Changes8
-rw-r--r--libev/ev.c157
-rw-r--r--libev/ev.h15
-rw-r--r--libev/ev.pod35
-rw-r--r--libev/ev_vars.h5
-rw-r--r--libev/ev_wrap.h4
13 files changed, 233 insertions, 32 deletions
diff --git a/Changes b/Changes
index 8cdb749..bbb8e64 100644
--- a/Changes
+++ b/Changes
@@ -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,
diff --git a/EV.pm b/EV.pm
index 21c48f6..8547d09 100644
--- a/EV.pm
+++ b/EV.pm
@@ -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;
diff --git a/META.json b/META.json
index 9a515d4..11623a4 100644
--- a/META.json
+++ b/META.json
@@ -38,5 +38,5 @@
}
},
"release_status" : "stable",
- "version" : "4.30"
+ "version" : "4.31"
}
diff --git a/META.yml b/META.yml
index f6c48c1..89a7a10 100644
--- a/META.yml
+++ b/META.yml
@@ -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.
diff --git a/libev/ev.c b/libev/ev.c
index 9dc2a24..5f68687 100644
--- a/libev/ev.c
+++ b/libev/ev.c
@@ -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)
diff --git a/libev/ev.h b/libev/ev.h
index 7966051..dfb82b3 100644
--- a/libev/ev.h
+++ b/libev/ev.h
@@ -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