@@ -42,9 +42,9 @@ import Data.IORef (IORef, atomicModifyIORef,
42 writeIORef)
42 writeIORef)
43import Data.List (delete)
43import Data.List (delete)
44import Data.Maybe (isJust)
44import Data.Maybe (isJust)
45+import Unsafe.Coerce (unsafeCoerce)
46import Asyncly.AsyncT
47import Asyncly.AsyncT
47−import Asyncly.Context
49type MonadAsync m = (MonadIO m, MonadBaseControl IO m, MonadThrow m)
49type MonadAsync m = (MonadIO m, MonadBaseControl IO m, MonadThrow m)
@@ -79,9 +79,9 @@ type MonadAsync m = (MonadIO m, MonadBaseControl IO m, MonadThrow m)
79-- | Continue execution of the closure that we were executing when we migrated
79-- | Continue execution of the closure that we were executing when we migrated
80-- to a new thread.
80-- to a new thread.
82−runContext :: Monad m => Context -> StateT Context m ()
82+runContext :: Monad m => Context -> AsyncT m a -> StateT Context m ()
83−runContext ctx = do
83+runContext ctx action = do
84− let s = runAsyncT (composeContext ctx)
84+ let s = runAsyncT $ action >>= unsafeCoerce (continuation ctx)
85 _ <- lift $ runStateT s ctx
85 _ <- lift $ runStateT s ctx
@@ -93,7 +93,7 @@ runContext ctx = do
93-- pchan. We can use bounded channels to throttle the creation of threads based
93-- pchan. We can use bounded channels to throttle the creation of threads based
94-- on consumption rate.
94-- on consumption rate.
95processOneEvent :: MonadIO m
95processOneEvent :: MonadIO m
96− => ChildEvent a
96+ => ChildEvent
97 -> [ThreadId]
97 -> [ThreadId]
98 -> m ([ThreadId], Maybe SomeException)
98 -> m ([ThreadId], Maybe SomeException)
99processOneEvent (ChildDone tid e) pending = do
99processOneEvent (ChildDone tid e) pending = do
@@ -101,7 +101,7 @@ processOneEvent (ChildDone tid e) pending = do
101 return (delete tid pending, Nothing)
101 return (delete tid pending, Nothing)
103drainChildren :: MonadIO m
103drainChildren :: MonadIO m
104− => TChan (ChildEvent a)
104+ => TChan ChildEvent
105 -> [ThreadId]
105 -> [ThreadId]
106 -> m ([ThreadId], Maybe SomeException)
106 -> m ([ThreadId], Maybe SomeException)
107drainChildren cchan pending =
107drainChildren cchan pending =
@@ -180,23 +180,27 @@ signalQSemB sem = atomicModifyIORef sem $ \n -> (n + 1, ())
181forkFinally1 :: (MonadIO m, MonadBaseControl IO m)
181forkFinally1 :: (MonadIO m, MonadBaseControl IO m)
182 => Context
182 => Context
183 -> (Either SomeException () -> IO ())
184 -> (Either SomeException () -> IO ())
184 -> StateT Context m ThreadId
185 -> StateT Context m ThreadId
185−forkFinally1 ctx preExit =
186+forkFinally1 ctx action preExit =
186 EL.mask $ \restore ->
187 EL.mask $ \restore ->
187 liftBaseWith $ \runInIO -> forkIO $ do
188 liftBaseWith $ \runInIO -> forkIO $ do
188− _ <- runInIO $ EL.try (restore (runContext ctx))
189+ _ <- runInIO $ EL.try (restore (runContext ctx action))
189 >>= liftIO . preExit
190 >>= liftIO . preExit
191+ -- XXX restore state here
190 return ()
192 return ()
192-- | Run a given context in a new thread.
194-- | Run a given context in a new thread.
194forkContext :: (MonadBaseControl IO m, MonadIO m, MonadThrow m)
196forkContext :: (MonadBaseControl IO m, MonadIO m, MonadThrow m)
195− => Context -> StateT Context m ()
197+ => AsyncT m a -> StateT Context m ()
196−forkContext context = do
198+forkContext action = do
197− child <- childContext context
200+ childCtx <- childContext parentCtx
201+ tid <- forkFinally1 childCtx action
198− tid <- forkFinally1 child (beforeExit child (childChannel context))
202+ (beforeExit childCtx (childChannel parentCtx))
199− updatePendingThreads context tid
203+ updatePendingThreads parentCtx tid
@@ -245,6 +249,7 @@ canFork context = do
245 -- special handling for those cases. Add those to
249 -- special handling for those cases. Add those to
246 -- unreclaimable list? And always execute them in an
250 -- unreclaimable list? And always execute them in an
247 -- async thread, cannot use sync for those.
251 -- async thread, cannot use sync for those.
248 waitForOneEvent context
253 waitForOneEvent context
249 canFork context
254 canFork context
250 True -> return True
255 True -> return True
@@ -254,16 +259,15 @@ canFork context = do
254-- the current thread quota.
259-- the current thread quota.
256resumeContextWith :: MonadAsync m
261resumeContextWith :: MonadAsync m
257− => Context -- the context to resume
258− -> Bool -- force synchronous
262+ => Bool -- force synchronous
259− -> AsyncT m a -- the action to execute in the resumed context
263+ -> AsyncT m a
260 -> StateT Context m ()
264 -> StateT Context m ()
261−resumeContextWith context synch action = do
265+resumeContextWith synch action = do
262− let ctx = setContextMailBox context action
266+ context <- get
263 can <- liftIO $ canFork context
267 can <- liftIO $ canFork context
264 case can && (not synch) of
268 case can && (not synch) of
265− False -> runContext ctx -- run synchronously
269+ False -> runContext context action
266− True -> forkContext ctx
270+ True -> forkContext action
268-- The current model is to start a new thread for every task. The input is
272-- The current model is to start a new thread for every task. The input is
269-- provided at the time of the creation and therefore no synchronization is
273-- provided at the time of the creation and therefore no synchronization is
@@ -291,32 +295,13 @@ spawningParentDone = do
291 when (loc /= RemoteNode) $ setLocation WaitingParent
295 when (loc /= RemoteNode) $ setLocation WaitingParent
292 return Nothing
296 return Nothing
294−-- | Captures the state of the current computation at this point, starts a new
295−-- thread, using the argument passed as the return value of the computation and
296−-- continues the computation from the capture point. The end result is as if
297−-- this function just returned the value passed as argument albeit in a new
300-- If a new thread cannot be created then the computation is run in the same
298-- If a new thread cannot be created then the computation is run in the same
301-- thread, but the functional behavior remains the same.
299-- thread, but the functional behavior remains the same.
303async :: MonadAsync m => AsyncT m a -> AsyncT m a
301async :: MonadAsync m => AsyncT m a -> AsyncT m a
304async action = AsyncT $ do
302async action = AsyncT $ do
305− val <- takeContextMailBox
308− Right m -> runAsyncT m
312− resumeContextWith ctx False action
303+ resumeContextWith False action
314− -- If we started the task asynchronously in a new thread then the
315− -- parent thread reaches here, immediately after spawning the task.
317− -- However, if the task was executed synchronously then we reach
318− -- here after it is completely done.
319− spawningParentDone
304+ spawningParentDone
321-- | Makes an asyncly action from a callback setter function; can be used to
306-- | Makes an asyncly action from a callback setter function; can be used to
322-- convert existing callback style code into asyncly style code. The first
307-- convert existing callback style code into asyncly style code. The first
@@ -325,17 +310,16 @@ async action = AsyncT $ do
325-- value of type 'a'. After the computation is done the result of the action
310-- value of type 'a'. After the computation is done the result of the action
326-- in second parameter is returned to the callback.
311-- in second parameter is returned to the callback.
328−makeAsync :: (MonadAsync m) => ((a -> m b) -> m ()) -> m b -> AsyncT m a
313+makeAsync :: MonadAsync m => ((a -> m ()) -> m ()) -> AsyncT m a
329−makeAsync cbsetter cbret = AsyncT $ do
314+makeAsync cbsetter = AsyncT $ do
330− val <- takeContextMailBox
315+ -- XXX should we force fork a thread or keep running the context of the
331− case val of
316+ -- callback?
332− Right m -> runAsyncT m -- child
317+ ctx <- get
333− Left ctx -> do -- parent
334− lift $ cbsetter $ \a -> do
318+ lift $ cbsetter $ \a -> do
335− let s = resumeContextWith ctx False (return a)
319+ let s = resumeContextWith False (return a)
336− _ <- runStateT s ctx
320+ _ <- runStateT s ctx
338− spawningParentDone
322+ spawningParentDone
340-- scatter
324-- scatter
341each :: (MonadIO m, MonadBaseControl IO m, MonadThrow m)
325each :: (MonadIO m, MonadBaseControl IO m, MonadThrow m)
@@ -380,15 +364,14 @@ threads n process = AsyncT $ do
381-- | Run an 'AsyncT m' computation and collect the results generated by each
365-- | Run an 'AsyncT m' computation and collect the results generated by each
382-- thread of the computation in a list.
366-- thread of the computation in a list.
383−waitAsync :: forall m a. (MonadIO m, MonadCatch m)
367+waitAsync :: (MonadIO m, MonadCatch m)
384 => (a -> AsyncT m a) -> Maybe (IORef [Log]) -> AsyncT m a -> m ()
368 => (a -> AsyncT m a) -> Maybe (IORef [Log]) -> AsyncT m a -> m ()
385waitAsync finalizer lref m = do
369waitAsync finalizer lref m = do
386 childChan <- liftIO $ atomically newTChan
370 childChan <- liftIO $ atomically newTChan
387 pendingRef <- liftIO $ newIORef []
371 pendingRef <- liftIO $ newIORef []
388 credit <- liftIO $ newIORef maxBound
372 credit <- liftIO $ newIORef maxBound
390− let ctx = initContext (empty :: AsyncT m a) childChan pendingRef credit
374+ let ctx = initContext childChan pendingRef credit finalizer lref
393 r <- try $ runStateT (runAsyncT $ m >>= finalizer) ctx
376 r <- try $ runStateT (runAsyncT $ m >>= finalizer) ctx