diff --git a/src/process/thread_group.rs b/src/process/thread_group.rs index 77f8444..b5937e9 100644 --- a/src/process/thread_group.rs +++ b/src/process/thread_group.rs @@ -1,5 +1,5 @@ -use super::{Task, Tid}; -use crate::{memory::uaccess::UserCopyable, sync::SpinLock}; +use super::{Task, TaskState, Tid}; +use crate::{memory::uaccess::UserCopyable, sched::waker::create_waker, sync::SpinLock}; use alloc::{ collections::btree_map::BTreeMap, sync::{Arc, Weak}, @@ -12,7 +12,7 @@ use core::{ }; use pid::PidT; use rsrc_lim::ResourceLimits; -use signal::{SigSet, SignalActionState}; +use signal::{SigId, SigSet, SignalActionState}; use wait::ChildNotifiers; pub mod builder; @@ -155,6 +155,30 @@ impl ThreadGroup { pub fn get(id: Tgid) -> Option> { TG_LIST.lock_save_irq().get(&id).and_then(|x| x.upgrade()) } + + pub fn deliver_signal(&self, signal: SigId) { + match signal { + SigId::SIGKILL => { + // Set the sigkill marker in the pending signals and wake up all + // tasks in this group. + *self.pending_signals.lock_save_irq() = SigSet::SIGKILL; + + for task in self.tasks.lock_save_irq().values() { + if let Some(task) = task.upgrade() + && matches!( + *task.state.lock_save_irq(), + TaskState::Stopped | TaskState::Sleeping + ) + { + create_waker(task.descriptor()).wake(); + } + } + } + _ => { + self.pending_signals.lock_save_irq().set_signal(signal); + } + } + } } impl Drop for ThreadGroup { diff --git a/src/process/thread_group/signal/kill.rs b/src/process/thread_group/signal/kill.rs index d2de055..e0c60a0 100644 --- a/src/process/thread_group/signal/kill.rs +++ b/src/process/thread_group/signal/kill.rs @@ -16,18 +16,15 @@ pub fn sys_kill(pid: PidT, signal: UserSigId) -> Result { let current_task = current_task(); // Kill ourselves if pid == current_task.process.tgid.value() as PidT { - current_task - .process - .pending_signals - .lock_save_irq() - .set_signal(signal); + current_task.process.deliver_signal(signal); + return Ok(0); } match pid { p if p > 0 => { let target_tg = ThreadGroup::get(Tgid(p as _)).ok_or(KernelError::NoProcess)?; - target_tg.pending_signals.lock_save_irq().set_signal(signal); + target_tg.deliver_signal(signal); } 0 => { @@ -41,7 +38,7 @@ pub fn sys_kill(pid: PidT, signal: UserSigId) -> Result { if let Some(tg) = tg_weak.upgrade() && *tg.pgid.lock_save_irq() == our_pgid { - tg.pending_signals.lock_save_irq().set_signal(signal); + tg.deliver_signal(signal); } } } @@ -55,7 +52,7 @@ pub fn sys_kill(pid: PidT, signal: UserSigId) -> Result { if let Some(tg) = tg_weak.upgrade() && *tg.pgid.lock_save_irq() == target_pgid { - tg.pending_signals.lock_save_irq().set_signal(signal); + tg.deliver_signal(signal); } } } diff --git a/src/sched/uspc_ret.rs b/src/sched/uspc_ret.rs index c87d6de..acc6b5a 100644 --- a/src/sched/uspc_ret.rs +++ b/src/sched/uspc_ret.rs @@ -274,10 +274,7 @@ pub fn dispatch_userspace_task(ctx: *mut UserCtx) { .child_notifiers .child_update(process.tgid, ChildState::Stop { signal }); - parent - .pending_signals - .lock_save_irq() - .set_signal(SigId::SIGCHLD); + parent.deliver_signal(SigId::SIGCHLD); } for thr_weak in process.tasks.lock_save_irq().values() { @@ -313,10 +310,8 @@ pub fn dispatch_userspace_task(ctx: *mut UserCtx) { parent .child_notifiers .child_update(process.tgid, ChildState::Continue); - parent - .pending_signals - .lock_save_irq() - .set_signal(SigId::SIGCHLD); + + parent.deliver_signal(SigId::SIGCHLD); } // Re-process kernel work for this task (there may be more to do). diff --git a/src/sched/waker.rs b/src/sched/waker.rs index 2ae8d07..4bac0ab 100644 --- a/src/sched/waker.rs +++ b/src/sched/waker.rs @@ -26,7 +26,7 @@ unsafe fn wake_waker(data: *const ()) { match *state { // If the task has been put to sleep, then wake it up. - TaskState::Sleeping => { + TaskState::Sleeping | TaskState::Stopped => { if locus == CpuId::this() { *state = TaskState::Runnable; SCHED_STATE.borrow_mut().wakeup(desc);