@@ -78,25 +78,34 @@ public struct Configuration: Sendable {
78
78
79
79
let processIdentifier = _spawnResult. execution. processIdentifier
80
80
81
- let result = try await withAsyncTaskCleanupHandler {
82
- let inputIO = _spawnResult. inputWriteEnd ( )
83
- let outputIO = _spawnResult. outputReadEnd ( )
84
- let errorIO = _spawnResult. errorReadEnd ( )
85
-
86
- // Body runs in the same isolation
87
- return try await body ( _spawnResult. execution, inputIO, outputIO, errorIO)
88
- } onCleanup: {
89
- // Attempt to terminate the child process
90
- await Execution . runTeardownSequence (
91
- self . platformOptions. teardownSequence,
92
- on: pid
93
- )
81
+ let result : Swift . Result < Result , Error >
82
+ do {
83
+ result = try await . success( withAsyncTaskCleanupHandler {
84
+ let inputIO = _spawnResult. inputWriteEnd ( )
85
+ let outputIO = _spawnResult. outputReadEnd ( )
86
+ let errorIO = _spawnResult. errorReadEnd ( )
87
+
88
+ // Body runs in the same isolation
89
+ return try await body ( _spawnResult. execution, inputIO, outputIO, errorIO)
90
+ } onCleanup: {
91
+ // Attempt to terminate the child process
92
+ await Execution . runTeardownSequence (
93
+ self . platformOptions. teardownSequence,
94
+ on: pid
95
+ )
96
+ } )
97
+ } catch {
98
+ result = . failure( error)
94
99
}
95
100
96
- return ExecutionResult (
97
- terminationStatus: try await monitorProcessTermination ( forProcessWithIdentifier: processIdentifier) ,
98
- value: result
99
- )
101
+ // Ensure that we begin monitoring process termination after `body` runs
102
+ // and regardless of whether `body` throws, so that the pid gets reaped
103
+ // even if `body` throws, and we are not leaving zombie processes in the
104
+ // process table which will cause the process termination monitoring thread
105
+ // to effectively hang due to the pid never being awaited
106
+ let terminationStatus = try await Subprocess . monitorProcessTermination ( forProcessWithIdentifier: processIdentifier)
107
+
108
+ return try ExecutionResult ( terminationStatus: terminationStatus, value: result. get ( ) )
100
109
}
101
110
}
102
111
0 commit comments