From 83b293e4f2e6aa56214fa026fe952fc32bcbb090 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Thu, 4 Jun 2026 19:51:47 +0200 Subject: [PATCH] LibCore: Keep main event loops alive Add an explicit initializer for process-lifetime event loops and use it for browser, helper service, and utility main loops. This preserves weak event loop references for cross-thread users while making main thread loop lifetime independent of normal program teardown. --- Libraries/LibCore/EventLoop.cpp | 5 +++++ Libraries/LibCore/EventLoop.h | 4 +++- Libraries/LibWebView/Application.cpp | 6 +++--- Libraries/LibWebView/Application.h | 4 ++-- Services/Compositor/main.cpp | 2 +- Services/ImageDecoder/main.cpp | 2 +- Services/RequestServer/main.cpp | 2 +- Services/WebContent/main.cpp | 2 +- Services/WebDriver/main.cpp | 2 +- Services/WebWorker/main.cpp | 2 +- UI/Android/src/main/cpp/ImageDecoderService.cpp | 2 +- UI/Android/src/main/cpp/RequestServerService.cpp | 2 +- UI/Android/src/main/cpp/WebContentService.cpp | 2 +- UI/AppKit/Application/Application.h | 2 +- UI/AppKit/Application/Application.mm | 2 +- UI/Gtk/Application.cpp | 6 +++--- UI/Gtk/Application.h | 2 +- UI/Qt/Application.cpp | 6 +++--- UI/Qt/Application.h | 2 +- Utilities/dns.cpp | 2 +- Utilities/dump-html-tree.cpp | 2 +- 21 files changed, 34 insertions(+), 27 deletions(-) diff --git a/Libraries/LibCore/EventLoop.cpp b/Libraries/LibCore/EventLoop.cpp index a076a9d9f3..b9bc6164b2 100644 --- a/Libraries/LibCore/EventLoop.cpp +++ b/Libraries/LibCore/EventLoop.cpp @@ -42,6 +42,11 @@ EventLoop::~EventLoop() current_event_loop() = nullptr; } +EventLoop& EventLoop::initialize_for_current_thread() +{ + return *new EventLoop; +} + bool EventLoop::is_running() { return current_event_loop() != nullptr; diff --git a/Libraries/LibCore/EventLoop.h b/Libraries/LibCore/EventLoop.h index bb684b8b09..4deb1943dc 100644 --- a/Libraries/LibCore/EventLoop.h +++ b/Libraries/LibCore/EventLoop.h @@ -44,7 +44,6 @@ class CORE_API EventLoop { AK_MAKE_NONMOVABLE(EventLoop); AK_MAKE_NONCOPYABLE(EventLoop); -private: public: enum class WaitMode { WaitForEvents, @@ -54,6 +53,9 @@ public: EventLoop(); ~EventLoop(); + // Create an event loop for the current thread and keep it alive for the rest of the program. + static EventLoop& initialize_for_current_thread(); + // Pump the event loop until its exit is requested. int exec(); diff --git a/Libraries/LibWebView/Application.cpp b/Libraries/LibWebView/Application.cpp index a3435a4931..d047c89296 100644 --- a/Libraries/LibWebView/Application.cpp +++ b/Libraries/LibWebView/Application.cpp @@ -451,7 +451,7 @@ ErrorOr Application::initialize(Main::Arguments const& arguments) initialize_actions(); - m_event_loop = create_platform_event_loop(); + m_event_loop = &create_platform_event_loop(); TRY(launch_services()); return {}; @@ -1036,9 +1036,9 @@ ErrorOr Application::execute() return m_event_loop->exec(); } -NonnullOwnPtr Application::create_platform_event_loop() +Core::EventLoop& Application::create_platform_event_loop() { - return make(); + return Core::EventLoop::initialize_for_current_thread(); } void Application::add_child_process(WebView::Process&& process) diff --git a/Libraries/LibWebView/Application.h b/Libraries/LibWebView/Application.h index de1388e402..33c75756df 100644 --- a/Libraries/LibWebView/Application.h +++ b/Libraries/LibWebView/Application.h @@ -213,7 +213,7 @@ protected: virtual void create_platform_arguments(Core::ArgsParser&) { } virtual void create_platform_options(BrowserOptions&, RequestServerOptions&, WebContentOptions&) { } - virtual NonnullOwnPtr create_platform_event_loop(); + virtual Core::EventLoop& create_platform_event_loop(); virtual Optional ask_user_for_download_path([[maybe_unused]] StringView file) const { return {}; } @@ -352,7 +352,7 @@ private: OwnPtr m_time_zone_watcher; - OwnPtr m_event_loop; + Core::EventLoop* m_event_loop { nullptr }; OwnPtr m_process_manager; RefPtr m_reload_action; diff --git a/Services/Compositor/main.cpp b/Services/Compositor/main.cpp index 77fafc7d2a..90bacbf20b 100644 --- a/Services/Compositor/main.cpp +++ b/Services/Compositor/main.cpp @@ -45,7 +45,7 @@ ErrorOr ladybird_main(Main::Arguments arguments) Gfx::SkiaBackendContext::initialize_gpu_backend(); auto skia_backend_context = Gfx::SkiaBackendContext::the_main_thread_context(); - Core::EventLoop event_loop; + auto& event_loop = Core::EventLoop::initialize_for_current_thread(); auto client = TRY(IPC::take_over_accepted_client_from_system_server( mach_server_name, move(skia_backend_context), !disable_async_scrolling)); diff --git a/Services/ImageDecoder/main.cpp b/Services/ImageDecoder/main.cpp index c911e9f4f0..4357bc7e99 100644 --- a/Services/ImageDecoder/main.cpp +++ b/Services/ImageDecoder/main.cpp @@ -28,7 +28,7 @@ ErrorOr ladybird_main(Main::Arguments arguments) if (wait_for_debugger) Core::Process::wait_for_debugger_and_break(); - Core::EventLoop event_loop; + auto& event_loop = Core::EventLoop::initialize_for_current_thread(); auto client = TRY(IPC::take_over_accepted_client_from_system_server(mach_server_name)); diff --git a/Services/RequestServer/main.cpp b/Services/RequestServer/main.cpp index e9f316f868..cf509122fb 100644 --- a/Services/RequestServer/main.cpp +++ b/Services/RequestServer/main.cpp @@ -71,7 +71,7 @@ ErrorOr ladybird_main(Main::Arguments arguments) MUST(Core::System::signal(SIGPIPE, SIG_IGN)); #endif - Core::EventLoop event_loop; + auto& event_loop = Core::EventLoop::initialize_for_current_thread(); // FIXME: Have another way to signal the event loop to gracefully quit on windows. #ifndef AK_OS_WINDOWS Core::EventLoop::register_signal(SIGINT, handle_signal); diff --git a/Services/WebContent/main.cpp b/Services/WebContent/main.cpp index 3b3cc3a04d..ec436d09a6 100644 --- a/Services/WebContent/main.cpp +++ b/Services/WebContent/main.cpp @@ -127,7 +127,7 @@ ErrorOr ladybird_main(Main::Arguments arguments) return -1; } - Core::EventLoop event_loop; + auto& event_loop = Core::EventLoop::initialize_for_current_thread(); WebView::platform_init(); diff --git a/Services/WebDriver/main.cpp b/Services/WebDriver/main.cpp index 0981d5924e..eb66bbf09c 100644 --- a/Services/WebDriver/main.cpp +++ b/Services/WebDriver/main.cpp @@ -115,7 +115,7 @@ ErrorOr ladybird_main(Main::Arguments arguments) auto webdriver_socket_path = ByteString::formatted("{}/webdriver", TRY(Core::StandardPaths::runtime_directory())); TRY(Core::Directory::create(webdriver_socket_path, Core::Directory::CreateDirectories::Yes)); - Core::EventLoop loop; + auto& loop = Core::EventLoop::initialize_for_current_thread(); auto server = TRY(Core::TCPServer::try_create()); HashTable> clients; diff --git a/Services/WebWorker/main.cpp b/Services/WebWorker/main.cpp index 9108f0020b..062b9f61d7 100644 --- a/Services/WebWorker/main.cpp +++ b/Services/WebWorker/main.cpp @@ -77,7 +77,7 @@ ErrorOr ladybird_main(Main::Arguments arguments) auto worker_type = TRY(agent_type_from_string(worker_type_string)); - Core::EventLoop event_loop; + auto& event_loop = Core::EventLoop::initialize_for_current_thread(); WebView::platform_init(); diff --git a/UI/Android/src/main/cpp/ImageDecoderService.cpp b/UI/Android/src/main/cpp/ImageDecoderService.cpp index 6abc08d279..b8cc06f9ac 100644 --- a/UI/Android/src/main/cpp/ImageDecoderService.cpp +++ b/UI/Android/src/main/cpp/ImageDecoderService.cpp @@ -13,7 +13,7 @@ ErrorOr service_main(int ipc_socket) { - Core::EventLoop event_loop; + auto& event_loop = Core::EventLoop::initialize_for_current_thread(); auto socket = TRY(Core::LocalSocket::adopt_fd(ipc_socket)); auto client = TRY(ImageDecoder::ConnectionFromClient::try_create(make(move(socket)))); diff --git a/UI/Android/src/main/cpp/RequestServerService.cpp b/UI/Android/src/main/cpp/RequestServerService.cpp index 7cbcf1c466..ca36b1a8b1 100644 --- a/UI/Android/src/main/cpp/RequestServerService.cpp +++ b/UI/Android/src/main/cpp/RequestServerService.cpp @@ -29,7 +29,7 @@ ErrorOr service_main(int ipc_socket) RequestServer::g_default_certificate_path = ByteString::formatted("{}/cacert.pem", WebView::s_ladybird_resource_root); - Core::EventLoop event_loop; + auto& event_loop = Core::EventLoop::initialize_for_current_thread(); auto socket = TRY(Core::LocalSocket::adopt_fd(ipc_socket)); auto client = TRY(RequestServer::ConnectionFromClient::try_create(make(move(socket)))); diff --git a/UI/Android/src/main/cpp/WebContentService.cpp b/UI/Android/src/main/cpp/WebContentService.cpp index e1e67d5860..1c0c2ae89b 100644 --- a/UI/Android/src/main/cpp/WebContentService.cpp +++ b/UI/Android/src/main/cpp/WebContentService.cpp @@ -46,7 +46,7 @@ static ErrorOr load_autoplay_allowlist(); ErrorOr service_main(int ipc_socket) { - Core::EventLoop event_loop; + auto& event_loop = Core::EventLoop::initialize_for_current_thread(); Web::Platform::EventLoopPlugin::install(*new Web::Platform::EventLoopPlugin); diff --git a/UI/AppKit/Application/Application.h b/UI/AppKit/Application/Application.h index 0a0ae0c2c3..020ce9ad94 100644 --- a/UI/AppKit/Application/Application.h +++ b/UI/AppKit/Application/Application.h @@ -18,7 +18,7 @@ class Application final : public WebView::Application { private: explicit Application(); - virtual NonnullOwnPtr create_platform_event_loop() override; + virtual Core::EventLoop& create_platform_event_loop() override; virtual Optional active_web_view() const override; virtual Optional open_blank_new_tab(Web::HTML::ActivateTab) const override; diff --git a/UI/AppKit/Application/Application.mm b/UI/AppKit/Application/Application.mm index b5aa93a2b9..b6dd9abef2 100644 --- a/UI/AppKit/Application/Application.mm +++ b/UI/AppKit/Application/Application.mm @@ -27,7 +27,7 @@ namespace Ladybird { Application::Application() = default; -NonnullOwnPtr Application::create_platform_event_loop() +Core::EventLoop& Application::create_platform_event_loop() { if (!browser_options().headless_mode.has_value()) { Core::EventLoopManager::install(*new EventLoopManagerMacOS); diff --git a/UI/Gtk/Application.cpp b/UI/Gtk/Application.cpp index 117f789061..39edd7380e 100644 --- a/UI/Gtk/Application.cpp +++ b/UI/Gtk/Application.cpp @@ -22,7 +22,7 @@ Application::~Application() g_clear_object(&m_adw_application); } -NonnullOwnPtr Application::create_platform_event_loop() +Core::EventLoop& Application::create_platform_event_loop() { if (!browser_options().headless_mode.has_value()) { Core::EventLoopManager::install(*new EventLoopManagerGtk); @@ -42,10 +42,10 @@ NonnullOwnPtr Application::create_platform_event_loop() setup_dbus_handlers(); } - auto event_loop = WebView::Application::create_platform_event_loop(); + auto& event_loop = WebView::Application::create_platform_event_loop(); if (!browser_options().headless_mode.has_value()) - static_cast(event_loop->impl()).set_main_loop(); + static_cast(event_loop.impl()).set_main_loop(); return event_loop; } diff --git a/UI/Gtk/Application.h b/UI/Gtk/Application.h index dcc186b2d8..9390e7cbb9 100644 --- a/UI/Gtk/Application.h +++ b/UI/Gtk/Application.h @@ -44,7 +44,7 @@ public: private: explicit Application(); - virtual NonnullOwnPtr create_platform_event_loop() override; + virtual Core::EventLoop& create_platform_event_loop() override; virtual Optional active_web_view() const override; virtual Optional open_blank_new_tab(Web::HTML::ActivateTab) const override; diff --git a/UI/Qt/Application.cpp b/UI/Qt/Application.cpp index 5ef5072e99..307803957d 100644 --- a/UI/Qt/Application.cpp +++ b/UI/Qt/Application.cpp @@ -124,17 +124,17 @@ void Application::create_platform_options(WebView::BrowserOptions&, WebView::Req web_content_options.config_path = Settings::the()->directory(); } -NonnullOwnPtr Application::create_platform_event_loop() +Core::EventLoop& Application::create_platform_event_loop() { if (!browser_options().headless_mode.has_value()) { Core::EventLoopManager::install(*new EventLoopManagerQt); m_application = make(arguments()); } - auto event_loop = WebView::Application::create_platform_event_loop(); + auto& event_loop = WebView::Application::create_platform_event_loop(); if (!browser_options().headless_mode.has_value()) - static_cast(event_loop->impl()).set_main_loop(); + static_cast(event_loop.impl()).set_main_loop(); return event_loop; } diff --git a/UI/Qt/Application.h b/UI/Qt/Application.h index 68831c370c..152287d179 100644 --- a/UI/Qt/Application.h +++ b/UI/Qt/Application.h @@ -42,7 +42,7 @@ private: explicit Application(); virtual void create_platform_options(WebView::BrowserOptions&, WebView::RequestServerOptions&, WebView::WebContentOptions&) override; - virtual NonnullOwnPtr create_platform_event_loop() override; + virtual Core::EventLoop& create_platform_event_loop() override; virtual Optional active_web_view() const override; virtual Optional open_blank_new_tab(Web::HTML::ActivateTab) const override; diff --git a/Utilities/dns.cpp b/Utilities/dns.cpp index 110589e735..8976190746 100644 --- a/Utilities/dns.cpp +++ b/Utilities/dns.cpp @@ -71,7 +71,7 @@ ErrorOr ladybird_main(Main::Arguments arguments) return 1; } - Core::EventLoop loop; + auto& loop = Core::EventLoop::initialize_for_current_thread(); DNS::Resolver resolver { [&] -> ErrorOr { diff --git a/Utilities/dump-html-tree.cpp b/Utilities/dump-html-tree.cpp index 9b99584a84..5df079bf9a 100644 --- a/Utilities/dump-html-tree.cpp +++ b/Utilities/dump-html-tree.cpp @@ -329,7 +329,7 @@ ErrorOr ladybird_main(Main::Arguments arguments) StringView input { input_data }; - [[maybe_unused]] Core::EventLoop event_loop; + [[maybe_unused]] auto& event_loop = Core::EventLoop::initialize_for_current_thread(); Web::Platform::EventLoopPlugin::install(*new Web::Platform::EventLoopPlugin); Web::Platform::FontPlugin::install(*new Web::Platform::FontPlugin(false)); Web::Bindings::initialize_main_thread_vm(Web::Bindings::AgentType::SimilarOriginWindow);