Start with full procmask, fix signal delivery.

This commit is contained in:
4lDO2
2024-01-26 11:49:02 +01:00
parent 5336cbd9e5
commit 5ac0be7ec1
6 changed files with 51 additions and 42 deletions
+1 -2
View File
@@ -242,8 +242,7 @@ impl Context {
ens: SchemeNamespace::from(0),
sig: SignalState {
pending: 0,
procmask: 0,
procmask: !0,
handler: None,
},
umask: 0o022,
+7 -10
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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