diff --git a/kernel/include/kernel/Process.h b/kernel/include/kernel/Process.h index e6b4d682..50c5cdc0 100644 --- a/kernel/include/kernel/Process.h +++ b/kernel/include/kernel/Process.h @@ -193,6 +193,7 @@ namespace Kernel BAN::ErrorOr sys_sigaction(int signal, const struct sigaction* act, struct sigaction* oact); BAN::ErrorOr sys_sigpending(sigset_t* set); BAN::ErrorOr sys_sigprocmask(int how, const sigset_t* set, sigset_t* oset); + BAN::ErrorOr sys_sigsuspend(const sigset_t* set); BAN::ErrorOr sys_futex(int op, const uint32_t* addr, uint32_t val, const timespec* abstime); BAN::ErrorOr sys_yield(); diff --git a/kernel/include/kernel/Thread.h b/kernel/include/kernel/Thread.h index 2e81e83e..c7f7965f 100644 --- a/kernel/include/kernel/Thread.h +++ b/kernel/include/kernel/Thread.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -60,6 +61,7 @@ namespace Kernel // Returns true if handled signal had SA_RESTART bool handle_signal(int signal = 0); void add_signal(int signal); + void set_suspend_signal_mask(uint64_t sigmask); // blocks current thread and returns either on unblock, eintr, spuriously or after timeout // if mutex is not nullptr, it will be atomically freed before blocking and automatically locked on wake @@ -160,6 +162,7 @@ namespace Kernel uint64_t m_signal_pending_mask { 0 }; uint64_t m_signal_block_mask { 0 }; + BAN::Optional m_signal_suspend_mask; SpinLock m_signal_lock; static_assert(_SIGMAX < 64); diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index 8173c7ea..6dda2e90 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -2651,6 +2651,20 @@ namespace Kernel return 0; } + BAN::ErrorOr Process::sys_sigsuspend(const sigset_t* set) + { + LockGuard _(m_process_lock); + TRY(validate_pointer_access(set, sizeof(sigset_t), false)); + + auto& thread = Thread::current(); + thread.set_suspend_signal_mask(*set & ~(SIGKILL | SIGSTOP)); + + while (!thread.is_interrupted_by_signal()) + Processor::scheduler().block_current_thread(nullptr, -1, &m_process_lock); + + return BAN::Error::from_errno(EINTR); + } + BAN::ErrorOr Process::sys_futex(int op, const uint32_t* addr, uint32_t val, const timespec* abstime) { const vaddr_t vaddr = reinterpret_cast(addr); diff --git a/kernel/kernel/Thread.cpp b/kernel/kernel/Thread.cpp index 333b2bf3..1c2aab02 100644 --- a/kernel/kernel/Thread.cpp +++ b/kernel/kernel/Thread.cpp @@ -547,6 +547,12 @@ namespace Kernel m_signal_pending_mask &= ~(1ull << signal); process().remove_pending_signal(signal); + if (m_signal_suspend_mask.has_value()) + { + m_signal_block_mask = m_signal_suspend_mask.value(); + m_signal_suspend_mask.clear(); + } + if (signal_handler == (vaddr_t)SIG_IGN) ; else if (signal_handler != (vaddr_t)SIG_DFL) @@ -643,6 +649,14 @@ namespace Kernel Processor::scheduler().unblock_thread(this); } + void Thread::set_suspend_signal_mask(uint64_t sigmask) + { + SpinLockGuard _(m_signal_lock); + ASSERT(!m_signal_suspend_mask.has_value()); + m_signal_suspend_mask = m_signal_block_mask; + m_signal_block_mask = sigmask; + } + BAN::ErrorOr Thread::sleep_or_eintr_ns(uint64_t ns) { if (is_interrupted_by_signal()) diff --git a/userspace/libraries/LibC/include/sys/syscall.h b/userspace/libraries/LibC/include/sys/syscall.h index fe48cc4c..9d8de9a9 100644 --- a/userspace/libraries/LibC/include/sys/syscall.h +++ b/userspace/libraries/LibC/include/sys/syscall.h @@ -90,6 +90,7 @@ __BEGIN_DECLS O(SYS_SIGACTION, sigaction) \ O(SYS_SIGPENDING, sigpending) \ O(SYS_SIGPROCMASK, sigprocmask) \ + O(SYS_SIGSUSPEND, sigsuspend) \ O(SYS_SETITIMER, setitimer) \ O(SYS_POSIX_OPENPT, posix_openpt) \ O(SYS_PTSNAME, ptsname) \ diff --git a/userspace/libraries/LibC/signal.cpp b/userspace/libraries/LibC/signal.cpp index 86ed5685..3c2d4a7a 100644 --- a/userspace/libraries/LibC/signal.cpp +++ b/userspace/libraries/LibC/signal.cpp @@ -164,3 +164,8 @@ int sigrelse(int sig) (void)sigaddset(&set, sig); return sigprocmask(SIG_UNBLOCK, &set, nullptr); } + +int sigsuspend(const sigset_t* sigmask) +{ + return syscall(SYS_SIGSUSPEND, sigmask); +}