*** empty log message ***

This commit is contained in:
Marc Alexander Lehmann 2019-12-20 20:51:46 +00:00
parent ebd88ad8a1
commit 598407e832
7 changed files with 216 additions and 27 deletions

View File

@ -5,9 +5,13 @@ TODO: maybe use timerfd to detect time jumps on linux
TODO: document EV_TSTAMP_T
4.31
TODO: use TFD_TIMER_CANCEL_ON_SET to call periodics_reschedule, maybe? (must)
- handle backends with minimum wait time a bit better by not
waiting in the presence of already-expired timers
(behaviour reported by Felipe Gsper).
(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

32
ev.3
View File

@ -133,7 +133,7 @@
.\" ========================================================================
.\"
.IX Title "LIBEV 3"
.TH LIBEV 3 "2019-07-07" "libev-4.27" "libev - high performance full featured event loop"
.TH LIBEV 3 "2019-12-20" "libev-4.27" "libev - high performance full featured event loop"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l
@ -595,6 +595,13 @@ threads that are not interested in handling them.
Signalfd will not be used by default as this changes your signal mask, and
there are a lot of shoddy libraries and programs (glib's threadpool for
example) that can't properly initialise their signal masks.
.ie n .IP """EVFLAG_NOTIMERFD""" 4
.el .IP "\f(CWEVFLAG_NOTIMERFD\fR" 4
.IX Item "EVFLAG_NOTIMERFD"
When this flag is specified, the libev will avoid using a \f(CW\*(C`timerfd\*(C'\fR 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.
.ie n .IP """EVFLAG_NOSIGMASK""" 4
.el .IP "\f(CWEVFLAG_NOSIGMASK\fR" 4
.IX Item "EVFLAG_NOSIGMASK"
@ -1656,7 +1663,7 @@ Many event loops support \fIwatcher priorities\fR, which are usually small
integers that influence the ordering of event callback invocation
between watchers in some way, all else being equal.
.PP
In libev, Watcher priorities can be set using \f(CW\*(C`ev_set_priority\*(C'\fR. See its
In libev, watcher priorities can be set using \f(CW\*(C`ev_set_priority\*(C'\fR. See its
description for the more technical details such as the actual priority
range.
.PP
@ -4756,6 +4763,27 @@ available and will probe for kernel support at runtime. This will improve
\&\f(CW\*(C`ev_signal\*(C'\fR and \f(CW\*(C`ev_async\*(C'\fR performance and reduce resource consumption.
If undefined, it will be enabled if the headers indicate GNU/Linux + Glibc
2.7 or newer, otherwise disabled.
.IP "\s-1EV_USE_SIGNALFD\s0" 4
.IX Item "EV_USE_SIGNALFD"
If defined to be \f(CW1\fR, then libev will assume that \f(CW\*(C`signalfd ()\*(C'\fR is
available and will probe for kernel support at runtime. This enables
the use of \s-1EVFLAG_SIGNALFD\s0 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.
.IP "\s-1EV_USE_TIMERFD\s0" 4
.IX Item "EV_USE_TIMERFD"
If defined to be \f(CW1\fR, then libev will assume that \f(CW\*(C`timerfd ()\*(C'\fR 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
\&\f(CW\*(C`TFD_TIMER_CANCEL_ON_SET\*(C'\fR, otherwise disabled.
.IP "\s-1EV_USE_EVENTFD\s0" 4
.IX Item "EV_USE_EVENTFD"
If defined to be \f(CW1\fR, then libev will assume that \f(CW\*(C`eventfd ()\*(C'\fR is
available and will probe for kernel support at runtime. This will improve
\&\f(CW\*(C`ev_signal\*(C'\fR and \f(CW\*(C`ev_async\*(C'\fR performance and reduce resource consumption.
If undefined, it will be enabled if the headers indicate GNU/Linux + Glibc
2.7 or newer, otherwise disabled.
.IP "\s-1EV_USE_SELECT\s0" 4
.IX Item "EV_USE_SELECT"
If undefined or defined to be \f(CW1\fR, libev will compile in support for the

146
ev.c
View File

@ -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 */
#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);
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);
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;
}
@ -4214,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)

15
ev.h
View File

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

35
ev.pod
View File

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

View File

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

View File

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