From 30295bd988831ee828f4d3d25078a6136403da2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?kleines=20Filmr=C3=B6llchen?= Date: Thu, 29 Dec 2022 13:20:44 +0100 Subject: [PATCH] LibCore: Allow EventLoop to manage and cancel promises 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. --- Userland/Libraries/LibCore/EventLoop.cpp | 20 ++++++++++++++++++++ Userland/Libraries/LibCore/EventLoop.h | 7 ++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/Userland/Libraries/LibCore/EventLoop.cpp b/Userland/Libraries/LibCore/EventLoop.cpp index 23c8866413..dd5bb3acb1 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 @@ public: { 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 1830223675..a8519507b4 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 @@ public: 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 @@ private: }; Vector m_queued_events; + Vector>>> m_pending_promises; static pid_t s_pid; bool m_exit_requested { false };