diff options
author | kleines Filmröllchen <filmroellchen@serenityos.org> | 2022-01-21 13:23:57 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-01-23 15:21:10 +0100 |
commit | 888faa3c9f83c8205b3758203b6a1c44f3e7f53d (patch) | |
tree | 5cc878ab32b0cdd5f722fd72be9e5df724eaaa09 /Userland | |
parent | a501b9c7df595f044cac4c474032447318a4979a (diff) | |
download | serenity-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.cpp | 13 |
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); |