Skip to content

Commit

Permalink
Do not deadlock on huge error output
Browse files Browse the repository at this point in the history
  • Loading branch information
sol committed Sep 19, 2023
1 parent 7983656 commit 814e0bb
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 5 deletions.
3 changes: 2 additions & 1 deletion src/Pager.hs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module Pager where
import Imports

import System.IO
import System.IO.Error
import System.Process
import Control.Concurrent.Async

Expand All @@ -19,8 +20,8 @@ pagerWith process input = do
pid <- newEmptyMVar
tid <- async $ withLockedHandle stdin $ do
(Just hin, Nothing, Nothing, p) <- createProcess process { delegate_ctlc = True, std_in = CreatePipe }
hPutStr hin input >> hClose hin
putMVar pid p
_ <- tryJust (guard . isResourceVanishedError) $ hPutStr hin input >> hClose hin
waitForProcess p
return $ do
readMVar pid >>= terminateProcess
Expand Down
25 changes: 21 additions & 4 deletions test/PagerSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,33 @@ spec = do

describe "pagerWith" $ do
it "pipes the provided input into a pager" $ do
(stdoutReadEnd, stdoutWriteEnd) <- createPipe
(readEnd, writeEnd) <- createPipe
let
process :: CreateProcess
process = (proc "cat" []) { std_out = UseHandle stdoutWriteEnd }
bracket (pagerWith process "foo") id $ \ _ -> do
hGetContents stdoutReadEnd `shouldReturn` "foo"
process = (proc "cat" []) { std_out = UseHandle writeEnd }

input :: String
input = "foo"

bracket (pagerWith process input) id $ \ _ -> do
hGetContents readEnd `shouldReturn` input

it "can be canceled" $ do
let
process :: CreateProcess
process = proc "sleep" ["1d"]
cancel <- pagerWith process "foo"
timeout cancel `shouldReturn` Just ()

context "when writing to stdin of the subprocess blocks" $ do
it "can still be canceled" $ do
(_, writeEnd) <- createPipe
let
process :: CreateProcess
process = (proc "cat" []) { std_out = UseHandle writeEnd }

input :: String
input = cycle "foo\n"

cancel <- pagerWith process input
timeout cancel `shouldReturn` Just ()

0 comments on commit 814e0bb

Please sign in to comment.