misc signal fixes
This commit is contained in:
committed by
Jeremy Soller
parent
576fd5fe01
commit
eeba32b3a2
@@ -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];
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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
@@ -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?
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user