@@ -6,13 +6,27 @@ import Data.Typeable (Typeable)
6import Control.Monad (join, replicateM, forever)
6import Control.Monad (join, replicateM, forever)
7import Control.Exception (IOException, throw)
7import Control.Exception (IOException, throw)
8import Control.Concurrent (forkIO, threadDelay)
8import Control.Concurrent (forkIO, threadDelay)
9−import Control.Concurrent.MVar (MVar, newEmptyMVar, readMVar, takeMVar, putMVar)
9+import Control.Concurrent.MVar
10import Control.Applicative ((<$>))
18import Control.Applicative ((<$>))
11import Network.Transport (Transport)
19import Network.Transport (Transport)
12−import Network.Transport.TCP (createTransport, defaultTCPParameters)
20+import Network.Transport.TCP
21+ ( createTransportExposeInternals
22+ , defaultTCPParameters
23+ , TransportInternals(socketBetween)
25+import Network.Socket (sClose)
13import Control.Distributed.Process
26import Control.Distributed.Process
14import Control.Distributed.Process.Closure
27import Control.Distributed.Process.Closure
15import Control.Distributed.Process.Node
28import Control.Distributed.Process.Node
29+import Control.Distributed.Process.Internal.Types (NodeId(nodeAddress))
16import Control.Distributed.Static (staticLabel, staticClosure)
30import Control.Distributed.Static (staticLabel, staticClosure)
17import TestAuxiliary
31import TestAuxiliary
@@ -53,6 +67,9 @@ typedPingServer () rport = forever $ do
53 sport <- receiveChan rport
67 sport <- receiveChan rport
54 sendChan sport ()
68 sendChan sport ()
70+signal :: ProcessId -> Process ()
71+signal pid = send pid ()
56remotable [ 'factorial
73remotable [ 'factorial
@@ -62,6 +79,7 @@ remotable [ 'factorial
62 , 'typedPingServer
79 , 'typedPingServer
63 , 'isPrime
80 , 'isPrime
64 , 'quintuple
81 , 'quintuple
67-- Just try creating a static polymorphic value
85-- Just try creating a static polymorphic value
@@ -337,9 +355,46 @@ testTDict transport rtable = do
337 liftIO $ putMVar done ()
355 liftIO $ putMVar done ()
338 takeMVar done
356 takeMVar done
359+testSpawnReconnect :: Transport -> RemoteTable -> TransportInternals -> IO ()
360+testSpawnReconnect transport rtable transportInternals = do
361+ [node1, node2] <- replicateM 2 $ newLocalNode transport rtable
362+ let nid1 = localNodeId node1
363+ nid2 = localNodeId node2
364+ done <- newEmptyMVar
365+ iv <- newMVar (0 :: Int)
367+ incr <- forkProcess node1 $ forever $ do
369+ liftIO $ modifyMVar_ iv (return . (+ 1))
371+ forkProcess node2 $ do
372+ _pid1 <- spawn nid1 ($(mkClosure 'signal) incr)
374+ -- Simulate network failure
376+ sock <- socketBetween transportInternals (nodeAddress nid2) (nodeAddress nid1)
379+ -- Implicit reconnect: spawn happens; but since we also receive the
380+ -- monitor signal, the process might not actually be started
381+ _pid2 <- spawn nid1 ($(mkClosure 'signal) incr)
384+ _pid3 <- spawn nid1 ($(mkClosure 'signal) incr)
386+ liftIO $ threadDelay 10000
388+ count <- liftIO $ takeMVar iv
389+ True <- return $ count == 2 || count == 3 -- Depending on whether we get the monitor notification first or not
391+ liftIO $ putMVar done ()
340main :: IO ()
395main :: IO ()
342− Right transport <- createTransport "127.0.0.1" "8080" defaultTCPParameters
397+ Right (transport, transportInternals) <- createTransportExposeInternals "127.0.0.1" "8080" defaultTCPParameters
343 let rtable = __remoteTable initRemoteTable
398 let rtable = __remoteTable initRemoteTable
344 runTests
399 runTests
345 [ ("Unclosure", testUnclosure transport rtable)
400 [ ("Unclosure", testUnclosure transport rtable)
@@ -356,4 +411,5 @@ main = do
356 , ("ClosureExpect", testClosureExpect transport rtable)
411 , ("ClosureExpect", testClosureExpect transport rtable)
357 , ("SpawnChannel", testSpawnChannel transport rtable)
412 , ("SpawnChannel", testSpawnChannel transport rtable)
358 , ("TDict", testTDict transport rtable)
413 , ("TDict", testTDict transport rtable)
414+ , ("SpawnReconnect", testSpawnReconnect transport rtable transportInternals)