@@ -45,60 +45,75 @@ data ChildEvent a =
4545
4646-- | Describes the context of a computation.
4747data Context = Context
48− { mailBox :: Maybe Any -- untyped,
49− -- ^ mailBox to send event data to the child thread
48+ {
49+ ---------------------------------------------------------------------------
50+ -- Execution state
51+ ---------------------------------------------------------------------------
52+
53+ mailBox :: Maybe Any -- untyped,
54+ -- ^ mailBox to send event data to the child thread
5055
51− -- the 'm' and 'f' in an 'm >>= f' operation of the monad
52− -- In nested binds we store the current m only, but the whole stack of fs
5356 , currentm :: Any -- untyped, the real type is: m a
57+ -- ^ The 'm' in an 'm >>= f' operation of the monad. This tells us where we
58+ -- are in the monadic computation at this point.
59+
5460 , fstack :: [Any] -- untyped, the real type is: [a -> m b]
55− -- XXX keep a composed computation instead
56− -- ^ List of continuations
61+ -- ^ The head of the list stores the 'f' corresponding to 'currentm' in an
62+ -- 'm >>= f' operation of the monad. This is stack because when a
63+ -- computation has nested binds we need to store the next 'f' for each
64+ -- layer of nesting.
5765
5866 -- log only when there is a restore or if we are teleporting
5967 -- We can use a HasLog constraint to statically enable/disable logging
6068 -- , journal :: Maybe Log
6169 , location :: Location
6270
71+ ---------------------------------------------------------------------------
72+ -- User state
73+ ---------------------------------------------------------------------------
74+
6375 , mfData :: M.Map TypeRep Any -- untyped, type coerced
6476 -- ^ State data accessed with get or put operations
6577
78+ ---------------------------------------------------------------------------
79+ -- Thread creation, communication and cleanup
80+ ---------------------------------------------------------------------------
81+ -- When a new thread is created the parent records it in the
82+ -- 'pendingThreads' field and 'threadCredit' is decremented. When a child
83+ -- thread is done it sends a done event to the parent on an unbounded
84+ -- channel and goes away. Before starting a new thread the parent always
85+ -- processes the unbounded channel to clear up the pending zombies. This
86+ -- strategy ensures that the zombie queue will never grow more than the
87+ -- number of running threads. Before exiting, the parent thread waits on
88+ -- the channel until all its children are cleaned up.
89+ ---------------------------------------------------------------------------
90+
6691 -- XXX use Either parentChannel accumResults
6792 , accumResults :: Maybe (IORef [Any])
6893 -- ^ Accumulated results, only the top level thread context accumulates.
6994 -- Child threads just pass on results via the parent channels.
70− -- XXX we can pass this at the time of fork rather than keeping it here.
7195
7296 , parentChannel :: Maybe (TChan (ChildEvent Any))
73− -- ^ Our parent thread's channel to communicate to when we die
74−
75− -- Thread creation and cleanup handling. When a new thread is created the
76− -- parent records it in the 'children' field and 'threadCredit' is
77− -- decremented. When a child thread is done it sends a done event to the
78− -- parent on an unbounded channel and goes away. Before starting a new
79− -- thread the parent always processes the unbounded channel to clear up the
80− -- pending zombies. This strategy ensures that the zombie queue will never
81− -- grow more than the number of running threads. Before exiting, the
82− -- parent thread waits on the channel until all its children are cleaned
83− -- up.
97+ -- ^ Parent thread's channel to communicate to when a child thread dies or
98+ -- yields a result value
8499
85100 , childChannel :: TChan (ChildEvent Any)
86− -- ^ A channel for the immediate children to communicate to us when they die.
87− -- Each thread has its own dedicated channel for its children
101+ -- ^ A channel for the immediate children to communicate to us when they
102+ -- die. Each thread has its own dedicated channel for its children
88103
89104 -- We always track the child threads, otherwise the programmer needs to
90− -- worry about if some threads may remain hanging due because they are
91− -- stuck in an infinite loop or a forever blocked IO. Also, it is not clear
92− -- whether there is a significant gain by disabling tracking. Instead of
93− -- using the threadIds we can also keep a count instead, that will allow us
94− -- to wait for all children to drain but we cannot kill them.
105+ -- worry about if some threads may remain hanging because they are stuck in
106+ -- an infinite loop or a forever blocked IO. Also, it is not clear whether
107+ -- there is a significant gain by disabling tracking. Instead of using
108+ -- threadIds we can also keep a count instead, that will allow us to wait
109+ -- for all children to drain but we cannot kill them.
95110 --
96111 -- We need these as IORefs since we need any changes to these to be
97112 -- reflected back in the calling code that waits for the children.
98113
99114 , pendingThreads :: IORef [ThreadId]
100− -- ^ Active immediate child threads of this thread, modified only by this
101− -- thread, therefore atomic modification is not needed.
115+ -- ^ Active immediate child threads spawned by this thread, modified only
116+ -- by this thread, therefore atomic modification is not needed.
102117
103118 -- By default this limit is shared by the current tree of threads. But at
104119 -- any point the 'threads' primitive can be used to start a new limit for