event/DeferEvent: add ScheduleNext()

This commit is contained in:
Max Kellermann 2025-01-13 14:05:57 +01:00 committed by Max Kellermann
parent 4bb379a218
commit 5e107c33d9
4 changed files with 40 additions and 1 deletions

@ -21,3 +21,12 @@ DeferEvent::ScheduleIdle() noexcept
assert(IsPending()); assert(IsPending());
} }
void
DeferEvent::ScheduleNext() noexcept
{
if (!IsPending())
loop.AddNext(*this);
assert(IsPending());
}

@ -49,6 +49,15 @@ public:
*/ */
void ScheduleIdle() noexcept; void ScheduleIdle() noexcept;
/**
* Schedule this event, but only after the next #EventLoop
* iteration (i.e. after the epoll_wait() call, after handling
* all pending I/O events). This is useful for repeated I/O
* operations that should not occupy the whole #EventLoop,
* starving all other I/O events.
*/
void ScheduleNext() noexcept;
void Cancel() noexcept { void Cancel() noexcept {
if (IsPending()) if (IsPending())
unlink(); unlink();

@ -45,6 +45,7 @@ EventLoop::~EventLoop() noexcept
assert(defer.empty()); assert(defer.empty());
assert(idle.empty()); assert(idle.empty());
assert(next.empty());
#ifdef HAVE_THREADED_EVENT_LOOP #ifdef HAVE_THREADED_EVENT_LOOP
assert(inject.empty()); assert(inject.empty());
#endif #endif
@ -201,6 +202,14 @@ EventLoop::AddIdle(DeferEvent &e) noexcept
#endif #endif
} }
void
EventLoop::AddNext(DeferEvent &e) noexcept
{
assert(IsInside());
next.push_back(e);
}
void void
EventLoop::RunDeferred() noexcept EventLoop::RunDeferred() noexcept
{ {
@ -295,7 +304,7 @@ EventLoop::Run() noexcept
/* invoke timers */ /* invoke timers */
const auto timeout = HandleTimers(); Event::Duration timeout = HandleTimers();
if (quit) if (quit)
break; break;
@ -331,8 +340,13 @@ EventLoop::Run() noexcept
/* wait for new event */ /* wait for new event */
if (!next.empty())
timeout = Event::Duration{0};
Wait(timeout); Wait(timeout);
idle.splice(std::next(idle.begin()), next);
FlushClockCaches(); FlushClockCaches();
#ifdef HAVE_THREADED_EVENT_LOOP #ifdef HAVE_THREADED_EVENT_LOOP

@ -67,6 +67,12 @@ class EventLoop final
*/ */
DeferList idle; DeferList idle;
/**
* This is like #idle, but gets invoked after the next
* epoll_wait() call.
*/
DeferList next;
#ifdef HAVE_THREADED_EVENT_LOOP #ifdef HAVE_THREADED_EVENT_LOOP
Mutex mutex; Mutex mutex;
@ -226,6 +232,7 @@ public:
*/ */
void AddDefer(DeferEvent &e) noexcept; void AddDefer(DeferEvent &e) noexcept;
void AddIdle(DeferEvent &e) noexcept; void AddIdle(DeferEvent &e) noexcept;
void AddNext(DeferEvent &e) noexcept;
#ifdef HAVE_THREADED_EVENT_LOOP #ifdef HAVE_THREADED_EVENT_LOOP
/** /**