@@ -1,3 +1,5 @@
1+{-# LANGUAGE RecordWildCards #-}
2+
13-- | Local nodes
24--
35module Control.Distributed.Process.Node
@@ -56,7 +58,7 @@ import Control.Exception
5658 , Exception
5759 , throwTo
5860 )
59−import qualified Control.Exception as Exception (Handler(..), catch, catches, finally)
61+import qualified Control.Exception as Exception (Handler(..), catches, finally)
6062import Control.Concurrent (forkIO, myThreadId)
6163import Control.Distributed.Process.Internal.StrictMVar
6264 ( newMVar
@@ -106,7 +108,7 @@ import Control.Distributed.Process.Internal.Types
106108 , LocalProcessId(..)
107109 , ProcessId(..)
108110 , LocalNode(..)
109− , Tracer(..)
111+ , MxEventBus(..)
110112 , LocalNodeState(..)
111113 , LocalProcess(..)
112114 , LocalProcessState(..)
@@ -149,19 +151,27 @@ import Control.Distributed.Process.Internal.Types
149151 , firstNonReservedProcessId
150152 , ImplicitReconnect(WithImplicitReconnect)
151153 )
152−import qualified Control.Distributed.Process.Internal.Trace.Remote as Trace
154+import Control.Distributed.Process.Management.Agent
155+ ( mxAgentController
156+ )
157+import qualified Control.Distributed.Process.Management.Table as Table
158+ ( mxTableCoordinator
159+ , startTableCoordinator
160+ )
161+import qualified Control.Distributed.Process.Management.Trace.Remote as Trace
153162 ( remoteTable
154163 )
155−import Control.Distributed.Process.Internal.Trace.Types
164+import Control.Distributed.Process.Management.Trace.Tracer
165+ ( defaultTracer
166+ )
167+import Control.Distributed.Process.Management.Trace.Types
156168 ( TraceArg(..)
157− , TraceEvent(..)
158169 , traceEvent
159170 , traceLogFmt
160171 , enableTrace
161172 )
162−import Control.Distributed.Process.Internal.Trace.Tracer
163− ( traceController
164− , defaultTracer
173+import Control.Distributed.Process.Management.Types
174+ ( MxEvent(..)
165175 )
166176import Control.Distributed.Process.Serializable (Serializable)
167177import Control.Distributed.Process.Internal.Messaging
@@ -179,14 +189,13 @@ import Control.Distributed.Process.Internal.Primitives
179189 , catch
180190 , unwrapMessage
181191 )
182−import Control.Distributed.Process.Internal.Types (SendPort)
192+import Control.Distributed.Process.Internal.Types (SendPort, Tracer(..))
183193import qualified Control.Distributed.Process.Internal.Closure.BuiltIn as BuiltIn (remoteTable)
184194import Control.Distributed.Process.Internal.WeakTQueue (TQueue, writeTQueue)
185195import qualified Control.Distributed.Process.Internal.StrictContainerAccessors as DAC
186196 ( mapMaybe
187197 , mapDefault
188198 )
189−import System.Environment (getEnv)
190199import Unsafe.Coerce
191200
192201--------------------------------------------------------------------------------
@@ -222,10 +231,10 @@ createBareLocalNode endPoint rtable = do
222231 , localEndPoint = endPoint
223232 , localState = state
224233 , localCtrlChan = ctrlChan
225− , localTracer = InactiveTracer
234+ , localEventBus = MxEventBusInitialising
226235 , remoteTable = rtable
227236 }
228− tracedNode <- startTracing node
237+ tracedNode <- startMxAgent node
229238
230239 -- Once the NC terminates, the endpoint isn't much use,
231240 void $ forkIO $ Exception.finally (runNodeController tracedNode)
@@ -243,38 +252,27 @@ createBareLocalNode endPoint rtable = do
243252 , ctrlMsgSignal = SigShutdown
244253 }
245254
246−startTracing :: LocalNode -> IO LocalNode
247−startTracing node =
248− -- TODO: use tryGetEnv once we drop support for GHC 7.2.x
249− Exception.catch
250− (getEnv "DISTRIBUTED_PROCESS_TRACE_ENABLED" >> procTracer node)
251− (\(_ :: IOError) -> return node)
252− where procTracer :: LocalNode -> IO LocalNode
253− procTracer n = do
254− -- see note [tracer/forkProcess races]
255− mv <- MVar.newEmptyMVar
256− pid <- forkProcess n (traceController mv)
257− wqRef <- MVar.takeMVar mv
258− return n { localTracer = (ActiveTracer pid wqRef) }
259−
260−startDefaultTracer :: LocalNode -> IO (Maybe ProcessId)
261−startDefaultTracer node =
262− Exception.catch
263− (getEnv "DISTRIBUTED_PROCESS_TRACE_ENABLED" >> go node)
264− (\(_ :: IOError) -> return Nothing)
265− where go :: LocalNode -> IO (Maybe ProcessId)
266− go node' = do
267− registerTraceController node'
268− pid <- forkProcess node' defaultTracer
269− enableTrace (localTracer node') pid
270− return (Just pid)
271−
272− registerTraceController :: LocalNode -> IO ()
273− registerTraceController n =
274− let t = localTracer n in
275− case t of
276− InactiveTracer -> return ()
277− (ActiveTracer pid _) -> runProcess n $ register "trace.controller" pid
255+startMxAgent :: LocalNode -> IO LocalNode
256+startMxAgent node = do
257+ -- see note [tracer/forkProcess races]
258+ let fork = forkProcess node
259+ mv <- MVar.newEmptyMVar
260+ pid <- fork $ mxAgentController fork mv
261+ (tracer', wqRef, mxNew') <- MVar.takeMVar mv
262+ return node { localEventBus = (MxEventBus pid tracer' wqRef mxNew') }
263+
264+startDefaultTracer :: LocalNode -> IO ()
265+startDefaultTracer node' = do
266+ let t = localEventBus node'
267+ case t of
268+ MxEventBus _ (Tracer pid _) _ _ -> do
269+ runProcess node' $ register "trace.controller" pid
270+ pid' <- forkProcess node' defaultTracer
271+ enableTrace (localEventBus node') pid'
272+ runProcess node' $ register "tracer.initial" pid'
273+ _ -> return ()
274+
275+-- TODO: we need a better mechanism for defining and registering services
278276
279277-- | Start and register the service processes on a node
280278startServiceProcesses :: LocalNode -> IO ()
@@ -283,26 +281,26 @@ startServiceProcesses node = do
283281 -- the default tracer first, even though it might @nsend@ to the logger
284282 -- before /that/ process has started - this is a totally harmless race
285283 -- however, so we deliberably ignore it
286− mPid <- startDefaultTracer node
287− case mPid of
288− Nothing -> return ()
289− Just pid -> runProcess node $ register "tracer.initial" pid
290−
284+ startDefaultTracer node
285+ tableCoordinatorPid <- fork $ Table.startTableCoordinator fork
286+ runProcess node $ register Table.mxTableCoordinator tableCoordinatorPid
291287 logger <- forkProcess node loop
292288 runProcess node $ register "logger" logger
293289 where
294− loop = do
295− receiveWait
296− [ match $ \((time, pid, string) ::(String, ProcessId, String)) -> do
297− liftIO . hPutStrLn stderr $ time ++ " " ++ show pid ++ ": " ++ string
298− loop
299− , match $ \((time, string) :: (String, String)) -> do
300− -- this is a 'trace' message from the local node tracer
301− liftIO . hPutStrLn stderr $ time ++ " [trace] " ++ string
302− loop
303− , match $ \(ch :: SendPort ()) -> -- a shutdown request
304− sendChan ch ()
305− ]
290+ fork = forkProcess node
291+
292+ loop = do
293+ receiveWait
294+ [ match $ \((time, pid, string) ::(String, ProcessId, String)) -> do
295+ liftIO . hPutStrLn stderr $ time ++ " " ++ show pid ++ ": " ++ string
296+ loop
297+ , match $ \((time, string) :: (String, String)) -> do
298+ -- this is a 'trace' message from the local node tracer
299+ liftIO . hPutStrLn stderr $ time ++ " [trace] " ++ string
300+ loop
301+ , match $ \(ch :: SendPort ()) -> -- a shutdown request
302+ sendChan ch ()
303+ ]
306304
307305-- | Force-close a local node
308306--
@@ -368,12 +366,13 @@ forkProcess node proc = modifyMVar (localState node) startProcess
368366 }
369367 return (tid', lproc)
370368
371−
372369 -- see note [tracer/forkProcess races]
373− trace node (TraceEvSpawned pid)
370+ trace node (MxSpawned pid)
374371
375372 if lpidCounter lpid == maxBound
376373 then do
374+ -- TODO: this doesn't look right at all - how do we know
375+ -- that newUnique represents a process id that is available!?
377376 newUnique <- randomIO
378377 return ( (localProcessWithId lpid ^= Just lproc)
379378 . (localPidCounter ^= firstNonReservedProcessId)
@@ -401,7 +400,7 @@ forkProcess node proc = modifyMVar (localState node) startProcess
401400--
402401-- Our startTracing function uses forkProcess to start the trace controller
403402-- 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
405404-- until /after/ the initial forkProcess completes, so the first call to
406405-- traceEvent behaves as if tracing were disabled (i.e., it is ignored).
407406--
@@ -450,7 +449,7 @@ handleIncomingMessages node = go initConnectionState
450449 NT.ConnectionOpened cid rel theirAddr ->
451450 if rel == NT.ReliableOrdered
452451 then
453− trace node (TraceEvConnected cid)
452+ trace node (MxConnected cid theirAddr)
454453 >> go (
455454 (incomingAt cid ^= Just (theirAddr, Uninit))
456455 . (incomingFrom theirAddr ^: Set.insert cid)
@@ -466,7 +465,7 @@ handleIncomingMessages node = go initConnectionState
466465 -- it from the NC state? (and same for channels, below)
467466 let msg = payloadToMessage payload
468467 enqueue queue msg -- 'enqueue' is strict
469− trace node (TraceEvReceived pid msg)
468+ trace node (MxReceived pid msg)
470469 go st
471470 Just (_, ToChan (TypedChannel chan')) -> do
472471 mChan <- deRefWeak chan'
@@ -515,7 +514,7 @@ handleIncomingMessages node = go initConnectionState
515514 Nothing ->
516515 invalidRequest cid st
517516 Just (src, _) -> do
518− trace node (TraceEvDisconnected cid)
517+ trace node (MxDisconnected cid src)
519518 go ( (incomingAt cid ^= Nothing)
520519 . (incomingFrom src ^: Set.delete cid)
521520 $ st
@@ -607,15 +606,15 @@ instance Show ProcessKillException where
607606-- Tracing/Debugging --
608607--------------------------------------------------------------------------------
609608
610−-- [Issue #104]
609+-- [Issue #104 / DP-13]
611610
612611traceNotifyDied :: LocalNode -> Identifier -> DiedReason -> NC ()
613612traceNotifyDied node ident reason =
614613 -- TODO: sendPortDied notifications
615614 liftIO $ withLocalTracer node $ \t ->
616615 case ident of
617− (NodeIdentifier nid) -> traceEvent t (TraceEvNodeDied nid reason)
618− (ProcessIdentifier pid) -> traceEvent t (TraceEvDied pid reason)
616+ (NodeIdentifier nid) -> traceEvent t (MxNodeDied nid reason)
617+ (ProcessIdentifier pid) -> traceEvent t (MxProcessDied pid reason)
619618 _ -> return ()
620619
621620traceEventFmtIO :: LocalNode
@@ -625,11 +624,11 @@ traceEventFmtIO :: LocalNode
625624traceEventFmtIO node fmt args =
626625 withLocalTracer node $ \t -> traceLogFmt t fmt args
627626
628−trace :: LocalNode -> TraceEvent -> IO ()
627+trace :: LocalNode -> MxEvent -> IO ()
629628trace node ev = withLocalTracer node $ \t -> traceEvent t ev
630629
631−withLocalTracer :: LocalNode -> (Tracer -> IO ()) -> IO ()
632−withLocalTracer node act = act (localTracer node)
630+withLocalTracer :: LocalNode -> (MxEventBus -> IO ()) -> IO ()
631+withLocalTracer node act = act (localEventBus node)
633632
634633--------------------------------------------------------------------------------
635634-- Core functionality --
@@ -796,7 +795,7 @@ ncEffectSpawn pid cProc ref = do
796795 mProc <- unClosure cProc
797796 -- If the closure does not exist, we spawn a process that throws an exception
798797 -- This allows the remote node to find out what's happening
799− -- TODO:
798+ -- TODO:
800799 let proc = case mProc of
801800 Left err -> fail $ "Error: Could not resolve closure: " ++ err
802801 Right p -> p
@@ -828,8 +827,8 @@ ncEffectRegister from label atnode mPid reregistration = do
828827 do modify' $ registeredHereFor label ^= mPid
829828 updateRemote node currentVal mPid
830829 case mPid of
831− (Just p) -> liftIO $ trace node (TraceEvRegistered p label)
832− Nothing -> liftIO $ trace node (TraceEvUnRegistered (fromJust currentVal) label)
830+ (Just p) -> liftIO $ trace node (MxRegistered p label)
831+ Nothing -> liftIO $ trace node (MxUnRegistered (fromJust currentVal) label)
833832 liftIO $ sendMessage node
834833 (NodeIdentifier (localNodeId node))
835834 (ProcessIdentifier from)
@@ -897,7 +896,7 @@ ncEffectLocalSend :: LocalNode -> ProcessId -> Message -> NC ()
897896ncEffectLocalSend node to msg =
898897 liftIO $ withLocalProc node to $ \p -> do
899898 enqueue (processQueue p) msg
900− trace node (TraceEvReceived to msg)
899+ trace node (MxReceived to msg)
901900
902901-- [Issue #DP-20]
903902ncEffectLocalPortSend :: SendPortId -> Message -> NC ()