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.
146 lines
3.8 KiB
C++
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();
|
|
}
|
|
|
|
}
|