@@ -106,8 +106,8 @@ type MonadAsync m = (MonadIO m, MonadBaseControl IO m, MonadThrow m)
106instance Monad m => Monoid (AsyncT m a) where
106instance Monad m => Monoid (AsyncT m a) where
107 mempty = AsyncT $ \_ stp _ -> stp
107 mempty = AsyncT $ \_ stp _ -> stp
108 mappend (AsyncT m1) m2 = AsyncT $ \ctx stp yld ->
108 mappend (AsyncT m1) m2 = AsyncT $ \ctx stp yld ->
109− m1 ctx ((runAsyncT m2) ctx stp yld) $ \a c r ->
109+ m1 ctx ((runAsyncT m2) ctx stp yld) $ \a _ r ->
110− let yield x = yld a c (Just x)
110+ let yield x = yld a ctx (Just x)
111 in maybe (yield m2) (\rx -> yield $ mappend rx m2) r
111 in maybe (yield m2) (\rx -> yield $ mappend rx m2) r
113-- We do not use bind for parallelism. That is, we do not start each iteration
113-- We do not use bind for parallelism. That is, we do not start each iteration
@@ -152,7 +152,7 @@ instance Monad m => Applicative (AsyncT m) where
152-- Alternative
152-- Alternative
153------------------------------------------------------------------------------
153------------------------------------------------------------------------------
155−{-# NOINLINE doFork #-}
155+{-# INLINE doFork #-}
156doFork :: (MonadIO m, MonadBaseControl IO m)
156doFork :: (MonadIO m, MonadBaseControl IO m)
158 -> (SomeException -> IO ())
158 -> (SomeException -> IO ())
@@ -160,6 +160,7 @@ doFork :: (MonadIO m, MonadBaseControl IO m)
160doFork action preExit =
160doFork action preExit =
161 EL.mask $ \restore ->
161 EL.mask $ \restore ->
162 liftBaseWith $ \runInIO -> forkIO $ do
162 liftBaseWith $ \runInIO -> forkIO $ do
163+ -- XXX test the exception handling
163 _ <- runInIO $ EL.catch (restore action) (liftIO . preExit)
164 _ <- runInIO $ EL.catch (restore action) (liftIO . preExit)
164 -- XXX restore state here?
165 -- XXX restore state here?
165 return ()
166 return ()
@@ -219,20 +220,21 @@ pull ctx = AsyncT $ \_ stp yld -> do
219 Just BlockedIndefinitelyOnSTM -> stp
220 Just BlockedIndefinitelyOnSTM -> stp
220 Nothing -> throwM e
221 Nothing -> throwM e
221 Right ev ->
222 Right ev ->
223+ let yield a = yld a Nothing (Just (pull ctx))
222− case ev of
224+ in case ev of
223− ChildYield a -> yld a Nothing (Just (pull ctx))
225+ ChildYield a -> yield a
224− ChildDone _ a -> yld a Nothing (Just (pull ctx))
226+ ChildDone _ a -> yield a
225 ChildStop _ e -> do
227 ChildStop _ e -> do
226 let continue = (runAsyncT (pull ctx)) (Just ctx) stp yld
228 let continue = (runAsyncT (pull ctx)) (Just ctx) stp yld
227− maybe continue throwM e
229+ in maybe continue throwM e
229-- | Split the original computation in a pull-push pair. The original
231-- | Split the original computation in a pull-push pair. The original
230-- computation pulls from a Channel while m1 and m2 push to the channel.
232-- computation pulls from a Channel while m1 and m2 push to the channel.
231−{-# INLINE pullFork #-}
233+{-# NOINLINE pullFork #-}
232pullFork :: MonadAsync m => AsyncT m a -> AsyncT m a -> AsyncT m a
234pullFork :: MonadAsync m => AsyncT m a -> AsyncT m a -> AsyncT m a
233pullFork m1 m2 = AsyncT $ \_ stp yld -> do
235pullFork m1 m2 = AsyncT $ \_ stp yld -> do
234 c <- liftIO $ newContext
236 c <- liftIO $ newContext
235− _ <- doFork (pushBoth c m1 m2) (handlePushException (childChannel c))
237+ _ <- doFork (push c (m1 <|> m2)) (handlePushException (childChannel c))
236 (runAsyncT (pull c)) (Just c) stp yld
238 (runAsyncT (pull c)) (Just c) stp yld
@@ -241,13 +243,8 @@ pullFork m1 m2 = AsyncT $ \_ stp yld -> do
241 childChan <- atomically newTChan
243 childChan <- atomically newTChan
242 return $ Context { childChannel = childChan }
244 return $ Context { childChannel = childChan }
244− pushBoth c ma mb = do
245− _ <- doFork (push c ma) (handlePushException (childChannel c))
246− -- XXX push from m2 only when the channel becomes empty
249canFork :: IO Bool
246canFork :: IO Bool
250−canFork = return True
247+canFork = return False
252-- Concurrency rate control. Our objective is to create more threads on
249-- Concurrency rate control. Our objective is to create more threads on
253-- demand if the consumer is running faster than us. As soon as we
250-- demand if the consumer is running faster than us. As soon as we
@@ -264,21 +261,20 @@ canFork = return True
264-- the rest of the computation at any point of time inside the Monad bind
261-- the rest of the computation at any point of time inside the Monad bind
265-- operation if the consumer is running at a faster speed.
262-- operation if the consumer is running at a faster speed.
267−{-# NOINLINE fork #-}
268−fork :: MonadAsync m => AsyncT m a -> AsyncT m a -> AsyncT m a
269−fork m1 m2 = AsyncT $ \ctx stp yld -> do
271− Nothing -> (runAsyncT (pullFork m1 m2)) ctx stp yld
272− Just c -> (runAsyncT (pushFork c m1 m2)) ctx stp yld
274instance MonadAsync m => Alternative (AsyncT m) where
264instance MonadAsync m => Alternative (AsyncT m) where
275 empty = mempty
265 empty = mempty
267+ -- XXX pullFork can have more than 2x penalty for smallish tasks. Can we
268+ -- avoid this automatically if the task is small?
269+ {-# INLINE (<|>) #-}
277 m1 <|> m2 = AsyncT $ \ctx stp yld -> do
270 m1 <|> m2 = AsyncT $ \ctx stp yld -> do
272+ Nothing -> (runAsyncT (pullFork m1 m2)) ctx stp yld
278− doAsync <- liftIO $ canFork
274+ doAsync <- liftIO $ canFork
279− if doAsync then
275+ if doAsync then
280− (runAsyncT $ fork m1 m2) ctx stp yld
276+ (runAsyncT (pushFork c m1 m2)) ctx stp yld
281− else (runAsyncT (m1 <> m2)) ctx stp yld
277+ else (runAsyncT (m1 <> m2)) ctx stp yld
283instance MonadAsync m => MonadPlus (AsyncT m) where
279instance MonadAsync m => MonadPlus (AsyncT m) where
284 mzero = empty
280 mzero = empty