From cf0ad3715eff8df0e6d4e56513a864df000d4033 Mon Sep 17 00:00:00 2001 From: Tim Schumacher Date: Fri, 13 May 2022 13:15:45 +0200 Subject: [PATCH] Kernel: Implement `sigsuspend` using a SignalBlocker `sigsuspend` was previously implemented using a poll on an empty set of file descriptors. However, this broke quite a few assumptions in `SelectBlocker`, as it verifies at least one file descriptor to be ready after waking up and as it relies on being notified by the file descriptor. A bare-bones `sigsuspend` may also be implemented by relying on any of the `sigwait` functions, but as `sigsuspend` features several (currently unimplemented) restrictions on how returns work, it is a syscall on its own. --- Kernel/API/Syscall.h | 1 + Kernel/Process.h | 1 + Kernel/Syscalls/sigaction.cpp | 24 ++++++++++++++++++++++++ Userland/Libraries/LibC/signal.cpp | 3 ++- 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/Kernel/API/Syscall.h b/Kernel/API/Syscall.h index 7347dbfe7d..72c89d587e 100644 --- a/Kernel/API/Syscall.h +++ b/Kernel/API/Syscall.h @@ -170,6 +170,7 @@ enum class NeedsBigProcessLock { S(sigpending, NeedsBigProcessLock::Yes) \ S(sigprocmask, NeedsBigProcessLock::Yes) \ S(sigreturn, NeedsBigProcessLock::Yes) \ + S(sigsuspend, NeedsBigProcessLock::Yes) \ S(sigtimedwait, NeedsBigProcessLock::Yes) \ S(socket, NeedsBigProcessLock::Yes) \ S(socketpair, NeedsBigProcessLock::Yes) \ diff --git a/Kernel/Process.h b/Kernel/Process.h index c5dfc4a96e..d5d85b156d 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -334,6 +334,7 @@ public: ErrorOr sys$sigaltstack(Userspace ss, Userspace old_ss); ErrorOr sys$sigprocmask(int how, Userspace set, Userspace old_set); ErrorOr sys$sigpending(Userspace); + ErrorOr sys$sigsuspend(Userspace); ErrorOr sys$sigtimedwait(Userspace, Userspace, Userspace); ErrorOr sys$getgroups(size_t, Userspace); ErrorOr sys$setgroups(size_t, Userspace); diff --git a/Kernel/Syscalls/sigaction.cpp b/Kernel/Syscalls/sigaction.cpp index 2226e816bd..63456e2971 100644 --- a/Kernel/Syscalls/sigaction.cpp +++ b/Kernel/Syscalls/sigaction.cpp @@ -326,4 +326,28 @@ ErrorOr Process::sys$sigtimedwait(Userspace set, Users return info_value.si_signo; } +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigsuspend.html +ErrorOr Process::sys$sigsuspend(Userspace mask) +{ + VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this) + + auto sigmask = TRY(copy_typed_from_user(mask)); + + auto* current_thread = Thread::current(); + + u32 previous_signal_mask = current_thread->update_signal_mask(sigmask); + ScopeGuard rollback_signal_mask([&]() { + current_thread->update_signal_mask(previous_signal_mask); + }); + + // TODO: Ensure that/check if we never return if the action is to terminate the process. + // TODO: Ensure that/check if we only return after an eventual signal-catching function returns. + Thread::BlockTimeout timeout = {}; + siginfo_t siginfo = {}; + if (current_thread->block(timeout, ~sigmask, siginfo).was_interrupted()) + return EINTR; + + return 0; +} + } diff --git a/Userland/Libraries/LibC/signal.cpp b/Userland/Libraries/LibC/signal.cpp index 37fba25965..7291059fdc 100644 --- a/Userland/Libraries/LibC/signal.cpp +++ b/Userland/Libraries/LibC/signal.cpp @@ -175,7 +175,8 @@ void siglongjmp(jmp_buf env, int val) // https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigsuspend.html int sigsuspend(sigset_t const* set) { - return pselect(0, nullptr, nullptr, nullptr, nullptr, set); + int rc = syscall(SC_sigsuspend, set); + __RETURN_WITH_ERRNO(rc, rc, -1); } // https://pubs.opengroup.org/onlinepubs/009604499/functions/sigwait.html