
Try forking a couple of threads to keep those handles clear.
Well ... at what point do these conveniences become too much work? Quick outline of the problems we can expect to encounter if we use runInteractiveProcess: -- because of Handles for the pipe I/O -- 1. library buffering defaults are the opposite of useful 2. now we find the depending on -threaded, garbage collection may cause handles to be closed -- because all three standard units are redirected to pipes -- 3. handles are likely to be unused, contributing to problem 2 above 4. unused handles are also liable to fill with process output and block. 5. particularly with unit 2 ("stderr"), diagnostic output will be discarded unless copied to output by the parent process 6. it's tricky to handle output on two units - have to avoid blocking read, if you don't know there's output. ... and I likely am forgetting one or two more. My recommendation would be to never use this function, and instead go to a process/pipe/exec that 1. creates only the required pipe connections, usually one. 2. returns the pipe Fd rather than making it into a Handle I append an example implementation - a little crude inasmuch as it does nothing about potential exceptional conditions like exec failure. Donn ------------ module Spawn (spawnFd) where import System.Directory import System.Posix.IO import System.Posix.Process import System.Posix.Types -- -- fork process, exec file -- -- exec parameters same as executeFile -- -- Fd spec is (unit, write) from the perspective of -- the child process. -- To spawn a process that only writes output, and -- get a pipe to read that output: [(1, True)] -- To spawn a process that only reads input: [(0, False)] -- To get all three units like runInteractiveProcess: -- [(0, False), (1, True), (2, True)] -- Returned fds are not super convenient, something like -- let p0 = fromJust $ lookup 0 pipelist spawnFd :: FilePath -> Bool -> [String] -> Maybe FilePath -> Maybe [(String, String)] -> [(Fd, Bool)] -> IO ([(Fd, Fd)], ProcessID) spawnFd path search args wd env fdreq = do pp <- mapM pipu fdreq pid <- forkProcess $ childPrep pp ppp <- mapM repipe pp return (ppp, pid) where pipu (u, w) = do p <- createPipe return (u, w, p) dopipe (u, w, (p0, p1)) = do if w then dupTo p1 u else dupTo p0 u closeFd p0 closeFd p1 repipe (u, w, (p0, p1)) | w = do closeFd p1 return (u, p0) | otherwise = do closeFd p0 return (u, p1) childPrep pp = do mapM_ dopipe pp case wd of Just d -> setCurrentDirectory d _ -> return () executeFile path search args env