@@ -642,18 +642,8 @@ open class Process: NSObject {
642
642
process. _terminationReason = . exit
643
643
}
644
644
645
- if let handler = process. terminationHandler {
646
- let thread : Thread = Thread { handler ( process) }
647
- thread. start ( )
648
- }
649
-
650
- process. isRunning = false
651
-
652
- // Invalidate the source and wake up the run loop, if it is available
653
- CFRunLoopSourceInvalidate ( process. runLoopSource)
654
- if let runloop = process. runLoop {
655
- CFRunLoopWakeUp ( runloop. _cfRunLoop)
656
- }
645
+ // Signal waitUntilExit() and optionally invoke termination handler.
646
+ process. terminateRunLoop ( )
657
647
658
648
CFSocketInvalidate ( socket)
659
649
} , & context)
@@ -829,28 +819,12 @@ open class Process: NSObject {
829
819
process. _terminationReason = . exit
830
820
}
831
821
832
- // Set the running flag to false
833
- process. isRunning = false
834
-
835
- // If a termination handler has been set, invoke it on a background thread
836
-
837
- if let terminationHandler = process. terminationHandler {
838
- let thread = Thread {
839
- terminationHandler ( process)
840
- }
841
- thread. start ( )
842
- }
843
-
844
- // Invalidate the source and wake up the run loop, if it's available
845
-
846
- CFRunLoopSourceInvalidate ( process. runLoopSource)
847
- if let runLoop = process. runLoop {
848
- CFRunLoopWakeUp ( runLoop. _cfRunLoop)
849
- }
822
+ // Signal waitUntilExit() and optionally invoke termination handler.
823
+ process. terminateRunLoop ( )
850
824
851
825
CFSocketInvalidate ( socket )
852
826
853
- } , & context )
827
+ } , & context )
854
828
855
829
CFSocketSetSocketFlags ( socket, CFOptionFlags ( kCFSocketCloseOnInvalidate) )
856
830
@@ -1165,6 +1139,26 @@ open class Process: NSObject {
1165
1139
self . runLoop = nil
1166
1140
self . runLoopSource = nil
1167
1141
}
1142
+
1143
+ private func terminateRunLoop( ) {
1144
+ // Ensure that the run loop source is invalidated before we mark the process
1145
+ // as no longer running. This serves as a semaphore to
1146
+ // `waitUntilExit` to decrement the `runLoopSource` retain count,
1147
+ // potentially releasing it.
1148
+ CFRunLoopSourceInvalidate ( self . runLoopSource)
1149
+ let runloopToWakeup = self . runLoop
1150
+ self . isRunning = false
1151
+
1152
+ // Wake up the run loop, *AFTER* clearing .isRunning to avoid an extra time out period.
1153
+ if let cfRunLoop = runloopToWakeup? . _cfRunLoop {
1154
+ CFRunLoopWakeUp ( cfRunLoop)
1155
+ }
1156
+
1157
+ if let handler = self . terminationHandler {
1158
+ let thread : Thread = Thread { handler ( self ) }
1159
+ thread. start ( )
1160
+ }
1161
+ }
1168
1162
}
1169
1163
1170
1164
extension Process {
0 commit comments