From 85014b5fa2363b0d615b03c7119093a4c898f8cc Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 13 Feb 2025 16:37:47 +0100 Subject: [PATCH] event/Loop: move code to Wait() --- src/event/Loop.cxx | 82 +++++++++++++++++++++++++++------------------- src/event/Loop.hxx | 10 ++++++ 2 files changed, 58 insertions(+), 34 deletions(-) diff --git a/src/event/Loop.cxx b/src/event/Loop.cxx index 14f803dfc..e9716649f 100644 --- a/src/event/Loop.cxx +++ b/src/event/Loop.cxx @@ -338,6 +338,53 @@ EventLoop::Poll(Event::Duration timeout) noexcept return poll_result.GetSize() > 0; } +#ifdef HAVE_URING + +inline void +EventLoop::UringWait(Event::Duration timeout) noexcept +{ + assert(uring); + + /* use io_uring_enter() and invoke epoll_wait() only if it's + reported to be ready */ + + if (!uring_poll) [[unlikely]] { + /* start polling on the epoll file descriptor */ + uring_poll = std::make_unique(*this); + uring_poll->Start(); + } + + /* repeat epoll_wait() until it returns no more events; this + is a temporary workaround because + io_uring_prep_poll_multishot() is edge-triggered, so we + have to consume all events to rearm it */ + + if (!epoll_ready) { + struct __kernel_timespec timeout_buffer; + auto *kernel_timeout = ExportTimeoutKernelTimespec(timeout, timeout_buffer); + Uring::Queue &uring_queue = *uring; + uring_queue.SubmitAndWaitDispatchCompletions(kernel_timeout); + } + + if (epoll_ready) { + /* invoke epoll_wait() */ + epoll_ready = Poll(Event::Duration{0}); + } +} + +#endif // HAVE_URING + +inline void +EventLoop::Wait(Event::Duration timeout) noexcept +{ +#ifdef HAVE_URING + if (uring) + return UringWait(timeout); +#endif + + Poll(timeout); +} + void EventLoop::Run() noexcept { @@ -405,40 +452,7 @@ EventLoop::Run() noexcept if (!next.empty()) timeout = Event::Duration{0}; -#ifdef HAVE_URING - if (uring) { - /* use io_uring_enter() and invoke - epoll_wait() only if it's reported - to be ready */ - - if (!uring_poll) [[unlikely]] { - /* start polling on the epoll - file descriptor */ - uring_poll = std::make_unique(*this); - uring_poll->Start(); - } - - /* repeat epoll_wait() until it - returns no more events; this is a - temporary workaround because - io_uring_prep_poll_multishot() is - edge-triggered, so we have to - consume all events to rearm it */ - - if (!epoll_ready) { - struct __kernel_timespec timeout_buffer; - auto *kernel_timeout = ExportTimeoutKernelTimespec(timeout, timeout_buffer); - Uring::Queue &uring_queue = *uring; - uring_queue.SubmitAndWaitDispatchCompletions(kernel_timeout); - } - - if (epoll_ready) { - /* invoke epoll_wait() */ - epoll_ready = Poll(Event::Duration{0}); - } - } else -#endif - Poll(timeout); + Wait(timeout); idle.splice(std::next(idle.begin()), next); diff --git a/src/event/Loop.hxx b/src/event/Loop.hxx index 9e9748b42..d1ee5c3b9 100644 --- a/src/event/Loop.hxx +++ b/src/event/Loop.hxx @@ -328,6 +328,16 @@ private: */ bool Poll(Event::Duration timeout) noexcept; +#ifdef HAVE_URING + void UringWait(Event::Duration timeout) noexcept; +#endif + + /** + * Wait for I/O (socket) events, either using Poll() or + * UringWait(). + */ + void Wait(Event::Duration timeout) noexcept; + #ifdef HAVE_THREADED_EVENT_LOOP void OnSocketReady(unsigned flags) noexcept; #endif