@@ -576,7 +576,7 @@ open class Process: NSObject {
576
576
577
577
var environment : [ String : String ] = [ : ]
578
578
if let env = self . environment {
579
- environment = env
579
+ environment = env
580
580
} else {
581
581
environment = ProcessInfo . processInfo. environment
582
582
}
@@ -600,67 +600,65 @@ open class Process: NSObject {
600
600
context. release = runLoopSourceRelease
601
601
context. info = Unmanaged . passUnretained ( self ) . toOpaque ( )
602
602
603
- let socket : CFSocket =
604
- CFSocketCreateWithNative ( nil , CFSocketNativeHandle ( sockets. first) , CFOptionFlags ( kCFSocketDataCallBack) , { ( socket, type, address, data, info) in
605
- let process : Process = NSObject . unretainedReference ( info!)
606
- process. processLaunchedCondition. lock ( )
607
- while process. isRunning == false {
608
- process. processLaunchedCondition. wait ( )
609
- }
610
- process. processLaunchedCondition. unlock ( )
611
-
612
- WaitForSingleObject ( process. processHandle, WinSDK . INFINITE)
613
-
614
- // On Windows, the top nibble of an NTSTATUS indicates severity, with
615
- // the top two bits both being set (0b11) indicating an error. In
616
- // addition, in a well formed NTSTATUS, the 4th bit must be 0.
617
- // The third bit indicates if the error is a Microsoft defined error
618
- // and may or may not be set.
619
- //
620
- // If we receive such an error, we'll indicate that the process
621
- // exited abnormally (confusingly indicating "signalled" so we match
622
- // POSIX behaviour for abnormal exits).
623
- //
624
- // However, we don't want user programs which normally exit -1, -2,
625
- // etc to count as exited abnormally, so we specifically check for a
626
- // top nibble of 0b11_0 so that e.g. 0xFFFFFFFF, won't trigger an
627
- // abnormal exit.
628
- //
629
- // Additionally, on Windows, an uncaught signal terminates the
630
- // program with the magic exit code 3, regardless of the signal (I'd
631
- // personally love to know the reason for this). So we also consider
632
- // 3 to be an abnormal exit.
633
- var dwExitCode : DWORD = 0
634
- GetExitCodeProcess ( process. processHandle, & dwExitCode)
635
- if ( dwExitCode & 0xF0000000 ) == 0xC0000000
603
+ let socket : CFSocket = CFSocketCreateWithNative ( nil , CFSocketNativeHandle ( sockets. first) , CFOptionFlags ( kCFSocketDataCallBack) , { ( socket, type, address, data, info) in
604
+ let process : Process = NSObject . unretainedReference ( info!)
605
+ process. processLaunchedCondition. lock ( )
606
+ while process. isRunning == false {
607
+ process. processLaunchedCondition. wait ( )
608
+ }
609
+ process. processLaunchedCondition. unlock ( )
610
+
611
+ WaitForSingleObject ( process. processHandle, WinSDK . INFINITE)
612
+
613
+ // On Windows, the top nibble of an NTSTATUS indicates severity, with
614
+ // the top two bits both being set (0b11) indicating an error. In
615
+ // addition, in a well formed NTSTATUS, the 4th bit must be 0.
616
+ // The third bit indicates if the error is a Microsoft defined error
617
+ // and may or may not be set.
618
+ //
619
+ // If we receive such an error, we'll indicate that the process
620
+ // exited abnormally (confusingly indicating "signalled" so we match
621
+ // POSIX behaviour for abnormal exits).
622
+ //
623
+ // However, we don't want user programs which normally exit -1, -2,
624
+ // etc to count as exited abnormally, so we specifically check for a
625
+ // top nibble of 0b11_0 so that e.g. 0xFFFFFFFF, won't trigger an
626
+ // abnormal exit.
627
+ //
628
+ // Additionally, on Windows, an uncaught signal terminates the
629
+ // program with the magic exit code 3, regardless of the signal (I'd
630
+ // personally love to know the reason for this). So we also consider
631
+ // 3 to be an abnormal exit.
632
+ var dwExitCode : DWORD = 0
633
+ GetExitCodeProcess ( process. processHandle, & dwExitCode)
634
+ if ( dwExitCode & 0xF0000000 ) == 0xC0000000
636
635
|| ( dwExitCode & 0xF0000000 ) == 0xE0000000
637
636
|| dwExitCode == 3 {
638
- process. _terminationStatus = Int32 ( dwExitCode & 0x3FFFFFFF )
639
- process. _terminationReason = . uncaughtSignal
640
- } else {
641
- process. _terminationStatus = Int32 ( bitPattern: dwExitCode)
642
- process. _terminationReason = . exit
643
- }
637
+ process. _terminationStatus = Int32 ( dwExitCode & 0x3FFFFFFF )
638
+ process. _terminationReason = . uncaughtSignal
639
+ } else {
640
+ process. _terminationStatus = Int32 ( bitPattern: dwExitCode)
641
+ process. _terminationReason = . exit
642
+ }
644
643
645
- if let handler = process. terminationHandler {
646
- let thread : Thread = Thread { handler ( process) }
647
- thread. start ( )
648
- }
644
+ if let handler = process. terminationHandler {
645
+ let thread : Thread = Thread { handler ( process) }
646
+ thread. start ( )
647
+ }
649
648
650
- process. isRunning = false
649
+ process. isRunning = false
651
650
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
- }
651
+ // Invalidate the source and wake up the run loop, if it is available
652
+ CFRunLoopSourceInvalidate ( process. runLoopSource)
653
+ if let runloop = process. runLoop {
654
+ CFRunLoopWakeUp ( runloop. _cfRunLoop)
655
+ }
657
656
658
- CFSocketInvalidate ( socket)
657
+ CFSocketInvalidate ( socket)
659
658
} , & context)
660
659
CFSocketSetSocketFlags ( socket, CFOptionFlags ( kCFSocketCloseOnInvalidate) )
661
660
662
- let source : CFRunLoopSource =
663
- CFSocketCreateRunLoopSource ( kCFAllocatorDefault, socket, 0 )
661
+ let source : CFRunLoopSource = CFSocketCreateRunLoopSource ( kCFAllocatorDefault, socket, 0 )
664
662
CFRunLoopAddSource ( managerThreadRunLoop? . _cfRunLoop, source, kCFRunLoopDefaultMode)
665
663
666
664
let workingDirectory = currentDirectoryURL? . path ?? FileManager . default. currentDirectoryPath
@@ -1153,10 +1151,15 @@ open class Process: NSObject {
1153
1151
1154
1152
// poll the runLoop in defaultMode until process completes
1155
1153
open func waitUntilExit( ) {
1156
-
1157
- repeat {
1158
-
1159
- } while ( self . isRunning == true && RunLoop . current. run ( mode: . default, before: Date ( timeIntervalSinceNow: 0.05 ) ) )
1154
+ let runInterval = 0.05
1155
+ let currentRunLoop = RunLoop . current
1156
+ let checkRunLoop : ( ) -> Bool = ( currentRunLoop == self . runLoop)
1157
+ ? { currentRunLoop. run ( mode: . default, before: Date ( timeIntervalSinceNow: runInterval) ) }
1158
+ : { currentRunLoop. run ( until: Date ( timeIntervalSinceNow: runInterval) ) ; return true }
1159
+
1160
+ // update .runLoop to allow early wakeup.
1161
+ self . runLoop = currentRunLoop
1162
+ while self . isRunning && checkRunLoop ( ) { }
1160
1163
1161
1164
self . runLoop = nil
1162
1165
self . runLoopSource = nil
0 commit comments