ladybird/Libraries/LibCore/ThreadEventQueue.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

146 lines
3.8 KiB
C++

/*
* Copyright (c) 2023, Andreas Kling <andreas@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/NeverDestroyed.h>
#include <AK/Vector.h>
#include <LibCore/EventLoopImplementation.h>
#include <LibCore/EventReceiver.h>
#include <LibCore/Promise.h>
#include <LibCore/ThreadEventQueue.h>
#include <LibSync/Mutex.h>
#include <LibSync/Once.h>
#include <errno.h>
#include <pthread.h>
namespace Core {
struct ThreadEventQueue::Private {
struct QueuedEvent {
AK_MAKE_NONCOPYABLE(QueuedEvent);
AK_MAKE_DEFAULT_MOVABLE(QueuedEvent);
public:
QueuedEvent(RefPtr<EventReceiver> const& receiver, Event::Type event_type)
: receiver(receiver)
, event_type(event_type)
{
}
QueuedEvent(Function<void()>&& invokee)
: m_invokee(move(invokee))
, event_type(Event::Type::DeferredInvoke)
{
}
~QueuedEvent() = default;
WeakPtr<EventReceiver> receiver;
Function<void()> m_invokee;
u8 event_type { Event::Type::Invalid };
};
Sync::Mutex mutex;
Vector<QueuedEvent> queued_events;
};
static pthread_key_t s_current_thread_event_queue_key;
static auto& current_thread_event_queue_key_once()
{
static NeverDestroyed<Sync::OnceFlag> once;
return *once;
}
ThreadEventQueue* ThreadEventQueue::current_or_null()
{
Sync::call_once(current_thread_event_queue_key_once(), [] {
pthread_key_create(&s_current_thread_event_queue_key, [](void* value) {
if (value)
delete static_cast<ThreadEventQueue*>(value);
});
});
return static_cast<ThreadEventQueue*>(pthread_getspecific(s_current_thread_event_queue_key));
}
ThreadEventQueue& ThreadEventQueue::current()
{
auto* ptr = current_or_null();
if (!ptr) {
ptr = new ThreadEventQueue;
pthread_setspecific(s_current_thread_event_queue_key, ptr);
}
return *ptr;
}
ThreadEventQueue::ThreadEventQueue()
: m_private(make<Private>())
{
}
ThreadEventQueue::~ThreadEventQueue() = default;
void ThreadEventQueue::post_event(Core::EventReceiver* receiver, Core::Event::Type event_type)
{
{
Sync::MutexLocker lock(m_private->mutex);
m_private->queued_events.empend(receiver, event_type);
}
Core::EventLoopManager::the().did_post_event();
}
void ThreadEventQueue::deferred_invoke(Function<void()>&& invokee)
{
{
Sync::MutexLocker lock(m_private->mutex);
m_private->queued_events.empend(move(invokee));
}
Core::EventLoopManager::the().did_post_event();
}
size_t ThreadEventQueue::process()
{
decltype(m_private->queued_events) events;
{
Sync::MutexLocker locker(m_private->mutex);
events = move(m_private->queued_events);
}
for (auto& queued_event : events) {
if (auto receiver = queued_event.receiver.strong_ref()) {
switch (queued_event.event_type) {
case Event::Type::Timer: {
TimerEvent timer_event;
receiver->dispatch_event(timer_event);
break;
}
case Event::Type::NotifierActivation: {
NotifierActivationEvent notifier_activation_event;
receiver->dispatch_event(notifier_activation_event);
break;
}
default:
VERIFY_NOT_REACHED();
}
} else {
if (queued_event.event_type == Event::Type::DeferredInvoke) {
queued_event.m_invokee();
} else {
// Receiver gone, drop the event.
}
}
}
return events.size();
}
bool ThreadEventQueue::has_pending_events() const
{
Sync::MutexLocker locker(m_private->mutex);
return !m_private->queued_events.is_empty();
}
}