Start with full procmask, fix signal delivery.
This commit is contained in:
@@ -242,8 +242,7 @@ impl Context {
|
||||
ens: SchemeNamespace::from(0),
|
||||
sig: SignalState {
|
||||
pending: 0,
|
||||
procmask: 0,
|
||||
|
||||
procmask: !0,
|
||||
handler: None,
|
||||
},
|
||||
umask: 0o022,
|
||||
|
||||
+7
-10
@@ -1,5 +1,5 @@
|
||||
use alloc::sync::Arc;
|
||||
use core::mem::{self, size_of};
|
||||
use core::mem::size_of;
|
||||
use syscall::{
|
||||
flag::{
|
||||
PTRACE_FLAG_IGNORE, PTRACE_STOP_SIGNAL, SIGCHLD, SIGCONT, SIGKILL, SIGSTOP, SIGTSTP,
|
||||
@@ -14,12 +14,7 @@ use crate::{
|
||||
syscall::usercopy::UserSlice,
|
||||
};
|
||||
|
||||
pub fn is_user_handled(handler: Option<extern "C" fn(usize)>) -> bool {
|
||||
let handler = handler.map(|ptr| ptr as usize).unwrap_or(0);
|
||||
handler != SIG_DFL && handler != SIG_IGN
|
||||
}
|
||||
|
||||
// TODO: Move everything but SIGKILL to userspace. SIGCONT and SIGSTOP does not necessarily need to
|
||||
// TODO: Move everything but SIGKILL to userspace. SIGCONT and SIGSTOP do not necessarily need to
|
||||
// be done from this current context.
|
||||
pub fn signal_handler() {
|
||||
let (action, sig) = {
|
||||
@@ -29,6 +24,9 @@ pub fn signal_handler() {
|
||||
|
||||
// Lowest-numbered signal first.
|
||||
// TODO: randomly?
|
||||
if context.sig.deliverable() == 0 {
|
||||
return;
|
||||
}
|
||||
let selected = context.sig.deliverable().trailing_zeros() as usize + 1;
|
||||
context.sig.pending &= !(1 << (selected - 1));
|
||||
|
||||
@@ -46,8 +44,7 @@ pub fn signal_handler() {
|
||||
|
||||
if sig != SIGKILL && thumbs_down.unwrap_or(false) {
|
||||
// If signal can be and was ignored
|
||||
crate::syscall::sigreturn().unwrap();
|
||||
unreachable!();
|
||||
return;
|
||||
}
|
||||
|
||||
if handler == SIG_DFL {
|
||||
@@ -166,7 +163,7 @@ pub fn signal_handler() {
|
||||
context.sig.procmask |= action.sa_mask;
|
||||
|
||||
if !action.sa_flags.contains(SigActionFlags::SA_NODEFER) {
|
||||
context.sig.procmask &= !(1 << (sig - 1));
|
||||
context.sig.procmask |= 1 << (sig - 1);
|
||||
}
|
||||
|
||||
let Some(regs) = context.regs_mut() else {
|
||||
|
||||
+26
-9
@@ -12,30 +12,37 @@ use crate::{
|
||||
|
||||
use super::{ContextId, Status};
|
||||
|
||||
unsafe fn update_runnable(context: &mut Context, cpu_id: LogicalCpuId) -> bool {
|
||||
enum UpdateResult {
|
||||
CanSwitch { signal: bool },
|
||||
Skip,
|
||||
}
|
||||
|
||||
unsafe fn update_runnable(context: &mut Context, cpu_id: LogicalCpuId) -> UpdateResult {
|
||||
// Ignore already running contexts
|
||||
if context.running {
|
||||
return false;
|
||||
return UpdateResult::Skip;
|
||||
}
|
||||
|
||||
// Ignore contexts stopped by ptrace
|
||||
if context.ptrace_stop {
|
||||
return false;
|
||||
return UpdateResult::Skip;
|
||||
}
|
||||
|
||||
// Ignore contexts assigned to other CPUs
|
||||
if !context.sched_affinity.contains(cpu_id) {
|
||||
return false;
|
||||
return UpdateResult::Skip;
|
||||
}
|
||||
|
||||
//TODO: HACK TO WORKAROUND HANGS BY PINNING TO ONE CPU
|
||||
if !context.cpu_id.map_or(true, |x| x == cpu_id) {
|
||||
return false;
|
||||
return UpdateResult::Skip;
|
||||
}
|
||||
|
||||
let signal = context.sig.deliverable() != 0;
|
||||
|
||||
// Unblock when there are pending nonmasked signals.
|
||||
if matches!(context.status, Status::Blocked) && context.sig.deliverable() != 0 {
|
||||
context.unblock();
|
||||
if matches!(context.status, Status::Blocked) && signal {
|
||||
context.unblock_no_ipi();
|
||||
}
|
||||
|
||||
// Wake from sleep
|
||||
@@ -50,7 +57,11 @@ unsafe fn update_runnable(context: &mut Context, cpu_id: LogicalCpuId) -> bool {
|
||||
}
|
||||
|
||||
// Switch to context if it needs to run
|
||||
context.status.is_runnable()
|
||||
if context.status.is_runnable() {
|
||||
UpdateResult::CanSwitch { signal }
|
||||
} else {
|
||||
UpdateResult::Skip
|
||||
}
|
||||
}
|
||||
|
||||
struct SwitchResult {
|
||||
@@ -144,9 +155,10 @@ pub unsafe fn switch() -> bool {
|
||||
let mut next_context_guard = next_context_lock.write_arc();
|
||||
|
||||
// Update state of next context and check if runnable
|
||||
if update_runnable(&mut *next_context_guard, cpu_id) {
|
||||
if let UpdateResult::CanSwitch { signal } = update_runnable(&mut *next_context_guard, cpu_id) {
|
||||
// Store locks for previous and next context
|
||||
switch_context_opt = Some((prev_context_guard, next_context_guard));
|
||||
percpu.switch_internals.switch_signal.set(signal);
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
@@ -186,6 +198,10 @@ pub unsafe fn switch() -> bool {
|
||||
|
||||
arch::switch_to(prev_context, next_context);
|
||||
|
||||
if percpu.switch_internals.switch_signal.replace(false) {
|
||||
crate::context::signal::signal_handler();
|
||||
}
|
||||
|
||||
// NOTE: After switch_to is called, the return address can even be different from the
|
||||
// current return address, meaning that we cannot use local variables here, and that we
|
||||
// need to use the `switch_finish_hook` to be able to release the locks.
|
||||
@@ -209,6 +225,7 @@ pub struct ContextSwitchPercpu {
|
||||
|
||||
// The ID of the idle process
|
||||
idle_id: Cell<ContextId>,
|
||||
switch_signal: Cell<bool>,
|
||||
}
|
||||
impl ContextSwitchPercpu {
|
||||
pub fn context_id(&self) -> ContextId {
|
||||
|
||||
Reference in New Issue
Block a user