Avoid calling read(2) on eventfd on each event-loop wakeup
This commit is contained in:
parent
dcbcfe5000
commit
5d01724d1e
@ -0,0 +1,93 @@
|
||||
From b137f071988d9b01c05cb693a56d4359f19cdb2c Mon Sep 17 00:00:00 2001
|
||||
From: Andy Pan <i@andypan.me>
|
||||
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
|
||||
|
||||
@ -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 <baiguo@kylinos.cn> - 2.1.12-11
|
||||
- Avoid calling read(2) on eventfd on each event-loop wakeup
|
||||
|
||||
* Mon Apr 01 2024 shixuantong <shixuantong1@huawei.com> - 2.1.12-10
|
||||
- evutil: don't call memset before memcpy
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user