@@ -1,5 +1,8 @@
1−{-# LANGUAGE FlexibleContexts #-}
1+{-# LANGUAGE FlexibleContexts #-}
2−{-# LANGUAGE ScopedTypeVariables #-}
2+{-# LANGUAGE ScopedTypeVariables #-}
3+{-# LANGUAGE StandaloneDeriving #-}
4+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
5+{-# LANGUAGE UndecidableInstances #-}
5-- Module : Asyncly.Threads
8-- Module : Asyncly.Threads
@@ -13,6 +16,9 @@
13module Asyncly.RunAsync
16module Asyncly.RunAsync
@@ -23,10 +29,13 @@ module Asyncly.RunAsync
32+import Control.Applicative (Alternative (..))
26import Control.Concurrent.STM (atomically, newTChan)
33import Control.Concurrent.STM (atomically, newTChan)
27import Control.Monad (liftM)
34import Control.Monad (liftM)
28−import Control.Monad.Catch (MonadCatch, throwM, try)
35+import Control.Monad.Catch (MonadCatch, MonadThrow, throwM, try)
29import Control.Monad.IO.Class (MonadIO (..))
36import Control.Monad.IO.Class (MonadIO (..))
37+import Control.Monad.Trans.Class (MonadTrans (lift))
38+import Control.Monad.Trans.Control (MonadBaseControl)
30import Control.Monad.State (StateT, runStateT)
39import Control.Monad.State (StateT, runStateT)
31import Control.Monad.Trans.Class (MonadTrans (lift))
40import Control.Monad.Trans.Class (MonadTrans (lift))
32import Data.Atomics (atomicModifyIORefCAS)
41import Data.Atomics (atomicModifyIORefCAS)
@@ -34,21 +43,34 @@ import Data.IORef (IORef, newIORef, readIORef)
35import Control.Monad.Trans.Recorder (MonadRecorder(..), RecorderT,
44import Control.Monad.Trans.Recorder (MonadRecorder(..), RecorderT,
36 Recording, blank, runRecorderT)
45 Recording, blank, runRecorderT)
37import Asyncly.Threads
48import Asyncly.Threads
38import Asyncly.AsyncT
49import Asyncly.AsyncT
51+newtype AsynclyT m a = AsynclyT { runAsynclyT :: AsyncT (StateT Context m) a }
53+deriving instance MonadAsync m => Functor (AsynclyT m)
54+deriving instance MonadAsync m => Applicative (AsynclyT m)
55+deriving instance MonadAsync m => Alternative (AsynclyT m)
56+deriving instance MonadAsync m => Monad (AsynclyT m)
57+deriving instance MonadAsync m => MonadIO (AsynclyT m)
58+instance MonadTrans (AsynclyT) where
59+ lift mx = AsynclyT $ AsyncT $ lift mx >>= return . (\a -> (Yield a stop))
40−getContext :: Monad m => (a -> AsyncT m a) -> Maybe (IORef [Recording]) -> IO Context
61+getContext :: Maybe (IORef [Recording]) -> IO Context
41−getContext f lref = do
62+getContext lref = do
42 childChan <- atomically newTChan
63 childChan <- atomically newTChan
43 pendingRef <- newIORef []
64 pendingRef <- newIORef []
44 credit <- newIORef maxBound
65 credit <- newIORef maxBound
45− return $ initContext childChan pendingRef credit f lref
66+ return $ initContext childChan pendingRef credit lref
47-- | Run an 'AsyncT m' computation, wait for it to finish and discard the
68-- | Run an 'AsyncT m' computation, wait for it to finish and discard the
48-- results.
69-- results.
70+{-# SPECIALIZE wait_ :: AsynclyT IO a -> IO () #-}
49−wait_ :: forall m a. (MonadAsync m, MonadCatch m) => AsyncT m a -> m ()
71+wait_ :: forall m a. (MonadAsync m, MonadCatch m) => AsynclyT m a -> m ()
50−wait_ m = do
72+wait_ (AsynclyT m) = do
51− ctx <- liftIO $ getContext (return :: a -> AsyncT m a) Nothing
73+ ctx <- liftIO $ getContext Nothing
52 _ <- runStateT (run m) ctx
74 _ <- runStateT (run m) ctx
@@ -60,6 +82,35 @@ wait_ m = do
60 -- XXX pull from children here
82 -- XXX pull from children here
61 _ -> return ()
83 _ -> return ()
85+wait :: forall m a. (MonadAsync m, MonadCatch m) => AsynclyT m a -> m [a]
86+wait (AsynclyT m) = liftIO (getContext Nothing) >>= run m
91+ (a, ctx') <- runStateT (runAsyncT ma) ctx
93+ Yield x mb -> liftM (x :) (run mb ctx')
94+ -- XXX pull from children here
99+{-# SPECIALIZE each :: [a] -> AsynclyT IO a #-}
100+each :: (MonadIO m, MonadBaseControl IO m, MonadThrow m)
101+ => [a] -> AsynclyT m a
102+each xs = foldr (<|>) empty $ map return xs
104+------------------------------------------------------------------------------
105+-- Controlling thread quota
106+------------------------------------------------------------------------------
108+-- | Runs a computation under a given thread limit. A limit of 0 means all new
109+-- tasks start synchronously in the current thread unless overridden by
111+threads :: MonadAsync m => Int -> AsynclyT m a -> AsynclyT m a
112+threads n action = AsynclyT $ AsyncT $ threadCtl n (runAsyncT $ runAsynclyT action)
64wait_ :: AsyncT IO a -> IO ()
115wait_ :: AsyncT IO a -> IO ()
65wait_ m = do
116wait_ m = do
@@ -74,7 +125,6 @@ wait_ m = do
74 Yield _ r -> run r
125 Yield _ r -> run r
75 -- XXX pull from children here
126 -- XXX pull from children here
76 _ -> return ()
127 _ -> return ()
79wait :: forall m a. (MonadAsync m, MonadCatch m) => AsyncT m a -> m [a]
129wait :: forall m a. (MonadAsync m, MonadCatch m) => AsyncT m a -> m [a]
80wait m = liftIO (getContext (return :: a -> AsyncT m a) Nothing) >>= run m
130wait m = liftIO (getContext (return :: a -> AsyncT m a) Nothing) >>= run m
@@ -87,6 +137,7 @@ wait m = liftIO (getContext (return :: a -> AsyncT m a) Nothing) >>= run m
87 Yield x mb -> liftM (x :) (run mb ctx')
137 Yield x mb -> liftM (x :) (run mb ctx')
88 -- XXX pull from children here
138 -- XXX pull from children here
89 Stop -> return []
139 Stop -> return []
92------------------------------------------------------------------------------
143------------------------------------------------------------------------------