readProcessWithTimeout 
    :: FilePath                 -- ^ command to run
    -> [String]                 -- ^ any arguments
    -> String                   -- ^ standard input
    -> Int                      -- ^ timeout in milliseconds
    -> IO String                -- ^ stdout
readProcessWithTimeout cmd args input microseconds = do
    (Just inh, Just outh, _, pid) <-
        createProcess (proc cmd args){ std_in  = CreatePipe,
                                       std_out = CreatePipe,
                                       std_err = Inherit }

    -- fork off a thread to start consuming the output
    output  <- hGetContents outh
    outMVar <- newEmptyMVar
    _ <- forkIO $ C.evaluate (length output) >> putMVar outMVar (Just ())

    -- now write and flush any input
    when (not (null input)) $ do hPutStr inh input; hFlush inh
    hClose inh -- done with stdin

    -- kill on a timeout
    forkIO $ do threadDelay $ microseconds * 1000
                got <- isJust <$> tryTakeMVar outMVar
                unless got $ do
                  terminateProcess pid
                  putMVar outMVar Nothing

    -- wait on the output
    success <- isJust <$> takeMVar outMVar
    hClose outh

    -- wait on the process
    ex <- waitForProcess pid

    case if success then ex else ExitFailure (-1) of
     ExitSuccess   -> return output
     ExitFailure r -> 
      ioError (mkIOError GHC.IO.Exception.OtherError
                         ("readProcess: " ++ cmd ++ 
                                     ' ':unwords (map show args) ++ 
                                     " (exit " ++ show r ++ ")")
                                 Nothing Nothing)
readProcessWithTimeout 
    :: FilePath                 -- ^ command to run
    -> [String]                 -- ^ any arguments
    -> String                   -- ^ standard input
    -> Int                      -- ^ timeout in milliseconds
    -> IO String
readProcessWithTimeout cmd args input microseconds = do
    (Just inh, Just outh, _, pid) <-
        createProcess (proc cmd args){ std_in  = CreatePipe,
                                       std_out = CreatePipe,
                                       std_err = Inherit }

    -- fork off a thread to start consuming the output
    output  <- hGetContents outh
    outMVar <- newEmptyMVar
    _ <- forkIO $ C.evaluate (length output) >> putMVar outMVar (Just ())

    -- now write and flush any input
    when (not (null input)) $ do hPutStr inh input; hFlush inh
    hClose inh -- done with stdin

    -- kill on a timeout
    forkIO $ do threadDelay $ microseconds * 1000
                got <- isJust <$> tryTakeMVar outMVar
                unless got $ do
                  terminateProcess pid
                  putMVar outMVar Nothing

    -- wait on the output
    success <- isJust <$> takeMVar outMVar
    hClose outh

    -- wait on the process
    ex <- waitForProcess pid

    case if success then ex else ExitFailure (-1) of
     ExitSuccess   -> return output
     ExitFailure r -> 
      ioError (mkIOError GHC.IO.Exception.OtherError
                         ("readProcess: " ++ cmd ++ 
                                     ' ':unwords (map show args) ++ 
                                     " (exit " ++ show r ++ ")")
                                 Nothing Nothing)
readProcessWithTimeout cmd args input microseconds = do
    (Just inh, Just outh, _, pid) <-
        createProcess (proc cmd args){ std_in  = CreatePipe,
                                       std_out = CreatePipe,
                                       std_err = Inherit }

    -- fork off a thread to start consuming the output
    output  <- hGetContents outh
    outMVar <- newEmptyMVar
    _ <- forkIO $ C.evaluate (length output) >> putMVar outMVar (Just ())

    -- now write and flush any input
    when (not (null input)) $ do hPutStr inh input; hFlush inh
    hClose inh -- done with stdin

    -- kill on a timeout
    forkIO $ do threadDelay $ microseconds * 1000
                got <- isJust <$> tryTakeMVar outMVar
                unless got $ do
                  terminateProcess pid
                  putMVar outMVar Nothing

    -- wait on the output
    success <- isJust <$> takeMVar outMVar
    hClose outh

    -- wait on the process
    ex <- waitForProcess pid

    case if success then ex else ExitFailure (-1) of
     ExitSuccess   -> return output
     ExitFailure r -> 
      ioError (mkIOError GHC.IO.Exception.OtherError
                         ("readProcess: " ++ cmd ++ 
                                     ' ':unwords (map show args) ++ 
                                     " (exit " ++ show r ++ ")")
                                 Nothing Nothing)