aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2014-01-05 01:37:22 +0100
committerMax Kellermann <max@duempel.org>2014-01-05 02:15:34 +0100
commite599b86424014d469874f67594112e0a7160a336 (patch)
tree0cda94c849fe2f4d06dba600a4cf452c87c8d576 /src
parentda9e5849212337f26d1fa0450ce71cd58aefc30d (diff)
downloadmpd-e599b86424014d469874f67594112e0a7160a336.tar.gz
mpd-e599b86424014d469874f67594112e0a7160a336.tar.xz
mpd-e599b86424014d469874f67594112e0a7160a336.zip
event/Loop: try to avoid the WakeFD when adding DeferredMonitor
Add a flag that indicates whether the EventLoop is currently "busy". As long as that flag is set, it does not need to be woken up - we can simply add the DeferredMonitor to the list, and it will be caught by EventLoop very soon. This eliminates nearly all of the DeferredMonitor overhead when compared to IdleMonitor, rendering IdleMonitor mostly obsolete.
Diffstat (limited to 'src')
-rw-r--r--src/event/Loop.cxx18
-rw-r--r--src/event/Loop.hxx8
2 files changed, 24 insertions, 2 deletions
diff --git a/src/event/Loop.cxx b/src/event/Loop.cxx
index 0e76afc25..58c25e040 100644
--- a/src/event/Loop.cxx
+++ b/src/event/Loop.cxx
@@ -31,7 +31,7 @@
EventLoop::EventLoop(Default)
:SocketMonitor(*this),
now_ms(::MonotonicClockMS()),
- quit(false),
+ quit(false), busy(true),
thread(ThreadId::Null())
{
SocketMonitor::Open(wake_fd.Get());
@@ -122,6 +122,7 @@ EventLoop::Run()
thread = ThreadId::GetCurrent();
assert(!quit);
+ assert(busy);
do {
now_ms = ::MonotonicClockMS();
@@ -161,6 +162,13 @@ EventLoop::Run()
return;
}
+ /* try to handle DeferredMonitors without WakeFD
+ overhead */
+ mutex.lock();
+ HandleDeferred();
+ busy = false;
+ mutex.unlock();
+
if (again)
/* re-evaluate timers because one of the
IdleMonitors may have added a new
@@ -173,6 +181,10 @@ EventLoop::Run()
now_ms = ::MonotonicClockMS();
+ mutex.lock();
+ busy = true;
+ mutex.unlock();
+
/* invoke sockets */
for (int i = 0; i < poll_result.GetSize(); ++i) {
auto events = poll_result.GetEvents(i);
@@ -190,6 +202,7 @@ EventLoop::Run()
} while (!quit);
#ifndef NDEBUG
+ assert(busy);
assert(thread.IsInside());
thread = ThreadId::Null();
#endif
@@ -209,10 +222,11 @@ EventLoop::AddDeferred(DeferredMonitor &d)
/* we don't need to wake up the EventLoop if another
DeferredMonitor has already done it */
- const bool must_wake = deferred.empty();
+ const bool must_wake = !busy && deferred.empty();
d.pending = true;
deferred.push_back(&d);
+ again = true;
mutex.unlock();
if (must_wake)
diff --git a/src/event/Loop.hxx b/src/event/Loop.hxx
index bfa8dc4a9..4bd2a3b2c 100644
--- a/src/event/Loop.hxx
+++ b/src/event/Loop.hxx
@@ -90,6 +90,14 @@ class EventLoop final : SocketMonitor
*/
bool again;
+ /**
+ * True when handling callbacks, false when waiting for I/O or
+ * timeout.
+ *
+ * Protected with #mutex.
+ */
+ bool busy;
+
PollGroup poll_group;
PollResult poll_result;