Skip to content

Instantly share code, notes, and snippets.

@dcoutts
Created April 6, 2020 17:45
Show Gist options
  • Save dcoutts/91746eb6c2d49e18a15097b5dd580c8e to your computer and use it in GitHub Desktop.
Save dcoutts/91746eb6c2d49e18a15097b5dd580c8e to your computer and use it in GitHub Desktop.
--shutdown-ipc FD pattern
module Main where
import Control.Exception
import Control.Concurrent
import Control.Concurrent.Async
import System.Environment
import System.IO
import System.IO.Error
import GHC.IO.Handle.FD (fdToHandle)
import Foreign.C.Types (CInt)
type FD = CInt
main = do
[fdstr] <- getArgs
let fd :: FD
fd = read fdstr
race_ (waitForEOF fd) app
waitForEOF :: FD -> IO ()
waitForEOF fd = do
hnd <- fdToHandle fd
r <- try $ hGetChar hnd
case r of
Left e | isEOFError e -> putStrLn "shutdown" >> return ()
| otherwise -> throwIO e
Right _ -> throwIO (userError "--shutdown-ipc FD does not expect input")
app :: IO ()
app = do
hSetBuffering stdout NoBuffering
putChar '.'
threadDelay 1000000
app
@dcoutts
Copy link
Author

dcoutts commented Apr 6, 2020

For example

$ (sleep 10; cat /dev/null) | ./ShutdownDemo 0
..........shutdown

FD 0 is of course stdin, but in general we'd pass an FD of a pipe.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment