From bcce7e18db7efccd75ab40a2b9b5f9d367d70d63 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 15 Jul 2024 23:24:41 +0200 Subject: [PATCH] Implement SA_RESTART for read and write. --- redox-rt/src/arch/x86_64.rs | 1 + redox-rt/src/signal.rs | 4 ++- redox-rt/src/sys.rs | 6 +++++ tests/Makefile | 1 + tests/sa_restart.c | 53 +++++++++++++++++++++++++++++++++++++ 5 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 tests/sa_restart.c diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index 0b3ffa68..4e53aef3 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -26,6 +26,7 @@ pub struct SigArea { pub altstack_bottom: usize, pub disable_signals_depth: u64, pub pctl: usize, // TODO: find out how to correctly reference that static + pub last_sig_was_restart: bool, } #[repr(C, align(16))] diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index 3c21bde1..c55b6f31 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -44,7 +44,6 @@ unsafe fn inner(stack: &mut SigStack) { // asm counts from 0 stack.sig_num += 1; - arch_pre(stack, &mut *os.arch.get()); let sigaction = { @@ -61,6 +60,7 @@ unsafe fn inner(stack: &mut SigStack) { } action }; + let shall_restart = sigaction.flags.contains(SigactionFlags::RESTART); let handler = match sigaction.kind { SigactionKind::Ignore => { @@ -123,6 +123,8 @@ unsafe fn inner(stack: &mut SigStack) { //let _ = syscall::write(1, alloc::format!("will return to {:x?}\n", stack.regs.eip).as_bytes()); + (*os.arch.get()).last_sig_was_restart = shall_restart; + // And re-enable them again control_flags.store(control_flags.load(Ordering::Relaxed) & !SigcontrolFlags::INHIBIT_DELIVERY.bits(), Ordering::Release); core::sync::atomic::compiler_fence(Ordering::Acquire); diff --git a/redox-rt/src/sys.rs b/redox-rt/src/sys.rs index 8cc3a0db..d450a562 100644 --- a/redox-rt/src/sys.rs +++ b/redox-rt/src/sys.rs @@ -2,16 +2,22 @@ use syscall::error::{Result, Error, EINTR}; use crate::arch::manually_enter_trampoline; use crate::signal::tmp_disable_signals; +use crate::Tcb; #[inline] fn wrapper(mut f: impl FnMut() -> Result<usize>) -> Result<usize> { loop { + let _guard = tmp_disable_signals(); + let rt_sigarea = unsafe { &Tcb::current().unwrap().os_specific }; let res = f(); if res == Err(Error::new(EINTR)) { unsafe { manually_enter_trampoline(); } + if unsafe { (*rt_sigarea.arch.get()).last_sig_was_restart } { + continue; + } } return res; diff --git a/tests/Makefile b/tests/Makefile index c27e6d85..2f4b35d1 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -31,6 +31,7 @@ EXPECT_NAMES=\ setjmp \ sigaction \ signal \ + sa_restart \ stdio/all \ stdio/buffer \ stdio/fgets \ diff --git a/tests/sa_restart.c b/tests/sa_restart.c new file mode 100644 index 00000000..75b08681 --- /dev/null +++ b/tests/sa_restart.c @@ -0,0 +1,53 @@ +#include <assert.h> +#include <signal.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> + +#include "test_helpers.h" + +void action(int sig, siginfo_t *info, void *context) { + assert (sig == SIGUSR1); + (void)info; + (void)context; + char *msg = "Signal handler\n"; + write(1, msg, strlen(msg)); + _exit(0); +} + +int main(void) { + int status; + + struct sigaction act; + act.sa_sigaction = action; + act.sa_flags = SA_RESTART; + sigemptyset(&act.sa_mask); + + status = sigaction(SIGUSR1, &act, NULL); + ERROR_IF(sigaction, status, == -1); + + int fds[2]; + status = pipe(fds); + ERROR_IF(pipe, status, == -1); + + int parent = getpid(); + + status = fork(); + ERROR_IF(fork, status, == -1); + + if (status == 0) { + for (int i = 0; i < 1000; i++) { + status = kill(parent, SIGUSR1); + ERROR_IF(kill, status, == -1); + } + return 0; + } + + char buffer[1]; + status = read(fds[0], buffer, 1); + ERROR_IF(read, status, == -1); + + return 1; +} -- GitLab