Fix SIGSTOP panic, ignore sigs for exited procs.

This commit is contained in:
4lDO2
2025-09-10 19:29:01 +02:00
parent bed0b52961
commit 3354a9148d
+36 -5
View File
@@ -926,7 +926,7 @@ impl<'a> ProcScheme<'a> {
}
Handle::Proc(fd_pid) => {
let Some(verb) = ProcCall::try_from_raw(metadata[0] as usize) else {
log::info!("Invalid proc call: {metadata:?}");
log::trace!("Invalid proc call: {metadata:?}");
return Response::ready_err(EINVAL, op);
};
fn cvt_u32(u: u32) -> Option<u32> {
@@ -1066,7 +1066,7 @@ impl<'a> ProcScheme<'a> {
Handle::Ps(_) => Response::ready_err(EOPNOTSUPP, op),
Handle::ProcCredsCapability => {
let Some(verb) = ProcCall::try_from_raw(metadata[0] as usize) else {
log::info!("Invalid proc call: {metadata:?}");
log::trace!("Invalid proc call: {metadata:?}");
return Response::ready_err(EINVAL, op);
};
match verb {
@@ -1278,6 +1278,7 @@ impl<'a> ProcScheme<'a> {
awoken: &mut VecDeque<VirtualId>,
tag: Option<Tag>,
) -> Poll<Response> {
log::trace!("ON_EXIT_START {pid:?} status {status:#x}");
let Some(proc_rc) = self.processes.get(&pid) else {
return if let Some(tag) = tag {
Response::ready_err(EBADFD, tag)
@@ -2060,10 +2061,25 @@ impl<'a> ProcScheme<'a> {
return SendResult::Succeeded;
};
// Similarly, don't send anything for already exiting or exited processes. It would be
// bad if e.g. SIGCONT could cause these to become PossiblyRunnable again.
if matches!(
target_proc.status,
ProcessStatus::Exited { .. } | ProcessStatus::Exiting { .. }
) {
return SendResult::Succeeded;
}
let Some(mut sig_pctl) = target_proc.sig_pctl.as_ref() else {
log::trace!("No pctl {caller_pid:?} => {target_pid:?}");
return SendResult::Invalid;
};
log::trace!("PCTL {:#x?}", &**sig_pctl);
log::trace!(
"STS {:?} NTHRD {}",
target_proc.status,
target_proc.threads.len()
);
if sig == SIGCONT
&& let ProcessStatus::Stopped(_sig) = target_proc.status
@@ -2130,11 +2146,23 @@ impl<'a> ProcScheme<'a> {
for thread in &target_proc.threads {
let thread = thread.borrow();
let _ = syscall::write(
match syscall::write(
*thread.status_hndl,
&(ContextVerb::Stop as usize).to_ne_bytes(),
)
.expect("TODO");
) {
Ok(_) => (),
// TODO: Write a test that this actually results in the thread eventually
// being removed from `threads`. A "dead thread" event should already have
// been triggered, but it is possible that happens during this code, or
// just before that event.
//
// Thread has state Dead, so ignore.
Err(Error { errno: EOWNERDEAD }) => continue,
Err(other) => {
log::error!("Unexpected error when stopping context: {other}, pid {target_pid:?} thread fd {}", *thread.status_hndl);
continue;
}
}
if let Some(ref tctl) = thread.sig_ctrl {
tctl.word[0].fetch_and(!sig_bit(SIGCONT), Ordering::Relaxed);
}
@@ -2145,6 +2173,7 @@ impl<'a> ProcScheme<'a> {
.pending
.fetch_and(!sig_bit(SIGCONT), Ordering::Relaxed);
log::trace!("SUCCEEDED SIGCHILD MY_PID {target_pid:?}");
return SendResult::SucceededSigchld {
orig_signal: nz_signal,
ppid: target_proc.ppid,
@@ -2238,6 +2267,7 @@ impl<'a> ProcScheme<'a> {
let Some(ref tctl) = thread.sig_ctrl else {
continue;
};
log::trace!("TCTL {:#x?}", &**tctl);
if (tctl.word[sig_group].load(Ordering::Relaxed) >> 32) & sig_bit(sig)
!= 0
{
@@ -2300,6 +2330,7 @@ impl<'a> ProcScheme<'a> {
}
// TODO(err): Just ignore EINVAL (missing signal config), otherwise handle error?
if ppid != INIT_PID {
log::trace!("SIGCHLDing {ppid:?}");
if let Err(err) = self.on_send_sig(
INIT_PID, // caller, TODO?
KillTarget::Proc(ppid),