Skip to content

Commit 2ef2c6d

Browse files
committed
fix(signal): preserve fatal thread-group semantics
Start fatal group exit for thread-directed signals as Linux does, so tgkill(SIGKILL) cannot terminate only the selected pthread and leave its process leader alive. Separate the private SIGKILL used by de_thread and an already-committed group exit from ordinary signal delivery. This keeps exec sibling teardown local without confusing external fatal signals or re-entering group-exit selection. Signed-off-by: longjin <longjin@dragonos.org>
1 parent a02db36 commit 2ef2c6d

4 files changed

Lines changed: 15 additions & 25 deletions

File tree

kernel/src/ipc/generic_signal.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -407,14 +407,14 @@ fn sig_terminate(sig: Signal) {
407407

408408
if sig == Signal::SIGKILL {
409409
let current = ProcessManager::current_pcb();
410-
if !current.is_thread_group_leader() {
411-
// 线程级 SIGKILL:仅终止当前线程,避免误杀整个线程组
412-
ProcessManager::exit(sig as usize);
413-
}
414410
let sighand = current.sighand();
415411
if sighand.flags_contains(SignalFlags::GROUP_EXEC) {
416412
if let Some(exec_task) = sighand.group_exec_task() {
417413
if !Arc::ptr_eq(&exec_task, &current) {
414+
// de_thread() privately injects SIGKILL into the siblings
415+
// that the exec owner is replacing. Only those siblings
416+
// exit individually; an externally delivered SIGKILL
417+
// targeting the exec owner remains process-fatal.
418418
ProcessManager::exit(sig as usize);
419419
}
420420
}

kernel/src/ipc/signal.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -466,9 +466,7 @@ impl Signal {
466466
return;
467467
};
468468

469-
if !is_thread_target
470-
&& self.start_fatal_group_exit_if_needed(pcb.clone(), target_pcb.clone())
471-
{
469+
if self.start_fatal_group_exit_if_needed(pcb.clone(), target_pcb.clone()) {
472470
return;
473471
}
474472

@@ -495,7 +493,7 @@ impl Signal {
495493

496494
let tasks = ProcessManager::thread_group_tasks_snapshot(target);
497495
for task in tasks {
498-
Self::queue_group_kill_to_thread(&task);
496+
Self::queue_private_sigkill_to_thread(&task);
499497
}
500498

501499
true
@@ -525,7 +523,13 @@ impl Signal {
525523
true
526524
}
527525

528-
fn queue_group_kill_to_thread(task: &Arc<ProcessControlBlock>) {
526+
/// Queue the private SIGKILL used after the kernel has already committed
527+
/// to tearing down sibling threads for group-exit or de_thread().
528+
///
529+
/// Unlike normal signal delivery, this must not run complete_signal()
530+
/// again: during de_thread() the exec owner is intentionally preserved,
531+
/// while during group-exit the shared exit state is already committed.
532+
pub(crate) fn queue_private_sigkill_to_thread(task: &Arc<ProcessControlBlock>) {
529533
if task.flags().contains(ProcessFlags::EXITING) || task.is_zombie() || task.is_dead() {
530534
return;
531535
}

kernel/src/process/exec.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@ fn de_thread(pcb: &Arc<ProcessControlBlock>) -> Result<(), SystemError> {
402402
}
403403

404404
for task in kill_list {
405-
let _ = Signal::SIGKILL.send_signal_info_to_pcb(None, task, PidType::PID);
405+
Signal::queue_private_sigkill_to_thread(&task);
406406
}
407407

408408
let pending_wait = sighand.wait_group_exec_event_killable(

kernel/src/process/manager/exit.rs

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ use crate::{
1515
driver::tty::tty_job_control::TtyJobCtrlManager,
1616
exception::InterruptArch,
1717
ipc::sighand::{NaturalParentNotifyToken, ReapTransition},
18-
ipc::signal_types::{SigCode, SigInfo, SigType},
1918
libs::futex::{
2019
constant::{FutexFlag, FUTEX_BITSET_MATCH_ANY},
2120
futex::{Futex, RobustListHead},
@@ -476,20 +475,7 @@ impl ProcessManager {
476475
if task.flags().contains(ProcessFlags::EXITING) {
477476
return;
478477
}
479-
let mut info = SigInfo::new(
480-
Signal::SIGKILL,
481-
0,
482-
SigCode::Kernel,
483-
SigType::Kill {
484-
pid: RawPid::new(0),
485-
uid: 0,
486-
},
487-
);
488-
let _ = Signal::SIGKILL.send_signal_info_to_pcb(
489-
Some(&mut info),
490-
task,
491-
PidType::PID,
492-
);
478+
Signal::queue_private_sigkill_to_thread(&task);
493479
};
494480

495481
// Obtain the full thread list from the thread group leader's

0 commit comments

Comments
 (0)