@@ -30,6 +30,11 @@ import System.IO.Unsafe
30
30
31
31
import System.Posix.Internals
32
32
import GHC.IO.Exception
33
+ ##if defined(__IO_MANAGER_WINIO__)
34
+ import GHC.IO.SubSystem
35
+ import Graphics.Win32.Misc
36
+ import qualified GHC.Event.Windows as Mgr
37
+ ##endif
33
38
import GHC.IO.Handle.FD
34
39
import GHC.IO.Handle.Types hiding (ClosedHandle )
35
40
import System.IO.Error
@@ -91,19 +96,77 @@ createProcess_Internal
91
96
-> CreateProcess
92
97
-> IO ProcRetHandles
93
98
94
- createProcess_Internal fun CreateProcess { cmdspec = cmdsp,
95
- cwd = mb_cwd,
96
- env = mb_env,
97
- std_in = mb_stdin,
98
- std_out = mb_stdout,
99
- std_err = mb_stderr,
100
- close_fds = mb_close_fds,
101
- create_group = mb_create_group,
102
- delegate_ctlc = _ignored,
103
- detach_console = mb_detach_console,
104
- create_new_console = mb_create_new_console,
105
- new_session = mb_new_session,
106
- use_process_jobs = use_job }
99
+ ##if defined(__IO_MANAGER_WINIO__)
100
+ createProcess_Internal = createProcess_Internal_mio <!> createProcess_Internal_winio
101
+ ##else
102
+ createProcess_Internal = createProcess_Internal_mio
103
+ ##endif
104
+
105
+ createProcess_Internal_mio
106
+ :: String -- ^ function name (for error messages)
107
+ -> CreateProcess
108
+ -> IO ProcRetHandles
109
+
110
+ createProcess_Internal_mio fun def@ CreateProcess {
111
+ std_in = mb_stdin,
112
+ std_out = mb_stdout,
113
+ std_err = mb_stderr,
114
+ close_fds = mb_close_fds,
115
+ create_group = mb_create_group,
116
+ delegate_ctlc = _ignored,
117
+ detach_console = mb_detach_console,
118
+ create_new_console = mb_create_new_console,
119
+ new_session = mb_new_session,
120
+ use_process_jobs = use_job }
121
+ = createProcess_Internal_wrapper fun def $
122
+ \ pfdStdInput pfdStdOutput pfdStdError hJob pEnv pWorkDir pcmdline -> do
123
+ fdin <- mbFd fun fd_stdin mb_stdin
124
+ fdout <- mbFd fun fd_stdout mb_stdout
125
+ fderr <- mbFd fun fd_stderr mb_stderr
126
+
127
+ -- #2650: we must ensure mutual exclusion of c_runInteractiveProcess,
128
+ -- because otherwise there is a race condition whereby one thread
129
+ -- has created some pipes, and another thread spawns a process which
130
+ -- accidentally inherits some of the pipe handles that the first
131
+ -- thread has created.
132
+ --
133
+ -- An MVar in Haskell is the best way to do this, because there
134
+ -- is no way to do one-time thread-safe initialisation of a mutex
135
+ -- the C code. Also the MVar will be cheaper when not running
136
+ -- the threaded RTS.
137
+ proc_handle <- withMVar runInteractiveProcess_lock $ \ _ ->
138
+ throwErrnoIfBadPHandle fun $
139
+ c_runInteractiveProcess pcmdline pWorkDir pEnv
140
+ fdin fdout fderr
141
+ pfdStdInput pfdStdOutput pfdStdError
142
+ ((if mb_close_fds then RUN_PROCESS_IN_CLOSE_FDS else 0 )
143
+ .|. (if mb_create_group then RUN_PROCESS_IN_NEW_GROUP else 0 )
144
+ .|. (if mb_detach_console then RUN_PROCESS_DETACHED else 0 )
145
+ .|. (if mb_create_new_console then RUN_PROCESS_NEW_CONSOLE else 0 )
146
+ .|. (if mb_new_session then RUN_PROCESS_NEW_SESSION else 0 ))
147
+ use_job
148
+ hJob
149
+
150
+ hndStdInput <- mbPipe mb_stdin pfdStdInput WriteMode
151
+ hndStdOutput <- mbPipe mb_stdout pfdStdOutput ReadMode
152
+ hndStdError <- mbPipe mb_stderr pfdStdError ReadMode
153
+
154
+ return (proc_handle, hndStdInput, hndStdOutput, hndStdError)
155
+
156
+
157
+ createProcess_Internal_wrapper
158
+ :: Storable a => String -- ^ function name (for error messages)
159
+ -> CreateProcess
160
+ -> (Ptr a -> Ptr a -> Ptr a -> Ptr PHANDLE -> Ptr CWString -> CWString
161
+ -> CWString -> IO (PHANDLE , Maybe Handle , Maybe Handle , Maybe Handle ))
162
+ -> IO ProcRetHandles
163
+
164
+ createProcess_Internal_wrapper _fun CreateProcess {
165
+ cmdspec = cmdsp,
166
+ cwd = mb_cwd,
167
+ env = mb_env,
168
+ delegate_ctlc = _ignored }
169
+ action
107
170
= do
108
171
let lenPtr = sizeOf (undefined :: WordPtr )
109
172
(cmd, cmdline) <- commandToProcess cmdsp
@@ -116,9 +179,43 @@ createProcess_Internal fun CreateProcess{ cmdspec = cmdsp,
116
179
maybeWith withCWString mb_cwd $ \ pWorkDir -> do
117
180
withCWString cmdline $ \ pcmdline -> do
118
181
119
- fdin <- mbFd fun fd_stdin mb_stdin
120
- fdout <- mbFd fun fd_stdout mb_stdout
121
- fderr <- mbFd fun fd_stderr mb_stderr
182
+ (proc_handle, hndStdInput, hndStdOutput, hndStdError)
183
+ <- action pfdStdInput pfdStdOutput pfdStdError hJob pEnv pWorkDir pcmdline
184
+
185
+ phJob <- peek hJob
186
+ ph <- mkProcessHandle proc_handle phJob
187
+ return ProcRetHandles { hStdInput = hndStdInput
188
+ , hStdOutput = hndStdOutput
189
+ , hStdError = hndStdError
190
+ , procHandle = ph
191
+ }
192
+
193
+ ##if defined(__IO_MANAGER_WINIO__)
194
+ createProcess_Internal_winio
195
+ :: String -- ^ function name (for error messages)
196
+ -> CreateProcess
197
+ -> IO ProcRetHandles
198
+
199
+ createProcess_Internal_winio fun def@ CreateProcess {
200
+ std_in = mb_stdin,
201
+ std_out = mb_stdout,
202
+ std_err = mb_stderr,
203
+ close_fds = mb_close_fds,
204
+ create_group = mb_create_group,
205
+ delegate_ctlc = _ignored,
206
+ detach_console = mb_detach_console,
207
+ create_new_console = mb_create_new_console,
208
+ new_session = mb_new_session,
209
+ use_process_jobs = use_job }
210
+ = createProcess_Internal_wrapper fun def $
211
+ \ pfdStdInput pfdStdOutput pfdStdError hJob pEnv pWorkDir pcmdline -> do
212
+
213
+ _stdin <- getStdHandle sTD_INPUT_HANDLE
214
+ _stdout <- getStdHandle sTD_OUTPUT_HANDLE
215
+ _stderr <- getStdHandle sTD_ERROR_HANDLE
216
+ hwnd_in <- mbHANDLE _stdin mb_stdin
217
+ hwnd_out <- mbHANDLE _stdout mb_stdout
218
+ hwnd_err <- mbHANDLE _stderr mb_stderr
122
219
123
220
-- #2650: we must ensure mutual exclusion of c_runInteractiveProcess,
124
221
-- because otherwise there is a race condition whereby one thread
@@ -132,8 +229,8 @@ createProcess_Internal fun CreateProcess{ cmdspec = cmdsp,
132
229
-- the threaded RTS.
133
230
proc_handle <- withMVar runInteractiveProcess_lock $ \ _ ->
134
231
throwErrnoIfBadPHandle fun $
135
- c_runInteractiveProcess pcmdline pWorkDir pEnv
136
- fdin fdout fderr
232
+ c_runInteractiveProcessHANDLE pcmdline pWorkDir pEnv
233
+ hwnd_in hwnd_out hwnd_err
137
234
pfdStdInput pfdStdOutput pfdStdError
138
235
((if mb_close_fds then RUN_PROCESS_IN_CLOSE_FDS else 0 )
139
236
.|. (if mb_create_group then RUN_PROCESS_IN_NEW_GROUP else 0 )
@@ -143,17 +240,20 @@ createProcess_Internal fun CreateProcess{ cmdspec = cmdsp,
143
240
use_job
144
241
hJob
145
242
146
- hndStdInput <- mbPipe mb_stdin pfdStdInput WriteMode
147
- hndStdOutput <- mbPipe mb_stdout pfdStdOutput ReadMode
148
- hndStdError <- mbPipe mb_stderr pfdStdError ReadMode
243
+ -- Attach the handle to the I/O manager's CompletionPort. This allows the
244
+ -- I/O manager to service requests for this Handle.
245
+ Mgr. associateHandle' =<< peek pfdStdInput
246
+ Mgr. associateHandle' =<< peek pfdStdOutput
247
+ Mgr. associateHandle' =<< peek pfdStdError
149
248
150
- phJob <- peek hJob
151
- ph <- mkProcessHandle proc_handle phJob
152
- return ProcRetHandles { hStdInput = hndStdInput
153
- , hStdOutput = hndStdOutput
154
- , hStdError = hndStdError
155
- , procHandle = ph
156
- }
249
+ -- Create the haskell mode handles as files.
250
+ hndStdInput <- mbPipeHANDLE mb_stdin pfdStdInput WriteMode
251
+ hndStdOutput <- mbPipeHANDLE mb_stdout pfdStdOutput ReadMode
252
+ hndStdError <- mbPipeHANDLE mb_stderr pfdStdError ReadMode
253
+
254
+ return (proc_handle, hndStdInput, hndStdOutput, hndStdError)
255
+
256
+ ##endif
157
257
158
258
{-# NOINLINE runInteractiveProcess_lock #-}
159
259
runInteractiveProcess_lock :: MVar ()
@@ -224,6 +324,24 @@ foreign import ccall unsafe "runInteractiveProcess"
224
324
-> Ptr PHANDLE -- Handle to Job
225
325
-> IO PHANDLE
226
326
327
+ ##if defined(__IO_MANAGER_WINIO__)
328
+ foreign import ccall unsafe " runInteractiveProcessHANDLE"
329
+ c_runInteractiveProcessHANDLE
330
+ :: CWString
331
+ -> CWString
332
+ -> Ptr CWString
333
+ -> HANDLE
334
+ -> HANDLE
335
+ -> HANDLE
336
+ -> Ptr HANDLE
337
+ -> Ptr HANDLE
338
+ -> Ptr HANDLE
339
+ -> CInt -- flags
340
+ -> Bool -- useJobObject
341
+ -> Ptr PHANDLE -- Handle to Job
342
+ -> IO PHANDLE
343
+ ##endif
344
+
227
345
commandToProcess
228
346
:: CmdSpec
229
347
-> IO (FilePath , String )
@@ -299,7 +417,14 @@ isDefaultSignal :: CLong -> Bool
299
417
isDefaultSignal = const False
300
418
301
419
createPipeInternal :: IO (Handle , Handle )
302
- createPipeInternal = do
420
+ ##if defined(__IO_MANAGER_WINIO__)
421
+ createPipeInternal = createPipeInternalPosix <!> createPipeInternalHANDLE
422
+ ##else
423
+ createPipeInternal = createPipeInternalPosix
424
+ ##endif
425
+
426
+ createPipeInternalPosix :: IO (Handle , Handle )
427
+ createPipeInternalPosix = do
303
428
(readfd, writefd) <- createPipeInternalFd
304
429
(do readh <- fdToHandle readfd
305
430
writeh <- fdToHandle writefd
@@ -313,6 +438,21 @@ createPipeInternalFd = do
313
438
writefd <- peekElemOff pfds 1
314
439
return (readfd, writefd)
315
440
441
+ ##if defined(__IO_MANAGER_WINIO__)
442
+ createPipeInternalHANDLE :: IO (Handle , Handle )
443
+ createPipeInternalHANDLE =
444
+ alloca $ \ pfdStdInput ->
445
+ alloca $ \ pfdStdOutput -> do
446
+ throwErrnoIf_ (== False ) " c_mkNamedPipe" $
447
+ c_mkNamedPipe pfdStdInput True pfdStdOutput True
448
+ Just hndStdInput <- mbPipeHANDLE CreatePipe pfdStdInput WriteMode
449
+ Just hndStdOutput <- mbPipeHANDLE CreatePipe pfdStdOutput ReadMode
450
+ return (hndStdInput, hndStdOutput)
451
+
452
+
453
+ foreign import ccall " mkNamedPipe" c_mkNamedPipe ::
454
+ Ptr HANDLE -> Bool -> Ptr HANDLE -> Bool -> IO Bool
455
+ ##endif
316
456
317
457
close' :: CInt -> IO ()
318
458
close' = throwErrnoIfMinus1_ " _close" . c__close
0 commit comments