Reputation: 1589
How are exceptions delivered in a concurrent Haskell program?
Let's say we have a process, with multiple threads and one of them is interacting with something over a TCP connection and we get a signal (say on a *nix system).
Which (green)thread will this signal be delivered to?
Will it be delivered to the one which is "using" the socket or a "main" designated thread will receive and it has to explicitly do a throwTo
to send the exception to that (green)thread?
Upvotes: 22
Views: 460
Reputation: 38758
There is no automatic correspondence between POSIX signals and Haskell exceptions.
In order for a signal to be turned into an exception, there needs to be a signal handler that will do just that — throw an exception to one of the Haskell threads. Which thread gets the exception depends entirely on how the signal handler is set up.
By default, GHC sets up such a handler for SIGINT only, and that signal delivers the exception to the main thread.
You can install similar handlers for the other signals:
import Control.Concurrent (mkWeakThreadId, myThreadId)
import Control.Exception (Exception(..), throwTo)
import Control.Monad (forM_)
import Data.Typeable (Typeable)
import System.Posix.Signals
import System.Mem.Weak (deRefWeak)
newtype SignalException = SignalException Signal
deriving (Show, Typeable)
instance Exception SignalException
installSignalHandlers :: IO ()
installSignalHandlers = do
main_thread_id <- myThreadId
weak_tid <- mkWeakThreadId main_thread_id
forM_ [ sigABRT, sigBUS, sigFPE, sigHUP, sigILL, sigQUIT, sigSEGV,
sigSYS, sigTERM, sigUSR1, sigUSR2, sigXCPU, sigXFSZ ] $ \sig ->
installHandler sig (Catch $ send_exception weak_tid sig) Nothing
where
send_exception weak_tid sig = do
m <- deRefWeak weak_tid
case m of
Nothing -> return ()
Just tid -> throwTo tid (toException $ SignalException sig)
main = do
installSignalHandlers
...
But you can also get creative and change the handler to deliver the signal to some other thread. E.g. if there is only one thread working with sockets, you can make sure that thread gets the exception. Or, depending on the signal you're interested in, maybe you can figure out the relevant thread based on the siginfo_t
structure (see sigaction(2)
) — perhaps the si_fd field?
Upvotes: 1