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:
		@@ -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();
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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 */
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user