@@ -15,11 +15,133 @@ import SwiftPrivate
15
15
import Darwin
16
16
#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) || os(Haiku)
17
17
import Glibc
18
+ #elseif os(Windows)
19
+ import MSVCRT
20
+ import WinSDK
18
21
#endif
19
22
20
-
23
+ internal func _signalToString( _ signal: Int ) -> String {
24
+ switch CInt ( signal) {
25
+ case SIGILL: return " SIGILL "
26
+ case SIGABRT: return " SIGABRT "
27
+ case SIGFPE: return " SIGFPE "
28
+ case SIGSEGV: return " SIGSEGV "
21
29
#if !os(Windows)
22
- // posix_spawn is not available on Windows.
30
+ case SIGTRAP: return " SIGTRAP "
31
+ case SIGBUS: return " SIGBUS "
32
+ case SIGSYS: return " SIGSYS "
33
+ #endif
34
+ default : return " SIG???? ( \( signal) ) "
35
+ }
36
+ }
37
+
38
+ public enum ProcessTerminationStatus : CustomStringConvertible {
39
+ case exit( Int )
40
+ case signal( Int )
41
+
42
+ public var description : String {
43
+ switch self {
44
+ case . exit( let status) :
45
+ return " Exit( \( status) ) "
46
+ case . signal( let signal) :
47
+ return " Signal( \( _signalToString ( signal) ) ) "
48
+ }
49
+ }
50
+ }
51
+
52
+
53
+ #if os(Windows)
54
+ public func spawnChild( _ args: [ String ] )
55
+ -> ( process: HANDLE , stdin: HANDLE , stdout: HANDLE , stderr: HANDLE ) {
56
+ var _stdin : ( read: HANDLE ? , write: HANDLE ? )
57
+ var _stdout : ( read: HANDLE ? , write: HANDLE ? )
58
+ var _stderr : ( read: HANDLE ? , write: HANDLE ? )
59
+
60
+ var saAttributes : SECURITY_ATTRIBUTES = SECURITY_ATTRIBUTES ( )
61
+ saAttributes. nLength = DWORD ( MemoryLayout< SECURITY_ATTRIBUTES> . size)
62
+ saAttributes. bInheritHandle = TRUE
63
+ saAttributes. lpSecurityDescriptor = nil
64
+
65
+ if CreatePipe ( & _stdin. read, & _stdin. write, & saAttributes, 0 ) == FALSE {
66
+ fatalError ( " CreatePipe() failed " )
67
+ }
68
+ if SetHandleInformation ( _stdin. write, HANDLE_FLAG_INHERIT, 0 ) == FALSE {
69
+ fatalError ( " SetHandleInformation() failed " )
70
+ }
71
+
72
+ if CreatePipe ( & _stdout. read, & _stdout. write, & saAttributes, 0 ) == FALSE {
73
+ fatalError ( " CreatePipe() failed " )
74
+ }
75
+ if SetHandleInformation ( _stdout. read, HANDLE_FLAG_INHERIT, 0 ) == FALSE {
76
+ fatalError ( " SetHandleInformation() failed " )
77
+ }
78
+
79
+ if CreatePipe ( & _stderr. read, & _stderr. write, & saAttributes, 0 ) == FALSE {
80
+ fatalError ( " CreatePipe() failed " )
81
+ }
82
+ if SetHandleInformation ( _stderr. read, HANDLE_FLAG_INHERIT, 0 ) == FALSE {
83
+ fatalError ( " SetHandleInformation() failed " )
84
+ }
85
+
86
+ var siStartupInfo : STARTUPINFOW = STARTUPINFOW ( )
87
+ siStartupInfo. cb = DWORD ( MemoryLayout< STARTUPINFOW> . size)
88
+ siStartupInfo. hStdError = _stderr. write
89
+ siStartupInfo. hStdOutput = _stdout. write
90
+ siStartupInfo. hStdInput = _stdin. read
91
+ siStartupInfo. dwFlags |= STARTF_USESTDHANDLES
92
+
93
+ var piProcessInfo : PROCESS_INFORMATION = PROCESS_INFORMATION ( )
94
+
95
+ // TODO(compnerd): properly quote the command line being invoked here. See
96
+ // https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/
97
+ // for more details on how to properly quote the command line for Windows.
98
+ let command : String =
99
+ ( [ CommandLine . arguments [ 0 ] ] + args) . joined ( separator: " " )
100
+ command. withCString ( encodedAs: UTF16 . self) { cString in
101
+ if CreateProcessW ( nil , UnsafeMutablePointer < WCHAR > ( mutating: cString) ,
102
+ nil , nil , TRUE, 0 , nil , nil ,
103
+ & siStartupInfo, & piProcessInfo) == FALSE {
104
+ let dwError : DWORD = GetLastError ( )
105
+ fatalError ( " CreateProcessW() failed \( dwError) " )
106
+ }
107
+ }
108
+
109
+ if CloseHandle ( _stdin. read) == FALSE {
110
+ fatalError ( " CloseHandle() failed " )
111
+ }
112
+ if CloseHandle ( _stdout. write) == FALSE {
113
+ fatalError ( " CloseHandle() failed " )
114
+ }
115
+ if CloseHandle ( _stderr. write) == FALSE {
116
+ fatalError ( " CloseHandle() failed " )
117
+ }
118
+
119
+ // CloseHandle(piProcessInfo.hProcess)
120
+ CloseHandle ( piProcessInfo. hThread)
121
+
122
+ return ( piProcessInfo. hProcess,
123
+ _stdin. write ?? INVALID_HANDLE_VALUE,
124
+ _stdout. read ?? INVALID_HANDLE_VALUE,
125
+ _stderr. read ?? INVALID_HANDLE_VALUE)
126
+ }
127
+
128
+ public func waitProcess( _ process: HANDLE ) -> ProcessTerminationStatus {
129
+ let result = WaitForSingleObject ( process, INFINITE)
130
+ if result != WAIT_OBJECT_0 {
131
+ fatalError ( " WaitForSingleObject() failed " )
132
+ }
133
+
134
+ var status : DWORD = 0
135
+ if GetExitCodeProcess ( process, & status) == FALSE {
136
+ fatalError ( " GetExitCodeProcess() failed " )
137
+ }
138
+
139
+ if status & DWORD ( 0x80000000 ) == DWORD ( 0x80000000 ) {
140
+ return . signal( Int ( status) )
141
+ }
142
+ return . exit( Int ( status) )
143
+ }
144
+ #else
23
145
// posix_spawn is not available on Android.
24
146
// posix_spawn is not available on Haiku.
25
147
#if !os(Android) && !os(Haiku)
@@ -237,33 +359,6 @@ internal func _make_posix_spawn_file_actions_t()
237
359
#endif
238
360
#endif
239
361
240
- internal func _signalToString( _ signal: Int ) -> String {
241
- switch CInt ( signal) {
242
- case SIGILL: return " SIGILL "
243
- case SIGTRAP: return " SIGTRAP "
244
- case SIGABRT: return " SIGABRT "
245
- case SIGFPE: return " SIGFPE "
246
- case SIGBUS: return " SIGBUS "
247
- case SIGSEGV: return " SIGSEGV "
248
- case SIGSYS: return " SIGSYS "
249
- default : return " SIG???? ( \( signal) ) "
250
- }
251
- }
252
-
253
- public enum ProcessTerminationStatus : CustomStringConvertible {
254
- case exit( Int )
255
- case signal( Int )
256
-
257
- public var description : String {
258
- switch self {
259
- case . exit( let status) :
260
- return " Exit( \( status) ) "
261
- case . signal( let signal) :
262
- return " Signal( \( _signalToString ( signal) ) ) "
263
- }
264
- }
265
- }
266
-
267
362
public func posixWaitpid( _ pid: pid_t ) -> ProcessTerminationStatus {
268
363
var status : CInt = 0
269
364
#if os(Cygwin)
0 commit comments