@@ -6,13 +6,27 @@ import Data.Typeable (Typeable)
66import Control.Monad (join, replicateM, forever)
77import Control.Exception (IOException, throw)
88import Control.Concurrent (forkIO, threadDelay)
9−import Control.Concurrent.MVar (MVar, newEmptyMVar, readMVar, takeMVar, putMVar)
9+import Control.Concurrent.MVar
10+ ( MVar
11+ , newEmptyMVar
12+ , readMVar
13+ , takeMVar
14+ , putMVar
15+ , modifyMVar_
16+ , newMVar
17+ )
1018import Control.Applicative ((<$>))
1119import Network.Transport (Transport)
12−import Network.Transport.TCP (createTransport, defaultTCPParameters)
20+import Network.Transport.TCP
21+ ( createTransportExposeInternals
22+ , defaultTCPParameters
23+ , TransportInternals(socketBetween)
24+ )
25+import Network.Socket (sClose)
1326import Control.Distributed.Process
1427import Control.Distributed.Process.Closure
1528import Control.Distributed.Process.Node
29+import Control.Distributed.Process.Internal.Types (NodeId(nodeAddress))
1630import Control.Distributed.Static (staticLabel, staticClosure)
1731import TestAuxiliary
1832
@@ -53,6 +67,9 @@ typedPingServer () rport = forever $ do
5367 sport <- receiveChan rport
5468 sendChan sport ()
5569
70+signal :: ProcessId -> Process ()
71+signal pid = send pid ()
72+
5673remotable [ 'factorial
5774 , 'addInt
5875 , 'putInt
@@ -62,6 +79,7 @@ remotable [ 'factorial
6279 , 'typedPingServer
6380 , 'isPrime
6481 , 'quintuple
82+ , 'signal
6583 ]
6684
6785-- Just try creating a static polymorphic value
@@ -337,9 +355,46 @@ testTDict transport rtable = do
337355 liftIO $ putMVar done ()
338356 takeMVar done
339357
358+
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)
366+
367+ incr <- forkProcess node1 $ forever $ do
368+ () <- expect
369+ liftIO $ modifyMVar_ iv (return . (+ 1))
370+
371+ forkProcess node2 $ do
372+ _pid1 <- spawn nid1 ($(mkClosure 'signal) incr)
373+
374+ -- Simulate network failure
375+ liftIO $ do
376+ sock <- socketBetween transportInternals (nodeAddress nid2) (nodeAddress nid1)
377+ sClose sock
378+
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)
382+
383+ -- As does this one
384+ _pid3 <- spawn nid1 ($(mkClosure 'signal) incr)
385+
386+ liftIO $ threadDelay 10000
387+
388+ count <- liftIO $ takeMVar iv
389+ True <- return $ count == 2 || count == 3 -- Depending on whether we get the monitor notification first or not
390+
391+ liftIO $ putMVar done ()
392+
393+ takeMVar done
394+
340395main :: IO ()
341396main = do
342− Right transport <- createTransport "127.0.0.1" "8080" defaultTCPParameters
397+ Right (transport, transportInternals) <- createTransportExposeInternals "127.0.0.1" "8080" defaultTCPParameters
343398 let rtable = __remoteTable initRemoteTable
344399 runTests
345400 [ ("Unclosure", testUnclosure transport rtable)
@@ -356,4 +411,5 @@ main = do
356411 , ("ClosureExpect", testClosureExpect transport rtable)
357412 , ("SpawnChannel", testSpawnChannel transport rtable)
358413 , ("TDict", testTDict transport rtable)
414+ , ("SpawnReconnect", testSpawnReconnect transport rtable transportInternals)
359415 ]