@@ -48,6 +48,10 @@ module Streamly.Core
49 , parallel
49 , parallel
53 , zipAsyncWith
57 , zipAsyncWith
@@ -66,18 +70,10 @@ module Streamly.Core
69−-- MVar diagnostics has some overhead - around 5% on asyncly null benchmark,
70−-- but keep it on for now to debug problems quickly if and when they happen.
73import Control.Concurrent (ThreadId, myThreadId, threadDelay)
73import Control.Concurrent (ThreadId, myThreadId, threadDelay)
74import Control.Concurrent.MVar (MVar, newEmptyMVar, tryTakeMVar,
74import Control.Concurrent.MVar (MVar, newEmptyMVar, tryTakeMVar,
75 tryPutMVar, takeMVar, putMVar)
75 tryPutMVar, takeMVar, putMVar)
76import Control.Exception (SomeException (..))
76import Control.Exception (SomeException (..))
78−import Control.Exception (catch,
79− BlockedIndefinitelyOnMVar(..))
81import qualified Control.Exception.Lifted as EL
77import qualified Control.Exception.Lifted as EL
82import Control.Monad (when)
78import Control.Monad (when)
83import Control.Monad.Catch (MonadThrow, throwM)
79import Control.Monad.Catch (MonadThrow, throwM)
@@ -105,6 +101,17 @@ import GHC.Exts
105import GHC.Conc (ThreadId(..))
101import GHC.Conc (ThreadId(..))
106import GHC.IO (IO(..))
102import GHC.IO (IO(..))
104+-- MVar diagnostics has some overhead - around 5% on asyncly null benchmark,
105+-- but keep it on for now to debug problems quickly if and when they happen.
109+import Control.Exception (catches, throwIO, Handler(..),
110+ BlockedIndefinitelyOnMVar(..),
111+ BlockedIndefinitelyOnSTM(..))
112+import System.IO (hPutStrLn, stderr)
108------------------------------------------------------------------------------
115------------------------------------------------------------------------------
109-- Parent child thread communication type
116-- Parent child thread communication type
110------------------------------------------------------------------------------
117------------------------------------------------------------------------------
@@ -193,41 +200,63 @@ data SVar m a =
193{-# NOINLINE dumpSVar #-}
200{-# NOINLINE dumpSVar #-}
194dumpSVar :: SVar m a -> IO String
201dumpSVar :: SVar m a -> IO String
195dumpSVar sv = do
202dumpSVar sv = do
196 (oqList, oqLen) <- readIORef $ outputQueue sv
204 (oqList, oqLen) <- readIORef $ outputQueue sv
197 db <- tryTakeMVar $ doorBell sv
205 db <- tryTakeMVar $ doorBell sv
198 srn <- tryTakeMVar $ siren sv
206 srn <- tryTakeMVar $ siren sv
208+ if svarStyle sv == AheadVar
199− (oheap, oheapSize) <- readIORef $ outputHeap sv
210+ (oheap, oheapSize) <- readIORef $ outputHeap sv
200− hsrn <- tryTakeMVar $ heapSiren sv
211+ hsrn <- tryTakeMVar $ heapSiren sv
201− (wq, wqSize) <- readIORef $ workQueue sv
212+ (wq, wqSize) <- readIORef $ workQueue sv
214+ [ "heap length computed = " ++ show (H.size oheap)
215+ , "heap length maintained = " ++ show oheapSize
216+ , "heap siren = " ++ show hsrn
217+ , "work queue length computed = " ++ show (length wq)
218+ , "work queue length maintained = " ++ show wqSize
202 waiting <- readIORef $ waitingForWork sv
222 waiting <- readIORef $ waitingForWork sv
203 rthread <- readIORef $ runningThreads sv
223 rthread <- readIORef $ runningThreads sv
204 workers <- readIORef $ activeWorkers sv
224 workers <- readIORef $ activeWorkers sv
205 -- XXX queueEmpty should be made IO return type
225 -- XXX queueEmpty should be made IO return type
207 return $ unlines
227 return $ unlines
228+ [ "tid = " ++ show tid
208− [ "style = " ++ show (svarStyle sv)
229+ , "style = " ++ show (svarStyle sv)
209 , "outputQueue length computed = " ++ show (length oqList)
230 , "outputQueue length computed = " ++ show (length oqList)
210 , "outputQueue length maintained = " ++ show oqLen
231 , "outputQueue length maintained = " ++ show oqLen
211 , "output doorBell = " ++ show db
232 , "output doorBell = " ++ show db
212 , "worker siren = " ++ show srn
233 , "worker siren = " ++ show srn
213− , "heap length computed = " ++ show (H.size oheap)
234+ ]
214− , "heap length maintained = " ++ show oheapSize
235+ ++ aheadDump ++ unlines
215− , "heap siren = " ++ show hsrn
216− , "work queue length computed = " ++ show (length wq)
217− , "work queue length maintained = " ++ show wqSize
218− , "waitingForWork = " ++ show waiting
236+ [ "waitingForWork = " ++ show waiting
219 , "running threads = " ++ show rthread
237 , "running threads = " ++ show rthread
220 , "running thread count = " ++ show workers
238 , "running thread count = " ++ show workers
223{-# NOINLINE mvarExcHandler #-}
241{-# NOINLINE mvarExcHandler #-}
224mvarExcHandler :: SVar m a -> String -> BlockedIndefinitelyOnMVar -> IO ()
242mvarExcHandler :: SVar m a -> String -> BlockedIndefinitelyOnMVar -> IO ()
225−mvarExcHandler sv label BlockedIndefinitelyOnMVar = do
243+mvarExcHandler sv label e@BlockedIndefinitelyOnMVar = do
226 svInfo <- dumpSVar sv
244 svInfo <- dumpSVar sv
227− error $ label ++ " " ++ "BlockedIndefinitelyOnMVar\n" ++ svInfo
245+ hPutStrLn stderr $ label ++ " " ++ "BlockedIndefinitelyOnMVar\n" ++ svInfo
248+{-# NOINLINE stmExcHandler #-}
249+stmExcHandler :: SVar m a -> String -> BlockedIndefinitelyOnSTM -> IO ()
250+stmExcHandler sv label e@BlockedIndefinitelyOnSTM = do
251+ svInfo <- dumpSVar sv
252+ hPutStrLn stderr $ label ++ " " ++ "BlockedIndefinitelyOnSTM\n" ++ svInfo
229withDBGMVar :: SVar m a -> String -> IO () -> IO ()
255withDBGMVar :: SVar m a -> String -> IO () -> IO ()
230−withDBGMVar sv label action = action `catch` mvarExcHandler sv label
256+withDBGMVar sv label action =
257+ action `catches` [ Handler (mvarExcHandler sv label)
258+ , Handler (stmExcHandler sv label)
232withDBGMVar :: SVar m a -> String -> IO () -> IO ()
261withDBGMVar :: SVar m a -> String -> IO () -> IO ()
233withDBGMVar _ _ action = action
262withDBGMVar _ _ action = action
@@ -759,7 +788,7 @@ delThread sv tid =
759-- If present then delete else add. This takes care of out of order add and
788-- If present then delete else add. This takes care of out of order add and
760-- delete i.e. a delete arriving before we even added a thread.
789-- delete i.e. a delete arriving before we even added a thread.
761-- This occurs when the forked thread is done even before the 'addThread' right
790-- This occurs when the forked thread is done even before the 'addThread' right
762−-- after the fork is executed.
791+-- after the fork gets a chance to run.
763{-# INLINE modifyThread #-}
792{-# INLINE modifyThread #-}
764modifyThread :: MonadIO m => SVar m a -> ThreadId -> m ()
793modifyThread :: MonadIO m => SVar m a -> ThreadId -> m ()
765modifyThread sv tid = do
794modifyThread sv tid = do
@@ -797,7 +826,10 @@ pushWorker sv = do
797-- using a CAS based modification.
826-- using a CAS based modification.
798{-# NOINLINE pushWorkerPar #-}
827{-# NOINLINE pushWorkerPar #-}
799pushWorkerPar :: MonadAsync m => SVar m a -> Stream m a -> m ()
828pushWorkerPar :: MonadAsync m => SVar m a -> Stream m a -> m ()
800−pushWorkerPar sv m =
829+pushWorkerPar sv m = do
830+ -- We do not use activeWorkers in case of ParallelVar but still there is no
831+ -- harm in maintaining it correctly.
832+ liftIO $ atomicModifyIORefCAS_ (activeWorkers sv) $ \n -> n + 1
801 doFork (runOne sv m) (handleChildException sv) >>= modifyThread sv
833 doFork (runOne sv m) (handleChildException sv) >>= modifyThread sv
803-- XXX When the queue is LIFO we can put a limit on the number of dispatches.
835-- XXX When the queue is LIFO we can put a limit on the number of dispatches.
@@ -1050,8 +1082,11 @@ newStreamVar1 style m = do
1050 -- Note: We must have all the work on the queue before sending the
1082 -- Note: We must have all the work on the queue before sending the
1051 -- pushworker, otherwise the pushworker may exit before we even get a
1083 -- pushworker, otherwise the pushworker may exit before we even get a
1052 -- chance to push.
1084 -- chance to push.
1085+ if style == ParallelVar
1086+ then pushWorkerPar sv m
1053− liftIO $ (enqueue sv) m
1088+ liftIO $ (enqueue sv) m
1054− pushWorker sv
1089+ pushWorker sv
1055 return sv
1090 return sv
1057-- | Create a new SVar and enqueue one stream computation on it.
1092-- | Create a new SVar and enqueue one stream computation on it.
@@ -1245,6 +1280,26 @@ _alt m1 m2 = Stream $ \_ stp sng yld ->
1245 let stop = runStream m2 Nothing stp sng yld
1280 let stop = runStream m2 Nothing stp sng yld
1246 in runStream m1 Nothing stop sng yld
1281 in runStream m1 Nothing stop sng yld
1283+------------------------------------------------------------------------------
1284+-- Stream to stream function application
1285+------------------------------------------------------------------------------
1287+applyWith :: MonadAsync m
1288+ => SVarStyle -> (Stream m a -> Stream m b) -> Stream m a -> Stream m b
1289+applyWith style f m = Stream $ \svr stp sng yld -> do
1290+ sv <- newStreamVar1 style m
1291+ runStream (f $ fromStreamVar sv) svr stp sng yld
1293+------------------------------------------------------------------------------
1294+-- Stream runner function application
1295+------------------------------------------------------------------------------
1297+runWith :: MonadAsync m
1298+ => SVarStyle -> (Stream m a -> m b) -> Stream m a -> m b
1299+runWith style f m = do
1300+ sv <- newStreamVar1 style m
1301+ f $ fromStreamVar sv
1248------------------------------------------------------------------------------
1303------------------------------------------------------------------------------
1249-- Zipping
1304-- Zipping
1250------------------------------------------------------------------------------
1305------------------------------------------------------------------------------
@@ -1261,10 +1316,6 @@ zipWith f m1 m2 = go m1 m2
1261 yield1 a ra = merge a ra
1316 yield1 a ra = merge a ra
1262 (runStream mx) Nothing stp single1 yield1
1317 (runStream mx) Nothing stp single1 yield1
1264−mkAsync :: MonadAsync m => Stream m a -> m (Stream m a)
1265−mkAsync m = newStreamVar1 AsyncVar m
1266− >>= return . fromStreamVar
1268zipAsyncWith :: MonadAsync m
1319zipAsyncWith :: MonadAsync m
1269 => (a -> b -> c) -> Stream m a -> Stream m b -> Stream m c
1320 => (a -> b -> c) -> Stream m a -> Stream m b -> Stream m c
1270zipAsyncWith f m1 m2 = Stream $ \_ stp sng yld -> do
1321zipAsyncWith f m1 m2 = Stream $ \_ stp sng yld -> do
@@ -1272,6 +1323,12 @@ zipAsyncWith f m1 m2 = Stream $ \_ stp sng yld -> do
1272 mb <- mkAsync m2
1323 mb <- mkAsync m2
1273 (runStream (zipWith f ma mb)) Nothing stp sng yld
1324 (runStream (zipWith f ma mb)) Nothing stp sng yld
1328+ mkAsync :: MonadAsync m => Stream m a -> m (Stream m a)
1329+ mkAsync m = newStreamVar1 AsyncVar m
1330+ >>= return . fromStreamVar
1275-------------------------------------------------------------------------------
1332-------------------------------------------------------------------------------
1276-- Transformers
1333-- Transformers
1277-------------------------------------------------------------------------------
1334-------------------------------------------------------------------------------