浏览代码

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.
kleines Filmröllchen 3 年之前
父节点
当前提交
704bb361bb

+ 3 - 3
Userland/DevTools/HackStudio/HackStudioWidget.cpp

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

+ 12 - 3
Userland/Libraries/LibCore/EventLoop.cpp

@@ -302,7 +302,8 @@ private:
 };
 
 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__
     if (!s_global_initializers_ran) {
@@ -487,11 +488,13 @@ size_t EventLoop::pump(WaitMode mode)
     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);
     dbgln_if(EVENTLOOP_DEBUG, "Core::EventLoop::post_event: ({}) << receiver={}, event={}", m_queued_events.size(), receiver, event);
     m_queued_events.empend(receiver, move(event));
+    if (should_wake == ShouldWake::Yes)
+        wake();
 }
 
 SignalHandlers::SignalHandlers(int signo, void (*handle_signal)(int))
@@ -839,10 +842,16 @@ void EventLoop::unregister_notifier(Badge<Notifier>, Notifier& notifier)
     s_notifiers->remove(&notifier);
 }
 
+void EventLoop::wake_current()
+{
+    EventLoop::current().wake();
+}
+
 void EventLoop::wake()
 {
+    dbgln_if(EVENTLOOP_DEBUG, "Core::EventLoop::wake()");
     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) {
         perror("EventLoop::wake: write");
         VERIFY_NOT_REACHED();

+ 11 - 2
Userland/Libraries/LibCore/EventLoop.h

@@ -34,6 +34,11 @@ public:
         Yes,
     };
 
+    enum class ShouldWake {
+        No,
+        Yes
+    };
+
     explicit EventLoop(MakeInspectable = MakeInspectable::No);
     ~EventLoop();
     static void initialize_wake_pipes();
@@ -51,7 +56,7 @@ public:
 
     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>
     static decltype(auto) with_main_locked(Callback callback)
@@ -79,7 +84,8 @@ public:
         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 void unregister_signal(int handler_id);
@@ -126,6 +132,9 @@ private:
     static thread_local int s_wake_pipe_fds[2];
     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;
     NonnullOwnPtr<Private> m_private;
 };

+ 1 - 1
Userland/Libraries/LibThreading/BackgroundAction.h

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