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 1/6] 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 0b3ffa68db..4e53aef393 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 3c21bde1a3..c55b6f313c 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 8cc3a0dbc1..d450a5625a 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) -> Result { 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 c27e6d8573..2f4b35d1be 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 0000000000..75b086813f --- /dev/null +++ b/tests/sa_restart.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include +#include + +#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; +} From 4c20a9abb22d485d89099acb2a68092b2ebd49ae Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 16 Jul 2024 11:55:06 +0200 Subject: [PATCH 2/6] Enable syscall restart in futex_wait. --- generic-rt/src/lib.rs | 7 +- redox-rt/src/arch/aarch64.rs | 12 +-- redox-rt/src/arch/i686.rs | 18 ++-- redox-rt/src/arch/x86_64.rs | 28 +++-- redox-rt/src/lib.rs | 27 +++-- redox-rt/src/proc.rs | 42 +++++--- redox-rt/src/signal.rs | 193 +++++++++++++++++++++++++---------- redox-rt/src/sync.rs | 14 ++- redox-rt/src/sys.rs | 41 ++++++-- redox-rt/src/thread.rs | 7 +- src/platform/linux/mod.rs | 7 +- src/platform/pal/mod.rs | 4 +- src/platform/redox/mod.rs | 37 +++---- src/sync/mod.rs | 6 +- 14 files changed, 292 insertions(+), 151 deletions(-) diff --git a/generic-rt/src/lib.rs b/generic-rt/src/lib.rs index 2999115c36..621cab3d48 100644 --- a/generic-rt/src/lib.rs +++ b/generic-rt/src/lib.rs @@ -1,8 +1,10 @@ #![no_std] #![feature(core_intrinsics)] -use core::arch::asm; -use core::mem::{self, offset_of}; +use core::{ + arch::asm, + mem::{self, offset_of}, +}; #[derive(Debug)] #[repr(C)] @@ -109,4 +111,3 @@ impl ExpectTlsFree for Option { } } } - diff --git a/redox-rt/src/arch/aarch64.rs b/redox-rt/src/arch/aarch64.rs index e4a5e8b54c..3379bca7f6 100644 --- a/redox-rt/src/arch/aarch64.rs +++ b/redox-rt/src/arch/aarch64.rs @@ -1,12 +1,12 @@ use core::mem::offset_of; -use syscall::data::*; -use syscall::error::*; +use syscall::{data::*, error::*}; -use crate::proc::{fork_inner, FdGuard}; -use crate::signal::SigStack; -use crate::signal::{inner_c, RtSigarea, PROC_CONTROL_STRUCT}; -use crate::Tcb; +use crate::{ + proc::{fork_inner, FdGuard}, + signal::{inner_c, RtSigarea, SigStack, PROC_CONTROL_STRUCT}, + Tcb, +}; // Setup a stack starting from the very end of the address space, and then growing downwards. pub(crate) const STACK_TOP: usize = 1 << 47; diff --git a/redox-rt/src/arch/i686.rs b/redox-rt/src/arch/i686.rs index 80296b835a..ec4decdde4 100644 --- a/redox-rt/src/arch/i686.rs +++ b/redox-rt/src/arch/i686.rs @@ -1,10 +1,11 @@ -use core::mem::offset_of; -use core::sync::atomic::Ordering; +use core::{mem::offset_of, sync::atomic::Ordering}; use syscall::*; -use crate::proc::{fork_inner, FdGuard}; -use crate::signal::{inner_fastcall, PROC_CONTROL_STRUCT, RtSigarea, SigStack}; +use crate::{ + proc::{fork_inner, FdGuard}, + signal::{inner_fastcall, RtSigarea, SigStack, PROC_CONTROL_STRUCT}, +}; // Setup a stack starting from the very end of the address space, and then growing downwards. pub(crate) const STACK_TOP: usize = 1 << 31; @@ -38,8 +39,8 @@ pub struct ArchIntRegs { pub edx: usize, // avail +32 pub eflags: usize, // avail +36 - pub eip: usize, // avail +40 - pub esp: usize, // avail +44 + pub eip: usize, // avail +40 + pub esp: usize, // avail +44 } /// Deactive TLS, used before exec() on Redox to not trick target executable into thinking TLS @@ -256,7 +257,10 @@ pub unsafe fn arch_pre(stack: &mut SigStack, area: &mut SigArea) { } pub unsafe fn manually_enter_trampoline() { let c = &crate::Tcb::current().unwrap().os_specific.control; - c.control_flags.store(c.control_flags.load(Ordering::Relaxed) | syscall::flag::INHIBIT_DELIVERY.bits(), Ordering::Release); + c.control_flags.store( + c.control_flags.load(Ordering::Relaxed) | syscall::flag::INHIBIT_DELIVERY.bits(), + Ordering::Release, + ); c.saved_archdep_reg.set(0); // TODO: Just reset DF on x86? core::arch::asm!(" diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index 4e53aef393..73db7cea29 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -1,14 +1,19 @@ -use core::mem::offset_of; -use core::sync::atomic::{AtomicU8, Ordering}; +use core::{ + mem::offset_of, + sync::atomic::{AtomicU8, Ordering}, +}; -use syscall::data::{Sigcontrol, SigProcControl}; -use syscall::error::*; -use syscall::flag::*; +use syscall::{ + data::{SigProcControl, Sigcontrol}, + error::*, + flag::*, +}; -use crate::proc::{fork_inner, FdGuard}; -use crate::signal::{tmp_disable_signals, SigStack}; -use crate::signal::{inner_c, RtSigarea, PROC_CONTROL_STRUCT}; -use crate::Tcb; +use crate::{ + proc::{fork_inner, FdGuard}, + signal::{inner_c, tmp_disable_signals, RtSigarea, SigStack, PROC_CONTROL_STRUCT}, + Tcb, +}; // Setup a stack starting from the very end of the address space, and then growing downwards. pub(crate) const STACK_TOP: usize = 1 << 47; @@ -378,7 +383,10 @@ static SUPPORTS_AVX: AtomicU8 = AtomicU8::new(1); // FIXME pub unsafe fn manually_enter_trampoline() { let c = &Tcb::current().unwrap().os_specific.control; - c.control_flags.store(c.control_flags.load(Ordering::Relaxed) | syscall::flag::INHIBIT_DELIVERY.bits(), Ordering::Release); + c.control_flags.store( + c.control_flags.load(Ordering::Relaxed) | syscall::flag::INHIBIT_DELIVERY.bits(), + Ordering::Release, + ); c.saved_archdep_reg.set(0); // TODO: Just reset DF on x86? core::arch::asm!(" diff --git a/redox-rt/src/lib.rs b/redox-rt/src/lib.rs index 8112c9b433..addc576dcf 100644 --- a/redox-rt/src/lib.rs +++ b/redox-rt/src/lib.rs @@ -1,5 +1,12 @@ #![no_std] -#![feature(asm_const, array_chunks, int_roundings, let_chains, slice_ptr_get, sync_unsafe_cell)] +#![feature( + asm_const, + array_chunks, + int_roundings, + let_chains, + slice_ptr_get, + sync_unsafe_cell +)] #![forbid(unreachable_patterns)] use generic_rt::{ExpectTlsFree, GenericTcb}; @@ -101,12 +108,18 @@ pub fn initialize_freestanding() { // TODO: TLS let page = unsafe { - &mut *(syscall::fmap(!0, &syscall::Map { - offset: 0, - size: syscall::PAGE_SIZE, - flags: syscall::MapFlags::PROT_READ | syscall::MapFlags::PROT_WRITE | syscall::MapFlags::MAP_PRIVATE, - address: 0, - }).unwrap() as *mut Tcb) + &mut *(syscall::fmap( + !0, + &syscall::Map { + offset: 0, + size: syscall::PAGE_SIZE, + flags: syscall::MapFlags::PROT_READ + | syscall::MapFlags::PROT_WRITE + | syscall::MapFlags::MAP_PRIVATE, + address: 0, + }, + ) + .unwrap() as *mut Tcb) }; page.tcb_ptr = page; page.tcb_len = syscall::PAGE_SIZE; diff --git a/redox-rt/src/proc.rs b/redox-rt/src/proc.rs index a89354f274..ff8ce24360 100644 --- a/redox-rt/src/proc.rs +++ b/redox-rt/src/proc.rs @@ -1,5 +1,5 @@ -use core::mem::size_of; use crate::{arch::*, auxv_defs::*}; +use core::mem::size_of; use alloc::{boxed::Box, collections::BTreeMap, vec}; @@ -267,18 +267,23 @@ where let new_page_no = sp / PAGE_SIZE; let new_page_off = sp % PAGE_SIZE; - let page = if let Some(ref mut page) = stack_page && old_page_no == new_page_no { + let page = if let Some(ref mut page) = stack_page + && old_page_no == new_page_no + { page } else if let Some(ref mut stack_page) = stack_page { stack_page.remap(new_page_no * PAGE_SIZE, PROT_WRITE)?; stack_page } else { - let new = MmapGuard::map(*grants_fd, &Map { - offset: new_page_no * PAGE_SIZE, - size: PAGE_SIZE, - flags: PROT_WRITE, - address: 0, // let kernel decide - })?; + let new = MmapGuard::map( + *grants_fd, + &Map { + offset: new_page_no * PAGE_SIZE, + size: PAGE_SIZE, + flags: PROT_WRITE, + address: 0, // let kernel decide + }, + )?; stack_page.insert(new) }; @@ -422,12 +427,15 @@ where push(argc)?; if let Ok(sighandler_fd) = syscall::dup(*open_via_dup, b"sighandler").map(FdGuard::new) { - let _ = syscall::write(*sighandler_fd, &SetSighandlerData { - user_handler: 0, - excp_handler: 0, - thread_control_addr: 0, - proc_control_addr: 0, - }); + let _ = syscall::write( + *sighandler_fd, + &SetSighandlerData { + user_handler: 0, + excp_handler: 0, + thread_control_addr: 0, + proc_control_addr: 0, + }, + ); } unsafe { @@ -818,9 +826,11 @@ pub fn fork_inner(initial_rsp: *mut usize) -> Result { // reference to the TCB and whatever pages stores the signal proc control struct. { let new_sighandler_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"sighandler")?); - let _ = syscall::write(*new_sighandler_fd, &crate::signal::current_setsighandler_struct())?; + let _ = syscall::write( + *new_sighandler_fd, + &crate::signal::current_setsighandler_struct(), + )?; } - } copy_env_regs(*cur_pid_fd, *new_pid_fd)?; } diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index c55b6f313c..9e77763660 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -1,12 +1,17 @@ -use core::cell::{Cell, UnsafeCell}; -use core::ffi::c_int; -use core::sync::atomic::{AtomicUsize, Ordering}; +use core::{ + cell::{Cell, UnsafeCell}, + ffi::c_int, + sync::atomic::{AtomicUsize, Ordering}, +}; -use syscall::{RawAction, ENOMEM, EPERM, SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGQUIT, SIGSEGV, SIGSYS, SIGTRAP, SIGXCPU, SIGXFSZ}; -use syscall::{Error, Result, SetSighandlerData, SigProcControl, Sigcontrol, SigcontrolFlags, EINVAL, SIGCHLD, SIGCONT, SIGKILL, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGWINCH, data::AtomicU64}; +use syscall::{ + data::AtomicU64, Error, RawAction, Result, SetSighandlerData, SigProcControl, Sigcontrol, + SigcontrolFlags, EINVAL, ENOMEM, EPERM, SIGABRT, SIGBUS, SIGCHLD, SIGCONT, SIGFPE, SIGILL, + SIGKILL, SIGQUIT, SIGSEGV, SIGSTOP, SIGSYS, SIGTRAP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, + SIGWINCH, SIGXCPU, SIGXFSZ, +}; -use crate::{arch::*, Tcb}; -use crate::sync::Mutex; +use crate::{arch::*, sync::Mutex, Tcb}; #[cfg(target_arch = "x86_64")] static CPUID_EAX1_ECX: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0); @@ -52,11 +57,15 @@ unsafe fn inner(stack: &mut SigStack) { if action.flags.contains(SigactionFlags::RESETHAND) { // TODO: other things that must be set drop(guard); - sigaction(stack.sig_num as u8, Some(&Sigaction { - kind: SigactionKind::Default, - mask: 0, - flags: SigactionFlags::empty(), - }), None); + sigaction( + stack.sig_num as u8, + Some(&Sigaction { + kind: SigactionKind::Default, + mask: 0, + flags: SigactionFlags::empty(), + }), + None, + ); } action }; @@ -86,21 +95,36 @@ unsafe fn inner(stack: &mut SigStack) { let sigallow_inside_hi = sigallow_inside >> 32; //let _ = syscall::write(1, &alloc::format!("WORD0 {:x?}\n", os.control.word).as_bytes()); - let prev_w0 = os.control.word[0].fetch_add((sigallow_inside_lo << 32).wrapping_sub(prev_sigallow_lo << 32), Ordering::Relaxed); - let prev_w1 = os.control.word[1].fetch_add((sigallow_inside_hi << 32).wrapping_sub(prev_sigallow_hi << 32), Ordering::Relaxed); + let prev_w0 = os.control.word[0].fetch_add( + (sigallow_inside_lo << 32).wrapping_sub(prev_sigallow_lo << 32), + Ordering::Relaxed, + ); + let prev_w1 = os.control.word[1].fetch_add( + (sigallow_inside_hi << 32).wrapping_sub(prev_sigallow_hi << 32), + Ordering::Relaxed, + ); //let _ = syscall::write(1, &alloc::format!("WORD1 {:x?}\n", os.control.word).as_bytes()); // TODO: If sa_mask caused signals to be unblocked, deliver one or all of those first? // Re-enable signals again. let control_flags = &os.control.control_flags; - control_flags.store(control_flags.load(Ordering::Relaxed) & !SigcontrolFlags::INHIBIT_DELIVERY.bits(), Ordering::Release); + control_flags.store( + control_flags.load(Ordering::Relaxed) & !SigcontrolFlags::INHIBIT_DELIVERY.bits(), + Ordering::Release, + ); core::sync::atomic::compiler_fence(Ordering::Acquire); // Call handler, either sa_handler or sa_siginfo depending on flag. - if sigaction.flags.contains(SigactionFlags::SIGINFO) && let Some(sigaction) = handler.sigaction { + if sigaction.flags.contains(SigactionFlags::SIGINFO) + && let Some(sigaction) = handler.sigaction + { //let _ = syscall::write(1, alloc::format!("SIGACTION {:p}\n", sigaction).as_bytes()); - sigaction(stack.sig_num as c_int, core::ptr::null_mut(), core::ptr::null_mut()); + sigaction( + stack.sig_num as c_int, + core::ptr::null_mut(), + core::ptr::null_mut(), + ); } else if let Some(handler) = handler.handler { //let _ = syscall::write(1, alloc::format!("HANDLER {:p}\n", handler).as_bytes()); handler(stack.sig_num as c_int); @@ -108,14 +132,23 @@ unsafe fn inner(stack: &mut SigStack) { //let _ = syscall::write(1, alloc::format!("RETURNED HANDLER\n").as_bytes()); // Disable signals while we modify the sigmask again - control_flags.store(control_flags.load(Ordering::Relaxed) | SigcontrolFlags::INHIBIT_DELIVERY.bits(), Ordering::Release); + control_flags.store( + control_flags.load(Ordering::Relaxed) | SigcontrolFlags::INHIBIT_DELIVERY.bits(), + Ordering::Release, + ); core::sync::atomic::compiler_fence(Ordering::Acquire); // Update allowset again. //let _ = syscall::write(1, &alloc::format!("WORD2 {:x?}\n", os.control.word).as_bytes()); - let prev_w0 = os.control.word[0].fetch_add((prev_sigallow_lo << 32).wrapping_sub(sigallow_inside_lo << 32), Ordering::Relaxed); - let prev_w1 = os.control.word[1].fetch_add((prev_sigallow_hi << 32).wrapping_sub(sigallow_inside_hi << 32), Ordering::Relaxed); + let prev_w0 = os.control.word[0].fetch_add( + (prev_sigallow_lo << 32).wrapping_sub(sigallow_inside_lo << 32), + Ordering::Relaxed, + ); + let prev_w1 = os.control.word[1].fetch_add( + (prev_sigallow_hi << 32).wrapping_sub(sigallow_inside_hi << 32), + Ordering::Relaxed, + ); //let _ = syscall::write(1, &alloc::format!("WORD3 {:x?}\n", os.control.word).as_bytes()); // TODO: If resetting the sigmask caused signals to be unblocked, then should they be delivered @@ -126,7 +159,10 @@ unsafe fn inner(stack: &mut SigStack) { (*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); + control_flags.store( + control_flags.load(Ordering::Relaxed) & !SigcontrolFlags::INHIBIT_DELIVERY.bits(), + Ordering::Release, + ); core::sync::atomic::compiler_fence(Ordering::Acquire); } #[cfg(not(target_arch = "x86"))] @@ -144,14 +180,27 @@ pub fn get_sigmask() -> Result { Ok(mask) } pub fn set_sigmask(new: Option, old: Option<&mut u64>) -> Result<()> { - modify_sigmask(old, new.map(move |newmask| move |_, upper| if upper { newmask >> 32 } else { newmask } as u32)) + modify_sigmask( + old, + new.map(move |newmask| move |_, upper| if upper { newmask >> 32 } else { newmask } as u32), + ) } pub fn or_sigmask(new: Option, old: Option<&mut u64>) -> Result<()> { // Parsing nightmare... :) - modify_sigmask(old, new.map(move |newmask| move |oldmask, upper| oldmask | if upper { newmask >> 32 } else { newmask } as u32)) + modify_sigmask( + old, + new.map(move |newmask| { + move |oldmask, upper| oldmask | if upper { newmask >> 32 } else { newmask } as u32 + }), + ) } pub fn andn_sigmask(new: Option, old: Option<&mut u64>) -> Result<()> { - modify_sigmask(old, new.map(move |newmask| move |oldmask, upper| oldmask & !if upper { newmask >> 32 } else { newmask } as u32)) + modify_sigmask( + old, + new.map(move |newmask| { + move |oldmask, upper| oldmask & !if upper { newmask >> 32 } else { newmask } as u32 + }), + ) } fn modify_sigmask(old: Option<&mut u64>, op: Option u32>) -> Result<()> { let _guard = tmp_disable_signals(); @@ -174,7 +223,10 @@ fn modify_sigmask(old: Option<&mut u64>, op: Option u32 let old_allow_bits = words[i] & 0xffff_ffff_0000_0000; let new_allow_bits = u64::from(!op(!((old_allow_bits >> 32) as u32), i == 1)) << 32; - ctl.word[i].fetch_add(new_allow_bits.wrapping_sub(old_allow_bits), Ordering::Relaxed); + ctl.word[i].fetch_add( + new_allow_bits.wrapping_sub(old_allow_bits), + Ordering::Relaxed, + ); } //let _ = syscall::write(1, &alloc::format!("NEWWORD {:x?}\n", ctl.word).as_bytes()); @@ -205,10 +257,12 @@ impl Sigaction { fn ip(&self) -> usize { unsafe { match self.kind { - SigactionKind::Handled { handler } => if self.flags.contains(SigactionFlags::SIGINFO) { - handler.sigaction.map_or(0, |a| a as usize) - } else { - handler.handler.map_or(0, |a| a as usize) + SigactionKind::Handled { handler } => { + if self.flags.contains(SigactionFlags::SIGINFO) { + handler.sigaction.map_or(0, |a| a as usize) + } else { + handler.handler.map_or(0, |a| a as usize) + } } _ => 0, } @@ -230,7 +284,9 @@ fn convert_old(action: &RawAction) -> Sigaction { } else if flags.contains(SigactionFlags::IGNORED) { SigactionKind::Ignore } else { - SigactionKind::Handled { handler: unsafe { core::mem::transmute(handler as usize) } } + SigactionKind::Handled { + handler: unsafe { core::mem::transmute(handler as usize) }, + } }; Sigaction { @@ -267,25 +323,33 @@ pub fn sigaction(signal: u8, new: Option<&Sigaction>, old: Option<&mut Sigaction // TODO: POSIX specifies that pending signals shall be discarded if set to SIG_IGN by // sigaction. // TODO: handle tmp_disable_signals - (MASK_DONTCARE, SigactionFlags::IGNORED, if matches!(new.kind, SigactionKind::Default) { - default_handler as usize - } else { - 0 - }) + ( + MASK_DONTCARE, + SigactionFlags::IGNORED, + if matches!(new.kind, SigactionKind::Default) { + default_handler as usize + } else { + 0 + }, + ) } // TODO: Handle pending signals before these flags are set. - (SIGTSTP | SIGTTOU | SIGTTIN, SigactionKind::Default) => (MASK_DONTCARE, SigactionFlags::SIG_SPECIFIC, default_handler as usize), + (SIGTSTP | SIGTTOU | SIGTTIN, SigactionKind::Default) => ( + MASK_DONTCARE, + SigactionFlags::SIG_SPECIFIC, + default_handler as usize, + ), (SIGCHLD, SigactionKind::Default) => { let nocldstop_bit = new.flags & SigactionFlags::SIG_SPECIFIC; - (MASK_DONTCARE, SigactionFlags::IGNORED | nocldstop_bit, default_handler as usize) + ( + MASK_DONTCARE, + SigactionFlags::IGNORED | nocldstop_bit, + default_handler as usize, + ) } - (_, SigactionKind::Default) => { - (new.mask, new.flags, default_handler as usize) - }, - (_, SigactionKind::Handled { .. }) => { - (new.mask, new.flags, explicit_handler) - } + (_, SigactionKind::Default) => (new.mask, new.flags, default_handler as usize), + (_, SigactionKind::Handled { .. }) => (new.mask, new.flags, explicit_handler), }; let new_first = (handler as u64) | (u64::from(flags.bits() & STORED_FLAGS) << 32); action.first.store(new_first, Ordering::Relaxed); @@ -298,12 +362,17 @@ fn current_sigctl() -> &'static Sigcontrol { &unsafe { Tcb::current() }.unwrap().os_specific.control } -pub struct TmpDisableSignalsGuard { _inner: () } +pub struct TmpDisableSignalsGuard { + _inner: (), +} pub fn tmp_disable_signals() -> TmpDisableSignalsGuard { unsafe { let ctl = ¤t_sigctl().control_flags; - ctl.store(ctl.load(Ordering::Relaxed) | syscall::flag::INHIBIT_DELIVERY.bits(), Ordering::Release); + ctl.store( + ctl.load(Ordering::Relaxed) | syscall::flag::INHIBIT_DELIVERY.bits(), + Ordering::Release, + ); core::sync::atomic::compiler_fence(Ordering::Acquire); // TODO: fence? @@ -315,12 +384,16 @@ pub fn tmp_disable_signals() -> TmpDisableSignalsGuard { impl Drop for TmpDisableSignalsGuard { fn drop(&mut self) { unsafe { - let depth = &mut (*Tcb::current().unwrap().os_specific.arch.get()).disable_signals_depth; + let depth = + &mut (*Tcb::current().unwrap().os_specific.arch.get()).disable_signals_depth; *depth -= 1; if *depth == 0 { let ctl = ¤t_sigctl().control_flags; - ctl.store(ctl.load(Ordering::Relaxed) & !syscall::flag::INHIBIT_DELIVERY.bits(), Ordering::Release); + ctl.store( + ctl.load(Ordering::Relaxed) & !syscall::flag::INHIBIT_DELIVERY.bits(), + Ordering::Release, + ); core::sync::atomic::compiler_fence(Ordering::Acquire); } } @@ -389,7 +462,10 @@ pub fn setup_sighandler(area: &RtSigarea) { } else { SigactionFlags::empty() }; - action.first.store((u64::from(bits.bits()) << 32) | default_handler as u64, Ordering::Relaxed); + action.first.store( + (u64::from(bits.bits()) << 32) | default_handler as u64, + Ordering::Relaxed, + ); } } let arch = unsafe { &mut *area.arch.get() }; @@ -433,7 +509,9 @@ pub fn current_setsighandler_struct() -> SetSighandlerData { SetSighandlerData { user_handler: sighandler_function(), excp_handler: 0, // TODO - thread_control_addr: core::ptr::addr_of!(unsafe { Tcb::current() }.unwrap().os_specific.control) as usize, + thread_control_addr: core::ptr::addr_of!( + unsafe { Tcb::current() }.unwrap().os_specific.control + ) as usize, proc_control_addr: &PROC_CONTROL_STRUCT as *const SigProcControl as usize, } } @@ -443,9 +521,16 @@ pub enum Sigaltstack { #[default] Disabled, - Enabled { onstack: bool, base: *mut (), size: usize }, + Enabled { + onstack: bool, + base: *mut (), + size: usize, + }, } -pub unsafe fn sigaltstack(new: Option<&Sigaltstack>, old_out: Option<&mut Sigaltstack>) -> Result<()> { +pub unsafe fn sigaltstack( + new: Option<&Sigaltstack>, + old_out: Option<&mut Sigaltstack>, +) -> Result<()> { let _g = tmp_disable_signals(); let tcb = &mut *Tcb::current().unwrap().os_specific.arch.get(); @@ -473,7 +558,11 @@ pub unsafe fn sigaltstack(new: Option<&Sigaltstack>, old_out: Option<&mut Sigalt tcb.altstack_top = usize::MAX; } Sigaltstack::Enabled { onstack: true, .. } => return Err(Error::new(EINVAL)), - Sigaltstack::Enabled { base, size, onstack: false } => { + Sigaltstack::Enabled { + base, + size, + onstack: false, + } => { if size < MIN_SIGALTSTACK_SIZE { return Err(Error::new(ENOMEM)); } diff --git a/redox-rt/src/sync.rs b/redox-rt/src/sync.rs index 172bd37b1f..5b56434d70 100644 --- a/redox-rt/src/sync.rs +++ b/redox-rt/src/sync.rs @@ -1,8 +1,10 @@ // TODO: Share code for simple futex-based mutex between relibc's Mutex<()> and this. -use core::cell::UnsafeCell; -use core::ops::{Deref, DerefMut}; -use core::sync::atomic::{AtomicU32, Ordering}; +use core::{ + cell::UnsafeCell, + ops::{Deref, DerefMut}, + sync::atomic::{AtomicU32, Ordering}, +}; pub struct Mutex { pub lockword: AtomicU32, @@ -24,7 +26,11 @@ impl Mutex { } } pub fn lock(&self) -> MutexGuard<'_, T> { - while self.lockword.compare_exchange(UNLOCKED, LOCKED, Ordering::Acquire, Ordering::Relaxed).is_err() { + while self + .lockword + .compare_exchange(UNLOCKED, LOCKED, Ordering::Acquire, Ordering::Relaxed) + .is_err() + { core::hint::spin_loop(); } MutexGuard { lock: self } diff --git a/redox-rt/src/sys.rs b/redox-rt/src/sys.rs index d450a5625a..29f7ef3350 100644 --- a/redox-rt/src/sys.rs +++ b/redox-rt/src/sys.rs @@ -1,17 +1,20 @@ -use syscall::error::{Result, Error, EINTR}; +use syscall::{ + error::{Error, Result, EINTR}, + TimeSpec, +}; -use crate::arch::manually_enter_trampoline; -use crate::signal::tmp_disable_signals; -use crate::Tcb; +use crate::{arch::manually_enter_trampoline, signal::tmp_disable_signals, Tcb}; #[inline] -fn wrapper(mut f: impl FnMut() -> Result) -> Result { +fn wrapper(mut f: impl FnMut() -> Result) -> Result { loop { let _guard = tmp_disable_signals(); let rt_sigarea = unsafe { &Tcb::current().unwrap().os_specific }; let res = f(); - if res == Err(Error::new(EINTR)) { + if let Err(err) = res + && err == Error::new(EINTR) + { unsafe { manually_enter_trampoline(); } @@ -47,3 +50,29 @@ pub fn posix_killpg(pgrp: usize, sig: usize) -> Result<()> { Err(error) => Err(error), } } +#[inline] +pub unsafe fn sys_futex_wait(addr: *mut u32, val: u32, deadline: Option<&TimeSpec>) -> Result<()> { + wrapper(|| { + syscall::syscall5( + syscall::SYS_FUTEX, + addr as usize, + syscall::FUTEX_WAIT, + val as usize, + deadline.map_or(0, |d| d as *const _ as usize), + 0, + ) + .map(|_| ()) + }) +} +#[inline] +pub unsafe fn sys_futex_wake(addr: *mut u32, num: u32) -> Result { + syscall::syscall5( + syscall::SYS_FUTEX, + addr as usize, + syscall::FUTEX_WAKE, + num as usize, + 0, + 0, + ) + .map(|awoken| awoken as u32) +} diff --git a/redox-rt/src/thread.rs b/redox-rt/src/thread.rs index 9b348a62d7..b869b50b5b 100644 --- a/redox-rt/src/thread.rs +++ b/redox-rt/src/thread.rs @@ -1,9 +1,6 @@ -use syscall::SetSighandlerData; -use syscall::{Result, O_CLOEXEC}; +use syscall::{Result, SetSighandlerData, O_CLOEXEC}; -use crate::arch::*; -use crate::proc::*; -use crate::signal::sighandler_function; +use crate::{arch::*, proc::*, signal::sighandler_function}; /// Spawns a new context sharing the same address space as the current one (i.e. a new thread). pub unsafe fn rlct_clone_impl(stack: *mut usize) -> Result { diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index 71f3ba0ce3..1c645386a7 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -242,8 +242,9 @@ impl Pal for Sys { unsafe fn futex_wait( addr: *mut u32, val: u32, - deadline: *const timespec, + deadline: Option<×pec>, ) -> Result<(), crate::pthread::Errno> { + let deadline = deadline.map_or(0, |d| d as *const _ as usize); e_raw(unsafe { syscall!( FUTEX, addr, // uaddr @@ -257,11 +258,11 @@ impl Pal for Sys { .map(|_| ()) } #[inline] - unsafe fn futex_wake(addr: *mut u32, num: u32) -> Result { + unsafe fn futex_wake(addr: *mut u32, num: u32) -> Result { e_raw(unsafe { syscall!(FUTEX, addr, 1 /* FUTEX_WAKE */, num) }) - .map(|n| n as c_int) + .map(|n| n as u32) } fn futimens(fd: c_int, times: *const timespec) -> c_int { diff --git a/src/platform/pal/mod.rs b/src/platform/pal/mod.rs index ea226f7ad9..8b30339e9e 100644 --- a/src/platform/pal/mod.rs +++ b/src/platform/pal/mod.rs @@ -82,9 +82,9 @@ pub trait Pal { unsafe fn futex_wait( addr: *mut u32, val: u32, - deadline: *const timespec, + deadline: Option<×pec>, ) -> Result<(), pthread::Errno>; - unsafe fn futex_wake(addr: *mut u32, num: u32) -> Result; + unsafe fn futex_wake(addr: *mut u32, num: u32) -> Result; fn futimens(fd: c_int, times: *const timespec) -> c_int; diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index c1d3b645f3..e6d415e0eb 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -1,4 +1,4 @@ -use core::{convert::TryFrom, mem, ptr, result::Result as CoreResult, slice, str}; +use core::{convert::TryFrom, mem, ptr, slice, str}; use syscall::{ self, data::{Map, Stat as redox_stat, StatVfs as redox_statvfs, TimeSpec as redox_timespec}, @@ -305,31 +305,18 @@ impl Pal for Sys { unsafe fn futex_wait( addr: *mut u32, val: u32, - deadline: *const timespec, - ) -> CoreResult<(), pthread::Errno> { - syscall::syscall5( - syscall::SYS_FUTEX, - addr as usize, - syscall::FUTEX_WAIT, - val as usize, - deadline as usize, - 0, - ) - .map_err(|s| pthread::Errno(s.errno)) - .map(|_| ()) + deadline: Option<×pec>, + ) -> Result<(), pthread::Errno> { + let deadline = deadline.map(|d| syscall::TimeSpec { + tv_sec: d.tv_sec, + tv_nsec: d.tv_nsec as i32, + }); + redox_rt::sys::sys_futex_wait(addr, val, deadline.as_ref())?; + Ok(()) } #[inline] - unsafe fn futex_wake(addr: *mut u32, num: u32) -> Result { - syscall::syscall5( - syscall::SYS_FUTEX, - addr as usize, - syscall::FUTEX_WAKE, - num as usize, - 0, - 0, - ) - .map_err(|s| pthread::Errno(s.errno)) - .map(|n| n as c_int) + unsafe fn futex_wake(addr: *mut u32, num: u32) -> Result { + Ok(redox_rt::sys::sys_futex_wake(addr, num)?) } // FIXME: unsound @@ -996,7 +983,7 @@ impl Pal for Sys { Ok(()) } - fn inner(utsname: *mut utsname) -> CoreResult<(), i32> { + fn inner(utsname: *mut utsname) -> Result<(), i32> { match gethostname(unsafe { slice::from_raw_parts_mut( (*utsname).nodename.as_mut_ptr() as *mut u8, diff --git a/src/sync/mod.rs b/src/sync/mod.rs index d851f925ca..77bda2d964 100644 --- a/src/sync/mod.rs +++ b/src/sync/mod.rs @@ -102,11 +102,7 @@ pub unsafe fn futex_wait_ptr( value: T, deadline_opt: Option<×pec>, ) -> FutexWaitResult { - match Sys::futex_wait( - ptr.cast(), - value.conv(), - deadline_opt.map_or(core::ptr::null(), |t| t as *const _), - ) { + match Sys::futex_wait(ptr.cast(), value.conv(), deadline_opt) { Ok(()) => FutexWaitResult::Waited, Err(Errno(EAGAIN)) => FutexWaitResult::Stale, Err(Errno(ETIMEDOUT)) if deadline_opt.is_some() => FutexWaitResult::TimedOut, From 17cb748217309b34b22d599f50256e9b3ef7c29e Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 16 Jul 2024 12:48:14 +0200 Subject: [PATCH 3/6] Implement syscall restart for waitpid. --- redox-rt/src/sys.rs | 10 ++++++++++ src/platform/redox/mod.rs | 7 +------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/redox-rt/src/sys.rs b/redox-rt/src/sys.rs index 29f7ef3350..6e8b1d823a 100644 --- a/redox-rt/src/sys.rs +++ b/redox-rt/src/sys.rs @@ -76,3 +76,13 @@ pub unsafe fn sys_futex_wake(addr: *mut u32, num: u32) -> Result { ) .map(|awoken| awoken as u32) } +pub fn sys_waitpid(pid: usize, status: &mut usize, flags: usize) -> Result { + wrapper(|| { + syscall::waitpid( + pid, + status, + syscall::WaitFlags::from_bits(flags) + .expect("waitpid: invalid bit pattern"), + ) + }) +} diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index e6d415e0eb..e1b1351f35 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -1058,12 +1058,7 @@ impl Pal for Sys { let mut status = 0; let inner = |status: &mut usize, flags| { - syscall::waitpid( - pid as usize, - status, - syscall::WaitFlags::from_bits(flags as usize) - .expect("waitpid: invalid bit pattern"), - ) + redox_rt::sys::sys_waitpid(pid as usize, status, flags as usize) }; // First, allow ptrace to handle waitpid From 22cab7ca8da904e4a6c51ee16c720ecd85af4fdd Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 16 Jul 2024 13:32:18 +0200 Subject: [PATCH 4/6] Fix errors on non-x86_64. --- redox-rt/src/arch/aarch64.rs | 1 + redox-rt/src/arch/i686.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/redox-rt/src/arch/aarch64.rs b/redox-rt/src/arch/aarch64.rs index 3379bca7f6..c9aaccbfe6 100644 --- a/redox-rt/src/arch/aarch64.rs +++ b/redox-rt/src/arch/aarch64.rs @@ -23,6 +23,7 @@ pub struct SigArea { pub onstack: u64, pub disable_signals_depth: u64, pub pctl: usize, // TODO: remove + pub last_sig_was_restart: bool, } #[repr(C)] #[derive(Debug, Default)] diff --git a/redox-rt/src/arch/i686.rs b/redox-rt/src/arch/i686.rs index ec4decdde4..4866571a58 100644 --- a/redox-rt/src/arch/i686.rs +++ b/redox-rt/src/arch/i686.rs @@ -21,6 +21,7 @@ pub struct SigArea { pub tmp_eax: usize, pub tmp_edx: usize, pub disable_signals_depth: u64, + pub last_sig_was_restart: bool, } #[derive(Debug, Default)] #[repr(C, align(16))] From 66a32016b580809bd231c41b68ca262308d66a11 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 16 Jul 2024 14:43:25 +0200 Subject: [PATCH 5/6] Move sa_restart test to correct category. --- tests/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Makefile b/tests/Makefile index 2f4b35d1be..37abe58dbb 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -31,7 +31,6 @@ EXPECT_NAMES=\ setjmp \ sigaction \ signal \ - sa_restart \ stdio/all \ stdio/buffer \ stdio/fgets \ @@ -158,6 +157,7 @@ NAMES=\ $(EXPECT_NAMES) \ dirent/main \ pwd \ + sa_restart \ sigchld \ stdio/tempnam \ stdio/tmpnam \ From dfb234079e33aad406919d6c84c33672b47a0466 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 16 Jul 2024 13:30:35 +0200 Subject: [PATCH 6/6] Fix signal fxrstor offset. --- redox-rt/src/arch/x86_64.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index 73db7cea29..b5e921f8cf 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -126,8 +126,8 @@ asmfunction!(__relibc_internal_fork_ret: [" mov rsi, [rsp + 8] call {child_hook} - ldmxcsr [rsp+16] - fldcw [rsp+24] + ldmxcsr [rsp + 16] + fldcw [rsp + 24] xor rax, rax @@ -152,14 +152,10 @@ asmfunction!(__relibc_internal_rlct_clone_ret: [" pop r8 pop r9 - sub rsp, 8 - - mov DWORD PTR [rsp], 0x00001F80 - ldmxcsr [rsp] - mov WORD PTR [rsp], 0x037F - fldcw [rsp] - - add rsp, 8 + mov DWORD PTR [rsp - 8], 0x00001F80 + ldmxcsr [rsp - 8] + mov WORD PTR [rsp - 8], 0x037F + fldcw [rsp - 8] # Call entry point call rax @@ -275,7 +271,7 @@ asmfunction!(__relibc_internal_sigentry: [" add rsp, 16 - fxrstor64 [rsp] + fxrstor64 [rsp + 16 * 16] cmp byte ptr [rip + {supports_avx}], 0 je 6f