Commit c58aaf54 authored by Max Kellermann's avatar Max Kellermann

event/IdleEvent: make a special case of DeferEvent

parent 990f2dc1
......@@ -28,3 +28,12 @@ DeferEvent::Schedule() noexcept
assert(IsPending());
}
void
DeferEvent::ScheduleIdle() noexcept
{
if (!IsPending())
loop.AddIdle(*this);
assert(IsPending());
}
......@@ -60,6 +60,12 @@ public:
void Schedule() noexcept;
/**
* Schedule this event, but only after the #EventLoop is idle,
* i.e. before going to sleep.
*/
void ScheduleIdle() noexcept;
void Cancel() noexcept {
if (IsPending())
unlink();
......
......@@ -97,7 +97,7 @@ FullyBufferedSocket::OnSocketReady(unsigned flags) noexcept
{
if (flags & SocketEvent::WRITE) {
assert(!output.empty());
assert(!idle_event.IsActive());
assert(!idle_event.IsPending());
if (!Flush())
return;
......
......@@ -18,26 +18,3 @@
*/
#include "IdleEvent.hxx"
#include "Loop.hxx"
#include <cassert>
void
IdleEvent::Schedule() noexcept
{
assert(loop.IsInside());
if (IsActive())
/* already scheduled */
return;
loop.AddIdle(*this);
}
void
IdleEvent::Run() noexcept
{
assert(loop.IsInside());
callback();
}
......@@ -20,8 +20,7 @@
#ifndef MPD_SOCKET_IDLE_EVENT_HXX
#define MPD_SOCKET_IDLE_EVENT_HXX
#include "util/BindMethod.hxx"
#include "util/IntrusiveList.hxx"
#include "DeferEvent.hxx"
class EventLoop;
......@@ -33,39 +32,30 @@ class EventLoop;
* thread that runs the #EventLoop, except where explicitly documented
* as thread-safe.
*/
class IdleEvent final : public AutoUnlinkIntrusiveListHook {
friend class EventLoop;
friend class IntrusiveList<IdleEvent>;
EventLoop &loop;
class IdleEvent final {
DeferEvent event;
using Callback = BoundMethod<void() noexcept>;
const Callback callback;
public:
IdleEvent(EventLoop &_loop, Callback _callback) noexcept
:loop(_loop), callback(_callback) {}
IdleEvent(const IdleEvent &) = delete;
IdleEvent &operator=(const IdleEvent &) = delete;
:event(_loop, _callback) {}
auto &GetEventLoop() const noexcept {
return loop;
return event.GetEventLoop();
}
bool IsActive() const noexcept {
return is_linked();
bool IsPending() const noexcept {
return event.IsPending();
}
void Schedule() noexcept;
void Schedule() noexcept {
event.ScheduleIdle();
}
void Cancel() noexcept {
if (IsActive())
unlink();
event.Cancel();
}
private:
void Run() noexcept;
};
#endif
......@@ -154,15 +154,6 @@ EventLoop::RemoveFD(int fd, SocketEvent &event) noexcept
}
void
EventLoop::AddIdle(IdleEvent &i) noexcept
{
assert(IsInside());
idle.push_back(i);
again = true;
}
void
EventLoop::AddTimer(TimerEvent &t, Event::Duration d) noexcept
{
assert(IsInside());
......@@ -203,6 +194,13 @@ EventLoop::AddDeferred(DeferEvent &d) noexcept
}
void
EventLoop::AddIdle(DeferEvent &e) noexcept
{
idle.push_front(e);
again = true;
}
void
EventLoop::RunDeferred() noexcept
{
while (!defer.empty() && !quit) {
......@@ -212,6 +210,19 @@ EventLoop::RunDeferred() noexcept
}
}
bool
EventLoop::RunOneIdle() noexcept
{
if (idle.empty())
return false;
idle.pop_front_and_dispose([](DeferEvent *e){
e->Run();
});
return true;
}
template<class ToDuration, class Rep, class Period>
static constexpr ToDuration
duration_cast_round_up(std::chrono::duration<Rep, Period> d) noexcept
......@@ -301,16 +312,12 @@ EventLoop::Run() noexcept
RunDeferred();
/* invoke idle */
while (!idle.empty()) {
IdleEvent &m = idle.front();
idle.pop_front();
m.Run();
if (quit)
return;
}
if (RunOneIdle())
/* check for other new events after each
"idle" invocation to ensure that the other
"idle" events are really invoked at the
very end */
continue;
#ifdef HAVE_THREADED_EVENT_LOOP
/* try to handle DeferEvents without WakeFD
......
......@@ -47,7 +47,6 @@ namespace Uring { class Queue; class Manager; }
#endif
class TimerEvent;
class IdleEvent;
class DeferEvent;
class InjectEvent;
......@@ -58,7 +57,7 @@ class InjectEvent;
* thread that runs it, except where explicitly documented as
* thread-safe.
*
* @see SocketEvent, MultiSocketMonitor, TimerEvent, IdleEvent
* @see SocketEvent, MultiSocketMonitor, TimerEvent, DeferEvent, InjectEvent
*/
class EventLoop final
{
......@@ -83,8 +82,10 @@ class EventLoop final
DeferList defer;
using IdleList = IntrusiveList<IdleEvent>;
IdleList idle;
/**
* This is like #defer, but gets invoked when the loop is idle.
*/
DeferList idle;
#ifdef HAVE_THREADED_EVENT_LOOP
Mutex mutex;
......@@ -203,14 +204,13 @@ public:
*/
bool AbandonFD(SocketEvent &event) noexcept;
void AddIdle(IdleEvent &i) noexcept;
void AddTimer(TimerEvent &t, Event::Duration d) noexcept;
/**
* Schedule a call to DeferEvent::RunDeferred().
*/
void AddDeferred(DeferEvent &d) noexcept;
void AddIdle(DeferEvent &e) noexcept;
#ifdef HAVE_THREADED_EVENT_LOOP
/**
......@@ -238,6 +238,13 @@ public:
private:
void RunDeferred() noexcept;
/**
* Invoke one "idle" #DeferEvent.
*
* @return false if there was no such event
*/
bool RunOneIdle() noexcept;
#ifdef HAVE_THREADED_EVENT_LOOP
/**
* Invoke all pending InjectEvents.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment