Signals in Haskell

When playing with Haskell I sometimes get the feeling that I’m the last one in the world to figure out how some things work. It’s almost embarrassing to write about it at times, but I fear I’ll forget and end up redoing my trivial experiments if I don’ti. So, here goes…

Dealing with signals in Haskell is fairly straight forward. Well, at least as far as dealing with signals ever is straight forward. In System.Posix.Signals you find installHandler. The arguments are a little funky but they get a little clearer if you look up the man-page for sigaction.

Here’s a simple example that installs a handler for SIGINT:

module Main where

import System.Posix.Signals
import Control.Concurrent

handler :: IO ()
handler = putStrLn "In handler"

doNothing :: IO ()
doNothing = do
    threadDelay 1000000
    putStrLn "Repeating"

main :: IO ()
main = do
    installHandler sigINT (Catch handler) Nothing
    sequence_ $ repeat doNothing

Now that’s fairly straight forward, I think. However, it’d be nice to be able to let the main thread know that we’ve recieved a signal in some way. From perusing the Haskell Wiki it seems the way to communicate between threads, at least for simple cases, is by using MVars. So, extending the example above to also keep track of how many times SIGINT has been received could look like this:

module Main where

import System.Posix.Signals
import Control.Concurrent
import Control.Concurrent.MVar

handler :: MVar Int -> IO ()
handler mi = do
    i <- takeMVar mi
    putStrLn "In handler"
    putMVar mi (i + 1)

doNothing :: MVar Int -> IO ()
doNothing mi = do
    threadDelay 1000000
    i <- readMVar mi
    putStrLn $ "Repeating " ++ (show i)

main :: IO ()
main = do
    mi <- newMVar 0
    installHandler sigINT (Catch $ handler mi) Nothing
    sequence_ $ repeat $ doNothing mi

It should be noted that, and here it all hinges on me having understood things correctly, handler has more or less become a sort of critical section. Taking the value out of the MVar makes sure that the readMVar in doNothing blocks until a new value is put back. Probably not a very useful thing in this particular example, but it’s still worth keeping in mind for the future.

  1. Or maybe I shouldn’t compare myself to the highly (dare I say it?) academical entries usually found on the Haskell Planet. Maybe I should just consider my writing to be “Haskell for mortals”.[back]
Share

3 Comments

  1. Thanks for the example code!

    I would like my Haskell program to exitFailure when the program is interrupted, so I changed the handler function to this:

    import System.Exit (exitFailure)

    handler :: MVar Int -> IO () handler mi = do i <- takeMVar mi putStrLn “In handler” exitFailure

    But when I run this code, the program doesn’t actually exit. It just prints out a notice that main.hs raised exitWith (Failure 1).

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>