From a14997ffb8db6dc363151f628c823991895de34a Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sun, 18 Oct 2020 19:39:21 +0200 Subject: [PATCH] event/Loop: manage all SocketEvents in a linked list Not only those which are "ready". --- src/event/Loop.cxx | 30 +++++++++++++++++++++--------- src/event/Loop.hxx | 16 ++++++++++------ src/event/SocketEvent.cxx | 2 +- src/event/SocketEvent.hxx | 5 +---- 4 files changed, 33 insertions(+), 20 deletions(-) diff --git a/src/event/Loop.cxx b/src/event/Loop.cxx index afc62b2f7..05c5bac1d 100644 --- a/src/event/Loop.cxx +++ b/src/event/Loop.cxx @@ -67,6 +67,8 @@ EventLoop::~EventLoop() noexcept { assert(idle.empty()); assert(timers.empty()); + assert(sockets.empty()); + assert(ready_sockets.empty()); } #ifdef HAVE_URING @@ -117,7 +119,11 @@ EventLoop::AddFD(int fd, unsigned events, SocketEvent &event) noexcept assert(!IsAlive() || IsInside()); #endif - return poll_group.Add(fd, events, &event); + if (!poll_group.Add(fd, events, &event)) + return false; + + sockets.push_back(event); + return true; } bool @@ -131,12 +137,13 @@ EventLoop::ModifyFD(int fd, unsigned events, SocketEvent &event) noexcept } bool -EventLoop::RemoveFD(int fd) noexcept +EventLoop::RemoveFD(int fd, SocketEvent &event) noexcept { #ifdef HAVE_THREADED_EVENT_LOOP assert(!IsAlive() || IsInside()); #endif + event.unlink(); return poll_group.Remove(fd); } @@ -213,11 +220,13 @@ EventLoop::Wait(Event::Duration timeout) noexcept const auto poll_result = poll_group.ReadEvents(ExportTimeoutMS(timeout)); - ready_sockets.clear(); for (size_t i = 0; i < poll_result.GetSize(); ++i) { - auto &s = *(SocketEvent *)poll_result.GetObject(i); - s.SetReadyFlags(poll_result.GetEvents(i)); - ready_sockets.push_back(s); + auto &socket_event = *(SocketEvent *)poll_result.GetObject(i); + socket_event.SetReadyFlags(poll_result.GetEvents(i)); + + /* move from "sockets" to "ready_sockets" */ + socket_event.unlink(); + ready_sockets.push_back(socket_event); } return poll_result.GetSize() > 0; @@ -309,10 +318,13 @@ EventLoop::Run() noexcept /* invoke sockets */ while (!ready_sockets.empty() && !quit) { - auto &sm = ready_sockets.front(); - ready_sockets.pop_front(); + auto &socket_event = ready_sockets.front(); - sm.Dispatch(); + /* move from "ready_sockets" back to "sockets" */ + socket_event.unlink(); + sockets.push_back(socket_event); + + socket_event.Dispatch(); } } while (!quit); diff --git a/src/event/Loop.hxx b/src/event/Loop.hxx index 864215995..fc6efcdef 100644 --- a/src/event/Loop.hxx +++ b/src/event/Loop.hxx @@ -91,18 +91,22 @@ class EventLoop final DeferredList deferred; #endif - using ReadySocketList = + using SocketList = boost::intrusive::list, + boost::intrusive::base_hook>>, boost::intrusive::constant_time_size>; + /** + * A list of scheduled #SocketEvent instances, without those + * which are ready (these are in #ready_sockets). + */ + SocketList sockets; + /** * A linked list of #SocketEvent instances which have a * non-zero "ready_flags" field, and need to be dispatched. */ - ReadySocketList ready_sockets; + SocketList ready_sockets; #ifdef HAVE_URING std::unique_ptr uring; @@ -188,7 +192,7 @@ public: bool AddFD(int fd, unsigned events, SocketEvent &event) noexcept; bool ModifyFD(int fd, unsigned events, SocketEvent &event) noexcept; - bool RemoveFD(int fd) noexcept; + bool RemoveFD(int fd, SocketEvent &event) noexcept; /** * Remove the given #SocketEvent after the file descriptor diff --git a/src/event/SocketEvent.cxx b/src/event/SocketEvent.cxx index 62fea1004..f560f9dab 100644 --- a/src/event/SocketEvent.cxx +++ b/src/event/SocketEvent.cxx @@ -69,7 +69,7 @@ SocketEvent::Schedule(unsigned flags) noexcept if (scheduled_flags == 0) success = loop.AddFD(fd.Get(), flags, *this); else if (flags == 0) - success = loop.RemoveFD(fd.Get()); + success = loop.RemoveFD(fd.Get(), *this); else success = loop.ModifyFD(fd.Get(), flags, *this); diff --git a/src/event/SocketEvent.hxx b/src/event/SocketEvent.hxx index feaca85ce..01a571410 100644 --- a/src/event/SocketEvent.hxx +++ b/src/event/SocketEvent.hxx @@ -45,14 +45,11 @@ class EventLoop; * thread that runs the #EventLoop, except where explicitly documented * as thread-safe. */ -class SocketEvent { +class SocketEvent final : public boost::intrusive::list_base_hook> { friend class EventLoop; EventLoop &loop; - using ReadyListHook = boost::intrusive::list_member_hook>; - ReadyListHook ready_siblings; - using Callback = BoundMethod; const Callback callback;