event/IdleEvent: make a special case of DeferEvent
This commit is contained in:
parent
990f2dc1cf
commit
c58aaf545f
@ -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
|
||||
|
@ -153,15 +153,6 @@ EventLoop::RemoveFD(int fd, SocketEvent &event) noexcept
|
||||
return poll_backend.Remove(fd);
|
||||
}
|
||||
|
||||
void
|
||||
EventLoop::AddIdle(IdleEvent &i) noexcept
|
||||
{
|
||||
assert(IsInside());
|
||||
|
||||
idle.push_back(i);
|
||||
again = true;
|
||||
}
|
||||
|
||||
void
|
||||
EventLoop::AddTimer(TimerEvent &t, Event::Duration d) noexcept
|
||||
{
|
||||
@ -202,6 +193,13 @@ EventLoop::AddDeferred(DeferEvent &d) noexcept
|
||||
again = true;
|
||||
}
|
||||
|
||||
void
|
||||
EventLoop::AddIdle(DeferEvent &e) noexcept
|
||||
{
|
||||
idle.push_front(e);
|
||||
again = true;
|
||||
}
|
||||
|
||||
void
|
||||
EventLoop::RunDeferred() noexcept
|
||||
{
|
||||
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user