@@ -645,6 +645,12 @@ func _childProcess() {
645
645
646
646
while let line = _stdlib_getline ( ) {
647
647
let parts = line. _split ( separator: " ; " )
648
+
649
+ if parts [ 0 ] == _stdlibUnittestStreamPrefix {
650
+ precondition ( parts [ 1 ] == " shutdown " )
651
+ return
652
+ }
653
+
648
654
let testSuiteName = parts [ 0 ]
649
655
let testName = parts [ 1 ]
650
656
var testParameter : Int ?
@@ -670,7 +676,7 @@ func _childProcess() {
670
676
}
671
677
672
678
struct _ParentProcess {
673
- internal var _pid : pid_t = - 1
679
+ internal var _pid : pid_t ? = nil
674
680
internal var _childStdin : _FDOutputStream = _FDOutputStream ( fd: - 1 )
675
681
internal var _childStdout : _FDInputStream = _FDInputStream ( fd: - 1 )
676
682
internal var _childStderr : _FDInputStream = _FDInputStream ( fd: - 1 )
@@ -695,8 +701,8 @@ struct _ParentProcess {
695
701
}
696
702
697
703
mutating func _waitForChild( ) -> ProcessTerminationStatus {
698
- let status = posixWaitpid ( _pid)
699
- _pid = - 1
704
+ let status = posixWaitpid ( _pid! )
705
+ _pid = nil
700
706
_childStdin. close ( )
701
707
_childStdout. close ( )
702
708
_childStderr. close ( )
@@ -706,6 +712,49 @@ struct _ParentProcess {
706
712
return status
707
713
}
708
714
715
+ internal mutating func _readFromChild(
716
+ onStdoutLine: ( String ) -> ( done: Bool , Void ) ,
717
+ onStderrLine: ( String ) -> ( done: Bool , Void )
718
+ ) {
719
+ var readfds = _stdlib_fd_set ( )
720
+ var writefds = _stdlib_fd_set ( )
721
+ var errorfds = _stdlib_fd_set ( )
722
+ var done = false
723
+ while !( ( _childStdout. isEOF && _childStderr. isEOF) || done) {
724
+ readfds. zero ( )
725
+ errorfds. zero ( )
726
+ if !_childStdout. isEOF {
727
+ readfds. set ( _childStdout. fd)
728
+ errorfds. set ( _childStdout. fd)
729
+ }
730
+ if !_childStderr. isEOF {
731
+ readfds. set ( _childStderr. fd)
732
+ errorfds. set ( _childStderr. fd)
733
+ }
734
+ var ret : CInt
735
+ repeat {
736
+ ret = _stdlib_select ( & readfds, & writefds, & errorfds, nil )
737
+ } while ret == - 1 && errno == EINTR
738
+ if ret <= 0 {
739
+ fatalError ( " select() returned an error " )
740
+ }
741
+ if readfds. isset ( _childStdout. fd) || errorfds. isset ( _childStdout. fd) {
742
+ _childStdout. read ( )
743
+ while let line = _childStdout. getline ( ) {
744
+ ( done: done, ( ) ) = onStdoutLine ( line)
745
+ }
746
+ continue
747
+ }
748
+ if readfds. isset ( _childStderr. fd) || errorfds. isset ( _childStderr. fd) {
749
+ _childStderr. read ( )
750
+ while let line = _childStderr. getline ( ) {
751
+ ( done: done, ( ) ) = onStderrLine ( line)
752
+ }
753
+ continue
754
+ }
755
+ }
756
+ }
757
+
709
758
/// Returns the values of the corresponding variables in the child process.
710
759
internal mutating func _runTestInChild(
711
760
_ testSuite: TestSuite ,
@@ -714,7 +763,7 @@ struct _ParentProcess {
714
763
) -> ( anyExpectFailed: Bool , seenExpectCrash: Bool ,
715
764
status: ProcessTerminationStatus ? ,
716
765
crashStdout: [ String ] , crashStderr: [ String ] ) {
717
- if _pid <= 0 {
766
+ if _pid == nil {
718
767
_spawnChild ( )
719
768
}
720
769
@@ -733,95 +782,66 @@ struct _ParentProcess {
733
782
_childStdin. close ( )
734
783
}
735
784
736
- var readfds = _stdlib_fd_set ( )
737
- var writefds = _stdlib_fd_set ( )
738
- var errorfds = _stdlib_fd_set ( )
739
785
var stdoutSeenCrashDelimiter = false
740
786
var stderrSeenCrashDelimiter = false
741
787
var stdoutEnd = false
742
788
var stderrEnd = false
743
789
var capturedCrashStdout : [ String ] = [ ]
744
790
var capturedCrashStderr : [ String ] = [ ]
745
791
var anyExpectFailedInChild = false
746
- while !( ( _childStdout. isEOF && _childStderr. isEOF) ||
747
- ( stdoutEnd && stderrEnd) ) {
748
792
749
- readfds. zero ( )
750
- errorfds. zero ( )
751
- if !_childStdout. isEOF {
752
- readfds. set ( _childStdout. fd)
753
- errorfds. set ( _childStdout. fd)
754
- }
755
- if !_childStderr. isEOF {
756
- readfds. set ( _childStderr. fd)
757
- errorfds. set ( _childStderr. fd)
758
- }
759
- var ret : CInt
760
- repeat {
761
- ret = _stdlib_select ( & readfds, & writefds, & errorfds, nil )
762
- } while ret == - 1 && errno == EINTR
763
- if ret <= 0 {
764
- fatalError ( " select() returned an error " )
765
- }
766
- if readfds. isset ( _childStdout. fd) || errorfds. isset ( _childStdout. fd) {
767
- _childStdout. read ( )
768
- while var line = _childStdout. getline ( ) {
769
- if let index = findSubstring ( line, _stdlibUnittestStreamPrefix) {
770
- let controlMessage =
771
- line [ index..< line. endIndex] . _split ( separator: " ; " )
772
- switch controlMessage [ 1 ] {
773
- case " expectCrash " :
774
- stdoutSeenCrashDelimiter = true
775
- anyExpectFailedInChild = controlMessage [ 2 ] == " true "
776
- case " end " :
777
- stdoutEnd = true
778
- anyExpectFailedInChild = controlMessage [ 2 ] == " true "
779
- default :
780
- fatalError ( " unexpected message " )
781
- }
782
- line = line [ line. startIndex..< index]
783
- if line. isEmpty {
784
- continue
785
- }
793
+ func processLine( _ line: String , isStdout: Bool ) -> ( done: Bool , Void ) {
794
+ var line = line
795
+ if let index = findSubstring ( line, _stdlibUnittestStreamPrefix) {
796
+ let controlMessage =
797
+ line [ index..< line. endIndex] . _split ( separator: " ; " )
798
+ switch controlMessage [ 1 ] {
799
+ case " expectCrash " :
800
+ if isStdout {
801
+ stdoutSeenCrashDelimiter = true
802
+ anyExpectFailedInChild = controlMessage [ 2 ] == " true "
803
+ } else {
804
+ stderrSeenCrashDelimiter = true
786
805
}
787
- if stdoutSeenCrashDelimiter {
788
- capturedCrashStdout. append ( line)
806
+ case " end " :
807
+ if isStdout {
808
+ stdoutEnd = true
809
+ anyExpectFailedInChild = controlMessage [ 2 ] == " true "
810
+ } else {
811
+ stderrEnd = true
789
812
}
790
- print ( " stdout>>> \( line) " )
813
+ default :
814
+ fatalError ( " unexpected message " )
815
+ }
816
+ line = line [ line. startIndex..< index]
817
+ if line. isEmpty {
818
+ return ( done: stdoutEnd && stderrEnd, ( ) )
791
819
}
792
- continue
793
820
}
794
- if readfds. isset ( _childStderr. fd) || errorfds. isset ( _childStderr. fd) {
795
- _childStderr. read ( )
796
- while var line = _childStderr. getline ( ) {
797
- if let index = findSubstring ( line, _stdlibUnittestStreamPrefix) {
798
- let controlMessage =
799
- line [ index..< line. endIndex] . _split ( separator: " ; " )
800
- switch controlMessage [ 1 ] {
801
- case " expectCrash " :
802
- stderrSeenCrashDelimiter = true
803
- case " end " :
804
- stderrEnd = true
805
- default :
806
- fatalError ( " unexpected message " )
807
- }
808
- line = line [ line. startIndex..< index]
809
- if line. isEmpty {
810
- continue
811
- }
812
- }
813
- if stderrSeenCrashDelimiter {
814
- capturedCrashStderr. append ( line)
815
- if findSubstring ( line, _crashedPrefix) != nil {
816
- line = " OK: saw expected \" \( line. lowercased ( ) ) \" "
817
- }
821
+ if isStdout {
822
+ if stdoutSeenCrashDelimiter {
823
+ capturedCrashStdout. append ( line)
824
+ }
825
+ } else {
826
+ if stderrSeenCrashDelimiter {
827
+ capturedCrashStderr. append ( line)
828
+ if findSubstring ( line, _crashedPrefix) != nil {
829
+ line = " OK: saw expected \" \( line. lowercased ( ) ) \" "
818
830
}
819
- print ( " stderr>>> \( line) " )
820
831
}
821
- continue
822
832
}
833
+ if isStdout {
834
+ print ( " stdout>>> \( line) " )
835
+ } else {
836
+ print ( " stderr>>> \( line) " )
837
+ }
838
+ return ( done: stdoutEnd && stderrEnd, ( ) )
823
839
}
824
840
841
+ _readFromChild (
842
+ onStdoutLine: { processLine ( $0, isStdout: true ) } ,
843
+ onStderrLine: { processLine ( $0, isStdout: false ) } )
844
+
825
845
// Check if the child has sent us "end" markers for the current test.
826
846
if stdoutEnd && stderrEnd {
827
847
var status : ProcessTerminationStatus ? = nil
@@ -851,6 +871,42 @@ struct _ParentProcess {
851
871
capturedCrashStdout, capturedCrashStderr)
852
872
}
853
873
874
+ internal mutating func _shutdownChild( ) -> ( failed: Bool , Void ) {
875
+ if _pid == nil {
876
+ // The child process is not running. Report that it didn't fail during
877
+ // shutdown.
878
+ return ( failed: false , ( ) )
879
+ }
880
+ print ( " \( _stdlibUnittestStreamPrefix) ;shutdown " , to: & _childStdin)
881
+
882
+ var childCrashed = false
883
+
884
+ func processLine( _ line: String , isStdout: Bool ) -> ( done: Bool , Void ) {
885
+ if isStdout {
886
+ print ( " stdout>>> \( line) " )
887
+ } else {
888
+ if findSubstring ( line, _crashedPrefix) != nil {
889
+ childCrashed = true
890
+ }
891
+ print ( " stderr>>> \( line) " )
892
+ }
893
+ return ( done: false , ( ) )
894
+ }
895
+
896
+ _readFromChild (
897
+ onStdoutLine: { processLine ( $0, isStdout: true ) } ,
898
+ onStderrLine: { processLine ( $0, isStdout: false ) } )
899
+
900
+ let status = _waitForChild ( )
901
+ switch status {
902
+ case . exit( 0 ) :
903
+ return ( failed: childCrashed, ( ) )
904
+ default :
905
+ print ( " Abnormal child process termination: \( status) . " )
906
+ return ( failed: true , ( ) )
907
+ }
908
+ }
909
+
854
910
internal enum _TestStatus {
855
911
case skip( [ TestRunPredicate ] )
856
912
case pass
@@ -1010,6 +1066,11 @@ struct _ParentProcess {
1010
1066
print ( " \( testSuite. name) : All tests passed " )
1011
1067
}
1012
1068
}
1069
+ let ( failed: failedOnShutdown, ( ) ) = _shutdownChild ( )
1070
+ if failedOnShutdown {
1071
+ print ( " The child process failed during shutdown, aborting. " )
1072
+ _testSuiteFailedCallback ( )
1073
+ }
1013
1074
}
1014
1075
}
1015
1076
0 commit comments