diff options
author | Max Kellermann <max@duempel.org> | 2014-01-04 14:56:02 +0100 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2014-01-04 15:58:59 +0100 |
commit | a357d84dce668d126fe984680e5d17f6d41b2fe6 (patch) | |
tree | a85f021ed1d7f999592f5fb3878a4b723755d1cd /src/event/Loop.cxx | |
parent | 48c96bbaea542491b930f244e22d17db5a281434 (diff) | |
download | mpd-a357d84dce668d126fe984680e5d17f6d41b2fe6.tar.gz mpd-a357d84dce668d126fe984680e5d17f6d41b2fe6.tar.xz mpd-a357d84dce668d126fe984680e5d17f6d41b2fe6.zip |
event/DeferredMonitor: make fully thread-safe
Instead of creating a new eventfd for each DeferredMonitor instance,
reuse EventLoop's eventfd, and add a std::list to EventLoop that
manages the list of pending DeferredMonitors. This std::list is
protected by the same mutex as the "calls" list.
The bottom line is: reduced overhead because the per-instance eventfd
was eliminated, slightly added overhead due to Mutex usage (but
negligible), and we're thread-safe now.
This subsystem is now good enough to replace EventLoop::AddCall().
Diffstat (limited to '')
-rw-r--r-- | src/event/Loop.cxx | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/src/event/Loop.cxx b/src/event/Loop.cxx index f7b3df022..c525fc103 100644 --- a/src/event/Loop.cxx +++ b/src/event/Loop.cxx @@ -26,6 +26,7 @@ #include "TimeoutMonitor.hxx" #include "SocketMonitor.hxx" #include "IdleMonitor.hxx" +#include "DeferredMonitor.hxx" #include <algorithm> @@ -204,6 +205,44 @@ EventLoop::AddCall(std::function<void()> &&f) wake_fd.Write(); } +void +EventLoop::AddDeferred(DeferredMonitor &d) +{ + mutex.lock(); + if (d.pending) { + mutex.unlock(); + return; + } + + assert(std::find(deferred.begin(), + deferred.end(), &d) == deferred.end()); + + d.pending = true; + deferred.push_back(&d); + mutex.unlock(); + + wake_fd.Write(); +} + +void +EventLoop::RemoveDeferred(DeferredMonitor &d) +{ + const ScopeLock protect(mutex); + + if (!d.pending) { + assert(std::find(deferred.begin(), + deferred.end(), &d) == deferred.end()); + return; + } + + d.pending = false; + + auto i = std::find(deferred.begin(), deferred.end(), &d); + assert(i != deferred.end()); + + deferred.erase(i); +} + bool EventLoop::OnSocketReady(gcc_unused unsigned flags) { @@ -213,6 +252,18 @@ EventLoop::OnSocketReady(gcc_unused unsigned flags) mutex.lock(); + while (!deferred.empty() && !quit) { + DeferredMonitor &m = *deferred.front(); + assert(m.pending); + + deferred.pop_front(); + m.pending = false; + + mutex.unlock(); + m.RunDeferred(); + mutex.lock(); + } + while (!calls.empty() && !quit) { auto f = std::move(calls.front()); calls.pop_front(); |