diff --git a/Userland/Libraries/LibCore/EventLoop.cpp b/Userland/Libraries/LibCore/EventLoop.cpp index 23c8866413f3d3..dd5bb3acb1dddd 100644 --- a/Userland/Libraries/LibCore/EventLoop.cpp +++ b/Userland/Libraries/LibCore/EventLoop.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -34,6 +35,7 @@ #include #include #include +#include #include #include @@ -76,6 +78,7 @@ static thread_local HashTable* 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() { @@ -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); } } @@ -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); @@ -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; } @@ -530,6 +545,11 @@ void EventLoop::wake_once(Object& receiver, int custom_event_type) post_event(receiver, make(custom_event_type), ShouldWake::Yes); } +void EventLoop::add_job(NonnullRefPtr>> 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)) diff --git a/Userland/Libraries/LibCore/EventLoop.h b/Userland/Libraries/LibCore/EventLoop.h index 18302236758e53..a8519507b45204 100644 --- a/Userland/Libraries/LibCore/EventLoop.h +++ b/Userland/Libraries/LibCore/EventLoop.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018-2020, Andreas Kling - * Copyright (c) 2022, kleines Filmröllchen + * Copyright (c) 2022, kleines Filmröllchen * Copyright (c) 2022, the SerenityOS developers. * * SPDX-License-Identifier: BSD-2-Clause @@ -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, @@ -84,6 +86,8 @@ class EventLoop { void post_event(Object& receiver, NonnullOwnPtr&&, ShouldWake = ShouldWake::No); void wake_once(Object& receiver, int custom_event_type); + void add_job(NonnullRefPtr>> job_promise); + void deferred_invoke(Function invokee) { auto context = DeferredInvocationContext::construct(); @@ -141,6 +145,7 @@ class EventLoop { }; Vector m_queued_events; + Vector>>> m_pending_promises; static pid_t s_pid; bool m_exit_requested { false };