git.iko.soy/distributed-process
on master help sign in
Monitor abnormal termination
commita75cb28a465d5be94169d1832c6706f278f1f84a authorEdsko de Vries <edsko@edsko.net> dateWed 13 Jun 2012, 13:49 (14 years ago) parent743e579
2 files changed+72−23
distributed-process/src/Control/Distributed/Process.hs+35−21 distributed-process/tests/TestCH.hs+37−2
distributed-process/src/Control/Distributed/Process.hs+35−21
@@ -103,13 +103,13 @@ import Data.Int (Int32)
103103import Data.Typeable (Typeable)
104104import Data.Foldable (forM_)
105105import Data.Maybe (isJust)
106−import Control.Monad (void, liftM2, liftM3, when, unless, forever)
106+import Control.Monad (void, when, unless, forever)
107107import Control.Monad.Reader (MonadReader(..), ReaderT, runReaderT)
108108import Control.Monad.IO.Class (MonadIO, liftIO)
109109import Control.Monad.State (MonadState, StateT, evalStateT, gets, modify)
110−import Control.Applicative ((<$>))
110+import Control.Applicative ((<$>), (<*>))
111111import Control.Category ((>>>))
112−import Control.Exception (Exception, throwIO, catch)
112+import Control.Exception (Exception, throwIO, catch, SomeException)
113113import Control.Concurrent (forkIO)
114114import Control.Concurrent.MVar ( MVar
115115 , newMVar
@@ -294,6 +294,7 @@ data MonitorReply = ProcessDied MonitorRef ProcessId DiedReason
294294
295295data DiedReason =
296296 DiedNormal
297+ | DiedException String -- TODO: would prefer SomeException instead of String, but exceptions don't implement Binary
297298 | DiedDisconnect
298299 | DiedNodeDown
299300
@@ -527,13 +528,24 @@ forkProcess node proc = do
527528 , lproc
528529 )
529530 void . forkIO $ do
530− runLocalProcess lproc proc
531− -- [Unified: Table 4]
532− let pid = processId lproc
533− writeChan (localCtrlChan node) $ NodeCtrlMsg
534− { ctrlMsgSender = Left pid
535− , ctrlMsgSignal = Died (Left pid) DiedNormal
536− }
531+ catch (do
532+ runLocalProcess lproc proc
533+ -- [Unified: Table 4]
534+ let pid = processId lproc
535+ writeChan (localCtrlChan node) $ NodeCtrlMsg
536+ { ctrlMsgSender = Left pid
537+ , ctrlMsgSignal = Died (Left pid) DiedNormal
538+ }
539+ )
540+ (\ex -> do
541+ let pid = processId lproc
542+ err = show (ex :: SomeException)
543+ writeChan (localCtrlChan node) $ NodeCtrlMsg
544+ { ctrlMsgSender = Left pid
545+ , ctrlMsgSignal = Died (Left pid) (DiedException err)
546+ }
547+ )
548+
537549 return (processId lproc)
538550
539551handleIncomingMessages :: LocalNode -> IO ()
@@ -727,19 +739,19 @@ runLocalProcess lproc proc = runReaderT (unProcess proc) lproc
727739
728740instance Binary LocalProcessId where
729741 put lpid = put (lpidUnique lpid) >> put (lpidCounter lpid)
730− get = liftM2 LocalProcessId get get
742+ get = LocalProcessId <$> get <*> get
731743
732744instance Binary ProcessId where
733745 put pid = put (processNodeId pid) >> put (processLocalId pid)
734− get = liftM2 ProcessId get get
746+ get = ProcessId <$> get <*> get
735747
736748instance Binary MonitorReply where
737749 put (ProcessDied ref pid reason) = put ref >> put pid >> put reason
738− get = liftM3 ProcessDied get get get
750+ get = ProcessDied <$> get <*> get <*> get
739751
740752instance Binary NodeCtrlMsg where
741753 put msg = put (ctrlMsgSender msg) >> put (ctrlMsgSignal msg)
742− get = liftM2 NodeCtrlMsg get get
754+ get = NodeCtrlMsg <$> get <*> get
743755
744756instance Binary ProcessSignal where
745757 put (Monitor pid ref) = putWord8 0 >> put pid >> put ref
@@ -747,20 +759,22 @@ instance Binary ProcessSignal where
747759 get = do
748760 header <- getWord8
749761 case header of
750− 0 -> liftM2 Monitor get get
751− 1 -> liftM2 Died get get
762+ 0 -> Monitor <$> get <*> get
763+ 1 -> Died <$> get <*> get
752764 _ -> fail "ProcessSignal.get: invalid"
753765
754766instance Binary DiedReason where
755− put DiedNormal = putWord8 0
756− put DiedDisconnect = putWord8 1
757− put DiedNodeDown = putWord8 2
767+ put DiedNormal = putWord8 0
768+ put (DiedException e) = putWord8 1 >> put e
769+ put DiedDisconnect = putWord8 2
770+ put DiedNodeDown = putWord8 3
758771 get = do
759772 header <- getWord8
760773 case header of
761774 0 -> return DiedNormal
762− 1 -> return DiedDisconnect
763− 2 -> return DiedNodeDown
775+ 1 -> DiedException <$> get
776+ 2 -> return DiedDisconnect
777+ 3 -> return DiedNodeDown
764778 _ -> fail "DiedReason.get: invalid"
765779
766780--------------------------------------------------------------------------------
distributed-process/tests/TestCH.hs+37−2
@@ -12,6 +12,7 @@ import Control.Concurrent.MVar ( newEmptyMVar
1212import Control.Monad (replicateM_)
1313import Control.Distributed.Process
1414import Control.Monad.IO.Class (liftIO)
15+import Control.Exception (throwIO)
1516import qualified Network.Transport as NT (Transport)
1617import Network.Transport.TCP (createTransport, defaultTCPParameters)
1718import TestAuxiliary
@@ -116,6 +117,39 @@ testMonitorNormalTermination transport = do
116117
117118 takeMVar done
118119
120+-- | Monitor a process which terminates abnormally
121+testMonitorAbnormalTermination :: NT.Transport -> IO ()
122+testMonitorAbnormalTermination transport = do
123+ monitorSetup <- newEmptyMVar
124+ monitoredProcess <- newEmptyMVar
125+ done <- newEmptyMVar
126+
127+ let err = userError "Abnormal termination"
128+
129+ forkIO $ do
130+ localNode <- newLocalNode transport
131+ addr <- forkProcess localNode . liftIO $ do
132+ readMVar monitorSetup
133+ throwIO err
134+ putMVar monitoredProcess addr
135+
136+ forkIO $ do
137+ localNode <- newLocalNode transport
138+ theirAddr <- readMVar monitoredProcess
139+ runProcess localNode $ do
140+ ref <- monitor theirAddr
141+ liftIO $ do
142+ -- Monitor is asynchronous, but we want to make sure the monitor has
143+ -- been fully created before allowing the remote process to terminate,
144+ -- otherwise we might get a different signal here
145+ threadDelay 100000
146+ putMVar monitorSetup ()
147+ ProcessDied ref' pid (DiedException err') <- expect
148+ True <- return $ ref' == ref && pid == theirAddr && err' == show err
149+ return ()
150+ putMVar done ()
151+
152+ takeMVar done
119153
120154
121155
@@ -226,8 +260,9 @@ main = do
226260 Right transport <- createTransport "127.0.0.1" "8080" defaultTCPParameters
227261 runTests
228262 [ --("Ping", testPing transport)
229− ("MonitorUnreachable", testMonitorUnreachable transport)
230− , ("MonitorNormalTermination", testMonitorNormalTermination transport)
263+ ("MonitorUnreachable", testMonitorUnreachable transport)
264+ , ("MonitorNormalTermination", testMonitorNormalTermination transport)
265+ , ("MonitorAbnormalTermination", testMonitorAbnormalTermination transport)
231266 {-
232267 , ("Monitor2", testMonitor2 transport)
233268 , ("Monitor3", testMonitor3 transport)