rawfilepath-0.2.0: src/RawFilePath/Process/Basic.hs
module RawFilePath.Process.Basic where
-- base modules
import RawFilePath.Import hiding (ClosedHandle)
-- local modules
import RawFilePath.Process.Common
import RawFilePath.Process.Internal
import RawFilePath.Process.Posix
-- | Start a new sub-process with the given configuration.
startProcess
:: (StreamType stdin, StreamType stdout, StreamType stderr)
=> ProcessConf stdin stdout stderr
-> IO (Process stdin stdout stderr)
startProcess = createProcessInternal
-- | Stop a sub-process. For now it simply calls 'terminateProcess' and then
-- 'waitForProcess'.
stopProcess :: Process stdin stdout stderr -> IO ExitCode
stopProcess p = do
terminateProcess p
waitForProcess p
-- | Wait (block) for a sub-process to exit and obtain its exit code.
waitForProcess
:: Process stdin stdout stderr
-> IO ExitCode
waitForProcess ph = lockWaitpid $ do
p_ <- modifyProcessHandle ph $ \ p_ -> return (p_,p_)
case p_ of
ClosedHandle e -> return e
OpenHandle h -> do
e <- alloca $ \ pret -> do
-- don't hold the MVar while we call c_waitForProcess...
throwErrnoIfMinus1Retry_ "waitForProcess" (c_waitForProcess h pret)
modifyProcessHandle ph $ \ p_' ->
case p_' of
ClosedHandle e -> return (p_', e)
OpenExtHandle{} -> return (p_', ExitFailure (-1))
OpenHandle ph' -> do
closePHANDLE ph'
code <- peek pret
let e = if code == 0
then ExitSuccess
else ExitFailure (fromIntegral code)
return (ClosedHandle e, e)
when delegatingCtlc $
endDelegateControlC e
return e
OpenExtHandle _ _job _iocp ->
return $ ExitFailure (-1)
where
-- If more than one thread calls `waitpid` at a time, `waitpid` will
-- return the exit code to one of them and (-1) to the rest of them,
-- causing an exception to be thrown.
-- Cf. https://github.com/haskell/process/issues/46, and
-- https://github.com/haskell/process/pull/58 for further discussion
lockWaitpid m = withMVar (waitpidLock ph) $ \ () -> m
delegatingCtlc = mbDelegateCtlc ph
-- | Terminate a sub-process by sending SIGTERM to it.
terminateProcess :: Process stdin stdout stderr -> IO ()
terminateProcess p = withProcessHandle p $ \ case
ClosedHandle _ -> return ()
OpenExtHandle{} -> error
"terminateProcess with OpenExtHandle should not happen on POSIX."
OpenHandle h -> do
throwErrnoIfMinus1Retry_ "terminateProcess" $ c_terminateProcess h
return ()
-- does not close the handle, we might want to try terminating it
-- again, or get its exit code.