diff --git a/Ladybird/EventLoopImplementationQt.cpp b/Ladybird/EventLoopImplementationQt.cpp index 29e49718ee..214b275eac 100644 --- a/Ladybird/EventLoopImplementationQt.cpp +++ b/Ladybird/EventLoopImplementationQt.cpp @@ -35,11 +35,6 @@ struct ThreadData { EventLoopImplementationQt::EventLoopImplementationQt() { - m_process_core_events_timer.setSingleShot(true); - m_process_core_events_timer.setInterval(0); - QObject::connect(&m_process_core_events_timer, &QTimer::timeout, [] { - Core::ThreadEventQueue::current().process(); - }); } EventLoopImplementationQt::~EventLoopImplementationQt() = default; @@ -79,7 +74,7 @@ void EventLoopImplementationQt::wake() m_event_loop.wakeUp(); } -void EventLoopImplementationQt::deferred_invoke(Function function) +void EventLoopManagerQt::deferred_invoke(Function function) { VERIFY(function); QTimer::singleShot(0, [function = move(function)] { @@ -97,7 +92,7 @@ static void qt_timer_fired(int timer_id, Core::TimerShouldFireWhenNotVisible sho object.dispatch_event(event); } -int EventLoopImplementationQt::register_timer(Core::Object& object, int milliseconds, bool should_reload, Core::TimerShouldFireWhenNotVisible should_fire_when_not_visible) +int EventLoopManagerQt::register_timer(Core::Object& object, int milliseconds, bool should_reload, Core::TimerShouldFireWhenNotVisible should_fire_when_not_visible) { auto& thread_data = ThreadData::the(); auto timer = make(); @@ -116,7 +111,7 @@ int EventLoopImplementationQt::register_timer(Core::Object& object, int millisec return timer_id; } -bool EventLoopImplementationQt::unregister_timer(int timer_id) +bool EventLoopManagerQt::unregister_timer(int timer_id) { auto& thread_data = ThreadData::the(); thread_data.timer_id_allocator.deallocate(timer_id); @@ -129,7 +124,7 @@ static void qt_notifier_activated(Core::Notifier& notifier) notifier.dispatch_event(event); } -void EventLoopImplementationQt::register_notifier(Core::Notifier& notifier) +void EventLoopManagerQt::register_notifier(Core::Notifier& notifier) { QSocketNotifier::Type type; switch (notifier.type()) { @@ -150,14 +145,34 @@ void EventLoopImplementationQt::register_notifier(Core::Notifier& notifier) ThreadData::the().notifiers.set(¬ifier, move(socket_notifier)); } -void EventLoopImplementationQt::unregister_notifier(Core::Notifier& notifier) +void EventLoopManagerQt::unregister_notifier(Core::Notifier& notifier) { ThreadData::the().notifiers.remove(¬ifier); } -void EventLoopImplementationQt::did_post_event() +void EventLoopManagerQt::did_post_event() { m_process_core_events_timer.start(); } +EventLoopManagerQt::EventLoopManagerQt() +{ + m_process_core_events_timer.setSingleShot(true); + m_process_core_events_timer.setInterval(0); + QObject::connect(&m_process_core_events_timer, &QTimer::timeout, [] { + Core::ThreadEventQueue::current().process(); + }); +} + +EventLoopManagerQt::~EventLoopManagerQt() = default; + +void EventLoopManagerQt::wake() +{ +} + +NonnullOwnPtr EventLoopManagerQt::make_implementation() +{ + return adopt_own(*new EventLoopImplementationQt); +} + } diff --git a/Ladybird/EventLoopImplementationQt.h b/Ladybird/EventLoopImplementationQt.h index b0ac788adb..6a99378aa5 100644 --- a/Ladybird/EventLoopImplementationQt.h +++ b/Ladybird/EventLoopImplementationQt.h @@ -16,16 +16,11 @@ namespace Ladybird { -class EventLoopImplementationQt final : public Core::EventLoopImplementation { +class EventLoopManagerQt final : public Core::EventLoopManager { public: - static NonnullOwnPtr create() { return adopt_own(*new EventLoopImplementationQt); } - - virtual ~EventLoopImplementationQt() override; - - virtual int exec() override; - virtual size_t pump(PumpMode) override; - virtual void quit(int) override; - virtual void wake() override; + EventLoopManagerQt(); + virtual ~EventLoopManagerQt() override; + virtual NonnullOwnPtr make_implementation() override; virtual void deferred_invoke(Function) override; @@ -37,21 +32,41 @@ public: virtual void did_post_event() override; + virtual void wake() override; + + // FIXME: These APIs only exist for obscure use-cases inside SerenityOS. Try to get rid of them. + virtual int register_signal(int, Function) override { return 0; } + virtual void unregister_signal(int) override { } + +private: + QTimer m_process_core_events_timer; +}; + +class EventLoopImplementationQt final : public Core::EventLoopImplementation { +public: + static NonnullOwnPtr create() { return adopt_own(*new EventLoopImplementationQt); } + + virtual ~EventLoopImplementationQt() override; + + virtual int exec() override; + virtual size_t pump(PumpMode) override; + virtual void quit(int) override; + virtual void wake() override; + // FIXME: These APIs only exist for obscure use-cases inside SerenityOS. Try to get rid of them. virtual void unquit() override { } virtual bool was_exit_requested() const override { return false; } virtual void notify_forked_and_in_child() override { } - virtual int register_signal(int, Function) override { return 0; } - virtual void unregister_signal(int) override { } void set_main_loop() { m_main_loop = true; } private: + friend class EventLoopManagerQt; + EventLoopImplementationQt(); bool is_main_loop() const { return m_main_loop; } QEventLoop m_event_loop; - QTimer m_process_core_events_timer; bool m_main_loop { false }; }; diff --git a/Ladybird/WebContent/main.cpp b/Ladybird/WebContent/main.cpp index 72b8e7326c..9b805652cc 100644 --- a/Ladybird/WebContent/main.cpp +++ b/Ladybird/WebContent/main.cpp @@ -40,7 +40,7 @@ ErrorOr serenity_main(Main::Arguments arguments) { QGuiApplication app(arguments.argc, arguments.argv); - Core::EventLoop::make_implementation = Ladybird::EventLoopImplementationQt::create; + Core::EventLoopManager::install(*new Ladybird::EventLoopManagerQt); Core::EventLoop event_loop; platform_init(); diff --git a/Ladybird/main.cpp b/Ladybird/main.cpp index 796267beda..1166568472 100644 --- a/Ladybird/main.cpp +++ b/Ladybird/main.cpp @@ -54,7 +54,7 @@ ErrorOr serenity_main(Main::Arguments arguments) { QApplication app(arguments.argc, arguments.argv); - Core::EventLoop::make_implementation = Ladybird::EventLoopImplementationQt::create; + Core::EventLoopManager::install(*new Ladybird::EventLoopManagerQt); Core::EventLoop event_loop; static_cast(event_loop.impl()).set_main_loop(); diff --git a/Userland/Libraries/LibCore/EventLoop.cpp b/Userland/Libraries/LibCore/EventLoop.cpp index 1d848760f9..330fd31a87 100644 --- a/Userland/Libraries/LibCore/EventLoop.cpp +++ b/Userland/Libraries/LibCore/EventLoop.cpp @@ -24,16 +24,10 @@ Vector& event_loop_stack() s_event_loop_stack = new Vector; return *s_event_loop_stack; } -bool has_event_loop() -{ - return !event_loop_stack().is_empty(); } -} - -Function()> EventLoop::make_implementation = EventLoopImplementationUnix::create; EventLoop::EventLoop() - : m_impl(make_implementation()) + : m_impl(EventLoopManager::the().make_implementation()) { if (event_loop_stack().is_empty()) { event_loop_stack().append(*this); @@ -94,7 +88,7 @@ size_t EventLoop::pump(WaitMode mode) void EventLoop::post_event(Object& receiver, NonnullOwnPtr&& event) { - m_impl->post_event(receiver, move(event)); + EventLoopManager::the().post_event(receiver, move(event)); } void EventLoop::add_job(NonnullRefPtr>> job_promise) @@ -104,16 +98,12 @@ void EventLoop::add_job(NonnullRefPtr>> job_promis int EventLoop::register_signal(int signal_number, Function handler) { - if (!has_event_loop()) - return 0; - return current().m_impl->register_signal(signal_number, move(handler)); + return EventLoopManager::the().register_signal(signal_number, move(handler)); } void EventLoop::unregister_signal(int handler_id) { - if (!has_event_loop()) - return; - current().m_impl->unregister_signal(handler_id); + EventLoopManager::the().unregister_signal(handler_id); } void EventLoop::notify_forked(ForkEvent) @@ -123,30 +113,22 @@ void EventLoop::notify_forked(ForkEvent) int EventLoop::register_timer(Object& object, int milliseconds, bool should_reload, TimerShouldFireWhenNotVisible fire_when_not_visible) { - if (!has_event_loop()) - return 0; - return current().m_impl->register_timer(object, milliseconds, should_reload, fire_when_not_visible); + return EventLoopManager::the().register_timer(object, milliseconds, should_reload, fire_when_not_visible); } bool EventLoop::unregister_timer(int timer_id) { - if (!has_event_loop()) - return false; - return current().m_impl->unregister_timer(timer_id); + return EventLoopManager::the().unregister_timer(timer_id); } void EventLoop::register_notifier(Badge, Notifier& notifier) { - if (!has_event_loop()) - return; - current().m_impl->register_notifier(notifier); + EventLoopManager::the().register_notifier(notifier); } void EventLoop::unregister_notifier(Badge, Notifier& notifier) { - if (!has_event_loop()) - return; - current().m_impl->unregister_notifier(notifier); + EventLoopManager::the().unregister_notifier(notifier); } void EventLoop::wake() @@ -170,9 +152,4 @@ bool EventLoop::was_exit_requested() const return m_impl->was_exit_requested(); } -void EventLoop::did_post_event(Badge) -{ - m_impl->did_post_event(); -} - } diff --git a/Userland/Libraries/LibCore/EventLoop.h b/Userland/Libraries/LibCore/EventLoop.h index 65061bea7b..e79ec3c2ad 100644 --- a/Userland/Libraries/LibCore/EventLoop.h +++ b/Userland/Libraries/LibCore/EventLoop.h @@ -94,8 +94,6 @@ public: static EventLoop& current(); - static Function()> make_implementation; - void did_post_event(Badge); EventLoopImplementation& impl() { return *m_impl; } diff --git a/Userland/Libraries/LibCore/EventLoopImplementation.cpp b/Userland/Libraries/LibCore/EventLoopImplementation.cpp index 4aaf8c157d..bc6a39e317 100644 --- a/Userland/Libraries/LibCore/EventLoopImplementation.cpp +++ b/Userland/Libraries/LibCore/EventLoopImplementation.cpp @@ -7,18 +7,36 @@ #include #include #include +#include #include namespace Core { -EventLoopImplementation::EventLoopImplementation() +EventLoopImplementation::EventLoopImplementation() = default; + +EventLoopImplementation::~EventLoopImplementation() = default; + +static EventLoopManager* s_event_loop_manager; +EventLoopManager& EventLoopManager::the() +{ + if (!s_event_loop_manager) + s_event_loop_manager = new EventLoopManagerUnix; + return *s_event_loop_manager; +} + +void EventLoopManager::install(Core::EventLoopManager& manager) +{ + s_event_loop_manager = &manager; +} + +EventLoopManager::EventLoopManager() : m_thread_event_queue(ThreadEventQueue::current()) { } -EventLoopImplementation::~EventLoopImplementation() = default; +EventLoopManager::~EventLoopManager() = default; -void EventLoopImplementation::post_event(Object& receiver, NonnullOwnPtr&& event) +void EventLoopManager::post_event(Object& receiver, NonnullOwnPtr&& event) { m_thread_event_queue.post_event(receiver, move(event)); diff --git a/Userland/Libraries/LibCore/EventLoopImplementation.h b/Userland/Libraries/LibCore/EventLoopImplementation.h index 7c94b58b69..ee556b6ec8 100644 --- a/Userland/Libraries/LibCore/EventLoopImplementation.h +++ b/Userland/Libraries/LibCore/EventLoopImplementation.h @@ -11,8 +11,40 @@ namespace Core { +class EventLoopImplementation; class ThreadEventQueue; +class EventLoopManager { +public: + static EventLoopManager& the(); + static void install(EventLoopManager&); + + virtual ~EventLoopManager(); + + virtual NonnullOwnPtr make_implementation() = 0; + + virtual int register_timer(Object&, int milliseconds, bool should_reload, TimerShouldFireWhenNotVisible) = 0; + virtual bool unregister_timer(int timer_id) = 0; + + virtual void register_notifier(Notifier&) = 0; + virtual void unregister_notifier(Notifier&) = 0; + + void post_event(Object& receiver, NonnullOwnPtr&&); + virtual void did_post_event() = 0; + + virtual void deferred_invoke(Function) = 0; + + // FIXME: These APIs only exist for obscure use-cases inside SerenityOS. Try to get rid of them. + virtual int register_signal(int signal_number, Function handler) = 0; + virtual void unregister_signal(int handler_id) = 0; + + virtual void wake() = 0; + +protected: + EventLoopManager(); + ThreadEventQueue& m_thread_event_queue; +}; + class EventLoopImplementation { public: virtual ~EventLoopImplementation(); @@ -22,34 +54,18 @@ public: DontWaitForEvents, }; - void post_event(Object& receiver, NonnullOwnPtr&&); - virtual int exec() = 0; virtual size_t pump(PumpMode) = 0; virtual void quit(int) = 0; virtual void wake() = 0; - virtual void deferred_invoke(Function) = 0; - - virtual int register_timer(Object&, int milliseconds, bool should_reload, TimerShouldFireWhenNotVisible) = 0; - virtual bool unregister_timer(int timer_id) = 0; - - virtual void register_notifier(Notifier&) = 0; - virtual void unregister_notifier(Notifier&) = 0; - - virtual void did_post_event() = 0; - // FIXME: These APIs only exist for obscure use-cases inside SerenityOS. Try to get rid of them. virtual void unquit() = 0; virtual bool was_exit_requested() const = 0; virtual void notify_forked_and_in_child() = 0; - virtual int register_signal(int signal_number, Function handler) = 0; - virtual void unregister_signal(int handler_id) = 0; protected: EventLoopImplementation(); - - ThreadEventQueue& m_thread_event_queue; }; } diff --git a/Userland/Libraries/LibCore/EventLoopImplementationUnix.cpp b/Userland/Libraries/LibCore/EventLoopImplementationUnix.cpp index c1d4a6a6a4..1dc525d1f2 100644 --- a/Userland/Libraries/LibCore/EventLoopImplementationUnix.cpp +++ b/Userland/Libraries/LibCore/EventLoopImplementationUnix.cpp @@ -105,11 +105,8 @@ int EventLoopImplementationUnix::exec() size_t EventLoopImplementationUnix::pump(PumpMode mode) { - // We can only pump the event loop of the current thread. - VERIFY(&m_thread_event_queue == &ThreadEventQueue::current()); - - wait_for_events(mode); - return m_thread_event_queue.process(); + static_cast(EventLoopManager::the()).wait_for_events(mode); + return ThreadEventQueue::current().process(); } void EventLoopImplementationUnix::quit(int code) @@ -135,14 +132,20 @@ void EventLoopImplementationUnix::wake() MUST(Core::System::write((*m_wake_pipe_fds)[1], { &wake_event, sizeof(wake_event) })); } -void EventLoopImplementationUnix::deferred_invoke(Function invokee) +void EventLoopManagerUnix::wake() +{ + int wake_event = 0; + MUST(Core::System::write(ThreadData::the().wake_pipe_fds[1], { &wake_event, sizeof(wake_event) })); +} + +void EventLoopManagerUnix::deferred_invoke(Function invokee) { // FIXME: Get rid of the useless DeferredInvocationContext object. auto context = DeferredInvocationContext::construct(); post_event(context, make(context, move(invokee))); } -void EventLoopImplementationUnix::wait_for_events(PumpMode mode) +void EventLoopManagerUnix::wait_for_events(EventLoopImplementation::PumpMode mode) { auto& thread_data = ThreadData::the(); @@ -177,7 +180,7 @@ retry: Time now; struct timeval timeout = { 0, 0 }; bool should_wait_forever = false; - if (mode == PumpMode::WaitForEvents && !has_pending_events) { + if (mode == EventLoopImplementation::PumpMode::WaitForEvents && !has_pending_events) { auto next_timer_expiration = get_next_timer_expiration(); if (next_timer_expiration.has_value()) { now = Time::now_monotonic_coarse(); @@ -196,11 +199,8 @@ try_select_again: // Because POSIX, we might spuriously return from select() with EINTR; just select again. if (marked_fd_count < 0) { int saved_errno = errno; - if (saved_errno == EINTR) { - if (m_exit_requested) - return; + if (saved_errno == EINTR) goto try_select_again; - } dbgln("EventLoopImplementationUnix::wait_for_events: {} ({}: {})", marked_fd_count, saved_errno, strerror(saved_errno)); VERIFY_NOT_REACHED(); } @@ -329,7 +329,7 @@ inline SignalHandlersInfo* signals_info() return s_signals.ptr(); } -void EventLoopImplementationUnix::dispatch_signal(int signal_number) +void EventLoopManagerUnix::dispatch_signal(int signal_number) { auto& info = *signals_info(); auto handlers = info.signal_handlers.find(signal_number); @@ -355,7 +355,7 @@ void EventLoopImplementationUnix::notify_forked_and_in_child() thread_data.pid = getpid(); } -Optional