diff --git a/0002-Avoid-calling-read-2-on-eventfd-on-each-event-loop-w.patch b/0002-Avoid-calling-read-2-on-eventfd-on-each-event-loop-w.patch new file mode 100644 index 0000000000000000000000000000000000000000..f80b7a79865e63aa1d37ff8fa69077e4680614a9 --- /dev/null +++ b/0002-Avoid-calling-read-2-on-eventfd-on-each-event-loop-w.patch @@ -0,0 +1,93 @@ +From b137f071988d9b01c05cb693a56d4359f19cdb2c Mon Sep 17 00:00:00 2001 +From: Andy Pan +Date: Wed, 17 Apr 2024 10:36:47 +0000 +Subject: [PATCH] Avoid calling read(2) on eventfd on each event-loop wakeup + +Register the eventfd with EPOLLET to enable edge-triggered notification +where we don't need to read the data from the eventfd for every wakeup +event. + +When the eventfd counter reaches the maximum value of the unsigned 64-bit, +we rewind the counter and retry again. This optimization saves one system +call on each event-loop wakeup, which eliminates the extra latency for epoll +as the EVFILT_USER filter does for the kqueue. +--- + event.c | 38 ++++++++++++++++++++++++-------------- + 1 file changed, 24 insertions(+), 14 deletions(-) + +diff --git a/event.c b/event.c +index 7a42b73..e37e588 100644 +--- a/event.c ++++ b/event.c +@@ -211,7 +211,7 @@ int event_debug_mode_on_ = 0; + * to be shared across threads (if thread support is enabled). + * + * When and if evthreads are initialized, this variable will be evaluated, +- * and if set to something other than zero, this means the evthread setup ++ * and if set to something other than zero, this means the evthread setup + * functions were called out of order. + * + * See: "Locks and threading" in the documentation. +@@ -2523,13 +2523,30 @@ evthread_notify_base_default(struct event_base *base) + static int + evthread_notify_base_eventfd(struct event_base *base) + { ++ int efd = base->th_notify_fd[0]; + ev_uint64_t msg = 1; +- int r; +- do { +- r = write(base->th_notify_fd[0], (void*) &msg, sizeof(msg)); +- } while (r < 0 && errno == EAGAIN); ++ ev_uint64_t val; + +- return (r < 0) ? -1 : 0; ++ int ret; ++ for (;;) { ++ ret = eventfd_write(efd, (eventfd_t) msg); ++ if (ret < 0) { ++ // When EAGAIN occurs, the eventfd counter hits the maximum value of the unsigned 64-bit. ++ // We need to first drain the eventfd and then write again. ++ // ++ // Check out https://man7.org/linux/man-pages/man2/eventfd.2.html for details. ++ if (errno == EAGAIN) { ++ // It's ready to retry. ++ if (eventfd_read(efd, &val) == 0 || errno == EAGAIN) { ++ continue; ++ } ++ } ++ // Unknown error occurs. ++ ret = -1; ++ } ++ break; ++ } ++ return ret; + } + #endif + +@@ -3582,14 +3599,7 @@ event_set_mem_functions(void *(*malloc_fn)(size_t sz), + static void + evthread_notify_drain_eventfd(evutil_socket_t fd, short what, void *arg) + { +- ev_uint64_t msg; +- ev_ssize_t r; + struct event_base *base = arg; +- +- r = read(fd, (void*) &msg, sizeof(msg)); +- if (r<0 && errno != EAGAIN) { +- event_sock_warn(fd, "Error reading from eventfd"); +- } + EVBASE_ACQUIRE_LOCK(base, th_base_lock); + base->is_notify_pending = 0; + EVBASE_RELEASE_LOCK(base, th_base_lock); +@@ -3667,7 +3677,7 @@ evthread_make_base_notifiable_nolock_(struct event_base *base) + + /* prepare an event that we can use for wakeup */ + event_assign(&base->th_notify, base, base->th_notify_fd[0], +- EV_READ|EV_PERSIST, cb, base); ++ EV_READ|EV_PERSIST|EV_ET, cb, base); + + /* we need to mark this as internal event */ + base->th_notify.ev_flags |= EVLIST_INTERNAL; +-- +2.27.0 + diff --git a/libevent.spec b/libevent.spec index 687dd3f9299521f36d3f69dc46fb9217cf192cdc..fc23fb93a97bfb76f1a5f6553b2aeadce6b709c6 100644 --- a/libevent.spec +++ b/libevent.spec @@ -1,6 +1,6 @@ Name: libevent Version: 2.1.12 -Release: 10 +Release: 11 Summary: An event notification library License: BSD @@ -23,6 +23,7 @@ Patch6001: backport-http-eliminate-redundant-bev-fd-manipulating-and-cac.patch Patch6002: backport-http-fix-fd-leak-on-fd-reset-by-using-bufferevent_re.patch Patch6003: backport-bufferevent-introduce-bufferevent_replacefd-like-set.patch Patch6004: backport-evutil-don-t-call-memset-before-memcpy.patch +Patch6005: 0002-Avoid-calling-read-2-on-eventfd-on-each-event-loop-w.patch %description Libevent additionally provides a sophisticated framework for buffered network IO, with support for sockets, @@ -83,6 +84,9 @@ rm -f %{buildroot}%{_libdir}/*.la %changelog +* Wed May 08 2024 baiguo - 2.1.12-11 +- Avoid calling read(2) on eventfd on each event-loop wakeup + * Mon Apr 01 2024 shixuantong - 2.1.12-10 - evutil: don't call memset before memcpy