@@ -39,6 +39,7 @@ module Control.Distributed.Process.Internal.Primitives
39 -- keep the exception constructor hidden, so that handling exit
39 -- keep the exception constructor hidden, so that handling exit
40 -- reasons /must/ take place via the 'catchExit' family of primitives
40 -- reasons /must/ take place via the 'catchExit' family of primitives
41 , ProcessExitException()
41 , ProcessExitException()
42 , getSelfPid
43 , getSelfPid
43 , getSelfNode
44 , getSelfNode
44 , ProcessInfo(..)
45 , ProcessInfo(..)
@@ -96,11 +97,6 @@ module Control.Distributed.Process.Internal.Primitives
96import Prelude hiding (catch)
97import Prelude hiding (catch)
99−import Data.Binary (decode)
100−import Data.Time.Clock (getCurrentTime)
101−import Data.Time.Format (formatTime)
102−import System.Locale (defaultTimeLocale)
103−import System.Timeout (timeout)
104import Control.Monad (when)
100import Control.Monad (when)
105import Control.Monad.Reader (ask)
101import Control.Monad.Reader (ask)
106import Control.Monad.IO.Class (MonadIO, liftIO)
102import Control.Monad.IO.Class (MonadIO, liftIO)
@@ -111,6 +107,7 @@ import Control.Distributed.Process.Internal.StrictMVar
111 ( StrictMVar
107 ( StrictMVar
112 , modifyMVar
108 , modifyMVar
113 , modifyMVar_
109 , modifyMVar_
115import Control.Concurrent.Chan (writeChan)
112import Control.Concurrent.Chan (writeChan)
116import Control.Concurrent.STM
113import Control.Concurrent.STM
@@ -124,13 +121,12 @@ import Control.Concurrent.STM
125import Control.Distributed.Process.Internal.CQueue
122import Control.Distributed.Process.Internal.CQueue
126 ( dequeue
123 ( dequeue
127 , BlockSpec(..)
125 , BlockSpec(..)
128 , MatchOn(..)
126 , MatchOn(..)
130import Control.Distributed.Process.Serializable (Serializable, fingerprint)
128import Control.Distributed.Process.Serializable (Serializable, fingerprint)
131−import Data.Accessor ((^.), (^:), (^=))
132import Control.Distributed.Static (Closure, Static)
129import Control.Distributed.Static (Closure, Static)
133−import Data.Rank1Typeable (Typeable)
134import qualified Control.Distributed.Static as Static (unstatic, unclosure)
130import qualified Control.Distributed.Static as Static (unstatic, unclosure)
135import Control.Distributed.Process.Internal.Types
131import Control.Distributed.Process.Internal.Types
136 ( NodeId(..)
132 ( NodeId(..)
@@ -149,10 +145,12 @@ import Control.Distributed.Process.Internal.Types
149 , ReceivePort(..)
145 , ReceivePort(..)
150 , channelCounter
146 , channelCounter
151 , typedChannelWithId
147 , typedChannelWithId
148+ , localProcessWithId
152 , TypedChannel(..)
149 , TypedChannel(..)
153 , SendPortId(..)
150 , SendPortId(..)
154 , Identifier(..)
151 , Identifier(..)
155 , ProcessExitException(..)
152 , ProcessExitException(..)
156 , DidUnmonitor(..)
154 , DidUnmonitor(..)
157 , DidUnlinkProcess(..)
155 , DidUnlinkProcess(..)
158 , DidUnlinkNode(..)
156 , DidUnlinkNode(..)
@@ -166,7 +164,7 @@ import Control.Distributed.Process.Internal.Types
166 , createUnencodedMessage
164 , createUnencodedMessage
167 , runLocalProcess
165 , runLocalProcess
168 , ImplicitReconnect(WithImplicitReconnect, NoImplicitReconnect)
166 , ImplicitReconnect(WithImplicitReconnect, NoImplicitReconnect)
169− , LocalProcessState
167+ , LocalProcessState(..)
170 , LocalSendPortId
168 , LocalSendPortId
171 , messageToPayload
169 , messageToPayload
@@ -178,10 +176,21 @@ import Control.Distributed.Process.Internal.Messaging
179import qualified Control.Distributed.Process.Internal.Trace as Trace
177import qualified Control.Distributed.Process.Internal.Trace as Trace
180import Control.Distributed.Process.Internal.WeakTQueue
178import Control.Distributed.Process.Internal.WeakTQueue
181− ( newTQueueIO
180+ , newTQueueIO
182 , readTQueue
181 , readTQueue
183 , mkWeakTQueue
182 , mkWeakTQueue
185+import Data.Accessor ((^.), (^:), (^=))
186+import Data.Binary (decode)
187+import Data.Foldable (forM_)
188+import Data.Rank1Typeable (Typeable)
189+import Data.Time.Clock (getCurrentTime)
190+import Data.Time.Format (formatTime)
191+import System.Locale (defaultTimeLocale)
192+import System.Mem.Weak (deRefWeak)
193+import System.Timeout (timeout)
185import Unsafe.Coerce
194import Unsafe.Coerce
187--------------------------------------------------------------------------------
196--------------------------------------------------------------------------------
@@ -1031,20 +1040,63 @@ trace s = do
1031 node <- processNode <$> ask
1040 node <- processNode <$> ask
1032 liftIO $ Trace.trace (localTracer node) s
1041 liftIO $ Trace.trace (localTracer node) s
1043+--------------------------------------------------------------------------------
1044+-- Messages to local processes --
1045+--------------------------------------------------------------------------------
1047+deliverToLocalProcess :: ProcessId -> Message -> Process ()
1048+deliverToLocalProcess pid msg = do
1049+ withLocalProc pid $ \p -> enqueue (processQueue p) msg
1051+deliverToLocalPort :: SendPortId -> Message -> Process ()
1052+deliverToLocalPort spId msg =
1053+ let pid = sendPortProcessId spId
1054+ cid = sendPortLocalId spId
1056+ withLocalProc pid $ \proc -> do
1057+ mChan <- withMVar (processState proc) $ return . (^. typedChannelWithId cid)
1059+ -- in the unlikely event we know nothing about this channel id,
1060+ -- see [note: missing recipients]
1061+ Nothing -> return ()
1062+ Just (TypedChannel chan') -> do
1063+ -- If ch is Nothing, the process has given up the read end of
1064+ -- the channel and we simply ignore the incoming message - this
1065+ ch <- deRefWeak chan'
1066+ forM_ ch $ \chan -> deliverChan msg chan
1067+ where deliverChan :: forall a . Message -> TQueue a -> IO ()
1068+ deliverChan (UnencodedMessage _ raw) chan' =
1069+ atomically $ writeTQueue chan' ((unsafeCoerce raw) :: a)
1070+ deliverChan (EncodedMessage _ _) _ =
1071+ -- this will /never/ happen
1072+ error "invalid local channel delivery"
1074+withLocalProc :: ProcessId -> (LocalProcess -> IO ()) -> Process ()
1075+withLocalProc pid p = do
1076+ node <- processNode <$> ask
1078+ -- see [note: missing recipients]
1079+ let lpid = processLocalId pid
1080+ mProc <- withMVar (localState node) $ return . (^. localProcessWithId lpid)
1083+-- [note: missing recipients]
1084+-- By [Unified: table 6, rule missing_process] messages to dead processes
1085+-- can silently be dropped
1034--------------------------------------------------------------------------------
1087--------------------------------------------------------------------------------
1035-- Auxiliary functions --
1088-- Auxiliary functions --
1036--------------------------------------------------------------------------------
1089--------------------------------------------------------------------------------
1038sendLocal :: (Serializable a) => ProcessId -> a -> Process ()
1091sendLocal :: (Serializable a) => ProcessId -> a -> Process ()
1039sendLocal pid msg =
1092sendLocal pid msg =
1040− sendCtrlMsg Nothing $ LocalSend pid (createUnencodedMessage msg)
1093+ -- sendCtrlMsg Nothing $ LocalSend pid (createUnencodedMessage msg)
1094+ deliverToLocalProcess pid (createUnencodedMessage msg)
1042sendChanLocal :: (Serializable a) => SendPortId -> a -> Process ()
1096sendChanLocal :: (Serializable a) => SendPortId -> a -> Process ()
1043sendChanLocal spId msg =
1097sendChanLocal spId msg =
1044− -- we *must* fully serialize/encode the message here, because
1045− -- attempting to use `unsafeCoerce' in the node controller
1046− -- won't work since we know nothing about the required type
1047− sendCtrlMsg Nothing $ LocalPortSend spId (createUnencodedMessage msg)
1098+ -- sendCtrlMsg Nothing $ LocalPortSend spId (createUnencodedMessage msg)
1099+ deliverToLocalPort spId (createUnencodedMessage msg)
1049getMonitorRefFor :: Identifier -> Process MonitorRef
1101getMonitorRefFor :: Identifier -> Process MonitorRef
1050getMonitorRefFor ident = do
1102getMonitorRefFor ident = do