Skip to content

Commit 0c76dbc

Browse files
committed
refactoring: Use tryJust instead of pattern guards
1 parent 971f04a commit 0c76dbc

File tree

1 file changed

+20
-19
lines changed

1 file changed

+20
-19
lines changed

src/System/Process/Typed.hs

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ module System.Process.Typed
130130
) where
131131

132132
import Control.Exception hiding (bracket, finally)
133+
import Control.Monad ((>=>), guard)
133134
import Control.Monad.IO.Class
134135
import qualified System.Process as P
135136
import System.IO (hClose)
@@ -256,32 +257,32 @@ startProcess pConfig'@ProcessConfig {..} = liftIO $ do
256257
-- Process didn't exit yet, let's terminate it and
257258
-- then call waitForProcess ourselves
258259
Left _ -> do
259-
eres <- try $ P.terminateProcess pHandle
260-
ec <-
261-
case eres of
262-
Left e
263-
-- On Windows, with the single-threaded runtime, it
264-
-- seems that if a process has already exited, the
265-
-- call to terminateProcess will fail with a
266-
-- permission denied error. To work around this, we
267-
-- catch this exception and then immediately
268-
-- waitForProcess. There's a chance that there may be
269-
-- other reasons for this permission error to appear,
270-
-- in which case this code may allow us to wait too
271-
-- long for a child process instead of erroring out.
272-
-- Recommendation: always use the multi-threaded
273-
-- runtime!
274-
| isPermissionError e && not multiThreadedRuntime && isWindows ->
275-
P.waitForProcess pHandle
276-
| otherwise -> throwIO e
277-
Right () -> P.waitForProcess pHandle
260+
terminateProcess pHandle
261+
ec <- P.waitForProcess pHandle
278262
success <- atomically $ tryPutTMVar pExitCode ec
279263
evaluate $ assert success ()
280264

281265
return Process {..}
282266
where
283267
pConfig = clearStreams pConfig'
284268

269+
terminateProcess :: P.ProcessHandle -> IO ()
270+
terminateProcess p = do
271+
-- On Windows, with the single-threaded runtime, it seems that if a
272+
-- process has already exited, the call to terminateProcess will fail
273+
-- with a permission denied error. To work around this, we ignore this
274+
-- exception. There's a chance that there may be other reasons for this
275+
-- permission error to appear, in which case this code may allow us to
276+
-- wait too long for a child process instead of erroring out on a
277+
-- subsequent call to `waitForProcess`.
278+
-- Recommendation: always use the multi-threaded runtime!
279+
ignorePermissionErrorOnSingleThreadedWindows $ P.terminateProcess p
280+
281+
ignorePermissionErrorOnSingleThreadedWindows :: IO () -> IO ()
282+
ignorePermissionErrorOnSingleThreadedWindows = tryJust (guard . p) >=> either return return
283+
where
284+
p e = isPermissionError e && not multiThreadedRuntime && isWindows
285+
285286
foreign import ccall unsafe "rtsSupportsBoundThreads"
286287
multiThreadedRuntime :: Bool
287288

0 commit comments

Comments
 (0)