diff --git a/kernel/include/kernel/Process.h b/kernel/include/kernel/Process.h index 50c5cdc0..7a66a547 100644 --- a/kernel/include/kernel/Process.h +++ b/kernel/include/kernel/Process.h @@ -194,6 +194,7 @@ namespace Kernel 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_sigwait(const sigset_t* set, int* sig); BAN::ErrorOr sys_futex(int op, const uint32_t* addr, uint32_t val, const timespec* abstime); BAN::ErrorOr sys_yield(); diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index 6dda2e90..3bb6cc69 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -2665,6 +2665,42 @@ namespace Kernel return BAN::Error::from_errno(EINTR); } + BAN::ErrorOr Process::sys_sigwait(const sigset_t* set, int* sig) + { + LockGuard _(m_process_lock); + + auto& thread = Thread::current(); + for (;;) + { + TRY(validate_pointer_access(set, sizeof(sigset_t), false)); + TRY(validate_pointer_access(sig, sizeof(int), true)); + + { + SpinLockGuard _1(thread.m_signal_lock); + SpinLockGuard _2(m_signal_lock); + + const uint64_t pending = thread.m_signal_pending_mask | this->m_signal_pending_mask; + if (const auto wait_mask = pending & *set) + { + for (size_t i = _SIGMIN; i <= _SIGMAX; i++) + { + const auto mask = 1ull << i; + if (!(wait_mask & mask)) + continue; + thread.m_signal_pending_mask &= ~mask; + this->m_signal_pending_mask &= ~mask; + *sig = i; + return 0; + } + + ASSERT_NOT_REACHED(); + } + } + + Processor::scheduler().block_current_thread(nullptr, -1, &m_process_lock); + } + } + 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/userspace/libraries/LibC/include/sys/syscall.h b/userspace/libraries/LibC/include/sys/syscall.h index 9d8de9a9..304dfdf5 100644 --- a/userspace/libraries/LibC/include/sys/syscall.h +++ b/userspace/libraries/LibC/include/sys/syscall.h @@ -91,6 +91,7 @@ __BEGIN_DECLS O(SYS_SIGPENDING, sigpending) \ O(SYS_SIGPROCMASK, sigprocmask) \ O(SYS_SIGSUSPEND, sigsuspend) \ + O(SYS_SIGWAIT, sigwait) \ 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 3c2d4a7a..082c09d6 100644 --- a/userspace/libraries/LibC/signal.cpp +++ b/userspace/libraries/LibC/signal.cpp @@ -169,3 +169,10 @@ int sigsuspend(const sigset_t* sigmask) { return syscall(SYS_SIGSUSPEND, sigmask); } + +int sigwait(const sigset_t* __restrict set, int* __restrict sig) +{ + if (syscall(SYS_SIGWAIT, set, sig) == -1) + return errno; + return 0; +}