Hi everyone, I have been trying to implement a Haskell-like version of shell pipelines using runInteractiveProcess. I am essentially using hGetContents to grab the output from one command, and passing that to (forkIO $ hPutStr) to write to the next. Slow, but this is just an experiment. This works OK to link together two external commands, but deadlocks when linking together three processes.
After staring at straces all afternoon, I think I have found the culprit. I observed that when I have three commands linked together, the second never sees EOF on its input. This even though I saw an explicit close on the other end of the pipe from the Haskell side. Why is this, I wondered? I stared at the source for the C runInteractiveProcess function for a bit, but then the answer was right there: this function does not sanitize FDs. What that means is that the write end of the stdin pipe for command 2 was open in the Haskell process. The Haskell process then forked off for command 3 later on. This write end of the stdin pipe for command 2 was never closed in the command 3 child environment. Therefore, closing it in the Haskell thread did not cause command 2 to get an EOF. Does that make sense? Many systems will just try to close *all* FDs except the ones they need after a fork(). Another approach would be to maintain a global list of FDs that the Haskell thread is using, and close all of them except the pipe ends in the child. Without something like this, it is not possible to use runInteractiveProcess more than twice simultaneously in a single program. That renders it almost useless for some tasks. Does this make sense to everyone? If so, I'll submit the bug on GHC. -- John _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe