misc signal fixes

This commit is contained in:
Jacob Lorentzon
2026-01-22 15:35:04 +01:00
committed by Jeremy Soller
parent 576fd5fe01
commit eeba32b3a2
6 changed files with 56 additions and 10 deletions
+5
View File
@@ -476,5 +476,10 @@ pub unsafe fn arch_pre(stack: &mut SigStack, os: &mut SigArea) -> PosixStackt {
flags: 0, // TODO
}
}
pub fn arch_ret_to_sig(stack: &mut SigStack, control: &Sigcontrol) {
let orig_pc = core::mem::replace(&mut stack.regs.pc, __relibc_internal_sigentry as usize);
control.saved_ip.set(orig_pc);
control.saved_archdep_reg.set(stack.regs.x0);
}
pub(crate) static PROC_FD: SyncUnsafeCell<usize> = SyncUnsafeCell::new(usize::MAX);
static PROC_CALL: [usize; 1] = [ProcCall::Sigdeq as usize];
+5
View File
@@ -371,6 +371,11 @@ pub unsafe fn arch_pre(stack: &mut SigStack, area: &mut SigArea) -> PosixStackt
flags: 0, // TODO
}
}
pub fn arch_ret_to_sig(stack: &mut SigStack, control: &Sigcontrol) {
let orig_eip = core::mem::replace(&mut stack.regs.eip, __relibc_internal_sigentry as usize);
control.saved_ip.set(orig_eip);
control.saved_archdep_reg.set(stack.regs.eflags);
}
#[unsafe(no_mangle)]
pub unsafe fn manually_enter_trampoline() {
let c = unsafe { &crate::Tcb::current().unwrap().os_specific.control };
+7
View File
@@ -643,5 +643,12 @@ pub unsafe fn arch_pre(stack: &mut SigStack, area: &mut SigArea) -> PosixStackt
get_sigaltstack(area, stack.regs.int_regs[1] as usize).into()
}
pub fn arch_ret_to_sig(stack: &mut SigStack, control: &Sigcontrol) {
let orig_pc = core::mem::replace(&mut stack.regs.pc, __relibc_internal_sigentry as u64);
control.saved_ip.set(orig_pc as usize);
control
.saved_archdep_reg
.set(stack.regs.int_regs[4] as usize); // t0
}
pub(crate) static PROC_FD: SyncUnsafeCell<usize> = SyncUnsafeCell::new(usize::MAX);
static PROC_CALL: [usize; 1] = [ProcCall::Sigdeq as usize];
+8
View File
@@ -482,6 +482,14 @@ pub unsafe fn arch_pre(stack: &mut SigStack, area: &mut SigArea) -> PosixStackt
get_sigaltstack(area, stack.regs.rsp).into()
}
/// Rearrange the restore-stack and sigarea in a way that makes it look like a new signal was
/// immediately delivered after restoring the allowset to what it was prior to the original signal delivery.
pub fn arch_ret_to_sig(stack: &mut SigStack, control: &Sigcontrol) {
let orig_rip = core::mem::replace(&mut stack.regs.rip, __relibc_internal_sigentry as usize);
control.saved_ip.set(orig_rip);
control.saved_archdep_reg.set(stack.regs.rflags);
}
pub(crate) static SUPPORTS_AVX: AtomicU8 = AtomicU8::new(0);
// __relibc will be prepended to the name, so no_mangle is fine
+23 -8
View File
@@ -242,15 +242,20 @@ unsafe fn inner(stack: &mut SigStack) {
);
core::sync::atomic::compiler_fence(Ordering::Acquire);
// Update allowset again.
// Update allowset again, and obtain the set of pending unblocked signals with this new
// allowset. If this is nonempty, we must deliver the signal here rather than wait for it
// asynchronously, as shown e.g. in https://gitlab.redox-os.org/redox-os/relibc/-/issues/239.
// We do this even if signals_were_disabled beforehand (where the caller hence explicitly
// must have jumped to this trampoline).
let new_mask = stack.old_mask;
let old_mask = get_allowset_raw(&os.control.word);
let _pending_when_restored_mask = set_allowset_raw(&os.control.word, old_mask, new_mask);
// TODO: If resetting the sigmask caused signals to be unblocked, then should they be delivered
// here? And would it be possible to tail-call-optimize that?
let pending_unblocked = {
let thread_pending = set_allowset_raw(&os.control.word, old_mask, new_mask);
let proc_pending = PROC_CONTROL_STRUCT.pending.load(Ordering::Relaxed);
(thread_pending | proc_pending) & new_mask
};
unsafe { (*os.arch.get()).last_sig_was_restart = shall_restart };
@@ -259,8 +264,18 @@ unsafe fn inner(stack: &mut SigStack) {
// TODO: Support restoring uc_stack?
// And re-enable them again
if !signals_were_disabled {
if pending_unblocked > 0 {
// If there were signals visible at the time we checked (otherwise it can be considered
// "asynchronous" and will be delivered the next time an EINTR is seen, or after the
// post-preemption check in the kernel), we delay clearing the INHIBIT_DELIVERY bit, and
// rearrange the saved instr ptr field on the stack and the sc_saved_rip field, so that it
// returns to the start of the trampoline in a way that makes it look like a new signal was
// immediately delivered. There's no need to worry about the __crit_* sections since
// INHIBIT_DELIVERY is still set.
arch_ret_to_sig(stack, &os.control);
} else if !signals_were_disabled {
// Re-enable signals again, except in the case where they were disabled and the trampoline
// was explicitly jumped to when handling EINTR.
core::sync::atomic::compiler_fence(Ordering::Release);
control_flags.store(
control_flags.load(Ordering::Relaxed) & !SigcontrolFlags::INHIBIT_DELIVERY.bits(),
@@ -747,7 +762,7 @@ pub fn currently_pending_blocked() -> u64 {
let w0 = control.word[0].load(Ordering::Relaxed);
let w1 = control.word[1].load(Ordering::Relaxed);
let allow = (w0 >> 32) | ((w1 >> 32) << 32);
let thread_pending = (w0 & 0xffff_ffff) | ((w1 >> 32) & 0xffff_ffff);
let thread_pending = (w0 & 0xffff_ffff) | ((w1 & 0xffff_ffff) << 32);
let proc_pending = PROC_CONTROL_STRUCT.pending.load(Ordering::Relaxed);
core::sync::atomic::fence(Ordering::Acquire); // TODO: Correct ordering?
+8 -2
View File
@@ -223,13 +223,19 @@ impl PalSignal for Sys {
set: Option<&sigset_t>,
oset: Option<&mut sigset_t>,
) -> Result<(), Errno> {
Ok(match how {
match how {
_ if set.is_none() => {
if let Some(oset) = oset {
*oset = redox_rt::signal::get_sigmask()?;
}
}
SIG_SETMASK => redox_rt::signal::set_sigmask(set.copied(), oset)?,
SIG_BLOCK => redox_rt::signal::or_sigmask(set.copied(), oset)?,
SIG_UNBLOCK => redox_rt::signal::andn_sigmask(set.copied(), oset)?,
_ => return Err(Errno(EINVAL)),
})
}
Ok(())
}
fn sigsuspend(mask: &sigset_t) -> Errno {