@@ -163,6 +163,7 @@ import Control.Distributed.Process.Internal.Types
163 , ProcessInfo(..)
163 , ProcessInfo(..)
164 , ProcessInfoNone(..)
164 , ProcessInfoNone(..)
165 , createMessage
165 , createMessage
166+ , createUnencodedMessage
166 , runLocalProcess
167 , runLocalProcess
167 , ImplicitReconnect(WithImplicitReconnect, NoImplicitReconnect)
168 , ImplicitReconnect(WithImplicitReconnect, NoImplicitReconnect)
168 , LocalProcessState
169 , LocalProcessState
@@ -181,6 +182,7 @@ import Control.Distributed.Process.Internal.WeakTQueue
181 , readTQueue
182 , readTQueue
182 , mkWeakTQueue
183 , mkWeakTQueue
185--------------------------------------------------------------------------------
187--------------------------------------------------------------------------------
186-- Basic messaging --
188-- Basic messaging --
@@ -192,11 +194,15 @@ send :: Serializable a => ProcessId -> a -> Process ()
192-- modify serializable to allow for stateful (IO) deserialization
194-- modify serializable to allow for stateful (IO) deserialization
193send them msg = do
195send them msg = do
194 proc <- ask
196 proc <- ask
197+ let node = localNodeId (processNode proc)
198+ destNode = (processNodeId them) in do
199+ case destNode == node of
200+ True -> sendLocal them msg
195− liftIO $ sendMessage (processNode proc)
201+ False -> liftIO $ sendMessage (processNode proc)
196− (ProcessIdentifier (processId proc))
202+ (ProcessIdentifier (processId proc))
197− (ProcessIdentifier them)
203+ (ProcessIdentifier them)
198− NoImplicitReconnect
204+ NoImplicitReconnect
201-- | Wait for a message of a specific type
207-- | Wait for a message of a specific type
202expect :: forall a. Serializable a => Process a
208expect :: forall a. Serializable a => Process a
@@ -234,11 +240,16 @@ newChan = do
234sendChan :: Serializable a => SendPort a -> a -> Process ()
240sendChan :: Serializable a => SendPort a -> a -> Process ()
235sendChan (SendPort cid) msg = do
241sendChan (SendPort cid) msg = do
236 proc <- ask
242 proc <- ask
243+ let node = localNodeId (processNode proc)
244+ destNode = processNodeId (sendPortProcessId cid) in do
245+ case destNode == node of
246+ True -> sendChanLocal cid msg
237− liftIO $ sendBinary (processNode proc)
248+ liftIO $ sendBinary (processNode proc)
238− (ProcessIdentifier (processId proc))
249+ (ProcessIdentifier (processId proc))
239− (SendPortIdentifier cid)
250+ (SendPortIdentifier cid)
240− NoImplicitReconnect
251+ NoImplicitReconnect
243-- | Wait for a message on a typed channel
254-- | Wait for a message on a typed channel
244receiveChan :: Serializable a => ReceivePort a -> Process a
255receiveChan :: Serializable a => ReceivePort a -> Process a
@@ -315,15 +326,22 @@ match = matchIf (const True)
315-- | Match against any message of the right type that satisfies a predicate
326-- | Match against any message of the right type that satisfies a predicate
316matchIf :: forall a b. Serializable a => (a -> Bool) -> (a -> Process b) -> Match b
327matchIf :: forall a b. Serializable a => (a -> Bool) -> (a -> Process b) -> Match b
317matchIf c p = Match $ MatchMsg $ \msg ->
328matchIf c p = Match $ MatchMsg $ \msg ->
318− case messageFingerprint msg == fingerprint (undefined :: a) of
329+ case messageFingerprint msg == fingerprint (undefined :: a) of
319− True | c decoded -> Just (p decoded)
330+ False -> Nothing
332+ (UnencodedMessage _ m) ->
333+ let m' = unsafeCoerce m :: a in
337+ (EncodedMessage _ _) ->
338+ if (c decoded) then Just (p decoded) else Nothing
321− decoded :: a
340+ decoded :: a
322− -- Make sure the value is fully decoded so that we don't hang to
341+ -- Make sure the value is fully decoded so that we don't hang to
323− -- bytestrings when the process calling 'matchIf' doesn't process
342+ -- bytestrings when the process calling 'matchIf' doesn't process
324− -- the values immediately
343+ -- the values immediately
325− !decoded = decode (messageEncoding msg)
344+ !decoded = decode (messageEncoding msg)
328-- | Match against any message, regardless of the underlying (contained) type
346-- | Match against any message, regardless of the underlying (contained) type
329matchMessage :: (Message -> Process Message) -> Match Message
347matchMessage :: (Message -> Process Message) -> Match Message
@@ -340,11 +358,16 @@ matchMessageIf c p = Match $ MatchMsg $ \msg ->
340forward :: Message -> ProcessId -> Process ()
358forward :: Message -> ProcessId -> Process ()
341forward msg them = do
359forward msg them = do
342 proc <- ask
360 proc <- ask
361+ let node = localNodeId (processNode proc)
362+ destNode = (processNodeId them) in do
363+ case destNode == node of
364+ True -> sendCtrlMsg Nothing (LocalSend them msg)
343− liftIO $ sendPayload (processNode proc)
365+ False -> liftIO $ sendPayload (processNode proc)
344− (ProcessIdentifier (processId proc))
366+ (ProcessIdentifier (processId proc))
345− (ProcessIdentifier them)
367+ (ProcessIdentifier them)
346− NoImplicitReconnect
368+ NoImplicitReconnect
347− (messageToPayload msg)
369+ (messageToPayload msg)
349-- | Wrap a 'Serializable' value in a 'Message'. Note that 'Message's are
372-- | Wrap a 'Serializable' value in a 'Message'. Note that 'Message's are
350-- 'Serializable' - like the datum they contain - but remember that deserializing
373-- 'Serializable' - like the datum they contain - but remember that deserializing
@@ -357,11 +380,11 @@ forward msg them = do
357-- send self (wrapMessage "blah")
380-- send self (wrapMessage "blah")
358-- Nothing <- expectTimeout 1000000 :: Process (Maybe String)
381-- Nothing <- expectTimeout 1000000 :: Process (Maybe String)
359-- (Just m) <- expectTimeout 1000000 :: Process (Maybe Message)
382-- (Just m) <- expectTimeout 1000000 :: Process (Maybe Message)
360−-- "blah" <- unwrapMessage m :: Process (Maybe String)
383+-- (Just "blah") <- unwrapMessage m :: Process (Maybe String)
363wrapMessage :: Serializable a => a -> Message
386wrapMessage :: Serializable a => a -> Message
364−wrapMessage = createMessage
387+wrapMessage = createMessage
366-- | Attempt to unwrap a raw 'Message'.
389-- | Attempt to unwrap a raw 'Message'.
367-- If the type of the decoded message payload matches the expected type, the
390-- If the type of the decoded message payload matches the expected type, the
@@ -377,13 +400,16 @@ wrapMessage = createMessage
377unwrapMessage :: forall a. Serializable a => Message -> Process (Maybe a)
400unwrapMessage :: forall a. Serializable a => Message -> Process (Maybe a)
378unwrapMessage msg =
401unwrapMessage msg =
379 case messageFingerprint msg == fingerprint (undefined :: a) of
402 case messageFingerprint msg == fingerprint (undefined :: a) of
403+ False -> return Nothing
405+ (UnencodedMessage _ m) ->
406+ let m' = unsafeCoerce m :: a
380− True -> return (Just (decoded))
407+ in return (Just m')
408+ (EncodedMessage _ _) ->
409+ return (Just (decoded))
382− decoded :: a
411+ decoded :: a -- note [decoding]
383− -- Make sure the value is fully decoded so that we don't hang to
384− -- bytestrings when the calling process doesn't evaluate immediately
385− !decoded = decode (messageEncoding msg)
412+ !decoded = decode (messageEncoding msg)
388-- | Attempt to handle a raw 'Message'.
414-- | Attempt to handle a raw 'Message'.
389-- If the type of the message matches the type of the first argument to
415-- If the type of the message matches the type of the first argument to
@@ -393,23 +419,28 @@ unwrapMessage msg =
393-- evaluation proceeds, the resulting value with be wrapped with @Just@.
419-- evaluation proceeds, the resulting value with be wrapped with @Just@.
395-- Intended for use in `catchesExit` and `matchAny` primitives.
421-- Intended for use in `catchesExit` and `matchAny` primitives.
397handleMessage :: forall a b. (Serializable a)
423handleMessage :: forall a b. (Serializable a)
398 => Message -> (a -> Process b) -> Process (Maybe b)
424 => Message -> (a -> Process b) -> Process (Maybe b)
399handleMessage msg proc = do
425handleMessage msg proc = do
400− case messageFingerprint msg == fingerprint (undefined :: a) of
426+ case messageFingerprint msg == fingerprint (undefined :: a) of
427+ False -> return Nothing
429+ (UnencodedMessage _ m) ->
430+ let m' = unsafeCoerce m :: a -- note [decoding]
431+ in do { r <- proc m'; return (Just r) }
432+ (EncodedMessage _ _) ->
401− True -> do { r <- proc (decoded :: a); return (Just r) }
433+ do { r <- proc (decoded :: a); return (Just r) }
403− decoded :: a
435+ decoded :: a -- note [decoding]
404− !decoded = decode (messageEncoding msg)
436+ !decoded = decode (messageEncoding msg)
407-- | Match against an arbitrary message. 'matchAny' removes the first available
438-- | Match against an arbitrary message. 'matchAny' removes the first available
408-- message from the process mailbox. To handle arbitrary /raw/ messages once
439-- message from the process mailbox. To handle arbitrary /raw/ messages once
409-- removed from the mailbox, see 'handleMessage' and 'unwrapMessage'.
440-- removed from the mailbox, see 'handleMessage' and 'unwrapMessage'.
411matchAny :: forall b. (Message -> Process b) -> Match b
442matchAny :: forall b. (Message -> Process b) -> Match b
412−matchAny p = Match $ MatchMsg $ \msg -> Just (p msg)
443+matchAny p = Match $ MatchMsg $ \msg -> Just (p msg)
414-- | Match against an arbitrary message. Intended for use with 'handleMessage'
445-- | Match against an arbitrary message. Intended for use with 'handleMessage'
415-- and 'unwrapMessage', this function /only/ removes a message from the process
446-- and 'unwrapMessage', this function /only/ removes a message from the process
@@ -425,15 +456,26 @@ matchAnyIf :: forall a b. (Serializable a)
425 -> (Message -> Process b)
456 -> (Message -> Process b)
426 -> Match b
457 -> Match b
427matchAnyIf c p = Match $ MatchMsg $ \msg ->
458matchAnyIf c p = Match $ MatchMsg $ \msg ->
428− case messageFingerprint msg == fingerprint (undefined :: a) of
459+ case messageFingerprint msg == fingerprint (undefined :: a) of
429− True | c decoded -> Just (p msg)
460+ True | check -> Just (p msg)
465+ (EncodedMessage _ _) -> c decoded
466+ (UnencodedMessage _ m') -> c (unsafeCoerce m')
431− decoded :: a
468+ decoded :: a -- note [decoding]
432− -- Make sure the value is fully decoded so that we don't hang to
433− -- bytestrings when the calling process doesn't evaluate immediately
434 !decoded = decode (messageEncoding msg)
469 !decoded = decode (messageEncoding msg)
435 _ -> Nothing
470 _ -> Nothing
473+For an EncodedMessage, we need to ensure the value is fully decoded so that
474+we don't hang to bytestrings if the calling process doesn't evaluate
475+immediately. For UnencodedMessage we know (because the fingerprint comparison
476+succeeds) that unsafeCoerce will not fail.
437-- | Remove any message from the queue
479-- | Remove any message from the queue
438matchUnknown :: Process b -> Match b
480matchUnknown :: Process b -> Match b
439matchUnknown p = Match $ MatchMsg (const (Just p))
481matchUnknown p = Match $ MatchMsg (const (Just p))
@@ -993,6 +1035,17 @@ trace s = do
993-- Auxiliary functions --
1035-- Auxiliary functions --
994--------------------------------------------------------------------------------
1036--------------------------------------------------------------------------------
1038+sendLocal :: (Serializable a) => ProcessId -> a -> Process ()
1040+ sendCtrlMsg Nothing $ LocalSend pid (createUnencodedMessage msg)
1042+sendChanLocal :: (Serializable a) => SendPortId -> a -> Process ()
1043+sendChanLocal 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)
996getMonitorRefFor :: Identifier -> Process MonitorRef
1049getMonitorRefFor :: Identifier -> Process MonitorRef
997getMonitorRefFor ident = do
1050getMonitorRefFor ident = do
998 proc <- ask
1051 proc <- ask