Skip to content

Commit 6b2d2ac

Browse files
committed
Fix hang in Linux process termination handler
Calling waitid inside the _childProcessContinuations lock can cause deadlocks in setting up the termination handlers of one process while waiting for another to complete. Instead, only hold the lock when the continuations map is actually being accessed.
1 parent 201f43b commit 6b2d2ac

File tree

1 file changed

+20
-20
lines changed

1 file changed

+20
-20
lines changed

Sources/Subprocess/Platforms/Subprocess+Linux.swift

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -281,26 +281,26 @@ private extension siginfo_t {
281281

282282
private let setup: () = {
283283
signalSource.setEventHandler {
284-
_childProcessContinuations.withLock { continuations in
285-
while true {
286-
var siginfo = siginfo_t()
287-
guard waitid(P_ALL, id_t(0), &siginfo, WEXITED) == 0 else {
288-
return
289-
}
290-
var status: TerminationStatus? = nil
291-
switch siginfo.si_code {
292-
case .init(CLD_EXITED):
293-
status = .exited(siginfo.si_status)
294-
case .init(CLD_KILLED), .init(CLD_DUMPED):
295-
status = .unhandledException(siginfo.si_status)
296-
case .init(CLD_TRAPPED), .init(CLD_STOPPED), .init(CLD_CONTINUED):
297-
// Ignore these signals because they are not related to
298-
// process exiting
299-
break
300-
default:
301-
fatalError("Unexpected exit status: \(siginfo.si_code)")
302-
}
303-
if let status = status {
284+
while true {
285+
var siginfo = siginfo_t()
286+
guard waitid(P_ALL, id_t(0), &siginfo, WEXITED) == 0 || errno == EINTR else {
287+
return
288+
}
289+
var status: TerminationStatus? = nil
290+
switch siginfo.si_code {
291+
case .init(CLD_EXITED):
292+
status = .exited(siginfo.si_status)
293+
case .init(CLD_KILLED), .init(CLD_DUMPED):
294+
status = .unhandledException(siginfo.si_status)
295+
case .init(CLD_TRAPPED), .init(CLD_STOPPED), .init(CLD_CONTINUED):
296+
// Ignore these signals because they are not related to
297+
// process exiting
298+
break
299+
default:
300+
fatalError("Unexpected exit status: \(siginfo.si_code)")
301+
}
302+
if let status = status {
303+
_childProcessContinuations.withLock { continuations in
304304
let pid = siginfo.si_pid
305305
if let existing = continuations.removeValue(forKey: pid),
306306
case .continuation(let c) = existing

0 commit comments

Comments
 (0)