@@ -34,6 +34,7 @@ module Streamly.Streams.Parallel
37+import Control.Concurrent (throwTo, myThreadId)
37import Control.Monad (ap)
38import Control.Monad (ap)
38import Control.Monad.Base (MonadBase(..), liftBaseDefault)
39import Control.Monad.Base (MonadBase(..), liftBaseDefault)
39import Control.Monad.Catch (MonadThrow, throwM)
40import Control.Monad.Catch (MonadThrow, throwM)
@@ -43,12 +44,15 @@ import Control.Monad.Reader.Class (MonadReader(..))
43import Control.Monad.State.Class (MonadState(..))
44import Control.Monad.State.Class (MonadState(..))
44import Control.Monad.Trans.Class (MonadTrans(lift))
45import Control.Monad.Trans.Class (MonadTrans(lift))
45import Data.Functor (void)
46import Data.Functor (void)
46−import Data.IORef (newIORef)
47+import Data.IORef (newIORef, readIORef)
48+import Data.List ((\\))
47import Data.Maybe (fromJust)
49import Data.Maybe (fromJust)
48import Data.Semigroup (Semigroup(..))
50import Data.Semigroup (Semigroup(..))
49import Prelude hiding (map)
51import Prelude hiding (map)
50import System.Clock
52import System.Clock
54+import qualified Data.Set as S
52import Streamly.Streams.SVar (fromSVar)
56import Streamly.Streams.SVar (fromSVar)
53import Streamly.Streams.Serial (map)
57import Streamly.Streams.Serial (map)
54import Streamly.SVar
58import Streamly.SVar
@@ -71,20 +75,33 @@ runOne st m = unStream m st stop single yieldk
71 yc <- newIORef 0
75 yc <- newIORef 0
72 wls <- newIORef (0, fromNanoSecs 0)
76 wls <- newIORef (0, fromNanoSecs 0)
73 return $ WorkerInfo 0 yc wls
77 return $ WorkerInfo 0 yc wls
74 sv = fromJust $ streamVar st
79 sv = fromJust $ streamVar st
81+ withLimitCheck action = do
82+ yieldLimitOk <- liftIO $ decrementYieldLimitPost sv
86+ workers <- readIORef (workerThreads sv)
88+ mapM_ (\tid -> throwTo tid ThreadAbort)
89+ (S.toList workers \\ [self])
75 stop = liftIO $ winfo >>= sendStop sv
91 stop = liftIO $ winfo >>= sendStop sv
76 sendit a = liftIO $ winfo >>= \x -> sendYield sv x (ChildYield a)
92 sendit a = liftIO $ winfo >>= \x -> sendYield sv x (ChildYield a)
77− single a = sendit a >> stop
93+ single a = sendit a >> withLimitCheck stop
78 -- XXX there is no flow control in parallel case. We should perhaps use a
95 -- XXX there is no flow control in parallel case. We should perhaps use a
79 -- queue and queue it back on that and exit the thread when the outputQueue
96 -- queue and queue it back on that and exit the thread when the outputQueue
80 -- overflows. Parallel is dangerous because it can accumulate unbounded
97 -- overflows. Parallel is dangerous because it can accumulate unbounded
81 -- output in the buffer.
98 -- output in the buffer.
82− yieldk a r = void (sendit a) >> runOne st r
99+ yieldk a r = void (sendit a) >> withLimitCheck (runOne st r)
84{-# NOINLINE forkSVarPar #-}
101{-# NOINLINE forkSVarPar #-}
85forkSVarPar :: MonadAsync m => Stream m a -> Stream m a -> Stream m a
102forkSVarPar :: MonadAsync m => Stream m a -> Stream m a -> Stream m a
86forkSVarPar m r = Stream $ \st stp sng yld -> do
103forkSVarPar m r = Stream $ \st stp sng yld -> do
87− sv <- newParallelVar
104+ sv <- newParallelVar st
88 pushWorkerPar sv (runOne st{streamVar = Just sv} m)
105 pushWorkerPar sv (runOne st{streamVar = Just sv} m)
89 pushWorkerPar sv (runOne st{streamVar = Just sv} r)
106 pushWorkerPar sv (runOne st{streamVar = Just sv} r)
90 (unStream (fromSVar sv)) (rstState st) stp sng yld
107 (unStream (fromSVar sv)) (rstState st) stp sng yld
@@ -97,7 +114,7 @@ joinStreamVarPar style m1 m2 = Stream $ \st stp sng yld ->
97 Just sv | svarStyle sv == style -> do
114 Just sv | svarStyle sv == style -> do
98 pushWorkerPar sv (runOne st m1)
115 pushWorkerPar sv (runOne st m1)
99 unStream m2 st stp sng yld
116 unStream m2 st stp sng yld
100− _ -> unStream (forkSVarPar m1 m2) (rstState st) stp sng yld
117+ _ -> unStream (forkSVarPar m1 m2) st stp sng yld
102{-# INLINE parallelStream #-}
119{-# INLINE parallelStream #-}
103parallelStream :: MonadAsync m => Stream m a -> Stream m a -> Stream m a
120parallelStream :: MonadAsync m => Stream m a -> Stream m a -> Stream m a
@@ -123,7 +140,7 @@ parallel m1 m2 = fromStream $ parallelStream (toStream m1) (toStream m2)
124mkParallel :: (IsStream t, MonadAsync m) => t m a -> m (t m a)
141mkParallel :: (IsStream t, MonadAsync m) => t m a -> m (t m a)
125mkParallel m = do
142mkParallel m = do
126− sv <- newParallelVar
143+ sv <- newParallelVar defState
127 pushWorkerPar sv (runOne defState{streamVar = Just sv} $ toStream m)
144 pushWorkerPar sv (runOne defState{streamVar = Just sv} $ toStream m)
128 return $ fromSVar sv
145 return $ fromSVar sv
@@ -134,7 +151,7 @@ mkParallel m = do
134{-# INLINE applyWith #-}
151{-# INLINE applyWith #-}
135applyWith :: (IsStream t, MonadAsync m) => (t m a -> t m b) -> t m a -> t m b
152applyWith :: (IsStream t, MonadAsync m) => (t m a -> t m b) -> t m a -> t m b
136applyWith f m = fromStream $ Stream $ \st stp sng yld -> do
153applyWith f m = fromStream $ Stream $ \st stp sng yld -> do
137− sv <- newParallelVar
154+ sv <- newParallelVar (rstState st)
138 pushWorkerPar sv (runOne st{streamVar = Just sv} (toStream m))
155 pushWorkerPar sv (runOne st{streamVar = Just sv} (toStream m))
139 unStream (toStream $ f $ fromSVar sv) (rstState st) stp sng yld
156 unStream (toStream $ f $ fromSVar sv) (rstState st) stp sng yld
@@ -145,7 +162,7 @@ applyWith f m = fromStream $ Stream $ \st stp sng yld -> do
145{-# INLINE runWith #-}
162{-# INLINE runWith #-}
146runWith :: (IsStream t, MonadAsync m) => (t m a -> m b) -> t m a -> m b
163runWith :: (IsStream t, MonadAsync m) => (t m a -> m b) -> t m a -> m b
147runWith f m = do
164runWith f m = do
148− sv <- newParallelVar
165+ sv <- newParallelVar defState
149 pushWorkerPar sv (runOne defState{streamVar = Just sv} $ toStream m)
166 pushWorkerPar sv (runOne defState{streamVar = Just sv} $ toStream m)
150 f $ fromSVar sv
167 f $ fromSVar sv