1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 19:17:44 +00:00

LibCore: Allow event loops on other threads to wake up

Because the wake pipe is thread-local, it was previously not possible
to wake an event loop across a thread. Therefore, this commit
rearchitects event loop waking by making the wake function a member of
the event loop itself and having it keep a pointer to its thread's wake
pipe. The global wake() function calls wake on the current thread's
event loop.

This also fixes a bug in BackgroundAction: it should wake the event loop
it was created on, instead of the current thread's event loop.
This commit is contained in:
kleines Filmröllchen 2022-02-11 16:57:10 +01:00 committed by Andreas Kling
parent 716a3429fa
commit 704bb361bb
4 changed files with 27 additions and 9 deletions

View file

@ -849,7 +849,7 @@ void HackStudioWidget::initialize_debugger()
m_disassembly_widget->update_state(*Debugger::the().session(), regs); m_disassembly_widget->update_state(*Debugger::the().session(), regs);
HackStudioWidget::reveal_action_tab(*m_debug_info_widget); HackStudioWidget::reveal_action_tab(*m_debug_info_widget);
}); });
Core::EventLoop::wake(); Core::EventLoop::wake_current();
return Debugger::HasControlPassedToUser::Yes; return Debugger::HasControlPassedToUser::Yes;
}, },
@ -859,7 +859,7 @@ void HackStudioWidget::initialize_debugger()
if (m_current_editor_in_execution) if (m_current_editor_in_execution)
m_current_editor_in_execution->editor().clear_execution_position(); m_current_editor_in_execution->editor().clear_execution_position();
}); });
Core::EventLoop::wake(); Core::EventLoop::wake_current();
}, },
[this]() { [this]() {
deferred_invoke([this] { deferred_invoke([this] {
@ -879,7 +879,7 @@ void HackStudioWidget::initialize_debugger()
HackStudioWidget::hide_action_tabs(); HackStudioWidget::hide_action_tabs();
GUI::MessageBox::show(window(), "Program Exited", "Debugger", GUI::MessageBox::Type::Information); GUI::MessageBox::show(window(), "Program Exited", "Debugger", GUI::MessageBox::Type::Information);
}); });
Core::EventLoop::wake(); Core::EventLoop::wake_current();
}); });
} }

View file

@ -302,7 +302,8 @@ private:
}; };
EventLoop::EventLoop([[maybe_unused]] MakeInspectable make_inspectable) EventLoop::EventLoop([[maybe_unused]] MakeInspectable make_inspectable)
: m_private(make<Private>()) : m_wake_pipe_fds(&s_wake_pipe_fds)
, m_private(make<Private>())
{ {
#ifdef __serenity__ #ifdef __serenity__
if (!s_global_initializers_ran) { if (!s_global_initializers_ran) {
@ -487,11 +488,13 @@ size_t EventLoop::pump(WaitMode mode)
return processed_events; return processed_events;
} }
void EventLoop::post_event(Object& receiver, NonnullOwnPtr<Event>&& event) void EventLoop::post_event(Object& receiver, NonnullOwnPtr<Event>&& event, ShouldWake should_wake)
{ {
Threading::MutexLocker lock(m_private->lock); Threading::MutexLocker lock(m_private->lock);
dbgln_if(EVENTLOOP_DEBUG, "Core::EventLoop::post_event: ({}) << receiver={}, event={}", m_queued_events.size(), receiver, event); dbgln_if(EVENTLOOP_DEBUG, "Core::EventLoop::post_event: ({}) << receiver={}, event={}", m_queued_events.size(), receiver, event);
m_queued_events.empend(receiver, move(event)); m_queued_events.empend(receiver, move(event));
if (should_wake == ShouldWake::Yes)
wake();
} }
SignalHandlers::SignalHandlers(int signo, void (*handle_signal)(int)) SignalHandlers::SignalHandlers(int signo, void (*handle_signal)(int))
@ -839,10 +842,16 @@ void EventLoop::unregister_notifier(Badge<Notifier>, Notifier& notifier)
s_notifiers->remove(&notifier); s_notifiers->remove(&notifier);
} }
void EventLoop::wake_current()
{
EventLoop::current().wake();
}
void EventLoop::wake() void EventLoop::wake()
{ {
dbgln_if(EVENTLOOP_DEBUG, "Core::EventLoop::wake()");
int wake_event = 0; int wake_event = 0;
int nwritten = write(s_wake_pipe_fds[1], &wake_event, sizeof(wake_event)); int nwritten = write((*m_wake_pipe_fds)[1], &wake_event, sizeof(wake_event));
if (nwritten < 0) { if (nwritten < 0) {
perror("EventLoop::wake: write"); perror("EventLoop::wake: write");
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();

View file

@ -34,6 +34,11 @@ public:
Yes, Yes,
}; };
enum class ShouldWake {
No,
Yes
};
explicit EventLoop(MakeInspectable = MakeInspectable::No); explicit EventLoop(MakeInspectable = MakeInspectable::No);
~EventLoop(); ~EventLoop();
static void initialize_wake_pipes(); static void initialize_wake_pipes();
@ -51,7 +56,7 @@ public:
void spin_until(Function<bool()>); void spin_until(Function<bool()>);
void post_event(Object& receiver, NonnullOwnPtr<Event>&&); void post_event(Object& receiver, NonnullOwnPtr<Event>&&, ShouldWake = ShouldWake::No);
template<typename Callback> template<typename Callback>
static decltype(auto) with_main_locked(Callback callback) static decltype(auto) with_main_locked(Callback callback)
@ -79,7 +84,8 @@ public:
m_queued_events.extend(move(other.m_queued_events)); m_queued_events.extend(move(other.m_queued_events));
} }
static void wake(); static void wake_current();
void wake();
static int register_signal(int signo, Function<void(int)> handler); static int register_signal(int signo, Function<void(int)> handler);
static void unregister_signal(int handler_id); static void unregister_signal(int handler_id);
@ -126,6 +132,9 @@ private:
static thread_local int s_wake_pipe_fds[2]; static thread_local int s_wake_pipe_fds[2];
static thread_local bool s_wake_pipe_initialized; static thread_local bool s_wake_pipe_initialized;
// The wake pipe of this event loop needs to be accessible from other threads.
int (*m_wake_pipe_fds)[2];
struct Private; struct Private;
NonnullOwnPtr<Private> m_private; NonnullOwnPtr<Private> m_private;
}; };

View file

@ -63,7 +63,7 @@ private:
m_on_complete(m_result.release_value()); m_on_complete(m_result.release_value());
remove_from_parent(); remove_from_parent();
}); });
Core::EventLoop::wake(); origin_event_loop->wake();
} else { } else {
this->remove_from_parent(); this->remove_from_parent();
} }