@@ -69,11 +69,12 @@ import Duct.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 :: Monad m => Context -> m (Maybe a)
72+resume :: MonadIO m => Context -> m Context
73resume ctx = do
73resume ctx = do
74 let s = runAsyncT (resumeContext ctx)
74 let s = runAsyncT (resumeContext ctx)
75+ -- The returned value is always 'Nothing', we just discard it
75− (a, _) <- runStateT s ctx
76+ (_, c) <- runStateT s ctx
78updateContextEvent :: Context -> a -> Context
79updateContextEvent :: Context -> a -> Context
79updateContextEvent ctx evdata = ctx { event = Just $ unsafeCoerce evdata }
80updateContextEvent ctx evdata = ctx { event = Just $ unsafeCoerce evdata }
@@ -96,9 +97,11 @@ processOneEvent ev pchan pending exc = do
96 Nothing ->
97 Nothing ->
97 case ev of
98 case ev of
98 ChildDone tid res -> do
99 ChildDone tid res -> do
99− dbg $ "Reaping child: " ++ show tid
100+ dbg $ "processOneEvent ChildDone: " ++ show tid
100− handleDone res
101+ handlePass res
101− PassOnResult res -> handlePass res
102+ PassOnResult res -> do
103+ dbg $ "processOneEvent PassOnResult"
102 Just _ -> return exc
105 Just _ -> return exc
103 let p = case ev of
106 let p = case ev of
104 ChildDone tid _ -> delete tid pending
107 ChildDone tid _ -> delete tid pending
@@ -107,29 +110,16 @@ processOneEvent ev pchan pending exc = do
110− handleDone :: MonadIO m
111− => Either SomeException (Maybe a) -> m (Maybe SomeException)
115− liftIO $ mapM_ killThread pending
119− Nothing -> return ()
120− Just x -> liftIO $ atomically
122− (PassOnResult (Right (unsafeCoerce x)))
125 handlePass :: MonadIO m
113 handlePass :: MonadIO m
126− => Either SomeException a -> m (Maybe SomeException)
114+ => Either SomeException [a] -> m (Maybe SomeException)
127 handlePass res =
115 handlePass res =
128 case res of
116 case res of
129 Left e -> do
117 Left e -> do
118+ dbg $ "handlePass: caught exception"
130 liftIO $ mapM_ killThread pending
119 liftIO $ mapM_ killThread pending
131 return (Just e)
120 return (Just e)
132− Right _ -> do
121+ Right [] -> return Nothing
133 liftIO $ atomically $ writeTChan pchan
123 liftIO $ atomically $ writeTChan pchan
134 (PassOnResult (unsafeCoerce res))
124 (PassOnResult (unsafeCoerce res))
135 return Nothing
125 return Nothing
@@ -230,10 +220,10 @@ instance Read SomeException where
231forkFinally1 :: (MonadIO m, MonadBaseControl IO m) =>
221forkFinally1 :: (MonadIO m, MonadBaseControl IO m) =>
232 m a -> (Either SomeException a -> IO ()) -> m ThreadId
222 m a -> (Either SomeException a -> IO ()) -> m ThreadId
233−forkFinally1 action and_then =
223+forkFinally1 action preExit =
234 EL.mask $ \restore ->
224 EL.mask $ \restore ->
235 liftBaseWith $ \runInIO -> forkIO $ do
225 liftBaseWith $ \runInIO -> forkIO $ do
236− _ <- runInIO $ EL.try (restore action) >>= liftIO . and_then
226+ _ <- runInIO $ EL.try (restore action) >>= liftIO . preExit
237 return ()
227 return ()
239-- | Run a given context in a new thread.
229-- | Run a given context in a new thread.
@@ -258,33 +248,38 @@ forkContextWith runCtx context = do
258 childContext ctx = do
248 childContext ctx = do
259 pendingRef <- liftIO $ newIORef []
249 pendingRef <- liftIO $ newIORef []
260 chan <- liftIO $ atomically newTChan
250 chan <- liftIO $ atomically newTChan
251+ resultsRef <- liftIO $ newIORef []
261 -- shares the threadCredit of the parent by default
252 -- shares the threadCredit of the parent by default
262 return $ ctx
253 return $ ctx
263 { parentChannel = Just (childChannel ctx)
254 { parentChannel = Just (childChannel ctx)
264 , pendingThreads = pendingRef
255 , pendingThreads = pendingRef
265 , childChannel = chan
256 , childChannel = chan
257+ , accumResults = resultsRef
268 beforeExit ctx res = do
260 beforeExit ctx res = do
269 exc <- case res of
262 exc <- case res of
270 Left e -> do
263 Left e -> do
264+ dbg $ "beforeExit: " ++ show tid ++ " caught exception"
271 liftIO $ killChildren ctx
265 liftIO $ killChildren ctx
272 return (Just e)
266 return (Just e)
273 Right _ -> return Nothing
267 Right _ -> return Nothing
275 e <- waitForChildren ctx exc
269 e <- waitForChildren ctx exc
278 -- We are guaranteed to have a parent because we have been explicitly
271 -- We are guaranteed to have a parent because we have been explicitly
279 -- forked by some parent.
272 -- forked by some parent.
280 let p = fromJust (parentChannel ctx)
273 let p = fromJust (parentChannel ctx)
274+ results <- liftIO $ readIORef (accumResults ctx)
281 signalQSemB (threadCredit ctx)
275 signalQSemB (threadCredit ctx)
282 liftIO $ atomically $ writeTChan p
276 liftIO $ atomically $ writeTChan p
283− (ChildDone tid (maybe (unsafeCoerce res) Left e))
277+ (ChildDone tid (maybe (unsafeCoerce (Right results)) Left e))
285-- | A wrapper to first decide whether to run the context in the same thread or
279-- | A wrapper to first decide whether to run the context in the same thread or
286-- a new thread and then run the context in that thread.
280-- a new thread and then run the context in that thread.
282+-- XXX create a canFork function
288resumeContextWith :: (MonadBaseControl IO m, MonadIO m, MonadThrow m)
283resumeContextWith :: (MonadBaseControl IO m, MonadIO m, MonadThrow m)
289 => (Context -> m (Maybe a)) -> Context -> m ()
284 => (Context -> m (Maybe a)) -> Context -> m ()
290resumeContextWith runCtx context = do
285resumeContextWith runCtx context = do
@@ -339,9 +334,11 @@ loopContextWith ioaction ctx = do
339 let ctx' = updateContextEvent ctx streamData
334 let ctx' = updateContextEvent ctx streamData
340 case streamData of
335 case streamData of
341 SMore _ -> do
336 SMore _ -> do
342− resumeContextWith resume ctx'
337+ resumeContextWith (\x -> resume x >> return Nothing) ctx'
343 loopContextWith ioaction ctx
338 loopContextWith ioaction ctx
344− _ -> resume ctx' -- run synchronously
340+ _ <- resume ctx' -- run synchronously
341+ return Nothing -- we are done with the loop
346-- | Run an IO action one or more times to generate a stream of tasks. The IO
343-- | Run an IO action one or more times to generate a stream of tasks. The IO
347-- action returns a 'StreamData'. When it returns an 'SMore' or 'SLast' a new
344-- action returns a 'StreamData'. When it returns an 'SMore' or 'SLast' a new
@@ -360,7 +357,7 @@ parallel ioaction = AsyncT $ do
360 -- generating the event data from the ioaction.
357 -- generating the event data from the ioaction.
361 context <- get
358 context <- get
362 case event context of
359 case event context of
363− -- We have already executed the ioaction in the parent thread and put the
360+ -- We have already executed the ioaction in the parent thread and put its
364 -- result in the context and now we are continuing the context in a new
361 -- result in the context and now we are continuing the context in a new
365 -- thread. Just return the result of the ioaction stored in the 'event'
362 -- thread. Just return the result of the ioaction stored in the 'event'
366 -- field.
363 -- field.