Skip to content

Commit f89cfe2

Browse files
authored
Merge pull request #6061 from cre4ture/fix/flaky_timeout_kill_subprocess
Fix/flaky timeout kill subprocess
2 parents eaa8458 + 7e22f99 commit f89cfe2

File tree

2 files changed

+31
-11
lines changed

2 files changed

+31
-11
lines changed

src/uu/timeout/src/timeout.rs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -202,14 +202,15 @@ fn send_signal(process: &mut Child, signal: usize, foreground: bool) {
202202
// NOTE: GNU timeout doesn't check for errors of signal.
203203
// The subprocess might have exited just after the timeout.
204204
// Sending a signal now would return "No such process", but we should still try to kill the children.
205-
_ = process.send_signal(signal);
206-
if !foreground {
207-
_ = process.send_signal_group(signal);
208-
let kill_signal = signal_by_name_or_value("KILL").unwrap();
209-
let continued_signal = signal_by_name_or_value("CONT").unwrap();
210-
if signal != kill_signal && signal != continued_signal {
211-
_ = process.send_signal(continued_signal);
212-
_ = process.send_signal_group(continued_signal);
205+
match foreground {
206+
true => _ = process.send_signal(signal),
207+
false => {
208+
_ = process.send_signal_group(signal);
209+
let kill_signal = signal_by_name_or_value("KILL").unwrap();
210+
let continued_signal = signal_by_name_or_value("CONT").unwrap();
211+
if signal != kill_signal && signal != continued_signal {
212+
_ = process.send_signal_group(continued_signal);
213+
}
213214
}
214215
}
215216
}
@@ -342,8 +343,15 @@ fn timeout(
342343
send_signal(process, signal, foreground);
343344
match kill_after {
344345
None => {
346+
let status = process.wait()?;
345347
if preserve_status {
346-
Err(ExitStatus::SignalSent(signal).into())
348+
if let Some(ec) = status.code() {
349+
Err(ec.into())
350+
} else if let Some(sc) = status.signal() {
351+
Err(ExitStatus::SignalSent(sc.try_into().unwrap()).into())
352+
} else {
353+
Err(ExitStatus::CommandTimedOut.into())
354+
}
347355
} else {
348356
Err(ExitStatus::CommandTimedOut.into())
349357
}

tests/by-util/test_timeout.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,18 @@ fn test_preserve_status() {
9393
.no_stdout();
9494
}
9595

96+
#[test]
97+
fn test_preserve_status_even_when_send_signal() {
98+
// When sending CONT signal, process doesn't get killed or stopped.
99+
// So, expected result is success and code 0.
100+
new_ucmd!()
101+
.args(&["-s", "CONT", "--preserve-status", ".1", "sleep", "5"])
102+
.succeeds()
103+
.code_is(0)
104+
.no_stderr()
105+
.no_stdout();
106+
}
107+
96108
#[test]
97109
fn test_dont_overflow() {
98110
new_ucmd!()
@@ -151,10 +163,10 @@ fn test_kill_subprocess() {
151163
"10",
152164
"sh",
153165
"-c",
154-
"sh -c \"trap 'echo xyz' TERM; sleep 30\"",
166+
"trap 'echo inside_trap' TERM; sleep 30",
155167
])
156168
.fails()
157169
.code_is(124)
158-
.stdout_contains("xyz")
170+
.stdout_contains("inside_trap")
159171
.stderr_contains("Terminated");
160172
}

0 commit comments

Comments
 (0)