summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
authorkleines Filmröllchen <filmroellchen@serenityos.org>2022-01-21 13:23:57 +0100
committerAndreas Kling <kling@serenityos.org>2022-01-23 15:21:10 +0100
commit888faa3c9f83c8205b3758203b6a1c44f3e7f53d (patch)
tree5cc878ab32b0cdd5f722fd72be9e5df724eaaa09 /Userland
parenta501b9c7df595f044cac4c474032447318a4979a (diff)
downloadserenity-888faa3c9f83c8205b3758203b6a1c44f3e7f53d.zip
LibCore: Fix signal handling race condition in EventLoop
The event loop is responsible for handling POSIX signals while it's running. The signal handler adds the signals to a wake pipe which is then read after the select'ing code in wait_for_event. Problems happen, however, when another signal comes in after the select wake: the signal will interrupt the next syscall, the `read` from the wake pipe, and the resulting EINTR in wait_for_event causes the program to crash. This is undesirable. Instead, we want to retry reading as long as we're interrupted.
Diffstat (limited to 'Userland')
-rw-r--r--Userland/Libraries/LibCore/EventLoop.cpp13
1 files changed, 11 insertions, 2 deletions
diff --git a/Userland/Libraries/LibCore/EventLoop.cpp b/Userland/Libraries/LibCore/EventLoop.cpp
index 387ddd72dc..7fe465ceeb 100644
--- a/Userland/Libraries/LibCore/EventLoop.cpp
+++ b/Userland/Libraries/LibCore/EventLoop.cpp
@@ -5,6 +5,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
+#include <AK/Assertions.h>
#include <AK/Badge.h>
#include <AK/Debug.h>
#include <AK/Format.h>
@@ -675,9 +676,17 @@ try_select_again:
}
if (FD_ISSET(s_wake_pipe_fds[0], &rfds)) {
int wake_events[8];
- auto nread = read(s_wake_pipe_fds[0], wake_events, sizeof(wake_events));
+ ssize_t nread;
+ // We might receive another signal while read()ing here. The signal will go to the handle_signal properly,
+ // but we get interrupted. Therefore, just retry while we were interrupted.
+ do {
+ errno = 0;
+ nread = read(s_wake_pipe_fds[0], wake_events, sizeof(wake_events));
+ if (nread == 0)
+ break;
+ } while (nread < 0 && errno == EINTR);
if (nread < 0) {
- perror("read from wake pipe");
+ perror("Core::EventLoop::wait_for_event: read from wake pipe");
VERIFY_NOT_REACHED();
}
VERIFY(nread > 0);