aboutsummaryrefslogtreecommitdiffstats
path: root/src/event/Loop.cxx
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2014-01-04 14:56:02 +0100
committerMax Kellermann <max@duempel.org>2014-01-04 15:58:59 +0100
commita357d84dce668d126fe984680e5d17f6d41b2fe6 (patch)
treea85f021ed1d7f999592f5fb3878a4b723755d1cd /src/event/Loop.cxx
parent48c96bbaea542491b930f244e22d17db5a281434 (diff)
downloadmpd-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.cxx51
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();