LibCore+Ladybird: Add EventLoopManager interface for persistent state

Things such as timers and notifiers aren't specific to one instance of
Core::EventLoop, so let's not tie them down to EventLoopImplementation.

Instead, move those APIs + signals & a few other things to a new
EventLoopManager interface. EventLoopManager also knows how to create a
new EventLoopImplementation object.
This commit is contained in:
Andreas Kling 2023-04-25 17:38:48 +02:00
parent c21eb30a2b
commit 7b963e1e98
Notes: sideshowbarker 2024-07-17 07:43:44 +09:00
11 changed files with 177 additions and 118 deletions

View File

@ -35,11 +35,6 @@ struct ThreadData {
EventLoopImplementationQt::EventLoopImplementationQt()
{
m_process_core_events_timer.setSingleShot(true);
m_process_core_events_timer.setInterval(0);
QObject::connect(&m_process_core_events_timer, &QTimer::timeout, [] {
Core::ThreadEventQueue::current().process();
});
}
EventLoopImplementationQt::~EventLoopImplementationQt() = default;
@ -79,7 +74,7 @@ void EventLoopImplementationQt::wake()
m_event_loop.wakeUp();
}
void EventLoopImplementationQt::deferred_invoke(Function<void()> function)
void EventLoopManagerQt::deferred_invoke(Function<void()> function)
{
VERIFY(function);
QTimer::singleShot(0, [function = move(function)] {
@ -97,7 +92,7 @@ static void qt_timer_fired(int timer_id, Core::TimerShouldFireWhenNotVisible sho
object.dispatch_event(event);
}
int EventLoopImplementationQt::register_timer(Core::Object& object, int milliseconds, bool should_reload, Core::TimerShouldFireWhenNotVisible should_fire_when_not_visible)
int EventLoopManagerQt::register_timer(Core::Object& object, int milliseconds, bool should_reload, Core::TimerShouldFireWhenNotVisible should_fire_when_not_visible)
{
auto& thread_data = ThreadData::the();
auto timer = make<QTimer>();
@ -116,7 +111,7 @@ int EventLoopImplementationQt::register_timer(Core::Object& object, int millisec
return timer_id;
}
bool EventLoopImplementationQt::unregister_timer(int timer_id)
bool EventLoopManagerQt::unregister_timer(int timer_id)
{
auto& thread_data = ThreadData::the();
thread_data.timer_id_allocator.deallocate(timer_id);
@ -129,7 +124,7 @@ static void qt_notifier_activated(Core::Notifier& notifier)
notifier.dispatch_event(event);
}
void EventLoopImplementationQt::register_notifier(Core::Notifier& notifier)
void EventLoopManagerQt::register_notifier(Core::Notifier& notifier)
{
QSocketNotifier::Type type;
switch (notifier.type()) {
@ -150,14 +145,34 @@ void EventLoopImplementationQt::register_notifier(Core::Notifier& notifier)
ThreadData::the().notifiers.set(&notifier, move(socket_notifier));
}
void EventLoopImplementationQt::unregister_notifier(Core::Notifier& notifier)
void EventLoopManagerQt::unregister_notifier(Core::Notifier& notifier)
{
ThreadData::the().notifiers.remove(&notifier);
}
void EventLoopImplementationQt::did_post_event()
void EventLoopManagerQt::did_post_event()
{
m_process_core_events_timer.start();
}
EventLoopManagerQt::EventLoopManagerQt()
{
m_process_core_events_timer.setSingleShot(true);
m_process_core_events_timer.setInterval(0);
QObject::connect(&m_process_core_events_timer, &QTimer::timeout, [] {
Core::ThreadEventQueue::current().process();
});
}
EventLoopManagerQt::~EventLoopManagerQt() = default;
void EventLoopManagerQt::wake()
{
}
NonnullOwnPtr<Core::EventLoopImplementation> EventLoopManagerQt::make_implementation()
{
return adopt_own(*new EventLoopImplementationQt);
}
}

View File

@ -16,16 +16,11 @@
namespace Ladybird {
class EventLoopImplementationQt final : public Core::EventLoopImplementation {
class EventLoopManagerQt final : public Core::EventLoopManager {
public:
static NonnullOwnPtr<EventLoopImplementationQt> create() { return adopt_own(*new EventLoopImplementationQt); }
virtual ~EventLoopImplementationQt() override;
virtual int exec() override;
virtual size_t pump(PumpMode) override;
virtual void quit(int) override;
virtual void wake() override;
EventLoopManagerQt();
virtual ~EventLoopManagerQt() override;
virtual NonnullOwnPtr<Core::EventLoopImplementation> make_implementation() override;
virtual void deferred_invoke(Function<void()>) override;
@ -37,21 +32,41 @@ public:
virtual void did_post_event() override;
virtual void wake() override;
// FIXME: These APIs only exist for obscure use-cases inside SerenityOS. Try to get rid of them.
virtual int register_signal(int, Function<void(int)>) override { return 0; }
virtual void unregister_signal(int) override { }
private:
QTimer m_process_core_events_timer;
};
class EventLoopImplementationQt final : public Core::EventLoopImplementation {
public:
static NonnullOwnPtr<EventLoopImplementationQt> create() { return adopt_own(*new EventLoopImplementationQt); }
virtual ~EventLoopImplementationQt() override;
virtual int exec() override;
virtual size_t pump(PumpMode) override;
virtual void quit(int) override;
virtual void wake() override;
// FIXME: These APIs only exist for obscure use-cases inside SerenityOS. Try to get rid of them.
virtual void unquit() override { }
virtual bool was_exit_requested() const override { return false; }
virtual void notify_forked_and_in_child() override { }
virtual int register_signal(int, Function<void(int)>) override { return 0; }
virtual void unregister_signal(int) override { }
void set_main_loop() { m_main_loop = true; }
private:
friend class EventLoopManagerQt;
EventLoopImplementationQt();
bool is_main_loop() const { return m_main_loop; }
QEventLoop m_event_loop;
QTimer m_process_core_events_timer;
bool m_main_loop { false };
};

View File

@ -40,7 +40,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
{
QGuiApplication app(arguments.argc, arguments.argv);
Core::EventLoop::make_implementation = Ladybird::EventLoopImplementationQt::create;
Core::EventLoopManager::install(*new Ladybird::EventLoopManagerQt);
Core::EventLoop event_loop;
platform_init();

View File

@ -54,7 +54,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
{
QApplication app(arguments.argc, arguments.argv);
Core::EventLoop::make_implementation = Ladybird::EventLoopImplementationQt::create;
Core::EventLoopManager::install(*new Ladybird::EventLoopManagerQt);
Core::EventLoop event_loop;
static_cast<Ladybird::EventLoopImplementationQt&>(event_loop.impl()).set_main_loop();

View File

@ -24,16 +24,10 @@ Vector<EventLoop&>& event_loop_stack()
s_event_loop_stack = new Vector<EventLoop&>;
return *s_event_loop_stack;
}
bool has_event_loop()
{
return !event_loop_stack().is_empty();
}
}
Function<NonnullOwnPtr<EventLoopImplementation>()> EventLoop::make_implementation = EventLoopImplementationUnix::create;
EventLoop::EventLoop()
: m_impl(make_implementation())
: m_impl(EventLoopManager::the().make_implementation())
{
if (event_loop_stack().is_empty()) {
event_loop_stack().append(*this);
@ -94,7 +88,7 @@ size_t EventLoop::pump(WaitMode mode)
void EventLoop::post_event(Object& receiver, NonnullOwnPtr<Event>&& event)
{
m_impl->post_event(receiver, move(event));
EventLoopManager::the().post_event(receiver, move(event));
}
void EventLoop::add_job(NonnullRefPtr<Promise<NonnullRefPtr<Object>>> job_promise)
@ -104,16 +98,12 @@ void EventLoop::add_job(NonnullRefPtr<Promise<NonnullRefPtr<Object>>> job_promis
int EventLoop::register_signal(int signal_number, Function<void(int)> handler)
{
if (!has_event_loop())
return 0;
return current().m_impl->register_signal(signal_number, move(handler));
return EventLoopManager::the().register_signal(signal_number, move(handler));
}
void EventLoop::unregister_signal(int handler_id)
{
if (!has_event_loop())
return;
current().m_impl->unregister_signal(handler_id);
EventLoopManager::the().unregister_signal(handler_id);
}
void EventLoop::notify_forked(ForkEvent)
@ -123,30 +113,22 @@ void EventLoop::notify_forked(ForkEvent)
int EventLoop::register_timer(Object& object, int milliseconds, bool should_reload, TimerShouldFireWhenNotVisible fire_when_not_visible)
{
if (!has_event_loop())
return 0;
return current().m_impl->register_timer(object, milliseconds, should_reload, fire_when_not_visible);
return EventLoopManager::the().register_timer(object, milliseconds, should_reload, fire_when_not_visible);
}
bool EventLoop::unregister_timer(int timer_id)
{
if (!has_event_loop())
return false;
return current().m_impl->unregister_timer(timer_id);
return EventLoopManager::the().unregister_timer(timer_id);
}
void EventLoop::register_notifier(Badge<Notifier>, Notifier& notifier)
{
if (!has_event_loop())
return;
current().m_impl->register_notifier(notifier);
EventLoopManager::the().register_notifier(notifier);
}
void EventLoop::unregister_notifier(Badge<Notifier>, Notifier& notifier)
{
if (!has_event_loop())
return;
current().m_impl->unregister_notifier(notifier);
EventLoopManager::the().unregister_notifier(notifier);
}
void EventLoop::wake()
@ -170,9 +152,4 @@ bool EventLoop::was_exit_requested() const
return m_impl->was_exit_requested();
}
void EventLoop::did_post_event(Badge<Core::ThreadEventQueue>)
{
m_impl->did_post_event();
}
}

View File

@ -94,8 +94,6 @@ public:
static EventLoop& current();
static Function<NonnullOwnPtr<EventLoopImplementation>()> make_implementation;
void did_post_event(Badge<ThreadEventQueue>);
EventLoopImplementation& impl() { return *m_impl; }

View File

@ -7,18 +7,36 @@
#include <AK/NonnullOwnPtr.h>
#include <LibCore/Event.h>
#include <LibCore/EventLoopImplementation.h>
#include <LibCore/EventLoopImplementationUnix.h>
#include <LibCore/ThreadEventQueue.h>
namespace Core {
EventLoopImplementation::EventLoopImplementation()
EventLoopImplementation::EventLoopImplementation() = default;
EventLoopImplementation::~EventLoopImplementation() = default;
static EventLoopManager* s_event_loop_manager;
EventLoopManager& EventLoopManager::the()
{
if (!s_event_loop_manager)
s_event_loop_manager = new EventLoopManagerUnix;
return *s_event_loop_manager;
}
void EventLoopManager::install(Core::EventLoopManager& manager)
{
s_event_loop_manager = &manager;
}
EventLoopManager::EventLoopManager()
: m_thread_event_queue(ThreadEventQueue::current())
{
}
EventLoopImplementation::~EventLoopImplementation() = default;
EventLoopManager::~EventLoopManager() = default;
void EventLoopImplementation::post_event(Object& receiver, NonnullOwnPtr<Event>&& event)
void EventLoopManager::post_event(Object& receiver, NonnullOwnPtr<Event>&& event)
{
m_thread_event_queue.post_event(receiver, move(event));

View File

@ -11,8 +11,40 @@
namespace Core {
class EventLoopImplementation;
class ThreadEventQueue;
class EventLoopManager {
public:
static EventLoopManager& the();
static void install(EventLoopManager&);
virtual ~EventLoopManager();
virtual NonnullOwnPtr<EventLoopImplementation> make_implementation() = 0;
virtual int register_timer(Object&, int milliseconds, bool should_reload, TimerShouldFireWhenNotVisible) = 0;
virtual bool unregister_timer(int timer_id) = 0;
virtual void register_notifier(Notifier&) = 0;
virtual void unregister_notifier(Notifier&) = 0;
void post_event(Object& receiver, NonnullOwnPtr<Event>&&);
virtual void did_post_event() = 0;
virtual void deferred_invoke(Function<void()>) = 0;
// FIXME: These APIs only exist for obscure use-cases inside SerenityOS. Try to get rid of them.
virtual int register_signal(int signal_number, Function<void(int)> handler) = 0;
virtual void unregister_signal(int handler_id) = 0;
virtual void wake() = 0;
protected:
EventLoopManager();
ThreadEventQueue& m_thread_event_queue;
};
class EventLoopImplementation {
public:
virtual ~EventLoopImplementation();
@ -22,34 +54,18 @@ public:
DontWaitForEvents,
};
void post_event(Object& receiver, NonnullOwnPtr<Event>&&);
virtual int exec() = 0;
virtual size_t pump(PumpMode) = 0;
virtual void quit(int) = 0;
virtual void wake() = 0;
virtual void deferred_invoke(Function<void()>) = 0;
virtual int register_timer(Object&, int milliseconds, bool should_reload, TimerShouldFireWhenNotVisible) = 0;
virtual bool unregister_timer(int timer_id) = 0;
virtual void register_notifier(Notifier&) = 0;
virtual void unregister_notifier(Notifier&) = 0;
virtual void did_post_event() = 0;
// FIXME: These APIs only exist for obscure use-cases inside SerenityOS. Try to get rid of them.
virtual void unquit() = 0;
virtual bool was_exit_requested() const = 0;
virtual void notify_forked_and_in_child() = 0;
virtual int register_signal(int signal_number, Function<void(int)> handler) = 0;
virtual void unregister_signal(int handler_id) = 0;
protected:
EventLoopImplementation();
ThreadEventQueue& m_thread_event_queue;
};
}

View File

@ -105,11 +105,8 @@ int EventLoopImplementationUnix::exec()
size_t EventLoopImplementationUnix::pump(PumpMode mode)
{
// We can only pump the event loop of the current thread.
VERIFY(&m_thread_event_queue == &ThreadEventQueue::current());
wait_for_events(mode);
return m_thread_event_queue.process();
static_cast<EventLoopManagerUnix&>(EventLoopManager::the()).wait_for_events(mode);
return ThreadEventQueue::current().process();
}
void EventLoopImplementationUnix::quit(int code)
@ -135,14 +132,20 @@ void EventLoopImplementationUnix::wake()
MUST(Core::System::write((*m_wake_pipe_fds)[1], { &wake_event, sizeof(wake_event) }));
}
void EventLoopImplementationUnix::deferred_invoke(Function<void()> invokee)
void EventLoopManagerUnix::wake()
{
int wake_event = 0;
MUST(Core::System::write(ThreadData::the().wake_pipe_fds[1], { &wake_event, sizeof(wake_event) }));
}
void EventLoopManagerUnix::deferred_invoke(Function<void()> invokee)
{
// FIXME: Get rid of the useless DeferredInvocationContext object.
auto context = DeferredInvocationContext::construct();
post_event(context, make<DeferredInvocationEvent>(context, move(invokee)));
}
void EventLoopImplementationUnix::wait_for_events(PumpMode mode)
void EventLoopManagerUnix::wait_for_events(EventLoopImplementation::PumpMode mode)
{
auto& thread_data = ThreadData::the();
@ -177,7 +180,7 @@ retry:
Time now;
struct timeval timeout = { 0, 0 };
bool should_wait_forever = false;
if (mode == PumpMode::WaitForEvents && !has_pending_events) {
if (mode == EventLoopImplementation::PumpMode::WaitForEvents && !has_pending_events) {
auto next_timer_expiration = get_next_timer_expiration();
if (next_timer_expiration.has_value()) {
now = Time::now_monotonic_coarse();
@ -196,11 +199,8 @@ try_select_again:
// Because POSIX, we might spuriously return from select() with EINTR; just select again.
if (marked_fd_count < 0) {
int saved_errno = errno;
if (saved_errno == EINTR) {
if (m_exit_requested)
return;
if (saved_errno == EINTR)
goto try_select_again;
}
dbgln("EventLoopImplementationUnix::wait_for_events: {} ({}: {})", marked_fd_count, saved_errno, strerror(saved_errno));
VERIFY_NOT_REACHED();
}
@ -329,7 +329,7 @@ inline SignalHandlersInfo* signals_info()
return s_signals.ptr();
}
void EventLoopImplementationUnix::dispatch_signal(int signal_number)
void EventLoopManagerUnix::dispatch_signal(int signal_number)
{
auto& info = *signals_info();
auto handlers = info.signal_handlers.find(signal_number);
@ -355,7 +355,7 @@ void EventLoopImplementationUnix::notify_forked_and_in_child()
thread_data.pid = getpid();
}
Optional<Time> EventLoopImplementationUnix::get_next_timer_expiration()
Optional<Time> EventLoopManagerUnix::get_next_timer_expiration()
{
auto now = Time::now_monotonic_coarse();
Optional<Time> soonest {};
@ -438,7 +438,7 @@ bool SignalHandlers::remove(int handler_id)
return m_handlers.remove(handler_id);
}
void EventLoopImplementationUnix::handle_signal(int signal_number)
void EventLoopManagerUnix::handle_signal(int signal_number)
{
VERIFY(signal_number != 0);
auto& thread_data = ThreadData::the();
@ -457,13 +457,13 @@ void EventLoopImplementationUnix::handle_signal(int signal_number)
}
}
int EventLoopImplementationUnix::register_signal(int signal_number, Function<void(int)> handler)
int EventLoopManagerUnix::register_signal(int signal_number, Function<void(int)> handler)
{
VERIFY(signal_number != 0);
auto& info = *signals_info();
auto handlers = info.signal_handlers.find(signal_number);
if (handlers == info.signal_handlers.end()) {
auto signal_handlers = adopt_ref(*new SignalHandlers(signal_number, EventLoopImplementationUnix::handle_signal));
auto signal_handlers = adopt_ref(*new SignalHandlers(signal_number, EventLoopManagerUnix::handle_signal));
auto handler_id = signal_handlers->add(move(handler));
info.signal_handlers.set(signal_number, move(signal_handlers));
return handler_id;
@ -472,7 +472,7 @@ int EventLoopImplementationUnix::register_signal(int signal_number, Function<voi
}
}
void EventLoopImplementationUnix::unregister_signal(int handler_id)
void EventLoopManagerUnix::unregister_signal(int handler_id)
{
VERIFY(handler_id != 0);
int remove_signal_number = 0;
@ -489,7 +489,7 @@ void EventLoopImplementationUnix::unregister_signal(int handler_id)
info.signal_handlers.remove(remove_signal_number);
}
int EventLoopImplementationUnix::register_timer(Object& object, int milliseconds, bool should_reload, TimerShouldFireWhenNotVisible fire_when_not_visible)
int EventLoopManagerUnix::register_timer(Object& object, int milliseconds, bool should_reload, TimerShouldFireWhenNotVisible fire_when_not_visible)
{
VERIFY(milliseconds >= 0);
auto& thread_data = ThreadData::the();
@ -505,25 +505,32 @@ int EventLoopImplementationUnix::register_timer(Object& object, int milliseconds
return timer_id;
}
bool EventLoopImplementationUnix::unregister_timer(int timer_id)
bool EventLoopManagerUnix::unregister_timer(int timer_id)
{
auto& thread_data = ThreadData::the();
thread_data.id_allocator.deallocate(timer_id);
return thread_data.timers.remove(timer_id);
}
void EventLoopImplementationUnix::register_notifier(Notifier& notifier)
void EventLoopManagerUnix::register_notifier(Notifier& notifier)
{
ThreadData::the().notifiers.set(&notifier);
}
void EventLoopImplementationUnix::unregister_notifier(Notifier& notifier)
void EventLoopManagerUnix::unregister_notifier(Notifier& notifier)
{
ThreadData::the().notifiers.remove(&notifier);
}
void EventLoopImplementationUnix::did_post_event()
void EventLoopManagerUnix::did_post_event()
{
}
EventLoopManagerUnix::~EventLoopManagerUnix() = default;
NonnullOwnPtr<EventLoopImplementation> EventLoopManagerUnix::make_implementation()
{
return adopt_own(*new EventLoopImplementationUnix);
}
}

View File

@ -10,6 +10,35 @@
namespace Core {
class EventLoopManagerUnix final : public EventLoopManager {
public:
virtual ~EventLoopManagerUnix() override;
virtual NonnullOwnPtr<EventLoopImplementation> make_implementation() override;
virtual void deferred_invoke(Function<void()>) override;
virtual int register_timer(Object&, int milliseconds, bool should_reload, TimerShouldFireWhenNotVisible) override;
virtual bool unregister_timer(int timer_id) override;
virtual void register_notifier(Notifier&) override;
virtual void unregister_notifier(Notifier&) override;
virtual void did_post_event() override;
virtual int register_signal(int signal_number, Function<void(int)> handler) override;
virtual void unregister_signal(int handler_id) override;
virtual void wake() override;
void wait_for_events(EventLoopImplementation::PumpMode);
static Optional<Time> get_next_timer_expiration();
private:
void dispatch_signal(int signal_number);
static void handle_signal(int signal_number);
};
class EventLoopImplementationUnix final : public EventLoopImplementation {
public:
static NonnullOwnPtr<EventLoopImplementationUnix> create() { return make<EventLoopImplementationUnix>(); }
@ -23,28 +52,11 @@ public:
virtual void wake() override;
virtual void deferred_invoke(Function<void()>) override;
virtual int register_timer(Object&, int milliseconds, bool should_reload, TimerShouldFireWhenNotVisible) override;
virtual bool unregister_timer(int timer_id) override;
virtual void register_notifier(Notifier&) override;
virtual void unregister_notifier(Notifier&) override;
virtual void did_post_event() override;
virtual void unquit() override;
virtual bool was_exit_requested() const override;
virtual void notify_forked_and_in_child() override;
virtual int register_signal(int signal_number, Function<void(int)> handler) override;
virtual void unregister_signal(int handler_id) override;
private:
void wait_for_events(PumpMode);
void dispatch_signal(int signal_number);
static void handle_signal(int signal_number);
static Optional<Time> get_next_timer_expiration();
bool m_exit_requested { false };
int m_exit_code { 0 };

View File

@ -6,6 +6,7 @@
#include <AK/Vector.h>
#include <LibCore/DeferredInvocationContext.h>
#include <LibCore/EventLoopImplementation.h>
#include <LibCore/Object.h>
#include <LibCore/Promise.h>
#include <LibCore/ThreadEventQueue.h>
@ -66,7 +67,7 @@ void ThreadEventQueue::post_event(Core::Object& receiver, NonnullOwnPtr<Core::Ev
Threading::MutexLocker lock(m_private->mutex);
m_private->queued_events.empend(receiver, move(event));
}
Core::EventLoop::current().did_post_event({});
Core::EventLoopManager::the().did_post_event();
}
void ThreadEventQueue::add_job(NonnullRefPtr<Promise<NonnullRefPtr<Object>>> promise)