Skip to content

Commit 8085f6a

Browse files
committed
Use jobs when calling subprocesses
Many toolchain tools written for POSIX systems rely on the exec system call. Unfortunately, it is not possible to implement `exec` in a POSIX-compliant manner on Windows. In particular, the semantics of the `exec` implementation provided by the widely-used `msvcrt` C runtime will cause process's waiting on the `exec`'ing process to incorrectly conclude that the process has successfully terminated when in fact it is still running in another process. For this reason, the `process` library exposes the `use_process_jobs` flag to use a more strict (although still not POSIX-compliant) mechanism for tracking process completion. This is explained in this comment [2]. Unfortunately, job support in the `process` library is currently quite broken and was only recently fixed [1]. Consequently, we only enable job object support for process releases >= 1.6.8. [1] haskell/process#168 [2] https://github.com/haskell/process/blob/master/System/Process.hs#L399
1 parent 1a31242 commit 8085f6a

File tree

1 file changed

+48
-2
lines changed

1 file changed

+48
-2
lines changed

Cabal/Distribution/Simple/Utils.hs

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,9 +234,9 @@ import Data.Time.Clock.POSIX (getPOSIXTime, POSIXTime)
234234
import Control.Exception (IOException, evaluate, throwIO, fromException)
235235
import Numeric (showFFloat)
236236
import qualified System.Process as Process
237-
( CreateProcess(..), StdStream(..), proc)
237+
( CreateProcess(..), StdStream(..), proc, createProcess )
238238
import System.Process
239-
( ProcessHandle, createProcess, rawSystem, runInteractiveProcess
239+
( ProcessHandle, rawSystem
240240
, showCommandForUser, waitForProcess)
241241

242242
import qualified GHC.IO.Exception as GHC
@@ -680,6 +680,52 @@ maybeExit cmd = do
680680
res <- cmd
681681
unless (res == ExitSuccess) $ exitWith res
682682

683+
-- | Enable process jobs to ensure accurate determination of process completion
684+
-- in the presence of @exec(3)@ on Windows.
685+
--
686+
-- Unfortunately the process job support is badly broken in @process@ releases
687+
-- prior to 1.6.8, so we disable it in these versions, despite the fact that
688+
-- this means we may see sporatic build failures without jobs.
689+
enableProcessJobs :: CreateProces -> CreateProcess
690+
#ifdef MIN_VERSION_process
691+
#if MIN_VERSION_process(1,6,8)
692+
enableProcessJobs cp = cp {Process.use_process_jobs = True}
693+
#else
694+
enableProcessJobs cp = cp
695+
#endif
696+
#else
697+
enableProcessJobs cp = cp
698+
#endif
699+
700+
-- | 'System.Process.createProcess' with process jobs enabled when appropriate.
701+
-- See 'enableProcessJobs'.
702+
createProcess :: CreateProcess
703+
-> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
704+
createProcess = Process.createProcess . enableProcessJobs
705+
706+
-- | 'System.Process.rawSystem' with process jobs enabled when appropriate.
707+
-- See 'enableProcessJobs'.
708+
rawSystem :: String -> [String] -> IO ExitCode
709+
rawSystem cmd args = do
710+
(_,_,_,p) <- createProcess (proc cmd args) { delegate_ctlc = True }
711+
waitForProcess p
712+
713+
-- | 'System.Process.runInteractiveProcess' with process jobs enabled when
714+
-- appropriate. See 'enableProcessJobs'.
715+
runInteractiveProcess
716+
:: FilePath -- ^ Filename of the executable (see 'RawCommand' for details)
717+
-> [String] -- ^ Arguments to pass to the executable
718+
-> Maybe FilePath -- ^ Optional path to the working directory
719+
-> Maybe [(String,String)] -- ^ Optional environment (otherwise inherit)
720+
-> IO (Handle,Handle,Handle,ProcessHandle)
721+
runInteractiveProcess cmd args mb_cwd mb_env = do
722+
(mb_in, mb_out, mb_err, p) <-
723+
createProcess fun
724+
cmd{ std_in = CreatePipe,
725+
std_out = CreatePipe,
726+
std_err = CreatePipe }
727+
return (fromJust mb_in, fromJust mb_out, fromJust mb_err, p)
728+
683729
printRawCommandAndArgs :: Verbosity -> FilePath -> [String] -> IO ()
684730
printRawCommandAndArgs verbosity path args = withFrozenCallStack $
685731
printRawCommandAndArgsAndEnv verbosity path args Nothing Nothing

0 commit comments

Comments
 (0)