event/Loop: manage all SocketEvents in a linked list

Not only those which are "ready".
This commit is contained in:
Max Kellermann 2020-10-18 19:39:21 +02:00
parent dd94f97572
commit a14997ffb8
4 changed files with 33 additions and 20 deletions

View File

@ -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);

View File

@ -91,18 +91,22 @@ class EventLoop final
DeferredList deferred;
#endif
using ReadySocketList =
using SocketList =
boost::intrusive::list<SocketEvent,
boost::intrusive::member_hook<SocketEvent,
SocketEvent::ReadyListHook,
&SocketEvent::ready_siblings>,
boost::intrusive::base_hook<boost::intrusive::list_base_hook<boost::intrusive::link_mode<boost::intrusive::auto_unlink>>>,
boost::intrusive::constant_time_size<false>>;
/**
* 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::Manager> 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

View File

@ -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);

View File

@ -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<boost::intrusive::link_mode<boost::intrusive::auto_unlink>> {
friend class EventLoop;
EventLoop &loop;
using ReadyListHook = boost::intrusive::list_member_hook<boost::intrusive::link_mode<boost::intrusive::auto_unlink>>;
ReadyListHook ready_siblings;
using Callback = BoundMethod<void(unsigned events) noexcept>;
const Callback callback;