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.
This commit is contained in:
Max Kellermann 2014-01-05 01:37:22 +01:00
parent da9e584921
commit e599b86424
2 changed files with 24 additions and 2 deletions

View File

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

View File

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