Proposal: overhaul System.Process

Duncan Coutts duncan.coutts at
Fri May 23 15:18:34 EDT 2008

On Thu, 2008-05-15 at 10:45 +0100, Simon Marlow wrote:
> The latest version of the Process overhaul is here:

We discussed some ideas on #ghc today and I'm posting them here so
people can comment.

      * runCommand
      * runProcess
      * runInteractiveCommand
      * runInteractiveCommand

The rationale is that these are all more limited than the new
createProcess and yet none of them are really convenient. It's better to
have fewer variations if they can all be expressed easily using
createProcess. It makes the API much simpler.

Also we'd not add `system` or `rawSystem` to `System.Process` and
instead add new equivalents with more consistent names.

That would leave just:

      * createProcess
      * readProcess
      * readProcessWithExitCode

Then add the following:

      * callProcess :: FilePath -> [String] -> IO ()
      * callCommand :: String -> IO ()

These would be synchronous like the current system and rawSystem. The
difference is they would throw IOErrors on failure rather than returning
the ExitCode which is so easily ignored.

These are of course only convenience functions. If someone wants the
exit code it should be easy to do it via createProcess and
waitForProcess. We need to make sure that is indeed the case.

We'd also add async versions of the above:

      * spawnProcess :: FilePath -> [String] -> IO ProcessHandle
      * spawnCommand :: String -> IO ProcessHandle

that do not wait for the process to finish and return the ProcessHandle.
Again these should be easy instances of createProcess. The docs should
probably say as much so it's clear how to make minor variations.

We also discussed how it should be safe to GC the ProcessHandle and not
end up with zombie processes on unix systems. On Windows it's actually
easy because you can close the process handle which means you don't get
the exit status of the process. On unix we have to collect the exit
status of every child process (actually you can ignore all of them, but
you cannot ignore them selectively).

The point is that with a convenient spawnProcess it's tempting to ignore
the ProcessHandle result and never bother calling waitForProcess on it.
We do want to support that. At the moment doing that would leave zombie

We discussed a mechanism to allow GC'ing ProcessHandles that does not
leave zombies. It'd probably involve keeping a Map PID (MVar ExitCode)
and embedding a MVar ExitCode in the ProcessHandle. Then when we get
notified that a child process terminated we would store the exit status
in the MVar. Then waitForProcess would just wait on that MVar ExitCode.

The one thing we have left that we cannot express with createProcess is
the behaviour with respect to ^C handling. For some processes we want to
delegate ^C handling to that child process (eg imagine calling ghci).
For others we want to handle ^C 'normally'. For details see #2301:


More information about the Libraries mailing list