From 808c97020afb81faa2c739fd395d5229a5970538 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Tue, 22 Apr 2025 02:42:44 +0300 Subject: [PATCH] Kernel/LibC: Implement SA_RESTART I have been thinking how to do this for a long time but I finally figured out a semi-clean way --- kernel/include/kernel/Thread.h | 3 ++- kernel/kernel/Process.cpp | 4 +--- kernel/kernel/Syscall.cpp | 4 +++- kernel/kernel/Thread.cpp | 6 +++++- userspace/libraries/LibC/include/errno.h | 1 + userspace/libraries/LibC/unistd.cpp | 5 ++++- 6 files changed, 16 insertions(+), 7 deletions(-) diff --git a/kernel/include/kernel/Thread.h b/kernel/include/kernel/Thread.h index 89448810..c9c2cd80 100644 --- a/kernel/include/kernel/Thread.h +++ b/kernel/include/kernel/Thread.h @@ -53,7 +53,8 @@ namespace Kernel // Returns true if pending signal can be added to thread bool can_add_signal_to_execute() const; bool will_execute_signal() const; - void handle_signal(int signal = 0); + // Returns true if handled signal had SA_RESTART + bool handle_signal(int signal = 0); bool add_signal(int signal); // blocks current thread and returns either on unblock, eintr, spuriously or after timeout diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index 21162df4..7689704f 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -2073,9 +2073,7 @@ namespace Kernel if (act) { - if (act->sa_flags == SA_RESTART) - dwarnln("FIXME: sigaction ignoring SA_RESTART", signal, act->sa_flags); - else if (act->sa_flags) + if (act->sa_flags & ~(SA_RESTART)) { dwarnln("TODO: sigaction({}, {H})", signal, act->sa_flags); return BAN::Error::from_errno(ENOTSUP); diff --git a/kernel/kernel/Syscall.cpp b/kernel/kernel/Syscall.cpp index 3e33243a..246d2768 100644 --- a/kernel/kernel/Syscall.cpp +++ b/kernel/kernel/Syscall.cpp @@ -79,7 +79,9 @@ namespace Kernel auto& current_thread = Thread::current(); if (current_thread.can_add_signal_to_execute()) - current_thread.handle_signal(); + if (current_thread.handle_signal()) + if (ret.is_error() && ret.error().get_error_code() == EINTR) + ret = BAN::Error::from_errno(ERESTART); ASSERT(Kernel::Thread::current().state() == Kernel::Thread::State::Executing); diff --git a/kernel/kernel/Thread.cpp b/kernel/kernel/Thread.cpp index 68ea8414..952b894a 100644 --- a/kernel/kernel/Thread.cpp +++ b/kernel/kernel/Thread.cpp @@ -435,7 +435,7 @@ namespace Kernel return interrupt_stack.ip == (uintptr_t)signal_trampoline; } - void Thread::handle_signal(int signal) + bool Thread::handle_signal(int signal) { ASSERT(&Thread::current() == this); ASSERT(is_userspace()); @@ -463,10 +463,12 @@ namespace Kernel } vaddr_t signal_handler; + bool has_sa_restart; { SpinLockGuard _(m_process->m_signal_lock); ASSERT(!(m_process->m_signal_handlers[signal].sa_flags & SA_SIGINFO)); signal_handler = (vaddr_t)m_process->m_signal_handlers[signal].sa_handler; + has_sa_restart = !!(m_process->m_signal_handlers[signal].sa_flags & SA_RESTART); } m_signal_pending_mask &= ~(1ull << signal); @@ -534,6 +536,8 @@ namespace Kernel ASSERT_NOT_REACHED(); } } + + return has_sa_restart; } bool Thread::add_signal(int signal) diff --git a/userspace/libraries/LibC/include/errno.h b/userspace/libraries/LibC/include/errno.h index 9658c581..a94cf825 100644 --- a/userspace/libraries/LibC/include/errno.h +++ b/userspace/libraries/LibC/include/errno.h @@ -90,6 +90,7 @@ __BEGIN_DECLS #define EXDEV 81 #define ENOTBLK 82 +#define ERESTART 0xFE /* internal errno for SA_RESTART */ #define EUNKNOWN 0xFF #define errno (*__errno_location()) diff --git a/userspace/libraries/LibC/unistd.cpp b/userspace/libraries/LibC/unistd.cpp index 98559f18..22a02895 100644 --- a/userspace/libraries/LibC/unistd.cpp +++ b/userspace/libraries/LibC/unistd.cpp @@ -83,7 +83,10 @@ long syscall(long syscall, ...) va_end(args); - long ret = Kernel::syscall(syscall, arg1, arg2, arg3, arg4, arg5); + long ret; + do + ret = Kernel::syscall(syscall, arg1, arg2, arg3, arg4, arg5); + while (ret == -ERESTART); if (ret < 0) {