Pārlūkot izejas kodu

CEventLoop: Add wake(), a mechanism for waking up when blocked in select().

This patch generalizes the concept used in Piano to wake up the event loop
so it can react to something happening on a secondary thread.
Basically, there's a pipe who is always part of the file descriptor set we
pass to select(), and calling wake() simply writes a little to that pipe.
Andreas Kling 6 gadi atpakaļ
vecāks
revīzija
17ee548bcd
2 mainītis faili ar 23 papildinājumiem un 0 dzēšanām
  1. 19 0
      Libraries/LibCore/CEventLoop.cpp
  2. 4 0
      Libraries/LibCore/CEventLoop.h

+ 19 - 0
Libraries/LibCore/CEventLoop.cpp

@@ -23,6 +23,7 @@ static Vector<CEventLoop*>* s_event_loop_stack;
 HashMap<int, OwnPtr<CEventLoop::EventLoopTimer>>* CEventLoop::s_timers;
 HashMap<int, OwnPtr<CEventLoop::EventLoopTimer>>* CEventLoop::s_timers;
 HashTable<CNotifier*>* CEventLoop::s_notifiers;
 HashTable<CNotifier*>* CEventLoop::s_notifiers;
 int CEventLoop::s_next_timer_id = 1;
 int CEventLoop::s_next_timer_id = 1;
+int CEventLoop::s_wake_pipe_fds[2];
 
 
 CEventLoop::CEventLoop()
 CEventLoop::CEventLoop()
 {
 {
@@ -34,6 +35,8 @@ CEventLoop::CEventLoop()
 
 
     if (!s_main_event_loop) {
     if (!s_main_event_loop) {
         s_main_event_loop = this;
         s_main_event_loop = this;
+        int rc = pipe(s_wake_pipe_fds);
+        ASSERT(rc == 0);
         s_event_loop_stack->append(this);
         s_event_loop_stack->append(this);
     }
     }
 
 
@@ -169,6 +172,7 @@ void CEventLoop::wait_for_event(WaitMode mode)
 
 
     int max_fd_added = -1;
     int max_fd_added = -1;
     add_file_descriptors_for_select(rfds, max_fd_added);
     add_file_descriptors_for_select(rfds, max_fd_added);
+    add_fd_to_set(s_wake_pipe_fds[1], rfds);
     max_fd = max(max_fd, max_fd_added);
     max_fd = max(max_fd, max_fd_added);
     for (auto& notifier : *s_notifiers) {
     for (auto& notifier : *s_notifiers) {
         if (notifier->event_mask() & CNotifier::Read)
         if (notifier->event_mask() & CNotifier::Read)
@@ -205,6 +209,11 @@ void CEventLoop::wait_for_event(WaitMode mode)
         ASSERT_NOT_REACHED();
         ASSERT_NOT_REACHED();
     }
     }
 
 
+    if (FD_ISSET(s_wake_pipe_fds[1], &rfds)) {
+        char buffer[32];
+        read(s_wake_pipe_fds[1], buffer, sizeof(buffer));
+    }
+
     if (!s_timers->is_empty()) {
     if (!s_timers->is_empty()) {
         gettimeofday(&now, nullptr);
         gettimeofday(&now, nullptr);
     }
     }
@@ -301,3 +310,13 @@ void CEventLoop::unregister_notifier(Badge<CNotifier>, CNotifier& notifier)
 {
 {
     s_notifiers->remove(&notifier);
     s_notifiers->remove(&notifier);
 }
 }
+
+void CEventLoop::wake()
+{
+    char ch = '!';
+    int nwritten = write(s_wake_pipe_fds[0], &ch, 1);
+    if (nwritten < 0) {
+        perror("CEventLoop::wake: write");
+        ASSERT_NOT_REACHED();
+    }
+}

+ 4 - 0
Libraries/LibCore/CEventLoop.h

@@ -50,6 +50,8 @@ public:
         m_queued_events.append(move(other.m_queued_events));
         m_queued_events.append(move(other.m_queued_events));
     }
     }
 
 
+    static void wake();
+
 protected:
 protected:
     virtual void add_file_descriptors_for_select(fd_set&, int& max_fd) { UNUSED_PARAM(max_fd); }
     virtual void add_file_descriptors_for_select(fd_set&, int& max_fd) { UNUSED_PARAM(max_fd); }
     virtual void process_file_descriptors_after_select(const fd_set&) {}
     virtual void process_file_descriptors_after_select(const fd_set&) {}
@@ -69,6 +71,8 @@ private:
     bool m_exit_requested { false };
     bool m_exit_requested { false };
     int m_exit_code { 0 };
     int m_exit_code { 0 };
 
 
+    static int s_wake_pipe_fds[2];
+
     CLock m_lock;
     CLock m_lock;
 
 
     struct EventLoopTimer {
     struct EventLoopTimer {