event/Loop: move TimerSet to separate class

This commit is contained in:
Max Kellermann 2021-02-04 21:25:57 +01:00 committed by Max Kellermann
parent 271b287356
commit e802f1f61a
6 changed files with 160 additions and 42 deletions

View File

@ -34,13 +34,6 @@
#include <stdio.h>
#endif
constexpr bool
EventLoop::TimerCompare::operator()(const TimerEvent &a,
const TimerEvent &b) const noexcept
{
return a.due < b.due;
}
EventLoop::EventLoop(
#ifdef HAVE_THREADED_EVENT_LOOP
ThreadId _thread
@ -60,7 +53,6 @@ EventLoop::EventLoop(
EventLoop::~EventLoop() noexcept
{
assert(timers.empty());
assert(defer.empty());
assert(idle.empty());
#ifdef HAVE_THREADED_EVENT_LOOP
@ -156,33 +148,14 @@ EventLoop::Insert(TimerEvent &t) noexcept
{
assert(IsInside());
timers.insert(t);
timers.Insert(t);
again = true;
}
inline Event::Duration
EventLoop::HandleTimers() noexcept
{
const auto now = SteadyNow();
Event::Duration timeout;
while (!quit) {
auto i = timers.begin();
if (i == timers.end())
break;
TimerEvent &t = *i;
timeout = t.due - now;
if (timeout > timeout.zero())
return timeout;
timers.erase(i);
t.Run();
}
return Event::Duration(-1);
return timers.Run(SteadyNow());
}
void

View File

@ -21,6 +21,7 @@
#define EVENT_LOOP_HXX
#include "Chrono.hxx"
#include "TimerList.hxx"
#include "Backend.hxx"
#include "SocketEvent.hxx"
#include "event/Features.h"
@ -45,7 +46,6 @@
namespace Uring { class Queue; class Manager; }
#endif
class TimerEvent;
class DeferEvent;
class InjectEvent;
@ -65,17 +65,7 @@ class EventLoop final
SocketEvent wake_event{*this, BIND_THIS_METHOD(OnSocketReady), wake_fd.GetSocket()};
#endif
struct TimerCompare {
constexpr bool operator()(const TimerEvent &a,
const TimerEvent &b) const noexcept;
};
using TimerSet =
boost::intrusive::multiset<TimerEvent,
boost::intrusive::base_hook<boost::intrusive::set_base_hook<boost::intrusive::link_mode<boost::intrusive::auto_unlink>>>,
boost::intrusive::compare<TimerCompare>,
boost::intrusive::constant_time_size<false>>;
TimerSet timers;
TimerList timers;
using DeferList = IntrusiveList<DeferEvent>;

View File

@ -38,7 +38,7 @@ class EventLoop;
class TimerEvent final
: public boost::intrusive::set_base_hook<boost::intrusive::link_mode<boost::intrusive::auto_unlink>>
{
friend class EventLoop;
friend class TimerList;
EventLoop &loop;
@ -59,6 +59,10 @@ public:
return loop;
}
constexpr auto GetDue() const noexcept {
return due;
}
bool IsPending() const noexcept {
return is_linked();
}

75
src/event/TimerList.cxx Normal file
View File

@ -0,0 +1,75 @@
/*
* Copyright 2007-2021 CM4all GmbH
* All rights reserved.
*
* author: Max Kellermann <mk@cm4all.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "Loop.hxx"
#include "TimerEvent.hxx"
constexpr bool
TimerList::Compare::operator()(const TimerEvent &a,
const TimerEvent &b) const noexcept
{
return a.due < b.due;
}
TimerList::TimerList() = default;
TimerList::~TimerList() noexcept
{
assert(timers.empty());
}
void
TimerList::Insert(TimerEvent &t) noexcept
{
timers.insert(t);
}
Event::Duration
TimerList::Run(const Event::Clock::time_point now) noexcept
{
while (true) {
auto i = timers.begin();
if (i == timers.end())
break;
TimerEvent &t = *i;
const auto timeout = t.due - now;
if (timeout > timeout.zero())
return timeout;
timers.erase(i);
t.Run();
}
return Event::Duration(-1);
}

75
src/event/TimerList.hxx Normal file
View File

@ -0,0 +1,75 @@
/*
* Copyright 2007-2021 CM4all GmbH
* All rights reserved.
*
* author: Max Kellermann <mk@cm4all.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include "Chrono.hxx"
#include "util/IntrusiveList.hxx"
#include <boost/intrusive/set.hpp>
class TimerEvent;
/**
* A list of #TimerEvent instances sorted by due time point.
*/
class TimerList final {
struct Compare {
constexpr bool operator()(const TimerEvent &a,
const TimerEvent &b) const noexcept;
};
boost::intrusive::multiset<TimerEvent,
boost::intrusive::base_hook<boost::intrusive::set_base_hook<boost::intrusive::link_mode<boost::intrusive::auto_unlink>>>,
boost::intrusive::compare<Compare>,
boost::intrusive::constant_time_size<false>> timers;
public:
TimerList();
~TimerList() noexcept;
TimerList(const TimerList &other) = delete;
TimerList &operator=(const TimerList &other) = delete;
bool IsEmpty() const noexcept {
return timers.empty();
}
void Insert(TimerEvent &t) noexcept;
/**
* Invoke all expired #TimerEvent instances and return the
* duration until the next timer expires. Returns a negative
* duration if there is no timeout.
*/
Event::Duration Run(Event::Clock::time_point now) noexcept;
};

View File

@ -22,6 +22,7 @@ endif
event = static_library(
'event',
'SignalMonitor.cxx',
'TimerList.cxx',
'TimerEvent.cxx',
'IdleEvent.cxx',
'InjectEvent.cxx',