ladybird/Libraries/LibCore/EventLoop.cpp
ayeteadoe 4cb7743915 LibCore: Expose register_process and implement for Windows event loop
This is the closest Windows equivalent to integrating process exit
handlers into the event loop.

Linux could also integrate register_process() into the poll() based
Unix event loop via the SYS_pidfd_open syscall; however, macOS requires
a kqueue. So for now register_process will only be used by Windows to
implement WebView::ProcessMonitor.

Co-authored-by: Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
2026-04-12 16:08:07 +02:00

218 lines
5 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 <AK/Vector.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)
{
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()
{
Threading::RWLockLocker<Threading::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;
}
}