@@ -1,3 +1,5 @@
1+{-# LANGUAGE RecordWildCards #-}
1-- | Local nodes
3-- | Local nodes
3module Control.Distributed.Process.Node
5module Control.Distributed.Process.Node
@@ -56,7 +58,7 @@ import Control.Exception
56 , Exception
58 , Exception
59−import qualified Control.Exception as Exception (Handler(..), catch, catches, finally)
61+import qualified Control.Exception as Exception (Handler(..), catches, finally)
60import Control.Concurrent (forkIO, myThreadId)
62import Control.Concurrent (forkIO, myThreadId)
61import Control.Distributed.Process.Internal.StrictMVar
63import Control.Distributed.Process.Internal.StrictMVar
@@ -106,7 +108,7 @@ import Control.Distributed.Process.Internal.Types
106 , LocalProcessId(..)
108 , LocalProcessId(..)
107 , ProcessId(..)
109 , ProcessId(..)
108 , LocalNode(..)
110 , LocalNode(..)
109− , Tracer(..)
111+ , MxEventBus(..)
110 , LocalNodeState(..)
112 , LocalNodeState(..)
111 , LocalProcess(..)
113 , LocalProcess(..)
112 , LocalProcessState(..)
114 , LocalProcessState(..)
@@ -149,19 +151,27 @@ import Control.Distributed.Process.Internal.Types
149 , firstNonReservedProcessId
151 , firstNonReservedProcessId
150 , ImplicitReconnect(WithImplicitReconnect)
152 , ImplicitReconnect(WithImplicitReconnect)
154+import Control.Distributed.Process.Management.Agent
152−import qualified Control.Distributed.Process.Internal.Trace.Remote as Trace
157+import qualified Control.Distributed.Process.Management.Table as Table
158+ ( mxTableCoordinator
159+ , startTableCoordinator
161+import qualified Control.Distributed.Process.Management.Trace.Remote as Trace
153 ( remoteTable
162 ( remoteTable
155−import Control.Distributed.Process.Internal.Trace.Types
164+import Control.Distributed.Process.Management.Trace.Tracer
167+import Control.Distributed.Process.Management.Trace.Types
156 ( TraceArg(..)
168 ( TraceArg(..)
158 , traceEvent
169 , traceEvent
159 , traceLogFmt
170 , traceLogFmt
160 , enableTrace
171 , enableTrace
162−import Control.Distributed.Process.Internal.Trace.Tracer
173+import Control.Distributed.Process.Management.Types
163− ( traceController
174+ ( MxEvent(..)
166import Control.Distributed.Process.Serializable (Serializable)
176import Control.Distributed.Process.Serializable (Serializable)
167import Control.Distributed.Process.Internal.Messaging
177import Control.Distributed.Process.Internal.Messaging
@@ -179,14 +189,13 @@ import Control.Distributed.Process.Internal.Primitives
180 , unwrapMessage
190 , unwrapMessage
182−import Control.Distributed.Process.Internal.Types (SendPort)
192+import Control.Distributed.Process.Internal.Types (SendPort, Tracer(..))
183import qualified Control.Distributed.Process.Internal.Closure.BuiltIn as BuiltIn (remoteTable)
193import qualified Control.Distributed.Process.Internal.Closure.BuiltIn as BuiltIn (remoteTable)
184import Control.Distributed.Process.Internal.WeakTQueue (TQueue, writeTQueue)
194import Control.Distributed.Process.Internal.WeakTQueue (TQueue, writeTQueue)
185import qualified Control.Distributed.Process.Internal.StrictContainerAccessors as DAC
195import qualified Control.Distributed.Process.Internal.StrictContainerAccessors as DAC
186 ( mapMaybe
196 ( mapMaybe
187 , mapDefault
197 , mapDefault
189−import System.Environment (getEnv)
190import Unsafe.Coerce
199import Unsafe.Coerce
192--------------------------------------------------------------------------------
201--------------------------------------------------------------------------------
@@ -222,10 +231,10 @@ createBareLocalNode endPoint rtable = do
222 , localEndPoint = endPoint
231 , localEndPoint = endPoint
223 , localState = state
232 , localState = state
224 , localCtrlChan = ctrlChan
233 , localCtrlChan = ctrlChan
225− , localTracer = InactiveTracer
234+ , localEventBus = MxEventBusInitialising
226 , remoteTable = rtable
235 , remoteTable = rtable
228− tracedNode <- startTracing node
237+ tracedNode <- startMxAgent node
230 -- Once the NC terminates, the endpoint isn't much use,
239 -- Once the NC terminates, the endpoint isn't much use,
231 void $ forkIO $ Exception.finally (runNodeController tracedNode)
240 void $ forkIO $ Exception.finally (runNodeController tracedNode)
@@ -243,38 +252,27 @@ createBareLocalNode endPoint rtable = do
243 , ctrlMsgSignal = SigShutdown
252 , ctrlMsgSignal = SigShutdown
246−startTracing :: LocalNode -> IO LocalNode
255+startMxAgent :: LocalNode -> IO LocalNode
247−startTracing node =
256+startMxAgent node = do
248− -- TODO: use tryGetEnv once we drop support for GHC 7.2.x
250− (getEnv "DISTRIBUTED_PROCESS_TRACE_ENABLED" >> procTracer node)
251− (\(_ :: IOError) -> return node)
252− where procTracer :: LocalNode -> IO LocalNode
254− -- see note [tracer/forkProcess races]
257+ -- see note [tracer/forkProcess races]
258+ let fork = forkProcess node
255− mv <- MVar.newEmptyMVar
259+ mv <- MVar.newEmptyMVar
256− pid <- forkProcess n (traceController mv)
260+ pid <- fork $ mxAgentController fork mv
257− wqRef <- MVar.takeMVar mv
261+ (tracer', wqRef, mxNew') <- MVar.takeMVar mv
258− return n { localTracer = (ActiveTracer pid wqRef) }
262+ return node { localEventBus = (MxEventBus pid tracer' wqRef mxNew') }
260−startDefaultTracer :: LocalNode -> IO (Maybe ProcessId)
264+startDefaultTracer :: LocalNode -> IO ()
261−startDefaultTracer node =
265+startDefaultTracer node' = do
262− Exception.catch
266+ let t = localEventBus node'
263− (getEnv "DISTRIBUTED_PROCESS_TRACE_ENABLED" >> go node)
264− (\(_ :: IOError) -> return Nothing)
265− where go :: LocalNode -> IO (Maybe ProcessId)
267− registerTraceController node'
268− pid <- forkProcess node' defaultTracer
269− enableTrace (localTracer node') pid
272− registerTraceController :: LocalNode -> IO ()
273− registerTraceController n =
274− let t = localTracer n in
275− case t of
267+ case t of
276− InactiveTracer -> return ()
268+ MxEventBus _ (Tracer pid _) _ _ -> do
277− (ActiveTracer pid _) -> runProcess n $ register "trace.controller" pid
269+ runProcess node' $ register "trace.controller" pid
270+ pid' <- forkProcess node' defaultTracer
271+ enableTrace (localEventBus node') pid'
272+ runProcess node' $ register "tracer.initial" pid'
275+-- TODO: we need a better mechanism for defining and registering services
279-- | Start and register the service processes on a node
277-- | Start and register the service processes on a node
280startServiceProcesses :: LocalNode -> IO ()
278startServiceProcesses :: LocalNode -> IO ()
@@ -283,26 +281,26 @@ startServiceProcesses node = do
283 -- the default tracer first, even though it might @nsend@ to the logger
281 -- the default tracer first, even though it might @nsend@ to the logger
284 -- before /that/ process has started - this is a totally harmless race
282 -- before /that/ process has started - this is a totally harmless race
285 -- however, so we deliberably ignore it
283 -- however, so we deliberably ignore it
286− mPid <- startDefaultTracer node
284+ startDefaultTracer node
287− case mPid of
285+ tableCoordinatorPid <- fork $ Table.startTableCoordinator fork
288− Nothing -> return ()
289− Just pid -> runProcess node $ register "tracer.initial" pid
286+ runProcess node $ register Table.mxTableCoordinator tableCoordinatorPid
291 logger <- forkProcess node loop
287 logger <- forkProcess node loop
292 runProcess node $ register "logger" logger
288 runProcess node $ register "logger" logger
290+ fork = forkProcess node
294− loop = do
292+ loop = do
295− receiveWait
293+ receiveWait
296− [ match $ \((time, pid, string) ::(String, ProcessId, String)) -> do
294+ [ match $ \((time, pid, string) ::(String, ProcessId, String)) -> do
297− liftIO . hPutStrLn stderr $ time ++ " " ++ show pid ++ ": " ++ string
295+ liftIO . hPutStrLn stderr $ time ++ " " ++ show pid ++ ": " ++ string
299− , match $ \((time, string) :: (String, String)) -> do
297+ , match $ \((time, string) :: (String, String)) -> do
300− -- this is a 'trace' message from the local node tracer
298+ -- this is a 'trace' message from the local node tracer
301− liftIO . hPutStrLn stderr $ time ++ " [trace] " ++ string
299+ liftIO . hPutStrLn stderr $ time ++ " [trace] " ++ string
303− , match $ \(ch :: SendPort ()) -> -- a shutdown request
301+ , match $ \(ch :: SendPort ()) -> -- a shutdown request
304− sendChan ch ()
302+ sendChan ch ()
307-- | Force-close a local node
305-- | Force-close a local node
@@ -368,12 +366,13 @@ forkProcess node proc = modifyMVar (localState node) startProcess
369 return (tid', lproc)
367 return (tid', lproc)
372 -- see note [tracer/forkProcess races]
369 -- see note [tracer/forkProcess races]
373− trace node (TraceEvSpawned pid)
370+ trace node (MxSpawned pid)
375 if lpidCounter lpid == maxBound
372 if lpidCounter lpid == maxBound
374+ -- TODO: this doesn't look right at all - how do we know
375+ -- that newUnique represents a process id that is available!?
377 newUnique <- randomIO
376 newUnique <- randomIO
378 return ( (localProcessWithId lpid ^= Just lproc)
377 return ( (localProcessWithId lpid ^= Just lproc)
379 . (localPidCounter ^= firstNonReservedProcessId)
378 . (localPidCounter ^= firstNonReservedProcessId)
@@ -401,7 +400,7 @@ forkProcess node proc = modifyMVar (localState node) startProcess
402-- Our startTracing function uses forkProcess to start the trace controller
401-- Our startTracing function uses forkProcess to start the trace controller
403-- process, and of course forkProcess attempts to call traceEvent once the
402-- process, and of course forkProcess attempts to call traceEvent once the
404−-- process has started. This is harmless, as the localTracer is not updated
403+-- process has started. This is harmless, as the localEventBus is not updated
405-- until /after/ the initial forkProcess completes, so the first call to
404-- until /after/ the initial forkProcess completes, so the first call to
406-- traceEvent behaves as if tracing were disabled (i.e., it is ignored).
405-- traceEvent behaves as if tracing were disabled (i.e., it is ignored).
@@ -450,7 +449,7 @@ handleIncomingMessages node = go initConnectionState
450 NT.ConnectionOpened cid rel theirAddr ->
449 NT.ConnectionOpened cid rel theirAddr ->
451 if rel == NT.ReliableOrdered
450 if rel == NT.ReliableOrdered
453− trace node (TraceEvConnected cid)
452+ trace node (MxConnected cid theirAddr)
455 (incomingAt cid ^= Just (theirAddr, Uninit))
454 (incomingAt cid ^= Just (theirAddr, Uninit))
456 . (incomingFrom theirAddr ^: Set.insert cid)
455 . (incomingFrom theirAddr ^: Set.insert cid)
@@ -466,7 +465,7 @@ handleIncomingMessages node = go initConnectionState
466 -- it from the NC state? (and same for channels, below)
465 -- it from the NC state? (and same for channels, below)
467 let msg = payloadToMessage payload
466 let msg = payloadToMessage payload
468 enqueue queue msg -- 'enqueue' is strict
467 enqueue queue msg -- 'enqueue' is strict
469− trace node (TraceEvReceived pid msg)
468+ trace node (MxReceived pid msg)
471 Just (_, ToChan (TypedChannel chan')) -> do
470 Just (_, ToChan (TypedChannel chan')) -> do
472 mChan <- deRefWeak chan'
471 mChan <- deRefWeak chan'
@@ -515,7 +514,7 @@ handleIncomingMessages node = go initConnectionState
515 Nothing ->
514 Nothing ->
516 invalidRequest cid st
515 invalidRequest cid st
517 Just (src, _) -> do
516 Just (src, _) -> do
518− trace node (TraceEvDisconnected cid)
517+ trace node (MxDisconnected cid src)
519 go ( (incomingAt cid ^= Nothing)
518 go ( (incomingAt cid ^= Nothing)
520 . (incomingFrom src ^: Set.delete cid)
519 . (incomingFrom src ^: Set.delete cid)
@@ -607,15 +606,15 @@ instance Show ProcessKillException where
607-- Tracing/Debugging --
606-- Tracing/Debugging --
608--------------------------------------------------------------------------------
607--------------------------------------------------------------------------------
610−-- [Issue #104]
609+-- [Issue #104 / DP-13]
612traceNotifyDied :: LocalNode -> Identifier -> DiedReason -> NC ()
611traceNotifyDied :: LocalNode -> Identifier -> DiedReason -> NC ()
613traceNotifyDied node ident reason =
612traceNotifyDied node ident reason =
614 -- TODO: sendPortDied notifications
613 -- TODO: sendPortDied notifications
615 liftIO $ withLocalTracer node $ \t ->
614 liftIO $ withLocalTracer node $ \t ->
616 case ident of
615 case ident of
617− (NodeIdentifier nid) -> traceEvent t (TraceEvNodeDied nid reason)
616+ (NodeIdentifier nid) -> traceEvent t (MxNodeDied nid reason)
618− (ProcessIdentifier pid) -> traceEvent t (TraceEvDied pid reason)
617+ (ProcessIdentifier pid) -> traceEvent t (MxProcessDied pid reason)
619 _ -> return ()
618 _ -> return ()
621traceEventFmtIO :: LocalNode
620traceEventFmtIO :: LocalNode
@@ -625,11 +624,11 @@ traceEventFmtIO :: LocalNode
625traceEventFmtIO node fmt args =
624traceEventFmtIO node fmt args =
626 withLocalTracer node $ \t -> traceLogFmt t fmt args
625 withLocalTracer node $ \t -> traceLogFmt t fmt args
628−trace :: LocalNode -> TraceEvent -> IO ()
627+trace :: LocalNode -> MxEvent -> IO ()
629trace node ev = withLocalTracer node $ \t -> traceEvent t ev
628trace node ev = withLocalTracer node $ \t -> traceEvent t ev
631−withLocalTracer :: LocalNode -> (Tracer -> IO ()) -> IO ()
630+withLocalTracer :: LocalNode -> (MxEventBus -> IO ()) -> IO ()
632−withLocalTracer node act = act (localTracer node)
631+withLocalTracer node act = act (localEventBus node)
634--------------------------------------------------------------------------------
633--------------------------------------------------------------------------------
635-- Core functionality --
634-- Core functionality --
@@ -796,7 +795,7 @@ ncEffectSpawn pid cProc ref = do
796 mProc <- unClosure cProc
795 mProc <- unClosure cProc
797 -- If the closure does not exist, we spawn a process that throws an exception
796 -- If the closure does not exist, we spawn a process that throws an exception
798 -- This allows the remote node to find out what's happening
797 -- This allows the remote node to find out what's happening
799− -- TODO:
798+ -- TODO:
800 let proc = case mProc of
799 let proc = case mProc of
801 Left err -> fail $ "Error: Could not resolve closure: " ++ err
800 Left err -> fail $ "Error: Could not resolve closure: " ++ err
802 Right p -> p
801 Right p -> p
@@ -828,8 +827,8 @@ ncEffectRegister from label atnode mPid reregistration = do
828 do modify' $ registeredHereFor label ^= mPid
827 do modify' $ registeredHereFor label ^= mPid
829 updateRemote node currentVal mPid
828 updateRemote node currentVal mPid
830 case mPid of
829 case mPid of
831− (Just p) -> liftIO $ trace node (TraceEvRegistered p label)
830+ (Just p) -> liftIO $ trace node (MxRegistered p label)
832− Nothing -> liftIO $ trace node (TraceEvUnRegistered (fromJust currentVal) label)
831+ Nothing -> liftIO $ trace node (MxUnRegistered (fromJust currentVal) label)
833 liftIO $ sendMessage node
832 liftIO $ sendMessage node
834 (NodeIdentifier (localNodeId node))
833 (NodeIdentifier (localNodeId node))
835 (ProcessIdentifier from)
834 (ProcessIdentifier from)
@@ -897,7 +896,7 @@ ncEffectLocalSend :: LocalNode -> ProcessId -> Message -> NC ()
897ncEffectLocalSend node to msg =
896ncEffectLocalSend node to msg =
898 liftIO $ withLocalProc node to $ \p -> do
897 liftIO $ withLocalProc node to $ \p -> do
899 enqueue (processQueue p) msg
898 enqueue (processQueue p) msg
900− trace node (TraceEvReceived to msg)
899+ trace node (MxReceived to msg)
902-- [Issue #DP-20]
901-- [Issue #DP-20]
903ncEffectLocalPortSend :: SendPortId -> Message -> NC ()
902ncEffectLocalPortSend :: SendPortId -> Message -> NC ()