@@ -37,6 +37,7 @@ module Streamly.Internal.Data.Stream.Channel.Types
37 Count (..)
37 Count (..)
38 , Limit (..)
38 , Limit (..)
39 , ThreadAbort (..)
39 , ThreadAbort (..)
40 , ChildEvent (..)
41 , ChildEvent (..)
42 -- * Stats
43 -- * Stats
@@ -60,6 +61,7 @@ module Streamly.Internal.Data.Stream.Channel.Types
61 -- * Configuration
62 -- * Configuration
62 , Rate (..)
63 , Rate (..)
65 -- ** Default config
67 -- ** Default config
@@ -72,6 +74,7 @@ module Streamly.Internal.Data.Stream.Channel.Types
72 , maxYields
74 , maxYields
73 , inspectMode
75 , inspectMode
74 , eagerEval
76 , eagerEval
@@ -88,6 +91,7 @@ module Streamly.Internal.Data.Stream.Channel.Types
88 , getYieldLimit
91 , getYieldLimit
89 , getInspectMode
92 , getInspectMode
90 , getEagerDispatch
93 , getEagerDispatch
92 -- * Cleanup
96 -- * Cleanup
93 , cleanupSVar
97 , cleanupSVar
@@ -107,7 +111,7 @@ module Streamly.Internal.Data.Stream.Channel.Types
110−import Control.Concurrent (ThreadId, myThreadId, throwTo, MVar, tryReadMVar)
114+import Control.Concurrent (ThreadId, throwTo, MVar, tryReadMVar)
111import Control.Concurrent.MVar (tryPutMVar)
115import Control.Concurrent.MVar (tryPutMVar)
112import Control.Exception
116import Control.Exception
113 ( SomeException(..), Exception, catches, throwIO, Handler(..)
117 ( SomeException(..), Exception, catches, throwIO, Handler(..)
@@ -163,10 +167,19 @@ instance Ord Limit where
163-- Parent child thread communication type
167-- Parent child thread communication type
164------------------------------------------------------------------------------
168------------------------------------------------------------------------------
170+-- | Channel driver throws this exception to all active workers to clean up
166data ThreadAbort = ThreadAbort deriving Show
172data ThreadAbort = ThreadAbort deriving Show
168instance Exception ThreadAbort
174instance Exception ThreadAbort
176+-- | If any stream in the channel throws this exception, the channel stops
178+data ChannelStop = ChannelStop deriving Show
180+instance Exception ChannelStop
182+-- XXX Use a ChildSingle event to speed up mapM?
170-- | Events that a child thread may send to a parent thread.
183-- | Events that a child thread may send to a parent thread.
171data ChildEvent a =
184data ChildEvent a =
172 ChildYield a
185 ChildYield a
@@ -298,6 +311,14 @@ data Rate = Rate
298 , rateBuffer :: Int -- ^ Maximum slack from the goal
311 , rateBuffer :: Int -- ^ Maximum slack from the goal
314+-- | Specify when the 'Channel' should stop. Note that for ordered streams only
315+-- 'FirstStops' and 'AnyStop' would be the same, and usually only 'AllStop'
316+-- would make sense. This option is most useful for eager unordered streams.
318+ FirstStops -- ^ Stop when the first stream/action ends.
319+ | AllStop -- ^ Stop when all the streams end.
320+ | AnyStops -- ^ Stop when any one stream ends.
301-- XXX we can put the resettable fields in a oneShotConfig field and others in
322-- XXX we can put the resettable fields in a oneShotConfig field and others in
302-- a persistentConfig field. That way reset would be fast and scalable
323-- a persistentConfig field. That way reset would be fast and scalable
303-- irrespective of the number of fields.
324-- irrespective of the number of fields.
@@ -323,6 +344,7 @@ data Config = Config
323 , _maxStreamRate :: Maybe Rate
344 , _maxStreamRate :: Maybe Rate
324 , _inspectMode :: Bool
345 , _inspectMode :: Bool
325 , _eagerDispatch :: Bool
346 , _eagerDispatch :: Bool
347+ , _stopWhen :: StopWhen
328-------------------------------------------------------------------------------
350-------------------------------------------------------------------------------
@@ -354,6 +376,7 @@ defaultConfig = Config
354 , _inspectMode = False
376 , _inspectMode = False
355 -- XXX Set it to True when Rate is not set?
377 -- XXX Set it to True when Rate is not set?
356 , _eagerDispatch = False
378 , _eagerDispatch = False
379+ , _stopWhen = AllStop
359-------------------------------------------------------------------------------
382-------------------------------------------------------------------------------
@@ -463,6 +486,8 @@ setStreamLatency n st =
463getStreamLatency :: Config -> Maybe NanoSecond64
486getStreamLatency :: Config -> Maybe NanoSecond64
464getStreamLatency = _streamLatency
487getStreamLatency = _streamLatency
489+-- XXX Rename to "inspect"
466-- | Print debug information about the 'Channel' when the stream ends.
491-- | Print debug information about the 'Channel' when the stream ends.
468-- /Pre-release/
493-- /Pre-release/
@@ -473,6 +498,8 @@ inspectMode st = st { _inspectMode = True }
473getInspectMode :: Config -> Bool
498getInspectMode :: Config -> Bool
474getInspectMode = _inspectMode
499getInspectMode = _inspectMode
501+-- XXX rename to "eager"
476-- | By default the stream is evaluated on demand, new evaluation may be
503-- | By default the stream is evaluated on demand, new evaluation may be
477-- deferred until the consumer consumes the evaluated stream. When 'eagerEval'
504-- deferred until the consumer consumes the evaluated stream. When 'eagerEval'
478-- option is on the evaluation is aggressive and does not wait for consumption
505-- option is on the evaluation is aggressive and does not wait for consumption
@@ -487,6 +514,13 @@ eagerEval st = st { _eagerDispatch = True }
487getEagerDispatch :: Config -> Bool
514getEagerDispatch :: Config -> Bool
488getEagerDispatch = _eagerDispatch
515getEagerDispatch = _eagerDispatch
517+-- | Specify when the 'Channel' should stop.
518+stopWhen :: StopWhen -> Config -> Config
519+stopWhen cond st = st { _stopWhen = cond }
521+getStopWhen :: Config -> StopWhen
522+getStopWhen = _stopWhen
490-------------------------------------------------------------------------------
524-------------------------------------------------------------------------------
491-- Initialization
525-- Initialization
492-------------------------------------------------------------------------------
526-------------------------------------------------------------------------------
@@ -740,13 +774,14 @@ printSVar dump how = do
740-- Cleanup
774-- Cleanup
741-------------------------------------------------------------------------------
775-------------------------------------------------------------------------------
743−-- Can be called from a worker as well, avoids throwing to itself
777+-- | Never called from a worker thread.
744cleanupSVar :: IORef (Set ThreadId) -> IO ()
778cleanupSVar :: IORef (Set ThreadId) -> IO ()
745cleanupSVar workerSet = do
779cleanupSVar workerSet = do
746 workers <- readIORef workerSet
780 workers <- readIORef workerSet
747− self <- myThreadId
781+ -- self <- myThreadId
748 Prelude.mapM_ (`throwTo` ThreadAbort)
782 Prelude.mapM_ (`throwTo` ThreadAbort)
749− (Prelude.filter (/= self) $ Set.toList workers)
783+ -- (Prelude.filter (/= self) $ Set.toList workers)
784+ (Set.toList workers)
751-------------------------------------------------------------------------------
786-------------------------------------------------------------------------------
752-- Evaluator
787-- Evaluator