Add config option to determine whether eventfd is used.

Add a new configuration option "reactor" / "use_eventfd" that is used by
the epoll_reactor. When true (the default), the reactor uses an eventfd
as its select_interrupter implementation. When false, a pipe is used
instead.
This commit is contained in:
Christopher Kohlhoff
2025-11-05 19:32:11 +11:00
parent fb037cfc73
commit 1916ff6568
8 changed files with 48 additions and 33 deletions

View File

@@ -29,7 +29,7 @@ class eventfd_select_interrupter
{
public:
// Constructor.
ASIO_DECL eventfd_select_interrupter();
ASIO_DECL explicit eventfd_select_interrupter(bool use_eventfd = true);
// Destructor.
ASIO_DECL ~eventfd_select_interrupter();
@@ -51,7 +51,7 @@ public:
private:
// Open the descriptors. Throws on error.
ASIO_DECL void open_descriptors();
ASIO_DECL void open_descriptors(bool use_eventfd);
// Close the descriptors.
ASIO_DECL void close_descriptors();

View File

@@ -41,7 +41,7 @@ epoll_reactor::epoll_reactor(asio::execution_context& ctx)
scheduler_(use_service<scheduler>(ctx)),
mutex_(config(ctx).get("reactor", "registration_locking", true),
config(ctx).get("reactor", "registration_locking_spin_count", 0)),
interrupter_(),
interrupter_(config(ctx).get("reactor", "use_eventfd", true)),
epoll_fd_(do_epoll_create()),
timer_fd_(config(ctx).get("reactor", "use_timerfd", true)
? do_timerfd_create() : -1),

View File

@@ -38,38 +38,43 @@
namespace asio {
namespace detail {
eventfd_select_interrupter::eventfd_select_interrupter()
eventfd_select_interrupter::eventfd_select_interrupter(bool use_eventfd)
{
open_descriptors();
open_descriptors(use_eventfd);
}
void eventfd_select_interrupter::open_descriptors()
void eventfd_select_interrupter::open_descriptors(bool use_eventfd)
{
if (use_eventfd)
{
#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 && !defined(__UCLIBC__)
write_descriptor_ = read_descriptor_ = syscall(__NR_eventfd, 0);
if (read_descriptor_ != -1)
{
::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC);
}
#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 && !defined(__UCLIBC__)
# if defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK)
write_descriptor_ = read_descriptor_ =
::eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
# else // defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK)
errno = EINVAL;
write_descriptor_ = read_descriptor_ = -1;
# endif // defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK)
if (read_descriptor_ == -1 && errno == EINVAL)
{
write_descriptor_ = read_descriptor_ = ::eventfd(0, 0);
write_descriptor_ = read_descriptor_ = syscall(__NR_eventfd, 0);
if (read_descriptor_ != -1)
{
::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC);
}
}
#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 && !defined(__UCLIBC__)
# if defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK)
write_descriptor_ = read_descriptor_ =
::eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
# else // defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK)
errno = EINVAL;
write_descriptor_ = read_descriptor_ = -1;
# endif // defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK)
if (read_descriptor_ == -1 && errno == EINVAL)
{
write_descriptor_ = read_descriptor_ = ::eventfd(0, 0);
if (read_descriptor_ != -1)
{
::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC);
}
}
#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 && !defined(__UCLIBC__)
}
else
write_descriptor_ = read_descriptor_ = -1;
if (read_descriptor_ == -1)
{
@@ -107,12 +112,10 @@ void eventfd_select_interrupter::close_descriptors()
void eventfd_select_interrupter::recreate()
{
bool use_eventfd = (write_descriptor_ == read_descriptor_);
close_descriptors();
write_descriptor_ = -1;
read_descriptor_ = -1;
open_descriptors();
write_descriptor_ = read_descriptor_ = -1;
open_descriptors(use_eventfd);
}
void eventfd_select_interrupter::interrupt()

View File

@@ -37,7 +37,7 @@
namespace asio {
namespace detail {
pipe_select_interrupter::pipe_select_interrupter()
pipe_select_interrupter::pipe_select_interrupter(bool)
{
open_descriptors();
}

View File

@@ -35,7 +35,7 @@
namespace asio {
namespace detail {
socket_select_interrupter::socket_select_interrupter()
socket_select_interrupter::socket_select_interrupter(bool)
{
open_descriptors();
}

View File

@@ -32,7 +32,7 @@ class pipe_select_interrupter
{
public:
// Constructor.
ASIO_DECL pipe_select_interrupter();
ASIO_DECL explicit pipe_select_interrupter(bool = true);
// Destructor.
ASIO_DECL ~pipe_select_interrupter();

View File

@@ -34,7 +34,7 @@ class socket_select_interrupter
{
public:
// Constructor.
ASIO_DECL socket_select_interrupter();
ASIO_DECL explicit socket_select_interrupter(bool = true);
// Destructor.
ASIO_DECL ~socket_select_interrupter();

View File

@@ -177,6 +177,18 @@ below.
fails with `EAGAIN`.
]
]
[
[`reactor`]
[`use_eventfd`]
[`bool`]
[`true`]
[
Linux [^epoll] backend only.
When `true`, the reactor uses an [^eventfd] descriptor to wake a blocked
[^epoll_wait] call. When `false`, a pipe is used instead.
]
]
[
[`reactor`]
[`use_timerfd`]