From 01009e081acc34512b4045da19bb9eeecd59cf62 Mon Sep 17 00:00:00 2001 From: baiguo Date: Wed, 8 May 2024 16:31:25 +0800 Subject: [PATCH 1/2] Avoid calling read(2) on eventfd on each event-loop wakeup --- ...ad-2-on-eventfd-on-each-event-loop-w.patch | 94 +++++++++++++++++++ libevent.spec | 6 +- 2 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 0002-Avoid-calling-read-2-on-eventfd-on-each-event-loop-w.patch 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 0000000..50053fb --- /dev/null +++ b/0002-Avoid-calling-read-2-on-eventfd-on-each-event-loop-w.patch @@ -0,0 +1,94 @@ +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 | 39 +++++++++++++++++++++++++-------------- + 1 file changed, 25 insertions(+), 14 deletions(-) + +diff --git a/event.c b/event.c +index 7a42b73..2c749df 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,31 @@ 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; ++ ++ 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 (r < 0) ? -1 : 0; ++ return ret; + } + #endif + +@@ -3582,14 +3600,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 +3678,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 42aba2c..feb4722 100644 --- a/libevent.spec +++ b/libevent.spec @@ -1,6 +1,6 @@ Name: libevent Version: 2.1.12 -Release: 8 +Release: 9 Summary: An event notification library License: BSD @@ -16,6 +16,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, @@ -88,6 +89,9 @@ EOF %changelog +% Wed May 08 2024 baiguo - 2.1.12-9 +- Avoid calling read(2) on eventfd on each event-loop wakeup + * Mon Apr 01 2024 shixuantong - 2.1.12-8 - Type:bugfix - CVE:NA -- Gitee From 1fae3291e72a4da55a376ec6e99708ce085160fd Mon Sep 17 00:00:00 2001 From: baiguo Date: Thu, 9 May 2024 17:24:19 +0800 Subject: [PATCH 2/2] Avoid calling read(2) on eventfd on each event-loop wakeup --- libevent.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevent.spec b/libevent.spec index feb4722..d3aeacd 100644 --- a/libevent.spec +++ b/libevent.spec @@ -89,7 +89,7 @@ EOF %changelog -% Wed May 08 2024 baiguo - 2.1.12-9 +* Wed May 08 2024 baiguo - 2.1.12-9 - Avoid calling read(2) on eventfd on each event-loop wakeup * Mon Apr 01 2024 shixuantong - 2.1.12-8 -- Gitee