@@ -12,6 +12,7 @@ import Control.Concurrent.MVar ( newEmptyMVar
12import Control.Monad (replicateM_)
12import Control.Monad (replicateM_)
13import Control.Monad.IO.Class (liftIO)
13import Control.Monad.IO.Class (liftIO)
14import Control.Exception (throwIO)
14import Control.Exception (throwIO)
15+import Control.Applicative ((<$>))
15import qualified Network.Transport as NT (Transport, closeEndPoint)
16import qualified Network.Transport as NT (Transport, closeEndPoint)
16import Network.Transport.TCP (createTransport, defaultTCPParameters)
17import Network.Transport.TCP (createTransport, defaultTCPParameters)
17import Control.Distributed.Process
18import Control.Distributed.Process
@@ -62,10 +63,14 @@ testPing transport = do
63 takeMVar clientDone
64 takeMVar clientDone
66+-- | Monitor or link to a remote node
67+monitorOrLink :: Bool -> ProcessId -> Process (Maybe MonitorRef)
68+monitorOrLink True pid = Just <$> monitor pid
69+monitorOrLink False pid = link pid >> return Nothing
66-- | Monitor an unreachable node
71-- | Monitor an unreachable node
67−testMonitorUnreachable :: NT.Transport -> IO ()
72+testMonitorUnreachable :: NT.Transport -> Bool -> IO ()
68−testMonitorUnreachable transport = do
73+testMonitorUnreachable transport mOrL = do
69 deadProcess <- newEmptyMVar
74 deadProcess <- newEmptyMVar
70 done <- newEmptyMVar
75 done <- newEmptyMVar
@@ -78,18 +83,20 @@ testMonitorUnreachable transport = do
78 forkIO $ do
83 forkIO $ do
79 localNode <- newLocalNode transport
84 localNode <- newLocalNode transport
80 theirAddr <- readMVar deadProcess
85 theirAddr <- readMVar deadProcess
81− runProcess localNode $ do
86+ runProcess localNode $
82− ref <- monitor theirAddr
87+ catch (do ref <- monitorOrLink mOrL theirAddr
83− ProcessDied ref' pid DiedDisconnect <- expect
88+ MonitorNotification ref' pid DiedDisconnect <- expect
84− True <- return $ ref' == ref && pid == theirAddr
89+ True <- return $ Just ref' == ref && pid == theirAddr && mOrL
85− return ()
90+ liftIO $ putMVar done ())
91+ (\(LinkException pid DiedDisconnect) -> do
92+ True <- return $ pid == theirAddr && not mOrL
86− putMVar done ()
93+ liftIO $ putMVar done ())
88 takeMVar done
95 takeMVar done
90-- | Monitor a process which terminates normally
97-- | Monitor a process which terminates normally
91−testMonitorNormalTermination :: NT.Transport -> IO ()
98+testMonitorNormalTermination :: NT.Transport -> Bool -> IO ()
92−testMonitorNormalTermination transport = do
99+testMonitorNormalTermination transport mOrL = do
93 monitorSetup <- newEmptyMVar
100 monitorSetup <- newEmptyMVar
94 monitoredProcess <- newEmptyMVar
101 monitoredProcess <- newEmptyMVar
95 done <- newEmptyMVar
102 done <- newEmptyMVar
@@ -103,24 +110,26 @@ testMonitorNormalTermination transport = do
103 forkIO $ do
110 forkIO $ do
104 localNode <- newLocalNode transport
111 localNode <- newLocalNode transport
105 theirAddr <- readMVar monitoredProcess
112 theirAddr <- readMVar monitoredProcess
106− runProcess localNode $ do
113+ runProcess localNode $
107− ref <- monitor theirAddr
114+ catch (do ref <- monitorOrLink mOrL theirAddr
108− liftIO $ do
115+ liftIO $ do
109− -- Monitor is asynchronous, but we want to make sure the monitor has
116+ -- Monitor is asynchronous, but we want to make sure the monitor has
110− -- been fully created before allowing the remote process to terminate,
117+ -- been fully created before allowing the remote process to terminate,
111− -- otherwise we might get a different signal here
118+ -- otherwise we might get a different signal here
112− threadDelay 100000
119+ threadDelay 100000
113− putMVar monitorSetup ()
120+ putMVar monitorSetup ()
114− ProcessDied ref' pid DiedNormal <- expect
121+ MonitorNotification ref' pid DiedNormal <- expect
115− True <- return $ ref' == ref && pid == theirAddr
122+ True <- return $ Just ref' == ref && pid == theirAddr && mOrL
116− return ()
123+ liftIO $ putMVar done ())
124+ (\(LinkException pid DiedNormal) -> do
125+ True <- return $ pid == theirAddr && not mOrL
117− putMVar done ()
126+ liftIO $ putMVar done ())
119 takeMVar done
128 takeMVar done
121-- | Monitor a process which terminates abnormally
130-- | Monitor a process which terminates abnormally
122−testMonitorAbnormalTermination :: NT.Transport -> IO ()
131+testMonitorAbnormalTermination :: NT.Transport -> Bool -> IO ()
123−testMonitorAbnormalTermination transport = do
132+testMonitorAbnormalTermination transport mOrL = do
124 monitorSetup <- newEmptyMVar
133 monitorSetup <- newEmptyMVar
125 monitoredProcess <- newEmptyMVar
134 monitoredProcess <- newEmptyMVar
126 done <- newEmptyMVar
135 done <- newEmptyMVar
@@ -137,24 +146,26 @@ testMonitorAbnormalTermination transport = do
137 forkIO $ do
146 forkIO $ do
138 localNode <- newLocalNode transport
147 localNode <- newLocalNode transport
139 theirAddr <- readMVar monitoredProcess
148 theirAddr <- readMVar monitoredProcess
140− runProcess localNode $ do
149+ runProcess localNode $
141− ref <- monitor theirAddr
150+ catch (do ref <- monitorOrLink mOrL theirAddr
142− liftIO $ do
151+ liftIO $ do
143− -- Monitor is asynchronous, but we want to make sure the monitor has
152+ -- Monitor is asynchronous, but we want to make sure the monitor has
144− -- been fully created before allowing the remote process to terminate,
153+ -- been fully created before allowing the remote process to terminate,
145− -- otherwise we might get a different signal here
154+ -- otherwise we might get a different signal here
146− threadDelay 100000
155+ threadDelay 100000
147− putMVar monitorSetup ()
156+ putMVar monitorSetup ()
148− ProcessDied ref' pid (DiedException err') <- expect
157+ MonitorNotification ref' pid (DiedException err') <- expect
149− True <- return $ ref' == ref && pid == theirAddr && err' == show err
158+ True <- return $ Just ref' == ref && pid == theirAddr && err' == show err && mOrL
150− return ()
159+ liftIO $ putMVar done ())
160+ (\(LinkException pid (DiedException err')) -> do
161+ True <- return $ pid == theirAddr && err' == show err && not mOrL
151− putMVar done ()
162+ liftIO $ putMVar done ())
153 takeMVar done
164 takeMVar done
155-- | Monitor a local process that is already dead
166-- | Monitor a local process that is already dead
156−testMonitorLocalDeadProcess :: NT.Transport -> IO ()
167+testMonitorLocalDeadProcess :: NT.Transport -> Bool -> IO ()
157−testMonitorLocalDeadProcess transport = do
168+testMonitorLocalDeadProcess transport mOrL = do
158 processDead <- newEmptyMVar
169 processDead <- newEmptyMVar
159 processAddr <- newEmptyMVar
170 processAddr <- newEmptyMVar
160 localNode <- newLocalNode transport
171 localNode <- newLocalNode transport
@@ -168,17 +179,19 @@ testMonitorLocalDeadProcess transport = do
168 theirAddr <- readMVar processAddr
179 theirAddr <- readMVar processAddr
169 readMVar processDead
180 readMVar processDead
170 runProcess localNode $ do
181 runProcess localNode $ do
171− ref <- monitor theirAddr
182+ catch (do ref <- monitorOrLink mOrL theirAddr
172− ProcessDied ref' pid DiedNoProc <- expect
183+ MonitorNotification ref' pid DiedNoProc <- expect
173− True <- return $ ref' == ref && pid == theirAddr
184+ True <- return $ Just ref' == ref && pid == theirAddr && mOrL
174− return ()
185+ liftIO $ putMVar done ())
186+ (\(LinkException pid DiedNoProc) -> do
187+ True <- return $ pid == theirAddr && not mOrL
175− putMVar done ()
188+ liftIO $ putMVar done ())
177 takeMVar done
190 takeMVar done
179-- | Monitor a remote process that is already dead
192-- | Monitor a remote process that is already dead
180−testMonitorRemoteDeadProcess :: NT.Transport -> IO ()
193+testMonitorRemoteDeadProcess :: NT.Transport -> Bool -> IO ()
181−testMonitorRemoteDeadProcess transport = do
194+testMonitorRemoteDeadProcess transport mOrL = do
182 processDead <- newEmptyMVar
195 processDead <- newEmptyMVar
183 processAddr <- newEmptyMVar
196 processAddr <- newEmptyMVar
184 done <- newEmptyMVar
197 done <- newEmptyMVar
@@ -193,17 +206,19 @@ testMonitorRemoteDeadProcess transport = do
193 theirAddr <- readMVar processAddr
206 theirAddr <- readMVar processAddr
194 readMVar processDead
207 readMVar processDead
195 runProcess localNode $ do
208 runProcess localNode $ do
196− ref <- monitor theirAddr
209+ catch (do ref <- monitorOrLink mOrL theirAddr
197− ProcessDied ref' pid DiedNoProc <- expect
210+ MonitorNotification ref' pid DiedNoProc <- expect
198− True <- return $ ref' == ref && pid == theirAddr
211+ True <- return $ Just ref' == ref && pid == theirAddr && mOrL
199− return ()
212+ liftIO $ putMVar done ())
213+ (\(LinkException pid DiedNoProc) -> do
214+ True <- return $ pid == theirAddr && not mOrL
200− putMVar done ()
215+ liftIO $ putMVar done ())
202 takeMVar done
217 takeMVar done
204-- | Monitor a process that becomes disconnected
219-- | Monitor a process that becomes disconnected
205−testMonitorDisconnect :: NT.Transport -> IO ()
220+testMonitorDisconnect :: NT.Transport -> Bool -> IO ()
206−testMonitorDisconnect transport = do
221+testMonitorDisconnect transport mOrL = do
207 processAddr <- newEmptyMVar
222 processAddr <- newEmptyMVar
208 monitorSetup <- newEmptyMVar
223 monitorSetup <- newEmptyMVar
209 done <- newEmptyMVar
224 done <- newEmptyMVar
@@ -219,13 +234,15 @@ testMonitorDisconnect transport = do
219 localNode <- newLocalNode transport
234 localNode <- newLocalNode transport
220 theirAddr <- readMVar processAddr
235 theirAddr <- readMVar processAddr
221 runProcess localNode $ do
236 runProcess localNode $ do
222− ref <- monitor theirAddr
237+ catch (do ref <- monitorOrLink mOrL theirAddr
223− liftIO $ threadDelay 100000 >> putMVar monitorSetup ()
238+ liftIO $ threadDelay 100000 >> putMVar monitorSetup ()
224− ProcessDied ref' pid DiedDisconnect <- expect
239+ MonitorNotification ref' pid DiedDisconnect <- expect
225− True <- return $ ref' == ref && pid == theirAddr
240+ True <- return $ Just ref' == ref && pid == theirAddr && mOrL
226− return ()
241+ liftIO $ putMVar done ())
242+ (\(LinkException pid DiedDisconnect) -> do
243+ True <- return $ pid == theirAddr && not mOrL
227− putMVar done ()
244+ liftIO $ putMVar done ())
229 takeMVar done
246 takeMVar done
@@ -336,12 +353,18 @@ main = do
336 Right transport <- createTransport "127.0.0.1" "8080" defaultTCPParameters
353 Right transport <- createTransport "127.0.0.1" "8080" defaultTCPParameters
337 runTests
354 runTests
338 [ --("Ping", testPing transport)
355 [ --("Ping", testPing transport)
339− ("MonitorUnreachable", testMonitorUnreachable transport)
356+ ("MonitorUnreachable", testMonitorUnreachable transport True)
340− , ("MonitorNormalTermination", testMonitorNormalTermination transport)
357+ , ("MonitorNormalTermination", testMonitorNormalTermination transport True)
341− , ("MonitorAbnormalTermination", testMonitorAbnormalTermination transport)
358+ , ("MonitorAbnormalTermination", testMonitorAbnormalTermination transport True)
342− , ("MonitorLocalDeadProcess", testMonitorLocalDeadProcess transport)
359+ , ("MonitorLocalDeadProcess", testMonitorLocalDeadProcess transport True)
343− , ("MonitorRemoteDeadProcess", testMonitorRemoteDeadProcess transport)
360+ , ("MonitorRemoteDeadProcess", testMonitorRemoteDeadProcess transport True)
344− , ("MonitorDisconnect", testMonitorDisconnect transport)
361+ , ("MonitorDisconnect", testMonitorDisconnect transport True)
362+ , ("LinkUnreachable", testMonitorUnreachable transport False)
363+ , ("LinkNormalTermination", testMonitorNormalTermination transport False)
364+ , ("LinkAbnormalTermination", testMonitorAbnormalTermination transport False)
365+ , ("LinkLocalDeadProcess", testMonitorLocalDeadProcess transport False)
366+ , ("LinkRemoteDeadProcess", testMonitorRemoteDeadProcess transport False)
367+ , ("LinkDisconnect", testMonitorDisconnect transport False)
346 , ("Monitor2", testMonitor2 transport)
369 , ("Monitor2", testMonitor2 transport)
347 , ("Monitor3", testMonitor3 transport)
370 , ("Monitor3", testMonitor3 transport)