on master help sign in
Refactor, simplify, add comments
commit0a69aecc0fcfa3206b9e970f3984e2cb6840c95a authorHarendra Kumar <harendra.kumar@gmail.com> dateSat 10 Jun 2017, 16:34 (9 years ago) parentdde36a3
3 files changed+63−45
src/Duct/AsyncT.hs+35−30 src/Duct/Event.hs+9−4 src/Duct/Threads.hs+19−11
src/Duct/AsyncT.hs+35−30
@@ -12,11 +12,9 @@
1212module Duct.AsyncT
1313 ( AsyncT (..)
1414 , waitAsync
15− , compose
1615 , (<**)
1716 , onNothing
1817 , RemoteStatus (..)
19− , back
2018 , waitForChildren
2119 , dbg
2220 )
@@ -44,13 +42,10 @@ import Data.Maybe (isJust, isNothing)
4442import Unsafe.Coerce (unsafeCoerce)
4543
4644import Duct.Event
47−import Duct.Log
4845
4946-- import Debug.Trace
5047
51−type StateM m = StateT EventF m
52−
53−newtype AsyncT m a = AsyncT { runAsyncT :: StateM m (Maybe a) }
48+newtype AsyncT m a = AsyncT { runAsyncT :: StateT EventF m (Maybe a) }
5449
5550------------------------------------------------------------------------------
5651-- Remote data types
@@ -89,6 +84,7 @@ instance Monad (AsyncT m) => Functor (AsyncT m) where
8984-- Applicative
9085------------------------------------------------------------------------------
9186
87+{-
9288-- | Warning: Radically untyped stuff. handle with care
9389getContinuations :: Monad m => StateM m [a -> AsyncT m b]
9490getContinuations = do
@@ -109,6 +105,8 @@ restoreStack :: MonadState EventF m => t -> m ()
109105restoreStack fs = modify $ \EventF {..} ->
110106 EventF { event = Nothing, fcomp = (unsafeCoerce fs), .. }
111107
108+-}
109+
112110instance Monad m => Applicative (AsyncT m) where
113111 pure a = AsyncT . return $ Just a
114112 m1 <*> m2 = do { x1 <- m1; x2 <- m2; return (x1 x2) }
@@ -145,24 +143,29 @@ tailsafe (_:xs) = xs
145143
146144instance Monad m => Monad (AsyncT m) where
147145 return = pure
148− m >>= f = AsyncT $ do
149− -- save m in xcomp and add f to the head of fcomp
150− -- _ <- setEventCont m f
151− modify $ \EventF { fcomp = fs, .. } ->
152− EventF { xcomp = unsafeCoerce m, fcomp = unsafeCoerce f : fs, .. }
153146
154− -- run m under this modified environment
147+ m >>= f = AsyncT $ do
148+ -- Save the 'm' and 'f', in case we migrate to a new thread before this
149+ -- bind operation completes, we run the operation manually in the new
150+ -- thread.
151+ modify $ \EventF { fstack = fs, .. } ->
152+ EventF { currentm = unsafeCoerce m
153+ , fstack = unsafeCoerce f : fs
154+ , .. }
155+
156+ -- Inner bind operations in 'm' add their 'f' to fstack. If we migrate to
157+ -- a new thread somewhere in the middle we unwind the fstack and run these
158+ -- functions manually after migration.
155159 mres <- runAsyncT m
156− -- remove the head of fcomp apply it to mres and that becomes the new xcomp.
157− -- is head of fcomp always the same as f?
160+
158161 let res = case mres of
159162 Nothing -> empty
160163 Just x -> f x
161164
162− -- XXX why would we have more than one continuation? Can we have just one
163− -- instead of a list and remove it after every bind?
164− modify $ \EventF { fcomp = fs, .. } ->
165− EventF { xcomp = unsafeCoerce res, fcomp = tailsafe fs, .. }
165+ modify $ \EventF { fstack = fs, .. } ->
166+ EventF { currentm = unsafeCoerce res
167+ , fstack = tailsafe fs
168+ , .. }
166169
167170 runAsyncT res
168171
@@ -178,15 +181,11 @@ instance (Monoid a, Monad (AsyncT m)) => Monoid (AsyncT m a) where
178181-- Backtracking
179182------------------------------------------------------------------------------
180183
184+{-
181185-- | Run the closure (the 'x' in 'x >>= f') of the current bind operation.
182186runClosure :: EventF -> StateM m (Maybe a)
183187runClosure EventF { xcomp = x } = runAsyncT (unsafeCoerce x)
184188
185−-- | Compose a list of continuations.
186−compose :: MonadIO m => [a -> AsyncT m a] -> (a -> AsyncT m b)
187−compose [] = const empty
188−compose (f:fs) = \x -> f x >>= compose fs
189−
190189-- | Run the continuation (the 'f' in 'x >>= f') of the current bind operation with the current state.
191190runContinuation :: MonadIO m => EventF -> a -> StateM m (Maybe b)
192191runContinuation EventF { fcomp = fs } =
@@ -226,18 +225,14 @@ back reason = AsyncT $ do
226225 Nothing -> runContinuation first x
227226 justreason -> goBackt $ Backtrack justreason bs
228227
228+-}
229+
229230------------------------------------------------------------------------------
230231-- MonadIO
231232------------------------------------------------------------------------------
232233
233234instance MonadIO m => MonadIO (AsyncT m) where
234− liftIO mx = do
235− ex <- liftIO' $ (mx >>= return . Right) `catch`
236− (\(e :: SomeException) -> return $ Left e)
237− case ex of
238− Left e -> back e
239− Right x -> return x
240− where liftIO' x = AsyncT $ liftIO x >>= return . Just
235+ liftIO mx = AsyncT $ liftIO mx >>= return . Just
241236
242237-------------------------------------------------------------------------------
243238-- AsyncT transformer
@@ -403,6 +398,7 @@ instance (Num a, Monad (AsyncT m)) => Num (AsyncT m a) where
403398 abs f = f >>= return . abs
404399 signum f = f >>= return . signum
405400
401+{-
406402class AdditionalOperators m where
407403
408404 -- | Run @m a@ discarding its result before running @m b@.
@@ -469,3 +465,12 @@ infixr 1 <***, <**, **>
469465 runAsyncT mb
470466 return $ Just x
471467
468+-}
469+
470+(<**) :: Monad m => AsyncT m a -> AsyncT m b -> AsyncT m a
471+(<**) ma mb = AsyncT $ do
472+ a <- runAsyncT ma
473+ runAsyncT mb
474+ return a
475+
476+infixr 1 <**
src/Duct/Event.hs+9−4
@@ -32,13 +32,18 @@ data EventF = forall m a b. EventF
3232 -- away with this?
3333 -- ^ event data to use in a continuation in a new thread
3434
35− , xcomp :: m a
36− , fcomp :: [b -> m b]
35+ -- the 'm' and 'f' in an 'm >>= f' operation of the monad
36+ -- In nested binds we store the current m only, but the whole stack of fs
37+ , currentm :: m a
38+ , fstack :: [b -> m b]
3739 -- ^ List of continuations
3840
3941 , mfData :: M.Map TypeRep SData
4042 -- ^ State data accessed with get or put operations
4143
44+ -- XXX All of the following can be removed
45+ -- Even the remote status can be removed by the same logic
46+
4247 , mfSequence :: Int
4348
4449 , parentChannel :: Maybe (TChan ThreadId)
@@ -91,8 +96,8 @@ initEventF
9196 -> EventF
9297initEventF x childChan pending credit =
9398 EventF { event = mempty
94− , xcomp = x
95− , fcomp = []
99+ , currentm = x
100+ , fstack = []
96101 , mfData = mempty
97102 , mfSequence = 0
98103 , parentChannel = Nothing
src/Duct/Threads.hs+19−11
@@ -12,7 +12,7 @@ module Duct.Threads
1212 )
1313where
1414
15−import Control.Applicative ((<|>))
15+import Control.Applicative ((<|>), empty)
1616import Control.Concurrent (ThreadId, forkIO, killThread,
1717 myThreadId, threadDelay)
1818import Control.Concurrent.STM (TChan, atomically, newTChan,
@@ -38,14 +38,22 @@ import Duct.AsyncT
3838import Duct.Event
3939
4040------------------------------------------------------------------------------
41−-- Utilities
41+-- Pick up from where we left in the previous thread
4242------------------------------------------------------------------------------
4343
44−-- | Run the closure and the continuation using the state data of the calling thread
45−runCont :: (MonadIO m, Monad (AsyncT m)) => EventF -> StateT EventF m (Maybe a)
46−runCont EventF { xcomp = x, fcomp = fs } = runAsyncT $ do
47− r <- unsafeCoerce x
48− compose (unsafeCoerce fs) r
44+-- | Continue execution of the closure that we were executing when we migrated
45+-- to a new thread. Run the stack of pending functions in fstack. The types
46+-- don't match. We just coerce the types here, we know that they actually match.
47+
48+continue :: (MonadIO m, Monad (AsyncT m)) => EventF -> StateT EventF m (Maybe a)
49+continue EventF { currentm = x, fstack = fs } =
50+ runAsyncT $ unsafeCoerce x >>= runfStack (unsafeCoerce fs)
51+
52+ where
53+
54+ runfStack :: Monad m => [a -> AsyncT m a] -> a -> AsyncT m b
55+ runfStack [] _ = empty
56+ runfStack (f:fs) x = f x >>= runfStack fs
4957
5058------------------------------------------------------------------------------
5159-- Thread Management (creation, reaping and killing)
@@ -210,7 +218,7 @@ genAsyncEvents parentc rec = forkMaybe parentc loop
210218 -- pass on the io result and then run the continuation
211219 runContWith dat cont = do
212220 let cont' = cont { event = Just $ unsafeCoerce dat }
213− _ <- runStateT (runCont cont') cont'
221+ _ <- runStateT (continue cont') cont'
214222 return ()
215223
216224-- | Run an IO action one or more times to generate a stream of tasks. The IO
@@ -248,7 +256,7 @@ waitEvents io = do
248256 mr <- parallel (SMore <$> io)
249257 case mr of
250258 SMore x -> return x
251− SError e -> back e
259+ -- SError e -> back e
252260
253261-- | Run an IO computation asynchronously and generate a single task carrying
254262-- the result of the computation when it completes. See 'parallel' for notes on
@@ -258,7 +266,7 @@ async io = do
258266 mr <- parallel (SLast <$> io)
259267 case mr of
260268 SLast x -> return x
261− SError e -> back e
269+ -- SError e -> back e
262270
263271-- | Force an async computation to run synchronously. It can be useful in an
264272-- 'Alternative' composition to run the alternative only after finishing a
@@ -310,7 +318,7 @@ react setHandler iob = AsyncT $ do
310318 case event cont of
311319 Nothing -> do
312320 lift $ setHandler $ \dat ->do
313− runStateT (runCont cont) cont{event= Just $ unsafeCoerce dat}
321+ runStateT (continue cont) cont{event= Just $ unsafeCoerce dat}
314322 liftIO iob
315323 was <- getData `onNothing` return NoRemote
316324 when (was /= WasRemote) $ setData WasParallel