From f2c0e550704fe004f053127664325610d450c903 Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Sun, 21 Jul 2019 13:46:53 +0200 Subject: [PATCH] Userspace: Deal with select() returning EINTR on a signal interruption Add a trivial CSafeSyscall template that calls a callback until it stops returning EINTR, and use it everywhere we use select() now. Thanks to Andreas for the suggestion of using a template parameter for the syscall function to invoke. --- Libraries/LibCore/CEventLoop.cpp | 7 ++----- Libraries/LibCore/CIODevice.cpp | 3 ++- Libraries/LibCore/CSyscallUtils.h | 25 +++++++++++++++++++++++++ Libraries/LibCore/CoreIPCClient.h | 3 ++- Servers/LookupServer/main.cpp | 3 ++- 5 files changed, 33 insertions(+), 8 deletions(-) create mode 100644 Libraries/LibCore/CSyscallUtils.h diff --git a/Libraries/LibCore/CEventLoop.cpp b/Libraries/LibCore/CEventLoop.cpp index 9b21c4214b..aaa45427f5 100644 --- a/Libraries/LibCore/CEventLoop.cpp +++ b/Libraries/LibCore/CEventLoop.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -203,11 +204,7 @@ void CEventLoop::wait_for_event(WaitMode mode) should_wait_forever = false; } - int marked_fd_count = select(max_fd + 1, &rfds, &wfds, nullptr, should_wait_forever ? nullptr : &timeout); - if (marked_fd_count < 0) { - ASSERT_NOT_REACHED(); - } - + int marked_fd_count = CSyscallUtils::safe_syscall(select, max_fd + 1, &rfds, &wfds, nullptr, should_wait_forever ? nullptr : &timeout); if (FD_ISSET(s_wake_pipe_fds[0], &rfds)) { char buffer[32]; auto nread = read(s_wake_pipe_fds[0], buffer, sizeof(buffer)); diff --git a/Libraries/LibCore/CIODevice.cpp b/Libraries/LibCore/CIODevice.cpp index 86393f6888..394050d9a0 100644 --- a/Libraries/LibCore/CIODevice.cpp +++ b/Libraries/LibCore/CIODevice.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -71,7 +72,7 @@ bool CIODevice::can_read_from_fd() const struct timeval timeout { 0, 0 }; - int rc = select(m_fd + 1, &rfds, nullptr, nullptr, &timeout); + int rc = CSyscallUtils::safe_syscall(select, m_fd + 1, &rfds, nullptr, nullptr, &timeout); if (rc < 0) { // NOTE: We don't set m_error here. perror("CIODevice::can_read: select"); diff --git a/Libraries/LibCore/CSyscallUtils.h b/Libraries/LibCore/CSyscallUtils.h new file mode 100644 index 0000000000..9a16901d11 --- /dev/null +++ b/Libraries/LibCore/CSyscallUtils.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include +#include +#include + +namespace CSyscallUtils { + +template +inline int safe_syscall(Syscall syscall, Args&& ... args) { + for (;;) { + int sysret = syscall(forward(args)...); + if (sysret == -1) { + dbgprintf("CSafeSyscall: %d (%d: %s)\n", sysret, errno, strerror(errno)); + if (errno == EINTR) + continue; + ASSERT_NOT_REACHED(); + } + return sysret; + } +} + +} + diff --git a/Libraries/LibCore/CoreIPCClient.h b/Libraries/LibCore/CoreIPCClient.h index 6d54d61e10..400da2bc0d 100644 --- a/Libraries/LibCore/CoreIPCClient.h +++ b/Libraries/LibCore/CoreIPCClient.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -106,7 +107,7 @@ public: fd_set rfds; FD_ZERO(&rfds); FD_SET(m_connection.fd(), &rfds); - int rc = select(m_connection.fd() + 1, &rfds, nullptr, nullptr, nullptr); + int rc = CSyscallUtils::safe_syscall(select, m_connection.fd() + 1, &rfds, nullptr, nullptr, nullptr); if (rc < 0) { perror("select"); } diff --git a/Servers/LookupServer/main.cpp b/Servers/LookupServer/main.cpp index 1bf9e75539..97df0b1f77 100644 --- a/Servers/LookupServer/main.cpp +++ b/Servers/LookupServer/main.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -108,7 +109,7 @@ int main(int argc, char** argv) fd_set rfds; FD_ZERO(&rfds); FD_SET(server_fd, &rfds); - rc = select(server_fd + 1, &rfds, nullptr, nullptr, nullptr); + rc = CSyscallUtils::safe_syscall(select, server_fd + 1, &rfds, nullptr, nullptr, nullptr); if (rc < 1) { perror("select"); return 1;