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.
248 lines
5.7 KiB
C++
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;
|
|
}
|
|
|
|
}
|