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 {
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ use crate::{
|
||||
syscall::{data::PtraceEvent, error::*, flag::*, ptrace_event},
|
||||
};
|
||||
|
||||
use alloc::{boxed::Box, collections::VecDeque, sync::Arc};
|
||||
use alloc::{collections::VecDeque, sync::Arc};
|
||||
use core::cmp;
|
||||
use hashbrown::hash_map::{Entry, HashMap};
|
||||
use spin::{Mutex, Once, RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
|
||||
+15
-19
@@ -11,7 +11,7 @@ use crate::{
|
||||
scheme::{self, FileHandle, KernelScheme},
|
||||
syscall::{
|
||||
self,
|
||||
data::{GrantDesc, Map, PtraceEvent, SigAction, Stat},
|
||||
data::{GrantDesc, Map, PtraceEvent, SigAction, SetSighandlerData, Stat},
|
||||
error::*,
|
||||
flag::*,
|
||||
usercopy::{UserSliceRo, UserSliceWo},
|
||||
@@ -934,15 +934,17 @@ impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
|
||||
&mut 0,
|
||||
),
|
||||
|
||||
// TODO: Struct
|
||||
Operation::Sighandler => {
|
||||
let handler = context::contexts().get(info.pid).ok_or(Error::new(ESRCH))?.read().sig.handler;
|
||||
let [entry, altstack_base, altstack_len] = buf.in_exact_chunks(mem::size_of::<usize>()).next_chunk().map_err(|_| Error::new(EINVAL))?;
|
||||
entry.write_usize(handler.map_or(0, |h| h.handler.get()))?;
|
||||
let altstack = handler.and_then(|h| h.altstack);
|
||||
altstack_base.write_usize(altstack.map_or(0, |a| a.base.get()))?;
|
||||
altstack_len.write_usize(altstack.map_or(0, |a| a.len.get()))?;
|
||||
Ok(3 * mem::size_of::<usize>())
|
||||
let data = SetSighandlerData {
|
||||
entry: handler.map_or(0, |h| h.handler.get()),
|
||||
altstack_base: altstack.map_or(0, |a| a.base.get()),
|
||||
altstack_len: altstack.map_or(0, |a| a.len.get()),
|
||||
};
|
||||
buf.copy_exactly(&data)?;
|
||||
|
||||
Ok(mem::size_of::<SetSighandlerData>())
|
||||
}
|
||||
Operation::Sigprocmask => {
|
||||
let procmask = context::contexts().get(info.pid).ok_or(Error::new(ESRCH))?.read().sig.procmask;
|
||||
@@ -1190,14 +1192,13 @@ impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
|
||||
|
||||
Ok(buf.len())
|
||||
}
|
||||
// TODO: Struct
|
||||
Operation::Sighandler => {
|
||||
let [handler, altstack_base, altstack_len] = buf.usizes().next_chunk().map_err(|_| Error::new(EINVAL))?;
|
||||
let data = unsafe { buf.read_exact::<SetSighandlerData>()? };
|
||||
|
||||
let new_handler = match NonZeroUsize::new(handler?) {
|
||||
let new_handler = match NonZeroUsize::new(data.entry) {
|
||||
Some(handler) => Some(SignalHandler {
|
||||
handler,
|
||||
altstack: match (NonZeroUsize::new(altstack_base?), NonZeroUsize::new(altstack_len?)) {
|
||||
altstack: match (NonZeroUsize::new(data.altstack_base), NonZeroUsize::new(data.altstack_len)) {
|
||||
(Some(base), Some(len)) => Some(Altstack { base, len }),
|
||||
_ => None,
|
||||
}
|
||||
@@ -1207,7 +1208,7 @@ impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
|
||||
|
||||
context::contexts().get(info.pid).ok_or(Error::new(ESRCH))?.write().sig.handler = new_handler;
|
||||
|
||||
Ok(3 * mem::size_of::<usize>())
|
||||
Ok(mem::size_of::<SetSighandlerData>())
|
||||
}
|
||||
Operation::Sigprocmask => {
|
||||
let new_procmask = buf.read_u64()?;
|
||||
@@ -1535,6 +1536,8 @@ fn inherit_context() -> Result<ContextId> {
|
||||
let current_context_lock = Arc::clone(context::contexts().current().ok_or(Error::new(ESRCH))?);
|
||||
let new_context_lock = Arc::clone(context::contexts_mut().spawn(true, clone_handler)?);
|
||||
|
||||
// (Starts with "all signals blocked".)
|
||||
|
||||
let current_context = current_context_lock.read();
|
||||
let mut new_context = new_context_lock.write();
|
||||
|
||||
@@ -1554,13 +1557,6 @@ fn inherit_context() -> Result<ContextId> {
|
||||
new_context.session_id = current_context.session_id;
|
||||
new_context.umask = current_context.umask;
|
||||
|
||||
// Start with "all signals blocked".
|
||||
new_context.sig = SignalState {
|
||||
pending: 0,
|
||||
procmask: !0,
|
||||
handler: None,
|
||||
};
|
||||
|
||||
new_context.id
|
||||
};
|
||||
|
||||
|
||||
+1
-1
Submodule syscall updated: 0652a057f9...f1719f57df
Reference in New Issue
Block a user