@@ -69,74 +69,20 @@ import Strands.Context
69-- | Continue execution of the closure that we were executing when we migrated
69-- | Continue execution of the closure that we were executing when we migrated
70-- to a new thread.
70-- to a new thread.
72−resume :: MonadIO m => Context -> StateT Context m ()
72+runContext :: MonadIO m => Context -> StateT Context m ()
73−resume ctx = do
73+runContext ctx = do
74 -- XXX rename to buildContext or buildState?
74 -- XXX rename to buildContext or buildState?
75 let s = runAsyncT (resumeContext ctx)
75 let s = runAsyncT (resumeContext ctx)
76− -- The returned value is always 'Nothing', we just discard it
77− (_, c) <- lift $ runStateT s ctx
76+ _ <- lift $ runStateT s ctx
79− -- XXX can we pass the result directly to the root thread instead of
80− -- passing through all the parents? We can let the parent go away and
81− -- handle the ChildDone events as well in the root thread.
82− case parentChannel c of
83− Nothing -> modify $ \x ->
84− x { accumResults = accumResults c ++ accumResults x }
86− let r = accumResults c
87− when (length r /= 0) $
88− -- there is only one result in case of a non-root thread
89− -- XXX change the return type to 'a' instead of '[a]'
90− liftIO $ atomically $ writeTChan chan (PassOnResult (Right r))
92------------------------------------------------------------------------------
79------------------------------------------------------------------------------
93-- Thread Management (creation, reaping and killing)
80-- Thread Management (creation, reaping and killing)
94------------------------------------------------------------------------------
81------------------------------------------------------------------------------
96−-- XXX We are using unbounded channels so this will not block on writing to
97−-- pchan. We can use bounded channels to throttle the creation of threads based
98−-- on consumption rate.
99−processOneEvent :: MonadIO m
101− -> TChan (ChildEvent a)
103− -> Maybe SomeException
104− -> m ([ThreadId], Maybe SomeException)
105−processOneEvent ev pchan pending exc = do
109− ChildDone tid res -> do
110− dbg $ "processOneEvent ChildDone: " ++ show tid
112− PassOnResult res -> do
113− dbg $ "processOneEvent PassOnResult"
115− Just _ -> return exc
117− ChildDone tid _ -> delete tid pending
123− handlePass :: MonadIO m
124− => Either SomeException [a] -> m (Maybe SomeException)
128− dbg $ "handlePass: caught exception"
129− liftIO $ mapM_ killThread pending
131− Right [] -> return Nothing
133− liftIO $ atomically $ writeTChan pchan
134− (PassOnResult (unsafeCoerce res))
137tryReclaimZombies :: (MonadIO m, MonadThrow m) => Context -> m ()
83tryReclaimZombies :: (MonadIO m, MonadThrow m) => Context -> m ()
138tryReclaimZombies ctx = do
84tryReclaimZombies ctx = do
139− let pchan = fromJust (parentChannel ctx)
85+ let dest = getCtxResultDest ctx
140 cchan = childChannel ctx
86 cchan = childChannel ctx
141 pendingRef = pendingThreads ctx
87 pendingRef = pendingThreads ctx
@@ -148,7 +94,7 @@ tryReclaimZombies ctx = do
148 case mev of
94 case mev of
149 Nothing -> return ()
95 Nothing -> return ()
150 Just ev -> do
96 Just ev -> do
151− (p, e) <- processOneEvent ev pchan pending Nothing
97+ (p, e) <- processOneEvent ev dest pending
152 liftIO $ writeIORef pendingRef p
98 liftIO $ writeIORef pendingRef p
153 maybe (return ()) throwM e
99 maybe (return ()) throwM e
154 tryReclaimZombies ctx
100 tryReclaimZombies ctx
@@ -157,40 +103,16 @@ waitForOneEvent :: (MonadIO m, MonadThrow m) => Context -> m ()
157waitForOneEvent ctx = do
103waitForOneEvent ctx = do
158 -- XXX assert pending must have at least one element
104 -- XXX assert pending must have at least one element
159 -- assert that the tid is found in our list
105 -- assert that the tid is found in our list
160− let pchan = fromJust (parentChannel ctx)
106+ let dest = getCtxResultDest ctx
161 cchan = childChannel ctx
107 cchan = childChannel ctx
162 pendingRef = pendingThreads ctx
108 pendingRef = pendingThreads ctx
164 ev <- liftIO $ atomically $ readTChan cchan
110 ev <- liftIO $ atomically $ readTChan cchan
165 pending <- liftIO $ readIORef pendingRef
111 pending <- liftIO $ readIORef pendingRef
166− (p, e) <- processOneEvent ev pchan pending Nothing
112+ (p, e) <- processOneEvent ev dest pending
167 liftIO $ writeIORef pendingRef p
113 liftIO $ writeIORef pendingRef p
168 maybe (return ()) throwM e
114 maybe (return ()) throwM e
170−drainChildren :: MonadIO m
171− => TChan (ChildEvent a)
172− -> TChan (ChildEvent a)
174− -> Maybe SomeException
175− -> m (Maybe SomeException)
176−drainChildren pchan cchan pending exc =
180− ev <- liftIO $ atomically $ readTChan cchan
181− (p, e) <- processOneEvent ev pchan pending exc
182− drainChildren pchan cchan p e
184−waitForChildren :: MonadIO m
185− => Context -> Maybe SomeException -> m (Maybe SomeException)
186−waitForChildren ctx exc = do
187− let pendingRef = pendingThreads ctx
188− pchan = fromJust (parentChannel ctx)
189− pending <- liftIO $ readIORef pendingRef
190− e <- drainChildren pchan (childChannel ctx) pending exc
191− liftIO $ writeIORef pendingRef []
194-- | kill all the child threads associated with the continuation context
116-- | kill all the child threads associated with the continuation context
195killChildren :: Context -> IO ()
117killChildren :: Context -> IO ()
196killChildren ctx = do
118killChildren ctx = do
@@ -233,7 +155,8 @@ forkFinally1 :: (MonadIO m, MonadBaseControl IO m)
233forkFinally1 ctx preExit =
155forkFinally1 ctx preExit =
234 EL.mask $ \restore ->
156 EL.mask $ \restore ->
235 liftBaseWith $ \runInIO -> forkIO $ do
157 liftBaseWith $ \runInIO -> forkIO $ do
236− _ <- runInIO $ EL.try (restore (resume ctx)) >>= liftIO . preExit
158+ _ <- runInIO $ EL.try (restore (runContext ctx))
159+ >>= liftIO . preExit
237 return ()
160 return ()
239-- | Run a given context in a new thread.
162-- | Run a given context in a new thread.
@@ -263,27 +186,22 @@ forkContext context = do
263 { parentChannel = Just (childChannel ctx)
186 { parentChannel = Just (childChannel ctx)
264 , pendingThreads = pendingRef
187 , pendingThreads = pendingRef
265 , childChannel = chan
188 , childChannel = chan
266− , accumResults = []
189+ , accumResults = Nothing
269 beforeExit ctx res = do
192 beforeExit ctx res = do
270 tid <- myThreadId
193 tid <- myThreadId
271− exc <- case res of
194+ r <- case res of
272− Left e -> do
195+ Left e -> do
273 dbg $ "beforeExit: " ++ show tid ++ " caught exception"
196 dbg $ "beforeExit: " ++ show tid ++ " caught exception"
274 liftIO $ killChildren ctx
197 liftIO $ killChildren ctx
275 return (Just e)
198 return (Just e)
276− Right _ -> return Nothing
278− e <- waitForChildren ctx exc
199+ Right _ -> waitForChildren ctx
280− -- We are guaranteed to have a parent because we have been explicitly
201+ -- We are guaranteed to have a parent because we are forked.
281− -- forked by some parent.
282 let p = fromJust (parentChannel ctx)
202 let p = fromJust (parentChannel ctx)
283 signalQSemB (threadCredit ctx)
203 signalQSemB (threadCredit ctx)
284− -- XXX change the return value type to Maybe SomeException
285− liftIO $ atomically $ writeTChan p
204+ liftIO $ atomically $ writeTChan p (ChildDone tid r)
286− (ChildDone tid (maybe (Right []) Left e))
288-- | Decide whether to resume the context in the same thread or a new thread
206-- | Decide whether to resume the context in the same thread or a new thread
@@ -318,7 +236,7 @@ resumeContextWith context synch action = do
318 let ctx = setContextMailBox context (action context)
236 let ctx = setContextMailBox context (action context)
319 can <- liftIO $ canFork context
237 can <- liftIO $ canFork context
320 case can && (not synch) of
238 case can && (not synch) of
321− False -> resume ctx -- run synchronously
239+ False -> runContext ctx -- run synchronously
322 True -> forkContext ctx
240 True -> forkContext ctx
324-- | 'StreamData' represents a task in a task stream being generated.
242-- | 'StreamData' represents a task in a task stream being generated.