From 1916ff6568561ac9bf87faebd7d161798dd40287 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Wed, 5 Nov 2025 19:32:11 +1100 Subject: [PATCH] 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. --- .../detail/eventfd_select_interrupter.hpp | 4 +- include/asio/detail/impl/epoll_reactor.ipp | 2 +- .../impl/eventfd_select_interrupter.ipp | 55 ++++++++++--------- .../detail/impl/pipe_select_interrupter.ipp | 2 +- .../detail/impl/socket_select_interrupter.ipp | 2 +- .../asio/detail/pipe_select_interrupter.hpp | 2 +- .../asio/detail/socket_select_interrupter.hpp | 2 +- src/doc/overview/configuration.qbk | 12 ++++ 8 files changed, 48 insertions(+), 33 deletions(-) diff --git a/include/asio/detail/eventfd_select_interrupter.hpp b/include/asio/detail/eventfd_select_interrupter.hpp index acf47fb4e..4c2f4ddd0 100644 --- a/include/asio/detail/eventfd_select_interrupter.hpp +++ b/include/asio/detail/eventfd_select_interrupter.hpp @@ -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(); diff --git a/include/asio/detail/impl/epoll_reactor.ipp b/include/asio/detail/impl/epoll_reactor.ipp index a058794c4..1de9a55f5 100644 --- a/include/asio/detail/impl/epoll_reactor.ipp +++ b/include/asio/detail/impl/epoll_reactor.ipp @@ -41,7 +41,7 @@ epoll_reactor::epoll_reactor(asio::execution_context& ctx) scheduler_(use_service(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), diff --git a/include/asio/detail/impl/eventfd_select_interrupter.ipp b/include/asio/detail/impl/eventfd_select_interrupter.ipp index bbdeb1af6..f87848a1b 100644 --- a/include/asio/detail/impl/eventfd_select_interrupter.ipp +++ b/include/asio/detail/impl/eventfd_select_interrupter.ipp @@ -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() diff --git a/include/asio/detail/impl/pipe_select_interrupter.ipp b/include/asio/detail/impl/pipe_select_interrupter.ipp index 854b1df14..db224a9d8 100644 --- a/include/asio/detail/impl/pipe_select_interrupter.ipp +++ b/include/asio/detail/impl/pipe_select_interrupter.ipp @@ -37,7 +37,7 @@ namespace asio { namespace detail { -pipe_select_interrupter::pipe_select_interrupter() +pipe_select_interrupter::pipe_select_interrupter(bool) { open_descriptors(); } diff --git a/include/asio/detail/impl/socket_select_interrupter.ipp b/include/asio/detail/impl/socket_select_interrupter.ipp index 5626d11c8..e22ffb44f 100644 --- a/include/asio/detail/impl/socket_select_interrupter.ipp +++ b/include/asio/detail/impl/socket_select_interrupter.ipp @@ -35,7 +35,7 @@ namespace asio { namespace detail { -socket_select_interrupter::socket_select_interrupter() +socket_select_interrupter::socket_select_interrupter(bool) { open_descriptors(); } diff --git a/include/asio/detail/pipe_select_interrupter.hpp b/include/asio/detail/pipe_select_interrupter.hpp index e235d1a51..85c005824 100644 --- a/include/asio/detail/pipe_select_interrupter.hpp +++ b/include/asio/detail/pipe_select_interrupter.hpp @@ -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(); diff --git a/include/asio/detail/socket_select_interrupter.hpp b/include/asio/detail/socket_select_interrupter.hpp index f0fd61c9a..3df033e9e 100644 --- a/include/asio/detail/socket_select_interrupter.hpp +++ b/include/asio/detail/socket_select_interrupter.hpp @@ -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(); diff --git a/src/doc/overview/configuration.qbk b/src/doc/overview/configuration.qbk index f77389607..f44c4d2e3 100644 --- a/src/doc/overview/configuration.qbk +++ b/src/doc/overview/configuration.qbk @@ -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`]