]> granicus.if.org Git - libevent/commitdiff
epoll: use epoll_pwait2() if available
authorDmitry Antipov <dantipov@cloudlinux.com>
Thu, 15 Sep 2022 11:06:50 +0000 (14:06 +0300)
committerAzat Khuzhin <a3at.mail@gmail.com>
Tue, 27 Sep 2022 19:07:43 +0000 (22:07 +0300)
On GNU/Linux with epoll backend, prefer epoll_pwait2() if available,
which is useful to support the timeout with microsecond precision.

CMakeLists.txt
configure.ac
epoll.c
event-config.h.cmake

index c66fe9e62b28dc572c2c6a5eb310b6a2082b7c82..20bdc92e064791f3f97cbcdb3f60f17aeedc91eb 100644 (file)
@@ -518,6 +518,7 @@ else()
         select
         epoll_create
         epoll_create1
+        epoll_pwait2
         epoll_ctl
         eventfd
         poll
index b0a37fe85eb00f49a677c9511cfc19afeadabba5..cc961692b67026564dac06b89a3a55f11968e4a9 100644 (file)
@@ -272,7 +272,7 @@ dnl Checks for typedefs, structures, and compiler characteristics.
 AC_C_INLINE
 
 dnl Checks for library functions.
-AC_CHECK_FUNCS([accept4 arc4random arc4random_buf arc4random_addrandom eventfd epoll_create1 fcntl getegid geteuid getifaddrs gettimeofday issetugid mach_absolute_time mmap nanosleep pipe pipe2 putenv sendfile setenv setrlimit sigaction signal strsignal strlcpy strsep strtok_r strtoll sysctl timerfd_create umask unsetenv usleep getrandom mmap64])
+AC_CHECK_FUNCS([accept4 arc4random arc4random_buf arc4random_addrandom eventfd epoll_create1 epoll_pwait2 fcntl getegid geteuid getifaddrs gettimeofday issetugid mach_absolute_time mmap nanosleep pipe pipe2 putenv sendfile setenv setrlimit sigaction signal strsignal strlcpy strsep strtok_r strtoll sysctl timerfd_create umask unsetenv usleep getrandom mmap64])
 
 AS_IF([test "$bwin32" = "true"],
   AC_CHECK_FUNCS(_gmtime64_s, , [AC_CHECK_FUNCS(_gmtime64)])
diff --git a/epoll.c b/epoll.c
index 24a63bb4da334876719f34d2f79ae209477e7052..9b4890772db718035e2b3a8c43cc1d782b0cb83e 100644 (file)
--- a/epoll.c
+++ b/epoll.c
 #if defined(EVENT__HAVE_SYS_TIMERFD_H) &&                        \
        defined(EVENT__HAVE_TIMERFD_CREATE) &&                    \
        defined(HAVE_POSIX_MONOTONIC) && defined(TFD_NONBLOCK) && \
-       defined(TFD_CLOEXEC)
+       defined(TFD_CLOEXEC) && !defined(EVENT__HAVE_EPOLL_PWAIT2)
 /* Note that we only use timerfd if TFD_NONBLOCK and TFD_CLOEXEC are available
    and working.  This means that we can't support it on 2.6.25 (where timerfd
-   was introduced) or 2.6.26, since 2.6.27 introduced those flags.
- */
+   was introduced) or 2.6.26, since 2.6.27 introduced those flags. On recent
+   enough systems (with 5.11 and never) and so epoll_pwait2() with nanosecond
+   precision for timeouts, timerfd is not needed at all.
+*/
 #define USING_TIMERFD
 #endif
 
@@ -459,7 +461,11 @@ epoll_dispatch(struct event_base *base, struct timeval *tv)
        struct epollop *epollop = base->evbase;
        struct epoll_event *events = epollop->events;
        int i, res;
+#if defined(EVENT__HAVE_EPOLL_PWAIT2)
+       struct timespec ts = { 0, 0 };
+#else /* no epoll_pwait2() */
        long timeout = -1;
+#endif /* EVENT__HAVE_EPOLL_PWAIT2 */
 
 #ifdef USING_TIMERFD
        if (epollop->timerfd >= 0) {
@@ -489,12 +495,16 @@ epoll_dispatch(struct event_base *base, struct timeval *tv)
        } else
 #endif
        if (tv != NULL) {
+#if defined(EVENT__HAVE_EPOLL_PWAIT2)
+               TIMEVAL_TO_TIMESPEC(tv, &ts);
+#else /* no epoll_pwait2() */
                timeout = evutil_tv_to_msec_(tv);
                if (timeout < 0 || timeout > MAX_EPOLL_TIMEOUT_MSEC) {
                        /* Linux kernels can wait forever if the timeout is
                         * too big; see comment on MAX_EPOLL_TIMEOUT_MSEC. */
                        timeout = MAX_EPOLL_TIMEOUT_MSEC;
                }
+#endif /* EVENT__HAVE_EPOLL_PWAIT2 */
        }
 
        epoll_apply_changes(base);
@@ -502,7 +512,11 @@ epoll_dispatch(struct event_base *base, struct timeval *tv)
 
        EVBASE_RELEASE_LOCK(base, th_base_lock);
 
+#if defined(EVENT__HAVE_EPOLL_PWAIT2)
+       res = epoll_pwait2(epollop->epfd, events, epollop->nevents, tv ? &ts : NULL, NULL);
+#else /* no epoll_pwait2() */
        res = epoll_wait(epollop->epfd, events, epollop->nevents, timeout);
+#endif /* EVENT__HAVE_EPOLL_PWAIT2 */
 
        EVBASE_ACQUIRE_LOCK(base, th_base_lock);
 
index a52e7136ea9dd9d1396c68e21ee30e64e5736bd4..a3cfafa164f2dec4c3816b21f01ab5d7e99fe701 100644 (file)
@@ -99,6 +99,9 @@
 /* Define to 1 if you have the `epoll_create1' function. */
 #cmakedefine EVENT__HAVE_EPOLL_CREATE1 1
 
+/* Define to 1 if you have the `epoll_pwait2' function. */
+#cmakedefine EVENT__HAVE_EPOLL_PWAIT2 1
+
 /* Define to 1 if you have the `epoll_ctl' function. */
 #cmakedefine EVENT__HAVE_EPOLL_CTL 1