add forkFinally
authorSimon Marlow <marlowsd@gmail.com>
Thu, 7 Jun 2012 15:10:47 +0000 (16:10 +0100)
committerSimon Marlow <marlowsd@gmail.com>
Thu, 7 Jun 2012 16:04:42 +0000 (17:04 +0100)
This is a more robust version of "forkIO (m `finally` k)", because it
closes a window between thread creation and the finally where the
thread can receive an async exception.  Useful for layers over threads
that need to catch threads dying with absolute certainty.

forkFinally :: IO a -> (Either SomeException a -> IO ()) -> IO ThreadId
forkFinally action and_then =
  mask $ \restore ->
    forkIO $ try (restore action) >>= and_then

Control/Concurrent.hs

index 770d9c3..1bac565 100644 (file)
@@ -36,6 +36,7 @@ module Control.Concurrent (
 
         forkIO,
 #ifdef __GLASGOW_HASKELL__
+        forkFinally,
         forkIOWithUnmask,
         killThread,
         throwTo,
@@ -205,6 +206,25 @@ Using Hugs, all I\/O operations and foreign calls will block all other
 Haskell threads.
 -}
 
+-- | fork a thread and call the supplied function when the thread is about
+-- to terminate, with an exception or a returned value.  The function is
+-- called with asynchronous exceptions masked.
+--
+-- > forkFinally action and_then =
+-- >   mask $ \restore ->
+-- >     forkIO $ try (restore action) >>= and_then
+--
+-- This function is useful for informing the parent when a child
+-- terminates, for example.
+--
+forkFinally :: IO a -> (Either SomeException a -> IO ()) -> IO ThreadId
+forkFinally action and_then =
+  mask $ \restore ->
+    forkIO $ try (restore action) >>= and_then
+
+-- -----------------------------------------------------------------------------
+-- Merging streams
+
 #ifndef __HUGS__
 max_buff_size :: Int
 max_buff_size = 1
@@ -598,11 +618,10 @@ foreign import ccall safe "fdReady"
 >   myForkIO :: IO () -> IO (MVar ())
 >   myForkIO io = do
 >     mvar <- newEmptyMVar
->     forkIO (io `finally` putMVar mvar ())
+>     forkFinally io (\_ -> putMVar mvar ())
 >     return mvar
 
-      Note that we use 'finally' from the
-      "Control.Exception" module to make sure that the
+      Note that we use 'forkFinally' to make sure that the
       'MVar' is written to even if the thread dies or
       is killed for some reason.
 
@@ -627,7 +646,7 @@ foreign import ccall safe "fdReady"
 >        mvar <- newEmptyMVar
 >        childs <- takeMVar children
 >        putMVar children (mvar:childs)
->        forkIO (io `finally` putMVar mvar ())
+>        forkFinally io (\_ -> putMVar mvar ())
 >
 >     main =
 >       later waitForChildren $