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());
|
assert(IsPending());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DeferEvent::ScheduleIdle() noexcept
|
||||||
|
{
|
||||||
|
if (!IsPending())
|
||||||
|
loop.AddIdle(*this);
|
||||||
|
|
||||||
|
assert(IsPending());
|
||||||
|
}
|
||||||
|
@ -60,6 +60,12 @@ public:
|
|||||||
|
|
||||||
void Schedule() noexcept;
|
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 {
|
void Cancel() noexcept {
|
||||||
if (IsPending())
|
if (IsPending())
|
||||||
unlink();
|
unlink();
|
||||||
|
@ -97,7 +97,7 @@ FullyBufferedSocket::OnSocketReady(unsigned flags) noexcept
|
|||||||
{
|
{
|
||||||
if (flags & SocketEvent::WRITE) {
|
if (flags & SocketEvent::WRITE) {
|
||||||
assert(!output.empty());
|
assert(!output.empty());
|
||||||
assert(!idle_event.IsActive());
|
assert(!idle_event.IsPending());
|
||||||
|
|
||||||
if (!Flush())
|
if (!Flush())
|
||||||
return;
|
return;
|
||||||
|
@ -18,26 +18,3 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "IdleEvent.hxx"
|
#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
|
#ifndef MPD_SOCKET_IDLE_EVENT_HXX
|
||||||
#define MPD_SOCKET_IDLE_EVENT_HXX
|
#define MPD_SOCKET_IDLE_EVENT_HXX
|
||||||
|
|
||||||
#include "util/BindMethod.hxx"
|
#include "DeferEvent.hxx"
|
||||||
#include "util/IntrusiveList.hxx"
|
|
||||||
|
|
||||||
class EventLoop;
|
class EventLoop;
|
||||||
|
|
||||||
@ -33,39 +32,30 @@ class EventLoop;
|
|||||||
* thread that runs the #EventLoop, except where explicitly documented
|
* thread that runs the #EventLoop, except where explicitly documented
|
||||||
* as thread-safe.
|
* as thread-safe.
|
||||||
*/
|
*/
|
||||||
class IdleEvent final : public AutoUnlinkIntrusiveListHook {
|
class IdleEvent final {
|
||||||
friend class EventLoop;
|
DeferEvent event;
|
||||||
friend class IntrusiveList<IdleEvent>;
|
|
||||||
|
|
||||||
EventLoop &loop;
|
|
||||||
|
|
||||||
using Callback = BoundMethod<void() noexcept>;
|
using Callback = BoundMethod<void() noexcept>;
|
||||||
const Callback callback;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IdleEvent(EventLoop &_loop, Callback _callback) noexcept
|
IdleEvent(EventLoop &_loop, Callback _callback) noexcept
|
||||||
:loop(_loop), callback(_callback) {}
|
:event(_loop, _callback) {}
|
||||||
|
|
||||||
IdleEvent(const IdleEvent &) = delete;
|
|
||||||
IdleEvent &operator=(const IdleEvent &) = delete;
|
|
||||||
|
|
||||||
auto &GetEventLoop() const noexcept {
|
auto &GetEventLoop() const noexcept {
|
||||||
return loop;
|
return event.GetEventLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsActive() const noexcept {
|
bool IsPending() const noexcept {
|
||||||
return is_linked();
|
return event.IsPending();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Schedule() noexcept;
|
void Schedule() noexcept {
|
||||||
|
event.ScheduleIdle();
|
||||||
|
}
|
||||||
|
|
||||||
void Cancel() noexcept {
|
void Cancel() noexcept {
|
||||||
if (IsActive())
|
event.Cancel();
|
||||||
unlink();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
void Run() noexcept;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -153,15 +153,6 @@ EventLoop::RemoveFD(int fd, SocketEvent &event) noexcept
|
|||||||
return poll_backend.Remove(fd);
|
return poll_backend.Remove(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
EventLoop::AddIdle(IdleEvent &i) noexcept
|
|
||||||
{
|
|
||||||
assert(IsInside());
|
|
||||||
|
|
||||||
idle.push_back(i);
|
|
||||||
again = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
EventLoop::AddTimer(TimerEvent &t, Event::Duration d) noexcept
|
EventLoop::AddTimer(TimerEvent &t, Event::Duration d) noexcept
|
||||||
{
|
{
|
||||||
@ -202,6 +193,13 @@ EventLoop::AddDeferred(DeferEvent &d) noexcept
|
|||||||
again = true;
|
again = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EventLoop::AddIdle(DeferEvent &e) noexcept
|
||||||
|
{
|
||||||
|
idle.push_front(e);
|
||||||
|
again = true;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
EventLoop::RunDeferred() noexcept
|
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>
|
template<class ToDuration, class Rep, class Period>
|
||||||
static constexpr ToDuration
|
static constexpr ToDuration
|
||||||
duration_cast_round_up(std::chrono::duration<Rep, Period> d) noexcept
|
duration_cast_round_up(std::chrono::duration<Rep, Period> d) noexcept
|
||||||
@ -301,16 +312,12 @@ EventLoop::Run() noexcept
|
|||||||
|
|
||||||
RunDeferred();
|
RunDeferred();
|
||||||
|
|
||||||
/* invoke idle */
|
if (RunOneIdle())
|
||||||
|
/* check for other new events after each
|
||||||
while (!idle.empty()) {
|
"idle" invocation to ensure that the other
|
||||||
IdleEvent &m = idle.front();
|
"idle" events are really invoked at the
|
||||||
idle.pop_front();
|
very end */
|
||||||
m.Run();
|
continue;
|
||||||
|
|
||||||
if (quit)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_THREADED_EVENT_LOOP
|
#ifdef HAVE_THREADED_EVENT_LOOP
|
||||||
/* try to handle DeferEvents without WakeFD
|
/* try to handle DeferEvents without WakeFD
|
||||||
|
@ -47,7 +47,6 @@ namespace Uring { class Queue; class Manager; }
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
class TimerEvent;
|
class TimerEvent;
|
||||||
class IdleEvent;
|
|
||||||
class DeferEvent;
|
class DeferEvent;
|
||||||
class InjectEvent;
|
class InjectEvent;
|
||||||
|
|
||||||
@ -58,7 +57,7 @@ class InjectEvent;
|
|||||||
* thread that runs it, except where explicitly documented as
|
* thread that runs it, except where explicitly documented as
|
||||||
* thread-safe.
|
* thread-safe.
|
||||||
*
|
*
|
||||||
* @see SocketEvent, MultiSocketMonitor, TimerEvent, IdleEvent
|
* @see SocketEvent, MultiSocketMonitor, TimerEvent, DeferEvent, InjectEvent
|
||||||
*/
|
*/
|
||||||
class EventLoop final
|
class EventLoop final
|
||||||
{
|
{
|
||||||
@ -83,8 +82,10 @@ class EventLoop final
|
|||||||
|
|
||||||
DeferList defer;
|
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
|
#ifdef HAVE_THREADED_EVENT_LOOP
|
||||||
Mutex mutex;
|
Mutex mutex;
|
||||||
@ -203,14 +204,13 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool AbandonFD(SocketEvent &event) noexcept;
|
bool AbandonFD(SocketEvent &event) noexcept;
|
||||||
|
|
||||||
void AddIdle(IdleEvent &i) noexcept;
|
|
||||||
|
|
||||||
void AddTimer(TimerEvent &t, Event::Duration d) noexcept;
|
void AddTimer(TimerEvent &t, Event::Duration d) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Schedule a call to DeferEvent::RunDeferred().
|
* Schedule a call to DeferEvent::RunDeferred().
|
||||||
*/
|
*/
|
||||||
void AddDeferred(DeferEvent &d) noexcept;
|
void AddDeferred(DeferEvent &d) noexcept;
|
||||||
|
void AddIdle(DeferEvent &e) noexcept;
|
||||||
|
|
||||||
#ifdef HAVE_THREADED_EVENT_LOOP
|
#ifdef HAVE_THREADED_EVENT_LOOP
|
||||||
/**
|
/**
|
||||||
@ -238,6 +238,13 @@ public:
|
|||||||
private:
|
private:
|
||||||
void RunDeferred() noexcept;
|
void RunDeferred() noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoke one "idle" #DeferEvent.
|
||||||
|
*
|
||||||
|
* @return false if there was no such event
|
||||||
|
*/
|
||||||
|
bool RunOneIdle() noexcept;
|
||||||
|
|
||||||
#ifdef HAVE_THREADED_EVENT_LOOP
|
#ifdef HAVE_THREADED_EVENT_LOOP
|
||||||
/**
|
/**
|
||||||
* Invoke all pending InjectEvents.
|
* Invoke all pending InjectEvents.
|
||||||
|
Loading…
Reference in New Issue
Block a user