ladybird/Libraries/LibCore/EventLoop.cpp
Andreas Kling 164ed80244 Meta: Enable exit-time destructor warnings for libraries
Enable -Wexit-time-destructors for all in-tree library targets and
update process-lifetime library statics so they no longer register
exit-time destructors. Long-lived caches, lookup tables, singleton
registries, and generated constants now use NeverDestroyed or leaked
references where the data is intended to live until process exit.

Update LibWeb, LibLine, and the binding generators so regenerated
sources follow the same rule instead of reintroducing destructed
statics.
2026-06-04 19:20:49 +02:00

248 lines
5.7 KiB
C++

/*
* Copyright (c) 2018-2023, Andreas Kling <andreas@ladybird.org>
* Copyright (c) 2022, kleines Filmröllchen <malu.bertsch@gmail.com>
* Copyright (c) 2022, the SerenityOS developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Assertions.h>
#include <AK/Badge.h>
#include <AK/Platform.h>
#include <AK/Vector.h>
#include <LibCore/EventLoop.h>
#include <LibCore/EventLoopImplementation.h>
#include <LibCore/EventReceiver.h>
#include <LibCore/Promise.h>
#include <LibCore/ThreadEventQueue.h>
#ifndef AK_OS_WINDOWS
# include <pthread.h>
#endif
namespace Core {
namespace {
#ifndef AK_OS_WINDOWS
static pthread_key_t s_event_loop_stack_key;
static pthread_once_t s_event_loop_stack_key_once = PTHREAD_ONCE_INIT;
static void destroy_event_loop_stack(void* value)
{
delete static_cast<Vector<EventLoop&>*>(value);
}
static void initialize_event_loop_stack_key()
{
VERIFY(pthread_key_create(&s_event_loop_stack_key, destroy_event_loop_stack) == 0);
}
static void ensure_event_loop_stack_key()
{
VERIFY(pthread_once(&s_event_loop_stack_key_once, initialize_event_loop_stack_key) == 0);
}
#endif
Vector<EventLoop&>*& event_loop_stack_uninitialized()
{
thread_local Vector<EventLoop&>* s_event_loop_stack = nullptr;
return s_event_loop_stack;
}
Vector<EventLoop&>& event_loop_stack()
{
auto& the_stack = event_loop_stack_uninitialized();
if (the_stack == nullptr) {
the_stack = new Vector<EventLoop&>();
#ifndef AK_OS_WINDOWS
ensure_event_loop_stack_key();
VERIFY(pthread_setspecific(s_event_loop_stack_key, the_stack) == 0);
#endif
}
return *the_stack;
}
}
EventLoop::EventLoop()
: m_impl(EventLoopManager::the().make_implementation())
{
if (event_loop_stack().is_empty()) {
event_loop_stack().append(*this);
}
}
EventLoop::~EventLoop()
{
if (m_weak)
m_weak->revoke();
if (!event_loop_stack().is_empty() && &event_loop_stack().last() == this) {
event_loop_stack().take_last();
}
}
bool EventLoop::is_running()
{
auto& stack = event_loop_stack_uninitialized();
return stack != nullptr && !stack->is_empty();
}
EventLoop& EventLoop::current()
{
if (event_loop_stack().is_empty())
dbgln("No EventLoop is present, unable to return current one!");
return event_loop_stack().last();
}
NonnullRefPtr<WeakEventLoopReference> EventLoop::current_weak()
{
auto& event_loop = current();
if (!event_loop.m_weak)
event_loop.m_weak = adopt_ref(*new (nothrow) WeakEventLoopReference(event_loop));
return *event_loop.m_weak;
}
void EventLoop::quit(int code)
{
m_impl->quit(code);
}
bool EventLoop::was_exit_requested()
{
return m_impl->was_exit_requested();
}
struct EventLoopPusher {
public:
EventLoopPusher(EventLoop& event_loop)
{
event_loop_stack().append(event_loop);
}
~EventLoopPusher()
{
event_loop_stack().take_last();
}
};
int EventLoop::exec()
{
EventLoopPusher pusher(*this);
return m_impl->exec();
}
void EventLoop::spin_until(Function<bool()> goal_condition)
{
EventLoopPusher pusher(*this);
while (!goal_condition())
pump();
}
size_t EventLoop::pump(WaitMode mode)
{
return m_impl->pump(mode == WaitMode::WaitForEvents ? EventLoopImplementation::PumpMode::WaitForEvents : EventLoopImplementation::PumpMode::DontWaitForEvents);
}
int EventLoop::register_signal(int signal_number, Function<void(int)> handler)
{
return EventLoopManager::the().register_signal(signal_number, move(handler));
}
void EventLoop::unregister_signal(int handler_id)
{
EventLoopManager::the().unregister_signal(handler_id);
}
intptr_t EventLoop::register_timer(EventReceiver& object, int milliseconds, bool should_reload)
{
return EventLoopManager::the().register_timer(object, milliseconds, should_reload);
}
void EventLoop::unregister_timer(intptr_t timer_id)
{
EventLoopManager::the().unregister_timer(timer_id);
}
void EventLoop::register_notifier(Badge<Notifier>, Notifier& notifier)
{
EventLoopManager::the().register_notifier(notifier);
}
void EventLoop::unregister_notifier(Badge<Notifier>, Notifier& notifier)
{
EventLoopManager::the().unregister_notifier(notifier);
}
void EventLoop::register_process(pid_t pid, ESCAPING Function<void(pid_t)> exit_handler)
{
EventLoopManager::the().register_process(pid, move(exit_handler));
}
void EventLoop::unregister_process(pid_t pid)
{
EventLoopManager::the().unregister_process(pid);
}
void EventLoop::wake()
{
m_impl->wake();
}
void EventLoop::deferred_invoke(Function<void()> invokee)
{
m_impl->deferred_invoke(move(invokee));
}
void deferred_invoke(Function<void()> invokee)
{
EventLoop::current().deferred_invoke(move(invokee));
}
WeakEventLoopReference::WeakEventLoopReference(EventLoop& event_loop)
: m_event_loop(&event_loop)
{
}
void WeakEventLoopReference::revoke()
{
Sync::RWLockLocker<Sync::LockMode::Write> locker { m_lock };
m_event_loop = nullptr;
}
StrongEventLoopReference WeakEventLoopReference::take()
{
return StrongEventLoopReference(*this);
}
StrongEventLoopReference::StrongEventLoopReference(WeakEventLoopReference& event_loop_weak)
{
event_loop_weak.m_lock.lock_read();
m_event_loop_weak = &event_loop_weak;
}
StrongEventLoopReference::~StrongEventLoopReference()
{
m_event_loop_weak->m_lock.unlock_read();
}
bool StrongEventLoopReference::is_alive() const
{
return m_event_loop_weak->m_event_loop != nullptr;
}
StrongEventLoopReference::operator bool() const
{
return is_alive();
}
EventLoop* StrongEventLoopReference::operator*() const
{
VERIFY(is_alive());
return m_event_loop_weak->m_event_loop;
}
EventLoop* StrongEventLoopReference::operator->() const
{
VERIFY(is_alive());
return m_event_loop_weak->m_event_loop;
}
}