event/Loop: use boost::intrusive::multiset to store TimeoutMonitors

By using an "intrusive" data structure, we can easily eliminate
struct TimerRecord.
This commit is contained in:
Max Kellermann 2017-08-29 14:25:23 +02:00
parent 71ed3ff992
commit 010855a294
4 changed files with 33 additions and 52 deletions

View File

@ -19,7 +19,6 @@
#include "config.h"
#include "Loop.hxx"
#include "TimeoutMonitor.hxx"
#include "SocketMonitor.hxx"
#include "IdleMonitor.hxx"
#include "DeferredMonitor.hxx"
@ -27,18 +26,6 @@
#include <algorithm>
inline std::chrono::steady_clock::time_point
EventLoop::TimerRecord::GetDue() const noexcept
{
return timer.due;
}
inline bool
EventLoop::TimerRecord::operator<(const TimerRecord &other) const noexcept
{
return timer.due < other.timer.due;
}
EventLoop::EventLoop(ThreadId _thread)
:SocketMonitor(*this), thread(_thread)
{
@ -106,7 +93,7 @@ EventLoop::AddTimer(TimeoutMonitor &t, std::chrono::steady_clock::duration d)
assert(IsInside());
t.due = now + d;
timers.insert(TimerRecord(t));
timers.insert(t);
again = true;
}
@ -115,12 +102,7 @@ EventLoop::CancelTimer(TimeoutMonitor &t)
{
assert(IsInside());
for (auto i = timers.begin(), end = timers.end(); i != end; ++i) {
if (&i->timer == &t) {
timers.erase(i);
return;
}
}
timers.erase(timers.iterator_to(t));
}
/**
@ -163,11 +145,11 @@ EventLoop::Run()
break;
}
timeout = i->GetDue() - now;
TimeoutMonitor &m = *i;
timeout = m.due - now;
if (timeout > timeout.zero())
break;
TimeoutMonitor &m = i->timer;
timers.erase(i);
m.Run();

View File

@ -28,6 +28,9 @@
#include "thread/Mutex.hxx"
#include "WakeFD.hxx"
#include "SocketMonitor.hxx"
#include "TimeoutMonitor.hxx"
#include <boost/intrusive/set.hpp>
#include <chrono>
#include <list>
@ -50,22 +53,23 @@ class DeferredMonitor;
*/
class EventLoop final : SocketMonitor
{
struct TimerRecord {
TimeoutMonitor &timer;
explicit constexpr TimerRecord(TimeoutMonitor &_timer)
:timer(_timer) {}
gcc_pure
std::chrono::steady_clock::time_point GetDue() const noexcept;
gcc_pure
bool operator<(const TimerRecord &other) const noexcept;
};
WakeFD wake_fd;
std::multiset<TimerRecord> timers;
struct TimerCompare {
constexpr bool operator()(const TimeoutMonitor &a,
const TimeoutMonitor &b) const {
return a.due < b.due;
}
};
typedef boost::intrusive::multiset<TimeoutMonitor,
boost::intrusive::member_hook<TimeoutMonitor,
TimeoutMonitor::TimerSetHook,
&TimeoutMonitor::timer_set_hook>,
boost::intrusive::compare<TimerCompare>,
boost::intrusive::constant_time_size<false>> TimerSet;
TimerSet timers;
std::list<IdleMonitor *> idle;
Mutex mutex;

View File

@ -24,10 +24,8 @@
void
TimeoutMonitor::Cancel()
{
if (IsActive()) {
active = false;
if (IsActive())
loop.CancelTimer(*this);
}
}
void
@ -35,13 +33,5 @@ TimeoutMonitor::Schedule(std::chrono::steady_clock::duration d)
{
Cancel();
active = true;
loop.AddTimer(*this, d);
}
void
TimeoutMonitor::Run()
{
active = false;
OnTimeout();
}

View File

@ -22,6 +22,8 @@
#include "check.h"
#include <boost/intrusive/set_hook.hpp>
#include <chrono>
class EventLoop;
@ -37,6 +39,9 @@ class EventLoop;
class TimeoutMonitor {
friend class EventLoop;
typedef boost::intrusive::set_member_hook<> TimerSetHook;
TimerSetHook timer_set_hook;
EventLoop &loop;
/**
@ -45,11 +50,9 @@ class TimeoutMonitor {
*/
std::chrono::steady_clock::time_point due;
bool active;
public:
TimeoutMonitor(EventLoop &_loop)
:loop(_loop), active(false) {
:loop(_loop) {
}
~TimeoutMonitor() {
@ -61,7 +64,7 @@ public:
}
bool IsActive() const {
return active;
return timer_set_hook.is_linked();
}
void Schedule(std::chrono::steady_clock::duration d);
@ -71,7 +74,9 @@ protected:
virtual void OnTimeout() = 0;
private:
void Run();
void Run() {
OnTimeout();
}
};
#endif /* MAIN_NOTIFY_H */