summaryrefslogtreecommitdiff
path: root/Libraries
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2019-07-14 10:20:57 +0200
committerAndreas Kling <awesomekling@gmail.com>2019-07-14 10:20:57 +0200
commit17ee548bcd8d9111addcc291457ad316e620d5e6 (patch)
tree37d6dda4eebe35ee78d15a1b0958f76e67e6e2b5 /Libraries
parentf1d6a37d5dca1593e78e39a33714730dc0348224 (diff)
downloadserenity-17ee548bcd8d9111addcc291457ad316e620d5e6.zip
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.
Diffstat (limited to 'Libraries')
-rw-r--r--Libraries/LibCore/CEventLoop.cpp19
-rw-r--r--Libraries/LibCore/CEventLoop.h4
2 files changed, 23 insertions, 0 deletions
diff --git a/Libraries/LibCore/CEventLoop.cpp b/Libraries/LibCore/CEventLoop.cpp
index 090f2a20af..88e719d9dd 100644
--- a/Libraries/LibCore/CEventLoop.cpp
+++ b/Libraries/LibCore/CEventLoop.cpp
@@ -23,6 +23,7 @@ static Vector<CEventLoop*>* s_event_loop_stack;
HashMap<int, OwnPtr<CEventLoop::EventLoopTimer>>* CEventLoop::s_timers;
HashTable<CNotifier*>* CEventLoop::s_notifiers;
int CEventLoop::s_next_timer_id = 1;
+int CEventLoop::s_wake_pipe_fds[2];
CEventLoop::CEventLoop()
{
@@ -34,6 +35,8 @@ CEventLoop::CEventLoop()
if (!s_main_event_loop) {
s_main_event_loop = this;
+ int rc = pipe(s_wake_pipe_fds);
+ ASSERT(rc == 0);
s_event_loop_stack->append(this);
}
@@ -169,6 +172,7 @@ void CEventLoop::wait_for_event(WaitMode mode)
int max_fd_added = -1;
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);
for (auto& notifier : *s_notifiers) {
if (notifier->event_mask() & CNotifier::Read)
@@ -205,6 +209,11 @@ void CEventLoop::wait_for_event(WaitMode mode)
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()) {
gettimeofday(&now, nullptr);
}
@@ -301,3 +310,13 @@ void CEventLoop::unregister_notifier(Badge<CNotifier>, CNotifier& 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();
+ }
+}
diff --git a/Libraries/LibCore/CEventLoop.h b/Libraries/LibCore/CEventLoop.h
index 7e3d5cb9e7..b404ef5c33 100644
--- a/Libraries/LibCore/CEventLoop.h
+++ b/Libraries/LibCore/CEventLoop.h
@@ -50,6 +50,8 @@ public:
m_queued_events.append(move(other.m_queued_events));
}
+ static void wake();
+
protected:
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&) {}
@@ -69,6 +71,8 @@ private:
bool m_exit_requested { false };
int m_exit_code { 0 };
+ static int s_wake_pipe_fds[2];
+
CLock m_lock;
struct EventLoopTimer {