replacement for popen

Glynn Clements glynn at gclements.plus.com
Thu Apr 14 17:44:10 EDT 2005


Uwe Schmidt wrote:

> in the ghc-6.4 release the posix module is deprecated.
> I'm looking for a replacement and tried the
> System.Process functions. the following first try
> does not work for large files. it blocks if the
> file "long.file" does not fit into one os-buffer.
> then cat blocks and therefor waitForProcess blocks
> 
> ------------------------------------
> 
> module Main where
> 
> import IO
> import System
> import System.Process
> 
> main :: IO ()
> main = do
>        (inpH, outH, errH, pH) <- runInteractiveProcess "cat" ["long.file"] Nothing Nothing
>        hClose inpH
>        res  <- hGetContents outH
>        errs <- hGetContents errH
> 
>        rc <- waitForProcess pH

Two relevant axioms:

1. Haskell's lazy I/O is only good for "simple, stupid programs". It
fails miserably when dealing with more complex I/O scenarios (e.g. any
situation where it matters as to *when* you read the data).

2. Implementing "coroutines" as two processes communicating with each
other by a pair of pipes (i.e. exactly what runInteractiveProcess
does) is prone to deadlock if either reads or writes are delayed.

Common variations on problem #2 (in any language) are:

a) With the "send request, read response" idiom, if you forget to
disable buffering or flush buffers, you get deadlock.

b) If you try to write too much data in one go, both pipes fill up and
you get deadlock.

> the following version works fine, but it looks very much like a hack

[snip]

> is there a simple replacement for the popen using the System.Process
> module?

How about moving the waitForProcess call until *after* you have
consumed the data? BTW, you would have exactly the same problem with
popen, AFAICT.

More generally, don't call waitForProcess until there's at least a
possibility that the process might terminate eventually.

-- 
Glynn Clements <glynn at gclements.plus.com>


More information about the Libraries mailing list