mirror of
https://github.com/libevent/libevent.git
synced 2025-01-31 09:12:55 +08:00
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.
This commit is contained in:
parent
e0a4574ba2
commit
6074d55822
37
event.c
37
event.c
@ -2589,13 +2589,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;
|
||||
|
||||
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
|
||||
|
||||
@ -3648,14 +3666,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);
|
||||
@ -3733,7 +3744,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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user