[Haskell-cafe] Can't establish subprocess communication

Donn Cave donn at avvanta.com
Sun Nov 13 18:23:21 CET 2011


As mentioned by the first person to follow up, you need to set
line buffering in the "copier" program.  It's filling up its buffer
while you write small lines to it - unlike the test run at the
terminal prompt, where it's connected to a TTY device and therefore
behaved differently.

In a situation where you can confidently say your software will
only ever be run in a POSIX environment, I like to use the Posix
functions directly, because a buffered Handle on a pipe is nothing
but extra trouble, and similarly the convenient wrapping of the
POSIX API seems to cause more trouble than it's worth.  Did your
first attempt fail because the file name was not a complete path?
Do that on purpose and see if runInteractiveProcess gives you a
useful error message.  Engineer some other kind of problem into
your copier program, and see what happens to the error message ...
oh, rats, it looks like runInteractiveProcess puts unit 2 on
another pipe, when you might have worked better for you to leave
it the way it was.  (This kind of thing is what we call a "user
friendly" API, which is why we say "with friends like that, who
needs enemies!")

Here's how the start process function could be written -

import System.Posix.IO
import System.Posix.Process

startproc = do
    ip <- createPipe
    op <- createPipe
    pid <- forkProcess $ do
        forRead ip >>= onStdUnit 0
        forWrite op >>= onStdUnit 1
        executeFile "./copier" False [] Nothing
    to <- forWrite ip
    from <- forWrite op
    return (to, from, pid)
	where
		forRead (i, o) = closeFd o >> return i
		forWrite (i, o) = closeFd i >> return o
		onStdUnit i fd = do
			dupTo fd i
			closeFd fd

-- and then for I/O to the file descriptors (remember to supply
-- explicit newlines, if the other process is line buffered, e.g. "boo\n",
-- But if the other process also uses Posix.readFd, it isn't buffered
-- at all, so you don't need newlines. "cat" is in the latter category,
-- but most command line applications are in the former, like, say, "awk".)

sendrecv to from s = do
    forkIO $ fdWrite to s >> return ()
    (v, _) <- fdRead from 1024
    putStrLn ("recvd: " ++ show v)

-- try it

	Donn



More information about the Haskell-Cafe mailing list