1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-31 13:07:46 +00:00

Merge pull request #6061 from cre4ture/fix/flaky_timeout_kill_subprocess

Fix/flaky timeout kill subprocess
This commit is contained in:
Sylvestre Ledru 2024-03-13 11:13:09 +01:00 committed by GitHub
commit f89cfe2a5e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 31 additions and 11 deletions

View file

@ -202,14 +202,15 @@ fn send_signal(process: &mut Child, signal: usize, foreground: bool) {
// NOTE: GNU timeout doesn't check for errors of signal. // NOTE: GNU timeout doesn't check for errors of signal.
// The subprocess might have exited just after the timeout. // The subprocess might have exited just after the timeout.
// Sending a signal now would return "No such process", but we should still try to kill the children. // Sending a signal now would return "No such process", but we should still try to kill the children.
_ = process.send_signal(signal); match foreground {
if !foreground { true => _ = process.send_signal(signal),
_ = process.send_signal_group(signal); false => {
let kill_signal = signal_by_name_or_value("KILL").unwrap(); _ = process.send_signal_group(signal);
let continued_signal = signal_by_name_or_value("CONT").unwrap(); let kill_signal = signal_by_name_or_value("KILL").unwrap();
if signal != kill_signal && signal != continued_signal { let continued_signal = signal_by_name_or_value("CONT").unwrap();
_ = process.send_signal(continued_signal); if signal != kill_signal && signal != continued_signal {
_ = process.send_signal_group(continued_signal); _ = process.send_signal_group(continued_signal);
}
} }
} }
} }
@ -342,8 +343,15 @@ fn timeout(
send_signal(process, signal, foreground); send_signal(process, signal, foreground);
match kill_after { match kill_after {
None => { None => {
let status = process.wait()?;
if preserve_status { if preserve_status {
Err(ExitStatus::SignalSent(signal).into()) if let Some(ec) = status.code() {
Err(ec.into())
} else if let Some(sc) = status.signal() {
Err(ExitStatus::SignalSent(sc.try_into().unwrap()).into())
} else {
Err(ExitStatus::CommandTimedOut.into())
}
} else { } else {
Err(ExitStatus::CommandTimedOut.into()) Err(ExitStatus::CommandTimedOut.into())
} }

View file

@ -93,6 +93,18 @@ fn test_preserve_status() {
.no_stdout(); .no_stdout();
} }
#[test]
fn test_preserve_status_even_when_send_signal() {
// When sending CONT signal, process doesn't get killed or stopped.
// So, expected result is success and code 0.
new_ucmd!()
.args(&["-s", "CONT", "--preserve-status", ".1", "sleep", "5"])
.succeeds()
.code_is(0)
.no_stderr()
.no_stdout();
}
#[test] #[test]
fn test_dont_overflow() { fn test_dont_overflow() {
new_ucmd!() new_ucmd!()
@ -151,10 +163,10 @@ fn test_kill_subprocess() {
"10", "10",
"sh", "sh",
"-c", "-c",
"sh -c \"trap 'echo xyz' TERM; sleep 30\"", "trap 'echo inside_trap' TERM; sleep 30",
]) ])
.fails() .fails()
.code_is(124) .code_is(124)
.stdout_contains("xyz") .stdout_contains("inside_trap")
.stderr_contains("Terminated"); .stderr_contains("Terminated");
} }