@@ -43,8 +43,14 @@ module Control.Distributed.Process.Internal.Primitives
43 , nsendRemote
43 , nsendRemote
44 -- * Closures
44 -- * Closures
45 , unClosure
45 , unClosure
46− -- * Auxiliary API
46+ -- * Exception handling
48 , expectTimeout
54 , expectTimeout
49 , spawnAsync
55 , spawnAsync
50 , linkNode
56 , linkNode
@@ -67,8 +73,8 @@ import System.Locale (defaultTimeLocale)
67import Control.Monad.Reader (ask)
73import Control.Monad.Reader (ask)
68import Control.Monad.IO.Class (MonadIO, liftIO)
74import Control.Monad.IO.Class (MonadIO, liftIO)
69import Control.Applicative ((<$>))
75import Control.Applicative ((<$>))
70−import Control.Exception (Exception, throw)
76+import Control.Exception (Exception, throw, throwIO, SomeException)
71−import qualified Control.Exception as Ex (catch)
77+import qualified Control.Exception as Ex (catch, mask)
72import Control.Concurrent.MVar (modifyMVar)
78import Control.Concurrent.MVar (modifyMVar)
73import Control.Concurrent.Chan (writeChan)
79import Control.Concurrent.Chan (writeChan)
74import Control.Concurrent.STM
80import Control.Concurrent.STM
@@ -258,7 +264,7 @@ instance Exception ProcessTerminationException
259-- | Terminate (throws a ProcessTerminationException)
265-- | Terminate (throws a ProcessTerminationException)
260terminate :: Process a
266terminate :: Process a
261−terminate = liftIO $ throw ProcessTerminationException
267+terminate = liftIO $ throwIO ProcessTerminationException
263-- | Our own process ID
269-- | Our own process ID
264getSelfPid :: Process ProcessId
270getSelfPid :: Process ProcessId
@@ -317,15 +323,51 @@ unmonitor ref = do
319--------------------------------------------------------------------------------
325--------------------------------------------------------------------------------
320−-- Auxiliary API --
326+-- Exception handling --
321--------------------------------------------------------------------------------
327--------------------------------------------------------------------------------
323−-- | Catch exceptions within a process
329+-- | Lift 'Control.Exception.catch'
324catch :: Exception e => Process a -> (e -> Process a) -> Process a
330catch :: Exception e => Process a -> (e -> Process a) -> Process a
325catch p h = do
331catch p h = do
326 lproc <- ask
332 lproc <- ask
327 liftIO $ Ex.catch (runLocalProcess lproc p) (runLocalProcess lproc . h)
333 liftIO $ Ex.catch (runLocalProcess lproc p) (runLocalProcess lproc . h)
335+-- | Lift 'Control.Exception.mask'
336+mask :: ((forall a. Process a -> Process a) -> Process b) -> Process b
339+ liftIO $ Ex.mask $ \restore ->
340+ runLocalProcess lproc (p (liftRestore lproc restore))
342+ liftRestore :: LocalProcess -> (forall a. IO a -> IO a) -> (forall a. Process a -> Process a)
343+ liftRestore lproc restoreIO = liftIO . restoreIO . runLocalProcess lproc
345+-- | Lift 'Control.Exception.onException'
346+onException :: Process a -> Process b -> Process a
347+onException p what = p `catch` \e -> do _ <- what
348+ liftIO $ throwIO (e :: SomeException)
350+-- | Lift 'Control.Exception.bracket'
351+bracket :: Process a -> (a -> Process b) -> (a -> Process c) -> Process c
352+bracket before after thing = do
353+ mask $ \restore -> do
355+ r <- restore (thing a) `onException` after a
359+-- | Lift 'Control.Exception.bracket_'
360+bracket_ :: Process a -> Process b -> Process c -> Process c
361+bracket_ before after thing = bracket before (const after) (const thing)
363+-- | Lift 'Control.Exception.finally'
364+finally :: Process a -> Process b -> Process a
365+finally a sequel = bracket_ (return ()) sequel a
367+--------------------------------------------------------------------------------
369+--------------------------------------------------------------------------------
329-- | Like 'expect' but with a timeout
371-- | Like 'expect' but with a timeout
330expectTimeout :: forall a. Serializable a => Int -> Process (Maybe a)
372expectTimeout :: forall a. Serializable a => Int -> Process (Maybe a)
331expectTimeout timeout = receiveTimeout timeout [match return]
373expectTimeout timeout = receiveTimeout timeout [match return]
@@ -464,7 +506,7 @@ unClosure :: forall a. Typeable a => Closure a -> Process a
464unClosure (Closure (Static label) env) = do
506unClosure (Closure (Static label) env) = do
465 rtable <- remoteTable . processNode <$> ask
507 rtable <- remoteTable . processNode <$> ask
466 case resolveClosure rtable label env of
508 case resolveClosure rtable label env of
467− Nothing -> throw . userError $ "Unregistered closure " ++ show label
509+ Nothing -> error $ "Unregistered closure " ++ show label
468 Just dyn -> return $ fromDyn dyn (throw (typeError dyn))
510 Just dyn -> return $ fromDyn dyn (throw (typeError dyn))
470 typeError dyn = userError $ "lookupStatic type error: "
512 typeError dyn = userError $ "lookupStatic type error: "