Skip to content

Commit 93439ee

Browse files
committed
Fix timeout on Linux: use SIGINT and elapsed-time detection
1 parent 86cedf7 commit 93439ee

1 file changed

Lines changed: 10 additions & 5 deletions

File tree

Sources/Core/ShellExecutor.swift

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public struct ShellExecutor: Sendable {
4141
}
4242

4343
/// Run a shell command and capture stdout, stderr, and exit code.
44-
/// Optionally terminates the process via SIGTERM if the timeout deadline passes.
44+
/// Terminates the process via SIGINT if the timeout deadline passes.
4545
public func execute(
4646
_ command: String,
4747
timeout: TimeInterval? = nil
@@ -64,13 +64,16 @@ public struct ShellExecutor: Sendable {
6464

6565
try process.run()
6666

67+
let startTime = DispatchTime.now()
6768
var timer: DispatchSourceTimer?
6869
if let timeout {
6970
let source = DispatchSource.makeTimerSource()
7071
source.schedule(deadline: .now() + timeout)
7172
source.setEventHandler {
7273
if process.isRunning {
73-
process.terminate()
74+
// SIGINT: bash forwards to child process group on both macOS and Linux.
75+
// SIGTERM doesn't work reliably — bash waits for children to finish.
76+
process.interrupt()
7477
}
7578
}
7679
source.resume()
@@ -85,9 +88,11 @@ public struct ShellExecutor: Sendable {
8588
timer?.cancel()
8689

8790
if let timeout {
88-
let wasTerminated =
89-
process.terminationReason == .uncaughtSignal && process.terminationStatus == SIGTERM
90-
if wasTerminated {
91+
let elapsedSeconds =
92+
Double(
93+
DispatchTime.now().uptimeNanoseconds - startTime.uptimeNanoseconds
94+
) / 1_000_000_000
95+
if elapsedSeconds >= timeout {
9196
throw ShellExecutorError.timeout(seconds: Int(timeout))
9297
}
9398
}

0 commit comments

Comments
 (0)