Skip to content

Commit

Permalink
LibCore: Allow EventLoop to manage and cancel promises
Browse files Browse the repository at this point in the history
In this context, the promises are considered "jobs", and such jobs
depend in some way on the event loop. Therefore, they can be added to
the event loop, and the event loop will cancel all of its pending jobs
when it ends.
  • Loading branch information
kleinesfilmroellchen authored and linusg committed Mar 13, 2023
1 parent bfd9f68 commit 30295bd
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 1 deletion.
20 changes: 20 additions & 0 deletions Userland/Libraries/LibCore/EventLoop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <LibCore/LocalServer.h>
#include <LibCore/Notifier.h>
#include <LibCore/Object.h>
#include <LibCore/Promise.h>
#include <LibCore/SessionManagement.h>
#include <LibCore/Socket.h>
#include <LibThreading/Mutex.h>
Expand All @@ -34,6 +35,7 @@
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>

Expand Down Expand Up @@ -76,6 +78,7 @@ static thread_local HashTable<Notifier*>* s_notifiers;
// While wake() pushes zero into the pipe, signal numbers (by defintion nonzero, see signal_numbers.h) are pushed into the pipe verbatim.
thread_local int EventLoop::s_wake_pipe_fds[2];
thread_local bool EventLoop::s_wake_pipe_initialized { false };
thread_local bool s_warned_promise_count { false };

void EventLoop::initialize_wake_pipes()
{
Expand Down Expand Up @@ -427,6 +430,11 @@ struct EventLoopPusher {
{
if (EventLoop::has_been_instantiated()) {
s_event_loop_stack->take_last();
for (auto& job : m_event_loop.m_pending_promises) {
// When this event loop was not running below another event loop, the jobs may very well have finished in the meantime.
if (!job->is_resolved())
job->cancel(Error::from_string_view("EventLoop is exiting"sv));
}
EventLoop::current().take_pending_events_from(m_event_loop);
}
}
Expand Down Expand Up @@ -463,6 +471,8 @@ size_t EventLoop::pump(WaitMode mode)
events = move(m_queued_events);
}

m_pending_promises.remove_all_matching([](auto& job) { return job->is_resolved() || job->is_canceled(); });

size_t processed_events = 0;
for (size_t i = 0; i < events.size(); ++i) {
auto& queued_event = events.at(i);
Expand Down Expand Up @@ -501,6 +511,11 @@ size_t EventLoop::pump(WaitMode mode)
}
}

if (m_pending_promises.size() > 30 && !s_warned_promise_count) {
s_warned_promise_count = true;
dbgln("EventLoop {:p} warning: Job queue wasn't designed for this load ({} promises). Please begin optimizing EventLoop::pump() -> m_pending_promises.remove_all_matching", this, m_pending_promises.size());
}

return processed_events;
}

Expand Down Expand Up @@ -530,6 +545,11 @@ void EventLoop::wake_once(Object& receiver, int custom_event_type)
post_event(receiver, make<CustomEvent>(custom_event_type), ShouldWake::Yes);
}

void EventLoop::add_job(NonnullRefPtr<Promise<NonnullRefPtr<Object>>> job_promise)
{
m_pending_promises.append(move(job_promise));
}

SignalHandlers::SignalHandlers(int signo, void (*handle_signal)(int))
: m_signo(signo)
, m_original_handler(signal(signo, handle_signal))
Expand Down
7 changes: 6 additions & 1 deletion Userland/Libraries/LibCore/EventLoop.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <[email protected]>
* Copyright (c) 2022, kleines Filmröllchen <[email protected]>
* Copyright (c) 2022, kleines Filmröllchen <[email protected]>
* Copyright (c) 2022, the SerenityOS developers.
*
* SPDX-License-Identifier: BSD-2-Clause
Expand Down Expand Up @@ -47,6 +47,8 @@ namespace Core {
//
// EventLoop has one final responsibility: Handling the InspectorServer connection and processing requests to the Object hierarchy.
class EventLoop {
friend struct EventLoopPusher;

public:
enum class MakeInspectable {
No,
Expand Down Expand Up @@ -84,6 +86,8 @@ class EventLoop {
void post_event(Object& receiver, NonnullOwnPtr<Event>&&, ShouldWake = ShouldWake::No);
void wake_once(Object& receiver, int custom_event_type);

void add_job(NonnullRefPtr<Promise<NonnullRefPtr<Object>>> job_promise);

void deferred_invoke(Function<void()> invokee)
{
auto context = DeferredInvocationContext::construct();
Expand Down Expand Up @@ -141,6 +145,7 @@ class EventLoop {
};

Vector<QueuedEvent, 64> m_queued_events;
Vector<NonnullRefPtr<Promise<NonnullRefPtr<Object>>>> m_pending_promises;
static pid_t s_pid;

bool m_exit_requested { false };
Expand Down

0 comments on commit 30295bd

Please sign in to comment.