[Haskell-cafe] createProcess interferes with sockets?

Evan Laforge qdunkan at gmail.com
Sun Apr 21 14:27:00 CEST 2013


I've had a strange bug that's baffled me for a long time.  I finally
got serious about tracking it down, and managed to reduce it to a
small program that exhibits the unexpected behaviour, namely that a
createProcess seems to block writing to and closing a socket.

Here's the example program:

---

import Control.Monad
import qualified Network
import qualified System.Environment as Environment
import qualified System.IO as IO
import qualified System.Process as Process


main :: IO ()
main = Network.withSocketsDo $ do
    args <- Environment.getArgs
    case args of
        ["server"] -> server
        ["client"] -> client
        _ -> error $ show args

server :: IO ()
server = do
    socket <- Network.listenOn port
    forever $ do
        putStrLn "accept"
        (hdl, _host, _port) <- Network.accept socket
        msg <- IO.hGetLine hdl
        putStrLn $ "from client: " ++ show msg
        sleep
        putStrLn "send response"
        IO.hPutStr hdl "response"
        IO.hClose hdl

client :: IO ()
client = do
    hdl <- Network.connectTo "localhost" port
    IO.hPutStr hdl "hi from client\n"
    IO.hFlush hdl
    resp <- IO.hGetContents hdl
    print resp

port = Network.UnixSocket "port"

sleep = Process.createProcess (Process.proc "sleep" ["5"])

---

You can test with:

% ghc --make Test.hs && rm -f port && ./Test server

then on another window:

% ./Test client

Since the createProcess is async (it doesn't wait on the pid), I
expect the response to come back to the client immediately.  And the
server immediately says "send response" then "accept", so it doesn't
get stuck on the sleep.  But the client waits 5 seconds before
displaying "response", so evidently even though the handle has already
been written to and closed from the server, the client waits until the
subprocess (of the server!) completes before getting the response.
Comment out the "sleep" line and everything is fast.

Can anyone else repro this?  I'm guessing it has to do with the ghc IO
manager, and the fork implied by a createProcess is causing it the
socket close to block, but I haven't dug any deeper yet, in case this
is a know issue, or I'm just doing something wrong.  This is OS X
10.8.3.

thanks!



More information about the Haskell-Cafe mailing list