@@ -6,22 +6,27 @@ module Control.Distributed.Process.Internal
7 , LocalProcessId(..)
7 , LocalProcessId(..)
8 , ProcessId(..)
8 , ProcessId(..)
9 -- * Local nodes and processes
10 -- * Local nodes and processes
10 , LocalNode(..)
11 , LocalNode(..)
11 , LocalNodeState(..)
12 , LocalNodeState(..)
12 , LocalProcess(..)
13 , LocalProcess(..)
13 , LocalProcessState(..)
14 , LocalProcessState(..)
14 -- * Messages
19 -- * Messages
15 , Message(..)
20 , Message(..)
16− -- * Monitoring and linking
21+ -- * Node controller user-visible data types
17 , MonitorRef(..)
22 , MonitorRef(..)
18 , MonitorNotification(..)
23 , MonitorNotification(..)
19 , LinkException(..)
24 , LinkException(..)
20 , DiedReason(..)
25 , DiedReason(..)
21 , DidUnmonitor(..)
26 , DidUnmonitor(..)
22 , DidUnlink(..)
27 , DidUnlink(..)
23− -- * Node controller data types
29+ -- * Node controller internal data types
25 , NCMsg(..)
30 , NCMsg(..)
26 , ProcessSignal(..)
31 , ProcessSignal(..)
27 -- * Serialization/deserialization
32 -- * Serialization/deserialization
@@ -34,9 +39,10 @@ module Control.Distributed.Process.Internal
34 , localProcesses
39 , localProcesses
35 , localPidCounter
40 , localPidCounter
36 , localPidUnique
41 , localPidUnique
37− , localMonitorCounter
38 , localProcessWithId
42 , localProcessWithId
39 , connections
43 , connections
40 , connectionTo
46 , connectionTo
@@ -51,6 +57,7 @@ import Data.Int (Int32)
51import Data.Typeable (Typeable)
57import Data.Typeable (Typeable)
52import Data.Dynamic (Dynamic)
58import Data.Dynamic (Dynamic)
53import Data.Binary (Binary, encode, put, get, putWord8, getWord8)
59import Data.Binary (Binary, encode, put, get, putWord8, getWord8)
60+import Data.ByteString.Lazy (ByteString)
54import Data.Accessor (Accessor, accessor)
61import Data.Accessor (Accessor, accessor)
55import qualified Data.Accessor.Container as DAC (mapMaybe)
62import qualified Data.Accessor.Container as DAC (mapMaybe)
56import qualified Data.ByteString.Lazy as BSL (ByteString, toChunks, fromChunks, splitAt)
63import qualified Data.ByteString.Lazy as BSL (ByteString, toChunks, fromChunks, splitAt)
@@ -58,6 +65,8 @@ import qualified Data.ByteString as BSS (ByteString, concat, splitAt)
58import qualified Network.Transport as NT (EndPoint, EndPointAddress, Connection)
65import qualified Network.Transport as NT (EndPoint, EndPointAddress, Connection)
59import qualified Network.Transport.Internal as NTI (encodeInt32, decodeInt32)
66import qualified Network.Transport.Internal as NTI (encodeInt32, decodeInt32)
60import Control.Applicative ((<$>), (<*>))
67import Control.Applicative ((<$>), (<*>))
68+import Control.Monad.Reader (MonadReader(..), ReaderT)
69+import Control.Monad.IO.Class (MonadIO)
61import Control.Distributed.Process.Serializable ( Fingerprint
70import Control.Distributed.Process.Serializable ( Fingerprint
62 , Serializable
71 , Serializable
63 , encodeFingerprint
72 , encodeFingerprint
@@ -67,6 +76,21 @@ import Control.Distributed.Process.Serializable ( Fingerprint
68import Control.Distributed.Process.Internal.CQueue (CQueue)
77import Control.Distributed.Process.Internal.CQueue (CQueue)
79+--------------------------------------------------------------------------------
81+--------------------------------------------------------------------------------
83+-- | Used to fake 'static' (see paper)
84+type RemoteTable = Map String Dynamic
86+-- | Initial (empty) remote-call meta data
87+initRemoteTable :: RemoteTable
88+initRemoteTable = Map.empty
90+--------------------------------------------------------------------------------
91+-- Node and process identifiers --
92+--------------------------------------------------------------------------------
70-- | Node identifier
94-- | Node identifier
71newtype NodeId = NodeId { nodeAddress :: NT.EndPointAddress }
95newtype NodeId = NodeId { nodeAddress :: NT.EndPointAddress }
72 deriving (Eq, Ord, Binary)
96 deriving (Eq, Ord, Binary)
@@ -95,12 +119,12 @@ data ProcessId = ProcessId
95instance Show ProcessId where
119instance Show ProcessId where
96 show pid = show (processNodeId pid) ++ ":" ++ show (processLocalId pid)
120 show pid = show (processNodeId pid) ++ ":" ++ show (processLocalId pid)
98−-- | Used to fake 'static' (see paper)
122+-- | Node or process identifier
99−type RemoteTable = Map String Dynamic
123+type Identifier = Either ProcessId NodeId
101−-- | Initial (empty) remote-call meta data
125+--------------------------------------------------------------------------------
102−initRemoteTable :: RemoteTable
126+-- Local nodes and processes --
103−initRemoteTable = Map.empty
127+--------------------------------------------------------------------------------
105-- | Local nodes
129-- | Local nodes
106data LocalNode = LocalNode
130data LocalNode = LocalNode
@@ -117,7 +141,6 @@ data LocalNodeState = LocalNodeState
117 { _localProcesses :: Map LocalProcessId LocalProcess
141 { _localProcesses :: Map LocalProcessId LocalProcess
118 , _localPidCounter :: Int32
142 , _localPidCounter :: Int32
119 , _localPidUnique :: Int32
143 , _localPidUnique :: Int32
120− , _localMonitorCounter :: Int32
123-- | Processes running on our local node
146-- | Processes running on our local node
@@ -132,17 +155,46 @@ data LocalProcess = LocalProcess
132-- | Local process state
155-- | Local process state
133data LocalProcessState = LocalProcessState
156data LocalProcessState = LocalProcessState
134 { _connections :: Map ProcessId NT.Connection
157 { _connections :: Map ProcessId NT.Connection
158+ , _monitorCounter :: Int32
159+ , _spawnCounter :: Int32
162+-- | The Cloud Haskell 'Process' type
163+newtype Process a = Process { unProcess :: ReaderT LocalProcess IO a }
164+ deriving (Functor, Monad, MonadIO, MonadReader LocalProcess, Typeable)
166+--------------------------------------------------------------------------------
168+--------------------------------------------------------------------------------
170+-- | A static value is one that is bound at top-level.
171+-- We represent it simply by a string
172+newtype Static a = Static String
173+ deriving (Typeable, Show)
175+-- | A closure is a static value and an encoded environment
176+data Closure a = Closure (Static (ByteString -> a)) ByteString
177+ deriving (Typeable, Show)
179+--------------------------------------------------------------------------------
181+--------------------------------------------------------------------------------
137-- | Messages consist of their typeRep fingerprint and their encoding
183-- | Messages consist of their typeRep fingerprint and their encoding
138data Message = Message
184data Message = Message
139 { messageFingerprint :: Fingerprint
185 { messageFingerprint :: Fingerprint
140 , messageEncoding :: BSL.ByteString
186 , messageEncoding :: BSL.ByteString
189+--------------------------------------------------------------------------------
190+-- Node controller user-visible data types --
191+--------------------------------------------------------------------------------
143-- | MonitorRef is opaque for regular Cloud Haskell processes
193-- | MonitorRef is opaque for regular Cloud Haskell processes
144data MonitorRef = MonitorRef
194data MonitorRef = MonitorRef
195+ { -- | PID of the process to be monitored (for routing purposes)
145− { monitorRefPid :: ProcessId
196+ monitorRefPid :: ProcessId
197+ -- | Unique to distinguish multiple monitor requests by the same process
146 , monitorRefCounter :: Int32
198 , monitorRefCounter :: Int32
148 deriving (Eq, Ord, Show)
200 deriving (Eq, Ord, Show)
@@ -157,14 +209,6 @@ data LinkException = LinkException ProcessId DiedReason
158instance Exception LinkException
210instance Exception LinkException
160−-- | (Asynchronous) reply from unmonitor
161−newtype DidUnmonitor = DidUnmonitor MonitorRef
162− deriving (Typeable, Binary)
164−-- | (Asynchronous) reply from unlink
165−newtype DidUnlink = DidUnlink ProcessId
166− deriving (Typeable, Binary)
168-- | Why did a process die?
212-- | Why did a process die?
169data DiedReason =
213data DiedReason =
170 -- | Normal termination
214 -- | Normal termination
@@ -180,8 +224,21 @@ data DiedReason =
180 | DiedNoProc
224 | DiedNoProc
181 deriving (Show, Eq)
225 deriving (Show, Eq)
183−-- | Node or process identifier
227+-- | (Asynchronous) reply from unmonitor
184−type Identifier = Either ProcessId NodeId
228+newtype DidUnmonitor = DidUnmonitor MonitorRef
229+ deriving (Typeable, Binary)
231+-- | (Asynchronous) reply from unlink
232+newtype DidUnlink = DidUnlink ProcessId
233+ deriving (Typeable, Binary)
235+-- | 'SpawnRef' are used to return pids of spawned processes
236+newtype SpawnRef = SpawnRef Int32
237+ deriving (Show, Binary, Typeable)
239+--------------------------------------------------------------------------------
240+-- Node controller internal data types --
241+--------------------------------------------------------------------------------
186-- | Messages to the node controller
243-- | Messages to the node controller
187data NCMsg = NCMsg
244data NCMsg = NCMsg
@@ -197,6 +254,7 @@ data ProcessSignal =
197 | Monitor ProcessId MonitorRef
254 | Monitor ProcessId MonitorRef
198 | Unmonitor MonitorRef
255 | Unmonitor MonitorRef
199 | Died Identifier DiedReason
256 | Died Identifier DiedReason
257+ | Spawn (Closure (Process ())) SpawnRef
200 deriving Show
258 deriving Show
202--------------------------------------------------------------------------------
260--------------------------------------------------------------------------------
@@ -241,6 +299,10 @@ payloadToId bss = let (bs1, bss') = BSS.splitAt 4 . BSS.concat $ bss
242 _ -> fail "payloadToId"
300 _ -> fail "payloadToId"
302+--------------------------------------------------------------------------------
303+-- Binary instances --
304+--------------------------------------------------------------------------------
244instance Binary LocalProcessId where
306instance Binary LocalProcessId where
245 put lpid = put (lpidUnique lpid) >> put (lpidCounter lpid)
307 put lpid = put (lpidUnique lpid) >> put (lpidCounter lpid)
246 get = LocalProcessId <$> get <*> get
308 get = LocalProcessId <$> get <*> get
@@ -267,6 +329,7 @@ instance Binary ProcessSignal where
267 put (Monitor pid ref) = putWord8 2 >> put pid >> put ref
329 put (Monitor pid ref) = putWord8 2 >> put pid >> put ref
268 put (Unmonitor ref) = putWord8 3 >> put ref
330 put (Unmonitor ref) = putWord8 3 >> put ref
269 put (Died who reason) = putWord8 4 >> put who >> put reason
331 put (Died who reason) = putWord8 4 >> put who >> put reason
332+ put (Spawn proc ref) = putWord8 5 >> put proc >> put ref
271 header <- getWord8
334 header <- getWord8
272 case header of
335 case header of
@@ -275,6 +338,7 @@ instance Binary ProcessSignal where
275 2 -> Monitor <$> get <*> get
338 2 -> Monitor <$> get <*> get
276 3 -> Unmonitor <$> get
339 3 -> Unmonitor <$> get
277 4 -> Died <$> get <*> get
340 4 -> Died <$> get <*> get
341+ 5 -> Spawn <$> get <*> get
278 _ -> fail "ProcessSignal.get: invalid"
342 _ -> fail "ProcessSignal.get: invalid"
280instance Binary DiedReason where
344instance Binary DiedReason where
@@ -293,6 +357,10 @@ instance Binary DiedReason where
293 4 -> return DiedNoProc
357 4 -> return DiedNoProc
294 _ -> fail "DiedReason.get: invalid"
358 _ -> fail "DiedReason.get: invalid"
360+instance Binary (Closure a) where
361+ put (Closure (Static label) env) = put label >> put env
362+ get = Closure <$> (Static <$> get) <*> get
296--------------------------------------------------------------------------------
364--------------------------------------------------------------------------------
297-- Accessors --
365-- Accessors --
298--------------------------------------------------------------------------------
366--------------------------------------------------------------------------------
@@ -306,14 +374,19 @@ localPidCounter = accessor _localPidCounter (\ctr st -> st { _localPidCounter =
306localPidUnique :: Accessor LocalNodeState Int32
374localPidUnique :: Accessor LocalNodeState Int32
307localPidUnique = accessor _localPidUnique (\unq st -> st { _localPidUnique = unq })
375localPidUnique = accessor _localPidUnique (\unq st -> st { _localPidUnique = unq })
309−localMonitorCounter :: Accessor LocalNodeState Int32
310−localMonitorCounter = accessor _localMonitorCounter (\ctr st -> st { _localMonitorCounter = ctr })
312localProcessWithId :: LocalProcessId -> Accessor LocalNodeState (Maybe LocalProcess)
377localProcessWithId :: LocalProcessId -> Accessor LocalNodeState (Maybe LocalProcess)
313localProcessWithId lpid = localProcesses >>> DAC.mapMaybe lpid
378localProcessWithId lpid = localProcesses >>> DAC.mapMaybe lpid
315connections :: Accessor LocalProcessState (Map ProcessId NT.Connection)
380connections :: Accessor LocalProcessState (Map ProcessId NT.Connection)
316connections = accessor _connections (\conns st -> st { _connections = conns })
381connections = accessor _connections (\conns st -> st { _connections = conns })
383+monitorCounter :: Accessor LocalProcessState Int32
384+monitorCounter = accessor _monitorCounter (\cnt st -> st { _monitorCounter = cnt })
386+spawnCounter :: Accessor LocalProcessState Int32
387+spawnCounter = accessor _spawnCounter (\cnt st -> st { _spawnCounter = cnt })
318connectionTo :: ProcessId -> Accessor LocalProcessState (Maybe NT.Connection)
389connectionTo :: ProcessId -> Accessor LocalProcessState (Maybe NT.Connection)
319connectionTo pid = connections >>> DAC.mapMaybe pid
390connectionTo pid = connections >>> DAC.mapMaybe pid