Reputation: 464
I'm trying to pipe the stdin of my program to an external process using the following
import System.IO
import System.Posix.IO
import System.Posix.Process
import qualified System.Process as P
import Control.Concurrent (forkIO, killThread)
import Control.Monad
main :: IO ()
main = do
h <- fdToHandle stdInput
(Just hIn, _, _, p) <-
P.createProcess (P.shell "runhaskell echo.hs"){ P.std_in = P.CreatePipe }
hSetBuffering hIn NoBuffering
tid <- forkIO $ getInput hIn
e <- P.waitForProcess p
killThread tid
print e
getInput hin = do
forever $ do
l <- getLine
hPutStrLn hin l
where echo.hs just echoes stdin to stdout, but if I wait a couple seconds between giving new input, I get the following error:
pipes.hs: <stdin>: hGetLine: invalid argument (Bad file descriptor)
when I tried compiling with ghc pipes.hs
, the compiled program would not redirect stdin to the stdin of echo.hs at all
Upvotes: 2
Views: 747
Reputation: 31315
Your fdToHandler stdInput
call creates a new Handle
pointing at file descriptor 0 (stdin) of the original process. After a bit of time, the garbage collector notices that it's no longer being used, and garbage collects the Handle
, which in turn causes the underlying file descriptor to be closed. Then your getLine
(which uses System.IO.stdin
) call fails. That's because that Handle
is still open, but the underlying file descriptor it's pointing at has been closed.
FWIW, I'd recommend using binary I/O on the handles to avoid issues with character encodings.
Upvotes: 4