1{-# LANGUAGE RecordWildCards #-}
3module Control.Distributed.Process.Management.Agent where
5import Control.Applicative ((<$>))
6import Control.Concurrent.MVar (MVar, newEmptyMVar, putMVar, takeMVar)
7import Control.Concurrent.STM (atomically)
8import Control.Concurrent.STM.TChan
14import Control.Distributed.Process.Internal.Primitives
21import Control.Distributed.Process.Internal.CQueue
25import Control.Distributed.Process.Management.Types
28import Control.Distributed.Process.Management.Trace.Tracer
31import Control.Distributed.Process.Internal.Types
39import Control.Exception (AsyncException(ThreadKilled), SomeException)
40import Control.Monad (void)
41import Control.Monad.IO.Class (liftIO)
42import Control.Monad.Reader (ask)
43import GHC.Weak (Weak, deRefWeak)
45--------------------------------------------------------------------------------
46-- Agent Controller Implementation --
47--------------------------------------------------------------------------------
50-- | A triple containing a configured tracer, weak pointer to the
51-- agent controller's mailbox (CQueue) and an expression used to
52-- instantiate new agents on the current node.
54 (Tracer, Weak (CQueue Message), ((TChan Message -> Process ()) -> IO ProcessId))
56-- | Starts a management agent for the current node. The agent process
57-- must not crash or be killed, so we generally avoid publishing its
58-- 'ProcessId' where possible.
60-- Our process is also responsible for forwarding messages to the trace
61-- controller, since having two /special processes/ handled via the
62-- @LocalNode@ would be inelegant. We forward messages directly to the
63-- trace controller's message queue, just as the @MxEventBus@ that's
64-- set up on the @LocalNode@ forwards messages directly to us. This
65-- optimises the code path for tracing and avoids overloading the node
66-- node controller's internal control plane with additional routing, at the
67-- cost of a little more complexity and two cases where we break
70mxAgentController :: Fork
73mxAgentController forkProcess mv = do
74 -- node <- processNode <$> ask
75 trc <- liftIO $ startTracing forkProcess
76 sigbus <- liftIO $ newBroadcastTChanIO
77 weakQueue <- processWeakQ <$> ask
78 liftIO $ putMVar mv (trc, weakQueue, mxStartAgent forkProcess sigbus)
79 go sigbus trc forkProcess
81 go bus tracer fork = forever' $ do
83 -- This is exactly what it appears to be: a "catch all" handler.
84 -- Since mxNotify can potentially pass an unevaluated thunk to
85 -- our mailbox, the dequeue (i.e., matchMessage) can fail and
86 -- crash this process, which we DO NOT want. Alternatively,
87 -- we handle IO exceptions here explicitly, since we don't want
88 -- this process to ever crash, and the assumption we therefore
91 -- 1. only ThreadKilled can tell this process to terminate
92 -- 2. all other exceptions are invalid and should be ignored
94 -- The outcome of course, is that /bad/ calls to mxNotify
95 -- (e.g., passing unevaluated thunks that will crash when
96 -- they're eventually forced) are thus silently ignored.
98 matchAny (\msg -> liftIO $ broadcast bus tracer msg)
99 ] `catches` [Handler (\ThreadKilled -> die "Killed"),
100 Handler (\(_ :: SomeException) -> return ())]
102 broadcast :: TChan Message -> Tracer -> Message -> IO ()
103 broadcast ch tr msg = do
104 tmQueue <- tracerQueue tr
105 atomicBroadcast ch tmQueue msg
107 tracerQueue :: Tracer -> IO (Maybe (CQueue Message))
108 tracerQueue (Tracer _ wQ) = deRefWeak wQ
110 atomicBroadcast :: TChan Message
111 -> Maybe (CQueue Message)
113 atomicBroadcast ch Nothing msg = liftIO $ atomically $ writeTChan ch msg
114 atomicBroadcast ch (Just q) msg = do
115 liftIO $ atomically $ enqueueSTM q msg >> writeTChan ch msg
117-- | Forks a new process in which an mxAgent is run.
118mxStartAgent :: Fork -> TChan Message -> (TChan Message -> Process ()) -> IO ProcessId
119mxStartAgent fork chan handler = (atomically (dupTChan chan)) >>= fork . handler
121startTracing :: Fork -> IO Tracer
122startTracing forkProcess = do
124 pid <- forkProcess $ traceController mv
125 wQ <- liftIO $ takeMVar mv
126 return $ Tracer pid wQ
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list