mirror of
https://github.com/zebrajr/ladybird.git
synced 2026-01-15 12:15:15 +00:00
Since the event loop has a very specifically scoped lifetime, we can't ensure that it outlives threads that hold a reference to it without blocking the thread that owns it. In order to make threads use the event loop safely, we now have an atomically ref-counted WeakEventLoopReference class that can be passed off to threads to safely post events/callbacks to it. Another possibility was to use an RWLock per event loop that each thread holds a read lock on, while ~EventLoop() uses a write lock to block and prevent it being destroyed until all its threads exit. However, media data providers don't receive a signal to exit due to the GC heap being intentionally leaked, so the process never actually exits. It would be possible to specifically drop the reference to PlaybackManager in HTMLMediaElement in order to make those data providers die on their own, but that doesn't help prevent this problem in other cases where it may arise.
215 lines
4.9 KiB
C++
215 lines
4.9 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/Badge.h>
|
|
#include <LibCore/Event.h>
|
|
#include <LibCore/EventLoop.h>
|
|
#include <LibCore/EventLoopImplementation.h>
|
|
#include <LibCore/EventReceiver.h>
|
|
#include <LibCore/Promise.h>
|
|
#include <LibCore/ThreadEventQueue.h>
|
|
|
|
namespace Core {
|
|
|
|
namespace {
|
|
|
|
OwnPtr<Vector<EventLoop&>>& event_loop_stack_uninitialized()
|
|
{
|
|
thread_local OwnPtr<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 = make<Vector<EventLoop&>>();
|
|
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)
|
|
{
|
|
ThreadEventQueue::current().cancel_all_pending_jobs();
|
|
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);
|
|
}
|
|
|
|
void EventLoop::add_job(NonnullRefPtr<Promise<NonnullRefPtr<EventReceiver>>> job_promise)
|
|
{
|
|
ThreadEventQueue::current().add_job(move(job_promise));
|
|
}
|
|
|
|
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::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()
|
|
{
|
|
Threading::RWLockLocker<Threading::LockMode::Read> 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();
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
}
|