concurrency 1.1.1.0 → 1.1.2.0
raw patch · 15 files changed
+489/−23 lines, 15 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Control.Concurrent.Classy.Async: concurrently_ :: MonadConc m => m a -> m b -> m ()
+ Control.Concurrent.Classy.Async: forConcurrently_ :: (Foldable f, MonadConc m) => f a -> (a -> m b) -> m ()
+ Control.Concurrent.Classy.Async: instance (Control.Monad.Conc.Class.MonadConc m, Data.Semigroup.Semigroup a) => Data.Semigroup.Semigroup (Control.Concurrent.Classy.Async.Concurrently m a)
+ Control.Concurrent.Classy.Async: instance (Control.Monad.Conc.Class.MonadConc m, GHC.Base.Monoid a) => GHC.Base.Monoid (Control.Concurrent.Classy.Async.Concurrently m a)
+ Control.Concurrent.Classy.Async: mapConcurrently_ :: (Foldable f, MonadConc m) => (a -> m b) -> f a -> m ()
+ Control.Concurrent.Classy.Async: replicateConcurrently :: MonadConc m => Int -> m a -> m [a]
+ Control.Concurrent.Classy.Async: replicateConcurrently_ :: MonadConc m => Int -> m a -> m ()
+ Control.Concurrent.Classy.Async: uninterruptibleCancel :: MonadConc m => Async m a -> m ()
+ Control.Monad.Conc.Class: mask_ :: MonadMask m => m a -> m a
+ Control.Monad.Conc.Class: uninterruptibleMask_ :: MonadMask m => m a -> m a
Files
- Control/Concurrent/Classy/Async.hs +169/−21
- Control/Concurrent/Classy/CRef.hs +6/−0
- Control/Concurrent/Classy/Chan.hs +12/−0
- Control/Concurrent/Classy/MVar.hs +16/−0
- Control/Concurrent/Classy/QSem.hs +8/−0
- Control/Concurrent/Classy/QSemN.hs +8/−0
- Control/Concurrent/Classy/STM/TArray.hs +3/−0
- Control/Concurrent/Classy/STM/TBQueue.hs +20/−0
- Control/Concurrent/Classy/STM/TChan.hs +24/−0
- Control/Concurrent/Classy/STM/TMVar.hs +26/−0
- Control/Concurrent/Classy/STM/TQueue.hs +18/−0
- Control/Concurrent/Classy/STM/TVar.hs +8/−0
- Control/Monad/Conc/Class.hs +133/−0
- Control/Monad/STM/Class.hs +36/−0
- concurrency.cabal +2/−2
Control/Concurrent/Classy/Async.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE CPP #-}+{-# LANGUAGE CPP #-} {-# LANGUAGE RankNTypes #-} -- | This module is a version of the@@ -47,6 +47,7 @@ , poll, pollSTM , waitCatch, waitCatchSTM , cancel+ , uninterruptibleCancel , cancelWith , asyncThreadId @@ -69,9 +70,10 @@ -- * Convenient utilities , race , race_- , concurrently- , mapConcurrently- , forConcurrently+ , concurrently, concurrently_+ , mapConcurrently, mapConcurrently_+ , forConcurrently, forConcurrently_+ , replicateConcurrently, replicateConcurrently_ , Concurrently(..) ) where @@ -82,9 +84,11 @@ import Control.Monad.Catch (finally, try, onException) import Control.Monad.Conc.Class import Control.Monad.STM.Class--#if !MIN_VERSION_base(4,8,0)+import Data.Foldable (foldMap) import Data.Traversable++#if MIN_VERSION_base(4,9,0)+import Data.Semigroup (Semigroup(..)) #endif -----------------------------------------------------------------------------------------@@ -98,14 +102,18 @@ -- Note that, unlike the \"async\" package, 'Async' here does not have -- an 'Ord' instance. This is because 'MonadConc' 'ThreadId's do not -- necessarily have one.+--+-- @since 1.1.1.0 data Async m a = Async { asyncThreadId :: !(ThreadId m) , _asyncWait :: STM m (Either SomeException a) } +-- | @since 1.1.1.0 instance MonadConc m => Eq (Async m a) where Async t1 _ == Async t2 _ = t1 == t2 +-- | @since 1.1.1.0 instance MonadConc m => Functor (Async m) where fmap f (Async t w) = Async t $ fmap f <$> w @@ -124,40 +132,65 @@ -- > <$> Concurrently (getURL "url1") -- > <*> Concurrently (getURL "url2") -- > <*> Concurrently (getURL "url3")+--+-- @since 1.1.1.0 newtype Concurrently m a = Concurrently { runConcurrently :: m a } +-- | @since 1.1.1.0 instance MonadConc m => Functor (Concurrently m) where fmap f (Concurrently a) = Concurrently $ f <$> a +-- | @since 1.1.1.0 instance MonadConc m => Applicative (Concurrently m) where pure = Concurrently . return Concurrently fs <*> Concurrently as = Concurrently $ (\(f, a) -> f a) <$> concurrently fs as +-- | @since 1.1.1.0 instance MonadConc m => Alternative (Concurrently m) where empty = Concurrently $ forever yield Concurrently as <|> Concurrently bs = Concurrently $ either id id <$> race as bs +#if MIN_VERSION_base(4,9,0)+-- | Only defined for base >= 4.9.0.0+--+-- @since 1.1.2.0+instance (MonadConc m, Semigroup a) => Semigroup (Concurrently m a) where+ (<>) = liftA2 (<>)+#endif +-- | @since 1.1.2.0+instance (MonadConc m, Monoid a) => Monoid (Concurrently m a) where+ mempty = pure mempty+ mappend = liftA2 mappend+ ------------------------------------------------------------------------------- -- Spawning -- | Spawn an asynchronous action in a separate thread.+--+-- @since 1.1.1.0 async :: MonadConc m => m a -> m (Async m a) async = asyncUsing fork -- | Like 'async' but using 'forkOn' internally.+--+-- @since 1.1.1.0 asyncOn :: MonadConc m => Int -> m a -> m (Async m a) asyncOn = asyncUsing . forkOn -- | Like 'async' but using 'forkWithUnmask' internally.+--+-- @since 1.1.1.0 asyncWithUnmask :: MonadConc m => ((forall b. m b -> m b) -> m a) -> m (Async m a) asyncWithUnmask = asyncUnmaskUsing forkWithUnmask -- | Like 'asyncOn' but using 'forkOnWithUnmask' internally.+--+-- @since 1.1.1.0 asyncOnWithUnmask :: MonadConc m => Int -> ((forall b. m b -> m b) -> m a) -> m (Async m a) asyncOnWithUnmask i = asyncUnmaskUsing (forkOnWithUnmask i) @@ -180,27 +213,35 @@ -- | Spawn an asynchronous action in a separate thread, and pass its -- @Async@ handle to the supplied function. When the function returns--- or throws an exception, 'cancel' is called on the @Async@.+-- or throws an exception, 'uninterruptibleCancel' is called on the @Async@. ----- > withAsync action inner = bracket (async action) cancel inner+-- > withAsync action inner = bracket (async action) uninterruptiblCancel inner -- -- This is a useful variant of 'async' that ensures an @Async@ is -- never left running unintentionally. ----- Since 'cancel' may block, 'withAsync' may also block; see 'cancel'--- for details.+-- Since 'uninterruptibleCancel' may block, 'withAsync' may also+-- block; see 'uninterruptibleCancel' for details.+--+-- @since 1.1.1.0 withAsync :: MonadConc m => m a -> (Async m a -> m b) -> m b withAsync = withAsyncUsing fork -- | Like 'withAsync' but uses 'forkOn' internally.+--+-- @since 1.1.1.0 withAsyncOn :: MonadConc m => Int -> m a -> (Async m a -> m b) -> m b withAsyncOn = withAsyncUsing . forkOn -- | Like 'withAsync' bit uses 'forkWithUnmask' internally.+--+-- @since 1.1.1.0 withAsyncWithUnmask :: MonadConc m => ((forall x. m x -> m x) -> m a) -> (Async m a -> m b) -> m b withAsyncWithUnmask = withAsyncUnmaskUsing forkWithUnmask -- | Like 'withAsyncOn' bit uses 'forkOnWithUnmask' internally.+--+-- @since 1.1.1.0 withAsyncOnWithUnmask :: MonadConc m => Int -> ((forall x. m x -> m x) -> m a) -> (Async m a -> m b) -> m b withAsyncOnWithUnmask i = withAsyncUnmaskUsing (forkOnWithUnmask i) @@ -216,7 +257,7 @@ let a = Async tid (readTMVar var) - res <- inner a `catchAll` (\e -> cancel a >> throw e)+ res <- inner a `catchAll` (\e -> uninterruptibleCancel a >> throw e) cancel a return res@@ -230,7 +271,7 @@ let a = Async tid (readTMVar var) - res <- inner a `catchAll` (\e -> cancel a >> throw e)+ res <- inner a `catchAll` (\e -> uninterruptibleCancel a >> throw e) cancel a return res@@ -246,10 +287,14 @@ -- exception is re-thrown by 'wait'. -- -- > wait = atomically . waitSTM+--+-- @since 1.1.1.0 wait :: MonadConc m => Async m a -> m a wait = atomically . waitSTM -- | A version of 'wait' that can be used inside a @MonadSTM@ transaction.+--+-- @since 1.1.1.0 waitSTM :: MonadConc m => Async m a -> STM m a waitSTM a = do r <- waitCatchSTM a@@ -261,39 +306,59 @@ -- exception @x@, or @Right a@ if it returned a value @a@. -- -- > poll = atomically . pollSTM+--+-- @since 1.1.1.0 poll :: MonadConc m => Async m a -> m (Maybe (Either SomeException a)) poll = atomically . pollSTM -- | A version of 'poll' that can be used inside a @MonadSTM@ transaction.+--+-- @since 1.1.1.0 pollSTM :: MonadConc m => Async m a -> STM m (Maybe (Either SomeException a)) pollSTM (Async _ w) = (Just <$> w) `orElse` return Nothing -- | Wait for an asynchronous action to complete, and return either -- @Left e@ if the action raised an exception @e@, or @Right a@ if it -- returned a value @a@.+--+-- @since 1.1.1.0 waitCatch :: MonadConc m => Async m a -> m (Either SomeException a) waitCatch = tryAgain . atomically . waitCatchSTM where -- See: https://github.com/simonmar/async/issues/14 tryAgain f = f `catch` \BlockedIndefinitelyOnSTM -> f -- | A version of 'waitCatch' that can be used inside a @MonadSTM@ transaction.+--+-- @since 1.1.1.0 waitCatchSTM :: MonadConc m => Async m a -> STM m (Either SomeException a) waitCatchSTM (Async _ w) = w -- | Cancel an asynchronous action by throwing the @ThreadKilled@--- exception to it. Has no effect if the 'Async' has already--- completed.+-- exception to it, and waiting for the 'Async' thread to quit. Has no+-- effect if the 'Async' has already completed. ----- > cancel a = throwTo (asyncThreadId a) ThreadKilled+-- > cancel a = throwTo (asyncThreadId a) ThreadKilled <* waitCatch a ----- Note that 'cancel' is synchronous in the same sense as 'throwTo'.--- It does not return until the exception has been thrown in the--- target thread, or the target thread has completed. An asynchronous--- 'cancel' can of course be obtained by wrapping 'cancel' itself in--- 'async'.+-- Note that 'cancel' will not terminate until the thread the 'Async'+-- refers to has terminated. This means that 'cancel' will block for+-- as long as said thread blocks when receiving an asynchronous+-- exception.+--+-- An asynchronous 'cancel' can of course be obtained by wrapping+-- 'cancel' itself in 'async'.+--+-- @since 1.1.1.0 cancel :: MonadConc m => Async m a -> m ()-cancel (Async tid _) = throwTo tid ThreadKilled+cancel a@(Async tid _) = throwTo tid ThreadKilled <* waitCatch a +-- | Cancel an asynchronous action.+--+-- This is a variant of 'cancel' but it is not interruptible.+--+-- @since 1.1.2.0+uninterruptibleCancel :: MonadConc m => Async m a -> m ()+uninterruptibleCancel = uninterruptibleMask_ . cancel+ -- | Cancel an asynchronous action by throwing the supplied exception -- to it. --@@ -301,6 +366,8 @@ -- -- The notes about the synchronous nature of 'cancel' also apply to -- 'cancelWith'.+--+-- @since 1.1.1.0 cancelWith :: (MonadConc m, Exception e) => Async m a -> e -> m () cancelWith (Async tid _) = throwTo tid @@ -314,11 +381,15 @@ -- -- If multiple 'Async's complete or have completed, then the value -- returned corresponds to the first completed 'Async' in the list.+--+-- @since 1.1.1.0 waitAny :: MonadConc m => [Async m a] -> m (Async m a, a) waitAny = atomically . waitAnySTM -- | A version of 'waitAny' that can be used inside a @MonadSTM@ -- transaction.+--+-- @since 1.1.1.0 waitAnySTM :: MonadConc m => [Async m a] -> STM m (Async m a, a) waitAnySTM = foldr (orElse . (\a -> do r <- waitSTM a; return (a, r))) retry @@ -328,43 +399,59 @@ -- -- If multiple 'Async's complete or have completed, then the value -- returned corresponds to the first completed 'Async' in the list.+--+-- @since 1.1.1.0 waitAnyCatch :: MonadConc m => [Async m a] -> m (Async m a, Either SomeException a) waitAnyCatch = atomically . waitAnyCatchSTM -- | A version of 'waitAnyCatch' that can be used inside a @MonadSTM@ -- transaction.+--+-- @since 1.1.1.0 waitAnyCatchSTM :: MonadConc m => [Async m a] -> STM m (Async m a, Either SomeException a) waitAnyCatchSTM = foldr (orElse . (\a -> do r <- waitCatchSTM a; return (a, r))) retry -- | Like 'waitAny', but also cancels the other asynchronous -- operations as soon as one has completed.+--+-- @since 1.1.1.0 waitAnyCancel :: MonadConc m => [Async m a] -> m (Async m a, a) waitAnyCancel asyncs = waitAny asyncs `finally` mapM_ cancel asyncs -- | Like 'waitAnyCatch', but also cancels the other asynchronous -- operations as soon as one has completed.+--+-- @since 1.1.1.0 waitAnyCatchCancel :: MonadConc m => [Async m a] -> m (Async m a, Either SomeException a) waitAnyCatchCancel asyncs = waitAnyCatch asyncs `finally` mapM_ cancel asyncs -- | Wait for the first of two @Async@s to finish. If the @Async@ -- that finished first raised an exception, then the exception is -- re-thrown by 'waitEither'.+--+-- @since 1.1.1.0 waitEither :: MonadConc m => Async m a -> Async m b -> m (Either a b) waitEither left right = atomically $ waitEitherSTM left right -- | A version of 'waitEither' that can be used inside a @MonadSTM@ -- transaction.+--+-- @since 1.1.1.0 waitEitherSTM :: MonadConc m => Async m a -> Async m b -> STM m (Either a b) waitEitherSTM left right = (Left <$> waitSTM left) `orElse` (Right <$> waitSTM right) -- | Wait for the first of two @Async@s to finish.+--+-- @since 1.1.1.0 waitEitherCatch :: MonadConc m => Async m a -> Async m b -> m (Either (Either SomeException a) (Either SomeException b)) waitEitherCatch left right = atomically $ waitEitherCatchSTM left right -- | A version of 'waitEitherCatch' that can be used inside a -- @MonadSTM@ transaction.+--+-- @since 1.1.1.0 waitEitherCatchSTM :: MonadConc m => Async m a -> Async m b -> STM m (Either (Either SomeException a) (Either SomeException b)) waitEitherCatchSTM left right =@@ -372,34 +459,46 @@ -- | Like 'waitEither', but also 'cancel's both @Async@s before -- returning.+--+-- @since 1.1.1.0 waitEitherCancel :: MonadConc m => Async m a -> Async m b -> m (Either a b) waitEitherCancel left right = waitEither left right `finally` (cancel left >> cancel right) -- | Like 'waitEitherCatch', but also 'cancel's both @Async@s before -- returning.+--+-- @since 1.1.1.0 waitEitherCatchCancel :: MonadConc m => Async m a -> Async m b -> m (Either (Either SomeException a) (Either SomeException b)) waitEitherCatchCancel left right = waitEitherCatch left right `finally` (cancel left >> cancel right) -- | Like 'waitEither', but the result is ignored.+--+-- @since 1.1.1.0 waitEither_ :: MonadConc m => Async m a -> Async m b -> m () waitEither_ left right = atomically $ waitEitherSTM_ left right -- | A version of 'waitEither_' that can be used inside a @MonadSTM@ -- transaction.+--+-- @since 1.1.1.0 waitEitherSTM_:: MonadConc m => Async m a -> Async m b -> STM m () waitEitherSTM_ left right = void $ waitEitherSTM left right -- | Waits for both @Async@s to finish, but if either of them throws -- an exception before they have both finished, then the exception is -- re-thrown by 'waitBoth'.+--+-- @since 1.1.1.0 waitBoth :: MonadConc m => Async m a -> Async m b -> m (a, b) waitBoth left right = atomically $ waitBothSTM left right -- | A version of 'waitBoth' that can be used inside a @MonadSTM@ -- transaction.+--+-- @since 1.1.1.0 waitBothSTM :: MonadConc m => Async m a -> Async m b -> STM m (a, b) waitBothSTM left right = do a <- waitSTM left `orElse` (waitSTM right >> retry)@@ -414,6 +513,7 @@ -- @Async@ raises an exception, that exception will be re-thrown in -- the current thread. --+-- @since 1.1.1.0 link :: MonadConc m => Async m a -> m () link (Async _ w) = do me <- myThreadId@@ -425,6 +525,8 @@ -- | Link two @Async@s together, such that if either raises an -- exception, the same exception is re-thrown in the other @Async@.+--+-- @since 1.1.1.0 link2 :: MonadConc m => Async m a -> Async m b -> m () link2 left@(Async tl _) right@(Async tr _) = void $ forkRepeat $ do@@ -458,6 +560,7 @@ -- > withAsync right $ \b -> -- > waitEither a b --+-- @since 1.1.1.0 race :: MonadConc m => m a -> m b -> m (Either a b) race left right = concurrently' left right collect where collect m = do@@ -472,6 +575,8 @@ -- > withAsync left $ \a -> -- > withAsync right $ \b -> -- > waitEither_ a b+--+-- @since 1.1.1.0 race_ :: MonadConc m => m a -> m b -> m () race_ a b = void $ race a b @@ -484,6 +589,8 @@ -- > withAsync left $ \a -> -- > withAsync right $ \b -> -- > waitBoth a b+--+-- @since 1.1.1.0 concurrently :: MonadConc m => m a -> m b -> m (a, b) concurrently left right = concurrently' left right (collect []) where collect [Left a, Right b] _ = return (a, b)@@ -494,6 +601,18 @@ Left ex -> throw ex Right r -> collect (r:xs) m +-- | 'concurrently_' is 'concurrently' but ignores the return values.+--+-- @since 1.1.2.0+concurrently_ :: MonadConc m => m a -> m b -> m ()+concurrently_ left right = concurrently' left right (collect 0) where+ collect 2 _ = pure ()+ collect i m = do+ e <- takeMVar m+ case e of+ Left ex -> throw ex+ Right _ -> collect (i+1::Int) m+ -- Run two things concurrently. Faster than the 'Async' version. concurrently' :: MonadConc m => m a -> m b -> (MVar m (Either SomeException (Either a b)) -> m r)@@ -525,6 +644,7 @@ -- -- > pages <- mapConcurrently getURL ["url1", "url2", "url3"] --+-- @since 1.1.1.0 mapConcurrently :: (Traversable t, MonadConc m) => (a -> m b) -> t a -> m (t b) mapConcurrently f = runConcurrently . traverse (Concurrently . f) @@ -532,5 +652,33 @@ -- -- > pages <- forConcurrently ["url1", "url2", "url3"] $ \url -> getURL url --+-- @since 1.1.1.0 forConcurrently :: (Traversable t, MonadConc m) => t a -> (a -> m b)-> m (t b) forConcurrently = flip mapConcurrently++-- | 'mapConcurrently_' is 'mapConcurrently' with the return value+-- discarded, just like 'mapM_'.+--+-- @since 1.1.2.0+mapConcurrently_ :: (Foldable f, MonadConc m) => (a -> m b) -> f a -> m ()+mapConcurrently_ f = runConcurrently . foldMap (Concurrently . void . f)++-- | 'forConcurrently_' is 'forConcurrently' with the return value+-- discarded, just like 'forM_'.+--+-- @since 1.1.2.0+forConcurrently_ :: (Foldable f, MonadConc m) => f a -> (a -> m b) -> m ()+forConcurrently_ = flip mapConcurrently_++-- | Perform the action in the given number of threads.+--+-- @since 1.1.2.0+replicateConcurrently :: MonadConc m => Int -> m a -> m [a]+replicateConcurrently i = runConcurrently . sequenceA . replicate i . Concurrently++-- | 'replicateConcurrently_' is 'replicateConcurrently' with the+-- return values discarded.+--+-- @since 1.1.2.0+replicateConcurrently_ :: MonadConc m => Int -> m a -> m ()+replicateConcurrently_ i = void . replicateConcurrently i
Control/Concurrent/Classy/CRef.hs view
@@ -96,10 +96,14 @@ -- >readCRef ref >>= print -- -- To avoid this problem, use 'modifyCRef'' instead.+--+-- @since 1.0.0.0 modifyCRef :: MonadConc m => CRef m a -> (a -> a) -> m () modifyCRef ref f = readCRef ref >>= writeCRef ref . f -- | Strict version of 'modifyCRef'+--+-- @since 1.0.0.0 modifyCRef' :: MonadConc m => CRef m a -> (a -> a) -> m () modifyCRef' ref f = do x <- readCRef ref@@ -107,6 +111,8 @@ -- | Strict version of 'atomicModifyCRef'. This forces both the value -- stored in the @CRef@ as well as the value returned.+--+-- @since 1.0.0.0 atomicModifyCRef' :: MonadConc m => CRef m a -> (a -> (a,b)) -> m b atomicModifyCRef' ref f = do b <- atomicModifyCRef ref $ \a -> case f a of
Control/Concurrent/Classy/Chan.hs view
@@ -33,6 +33,8 @@ -- | 'Chan' is an abstract type representing an unbounded FIFO -- channel.+--+-- @since 1.0.0.0 data Chan m a = Chan (MVar m (Stream m a)) (MVar m (Stream m a)) -- Invariant: the Stream a is always an empty MVar@@ -42,6 +44,8 @@ data ChItem m a = ChItem a (Stream m a) -- | Build and returns a new instance of 'Chan'.+--+-- @since 1.0.0.0 newChan :: MonadConc m => m (Chan m a) newChan = do hole <- newEmptyMVar@@ -50,6 +54,8 @@ pure (Chan readVar writeVar) -- | Write a value to a 'Chan'.+--+-- @since 1.0.0.0 writeChan :: MonadConc m => Chan m a -> a -> m () writeChan (Chan _ writeVar) val = do new_hole <- newEmptyMVar@@ -59,6 +65,8 @@ putMVar writeVar new_hole -- | Read the next value from the 'Chan'.+--+-- @since 1.0.0.0 readChan :: MonadConc m => Chan m a -> m a readChan (Chan readVar _) = modifyMVarMasked readVar $ \read_end -> do (ChItem val new_read_end) <- readMVar read_end@@ -68,6 +76,8 @@ -- written to either channel from then on will be available from both. -- Hence this creates a kind of broadcast channel, where data written -- by anyone is seen by everyone else.+--+-- @since 1.0.0.0 dupChan :: MonadConc m => Chan m a -> m (Chan m a) dupChan (Chan _ writeVar) = do hole <- readMVar writeVar@@ -75,5 +85,7 @@ pure (Chan newReadVar writeVar) -- | Write an entire list of items to a 'Chan'.+--+-- @since 1.0.0.0 writeList2Chan :: MonadConc m => Chan m a -> [a] -> m () writeList2Chan = mapM_ . writeChan
Control/Concurrent/Classy/MVar.hs view
@@ -54,6 +54,8 @@ -- | Swap the contents of a @MVar@, and return the value taken. This -- function is atomic only if there are no other producers fro this -- @MVar@.+--+-- @since 1.0.0.0 swapMVar :: MonadConc m => MVar m a -> a -> m a swapMVar cvar a = mask_ $ do old <- takeMVar cvar@@ -61,6 +63,8 @@ return old -- | Check if a @MVar@ is empty.+--+-- @since 1.0.0.0 isEmptyMVar :: MonadConc m => MVar m a -> m Bool isEmptyMVar cvar = do val <- tryTakeMVar cvar@@ -72,6 +76,8 @@ -- finishing. This operation is exception-safe: it will replace the -- original contents of the @MVar@ if an exception is raised. However, -- it is only atomic if there are no other producers for this @MVar@.+--+-- @since 1.0.0.0 {-# INLINE withMVar #-} withMVar :: MonadConc m => MVar m a -> (a -> m b) -> m b withMVar cvar f = mask $ \restore -> do@@ -83,6 +89,8 @@ -- | Like 'withMVar', but the @IO@ action in the second argument is -- executed with asynchronous exceptions masked.+--+-- @since 1.0.0.0 {-# INLINE withMVarMasked #-} withMVarMasked :: MonadConc m => MVar m a -> (a -> m b) -> m b withMVarMasked cvar f = mask_ $ do@@ -97,12 +105,16 @@ -- the @MVar@ if an exception is raised during the operation. This -- function is only atomic if there are no other producers for this -- @MVar@.+--+-- @since 1.0.0.0 {-# INLINE modifyMVar_ #-} modifyMVar_ :: MonadConc m => MVar m a -> (a -> m a) -> m () modifyMVar_ cvar f = modifyMVar cvar $ fmap (\a -> (a,())) . f -- | A slight variation on 'modifyMVar_' that allows a value to be -- returned (@b@) in addition to the modified value of the @MVar@.+--+-- @since 1.0.0.0 {-# INLINE modifyMVar #-} modifyMVar :: MonadConc m => MVar m a -> (a -> m (a, b)) -> m b modifyMVar cvar f = mask $ \restore -> do@@ -113,12 +125,16 @@ -- | Like 'modifyMVar_', but the @IO@ action in the second argument is -- executed with asynchronous exceptions masked.+--+-- @since 1.0.0.0 {-# INLINE modifyMVarMasked_ #-} modifyMVarMasked_ :: MonadConc m => MVar m a -> (a -> m a) -> m () modifyMVarMasked_ cvar f = modifyMVarMasked cvar $ fmap (\a -> (a,())) . f -- | Like 'modifyMVar', but the @IO@ action in the second argument is -- executed with asynchronous exceptions masked.+--+-- @since 1.0.0.0 {-# INLINE modifyMVarMasked #-} modifyMVarMasked :: MonadConc m => MVar m a -> (a -> m (a, b)) -> m b modifyMVarMasked cvar f = mask_ $ do
Control/Concurrent/Classy/QSem.hs view
@@ -27,19 +27,27 @@ -- > bracket_ qaitQSem signalSSem (...) -- -- is safe; it never loses a unit of the resource.+--+-- @since 1.0.0.0 newtype QSem m = QSem (QSemN m) -- | Build a new 'QSem' with a supplied initial quantity. The initial -- quantity must be at least 0.+--+-- @since 1.0.0.0 newQSem :: MonadConc m => Int -> m (QSem m) newQSem initial | initial < 0 = fail "newQSem: Initial quantity mus tbe non-negative." | otherwise = QSem <$> newQSemN initial -- | Wait for a unit to become available.+--+-- @since 1.0.0.0 waitQSem :: MonadConc m => QSem m -> m () waitQSem (QSem qSemN) = waitQSemN qSemN 1 -- | Signal that a unit of the 'QSem' is available.+--+-- @since 1.0.0.0 signalQSem :: MonadConc m => QSem m -> m () signalQSem (QSem qSemN) = signalQSemN qSemN 1
Control/Concurrent/Classy/QSemN.hs view
@@ -30,16 +30,22 @@ -- > bracket_ (waitQSemN n) (signalQSemN n) (...) -- -- is safe; it never loses any of the resource.+--+-- @since 1.0.0.0 newtype QSemN m = QSemN (MVar m (Int, [(Int, MVar m ())], [(Int, MVar m ())])) -- | Build a new 'QSemN' with a supplied initial quantity. -- The initial quantity must be at least 0.+--+-- @since 1.0.0.0 newQSemN :: MonadConc m => Int -> m (QSemN m) newQSemN initial | initial < 0 = fail "newQSemN: Initial quantity must be non-negative" | otherwise = QSemN <$> newMVar (initial, [], []) -- | Wait for the specified quantity to become available+--+-- @since 1.0.0.0 waitQSemN :: MonadConc m => QSemN m -> Int -> m () waitQSemN (QSemN m) sz = mask_ $ do (quantity, b1, b2) <- takeMVar m@@ -64,6 +70,8 @@ putMVar m r') -- | Signal that a given quantity is now available from the 'QSemN'.+--+-- @since 1.0.0.0 signalQSemN :: MonadConc m => QSemN m -> Int -> m () signalQSemN (QSemN m) sz = uninterruptibleMask_ $ do r <- takeMVar m
Control/Concurrent/Classy/STM/TArray.hs view
@@ -28,8 +28,11 @@ -- It is currently implemented as @Array ix (TVar stm e)@, but it may -- be replaced by a more efficient implementation in the future (the -- interface will remain the same, however).+--+-- @since 1.0.0.0 newtype TArray stm i e = TArray (Array i (TVar stm e)) +-- | @since 1.0.0.0 instance MonadSTM stm => MArray (TArray stm) e stm where getBounds (TArray a) = pure (bounds a)
Control/Concurrent/Classy/STM/TBQueue.hs view
@@ -37,6 +37,8 @@ -- | 'TBQueue' is an abstract type representing a bounded FIFO -- channel.+--+-- @since 1.0.0.0 data TBQueue stm a = TBQueue (TVar stm Int) (TVar stm [a])@@ -44,6 +46,8 @@ (TVar stm [a]) -- | Build and returns a new instance of 'TBQueue'+--+-- @since 1.0.0.0 newTBQueue :: MonadSTM stm => Int -- ^ maximum number of elements the queue can hold -> stm (TBQueue stm a)@@ -55,6 +59,8 @@ pure (TBQueue rsize readT wsize writeT) -- | Write a value to a 'TBQueue'; retries if the queue is full.+--+-- @since 1.0.0.0 writeTBQueue :: MonadSTM stm => TBQueue stm a -> a -> stm () writeTBQueue (TBQueue rsize _ wsize writeT) a = do w <- readTVar wsize@@ -71,6 +77,8 @@ writeTVar writeT (a:listend) -- | Read the next value from the 'TBQueue'.+--+-- @since 1.0.0.0 readTBQueue :: MonadSTM stm => TBQueue stm a -> stm a readTBQueue (TBQueue rsize readT _ writeT) = do xs <- readTVar readT@@ -92,11 +100,15 @@ -- | A version of 'readTBQueue' which does not retry. Instead it -- returns @Nothing@ if no value is available.+--+-- @since 1.0.0.0 tryReadTBQueue :: MonadSTM stm => TBQueue stm a -> stm (Maybe a) tryReadTBQueue c = (Just <$> readTBQueue c) `orElse` pure Nothing -- | Get the next value from the @TBQueue@ without removing it, -- retrying if the channel is empty.+--+-- @since 1.0.0.0 peekTBQueue :: MonadSTM stm => TBQueue stm a -> stm a peekTBQueue c = do x <- readTBQueue c@@ -105,6 +117,8 @@ -- | A version of 'peekTBQueue' which does not retry. Instead it -- returns @Nothing@ if no value is available.+--+-- @since 1.0.0.0 tryPeekTBQueue :: MonadSTM stm => TBQueue stm a -> stm (Maybe a) tryPeekTBQueue c = do m <- tryReadTBQueue c@@ -116,6 +130,8 @@ -- | Put a data item back onto a channel, where it will be the next item read. -- Retries if the queue is full.+--+-- @since 1.0.0.0 unGetTBQueue :: MonadSTM stm => TBQueue stm a -> a -> stm () unGetTBQueue (TBQueue rsize readT wsize _) a = do r <- readTVar rsize@@ -130,6 +146,8 @@ writeTVar readT (a:xs) -- | Returns 'True' if the supplied 'TBQueue' is empty.+--+-- @since 1.0.0.0 isEmptyTBQueue :: MonadSTM stm => TBQueue stm a -> stm Bool isEmptyTBQueue (TBQueue _ readT _ writeT) = do xs <- readTVar readT@@ -138,6 +156,8 @@ [] -> null <$> readTVar writeT -- | Returns 'True' if the supplied 'TBQueue' is full.+--+-- @since 1.0.0.0 isFullTBQueue :: MonadSTM stm => TBQueue stm a -> stm Bool isFullTBQueue (TBQueue rsize _ wsize _) = do w <- readTVar wsize
Control/Concurrent/Classy/STM/TChan.hs view
@@ -36,6 +36,8 @@ -- | 'TChan' is an abstract type representing an unbounded FIFO -- channel.+--+-- @since 1.0.0.0 data TChan stm a = TChan (TVar stm (TVarList stm a)) (TVar stm (TVarList stm a)) @@ -43,6 +45,8 @@ data TList stm a = TNil | TCons a (TVarList stm a) -- |Build and return a new instance of 'TChan'+--+-- @since 1.0.0.0 newTChan :: MonadSTM stm => stm (TChan stm a) newTChan = do hole <- newTVar TNil@@ -53,6 +57,8 @@ -- | Create a write-only 'TChan'. More precisely, 'readTChan' will 'retry' -- even after items have been written to the channel. The only way to -- read a broadcast channel is to duplicate it with 'dupTChan'.+--+-- @since 1.0.0.0 newBroadcastTChan :: MonadSTM stm => stm (TChan stm a) newBroadcastTChan = do hole <- newTVar TNil@@ -61,6 +67,8 @@ pure (TChan readT writeT) -- | Write a value to a 'TChan'.+--+-- @since 1.0.0.0 writeTChan :: MonadSTM stm => TChan stm a -> a -> stm () writeTChan (TChan _ writeT) a = do listend <- readTVar writeT@@ -69,11 +77,15 @@ writeTVar writeT listend' -- | Read the next value from the 'TChan'.+--+-- @since 1.0.0.0 readTChan :: MonadSTM stm => TChan stm a -> stm a readTChan tchan = tryReadTChan tchan >>= maybe retry pure -- | A version of 'readTChan' which does not retry. Instead it -- returns @Nothing@ if no value is available.+--+-- @since 1.0.0.0 tryReadTChan :: MonadSTM stm => TChan stm a -> stm (Maybe a) tryReadTChan (TChan readT _) = do listhead <- readTVar readT@@ -86,11 +98,15 @@ -- | Get the next value from the 'TChan' without removing it, -- retrying if the channel is empty.+--+-- @since 1.0.0.0 peekTChan :: MonadSTM stm => TChan stm a -> stm a peekTChan tchan = tryPeekTChan tchan >>= maybe retry pure -- | A version of 'peekTChan' which does not retry. Instead it -- returns @Nothing@ if no value is available.+--+-- @since 1.0.0.0 tryPeekTChan :: MonadSTM stm => TChan stm a -> stm (Maybe a) tryPeekTChan (TChan readT _) = do listhead <- readTVar readT@@ -103,6 +119,8 @@ -- either channel from then on will be available from both. Hence -- this creates a kind of broadcast channel, where data written by -- anyone is seen by everyone else.+--+-- @since 1.0.0.0 dupTChan :: MonadSTM stm => TChan stm a -> stm (TChan stm a) dupTChan (TChan _ writeT) = do hole <- readTVar writeT@@ -111,6 +129,8 @@ -- | Put a data item back onto a channel, where it will be the next -- item read.+--+-- @since 1.0.0.0 unGetTChan :: MonadSTM stm => TChan stm a -> a -> stm () unGetTChan (TChan readT _) a = do listhead <- readTVar readT@@ -118,6 +138,8 @@ writeTVar readT head' -- | Returns 'True' if the supplied 'TChan' is empty.+--+-- @since 1.0.0.0 isEmptyTChan :: MonadSTM stm => TChan stm a -> stm Bool isEmptyTChan (TChan readT _) = do listhead <- readTVar readT@@ -128,6 +150,8 @@ -- | Clone a 'TChan': similar to 'dupTChan', but the cloned channel starts with the -- same content available as the original channel.+--+-- @since 1.0.0.0 cloneTChan :: MonadSTM stm => TChan stm a -> stm (TChan stm a) cloneTChan (TChan readT writeT) = do readpos <- readTVar readT
Control/Concurrent/Classy/STM/TMVar.hs view
@@ -36,9 +36,13 @@ -- | A @TMVar@ is like an @MVar@ or a @mVar@, but using transactional -- memory. As transactions are atomic, this makes dealing with -- multiple @TMVar@s easier than wrangling multiple @mVar@s.+--+-- @since 1.0.0.0 newtype TMVar stm a = TMVar (TVar stm (Maybe a)) -- | Create a 'TMVar' containing the given value.+--+-- @since 1.0.0.0 newTMVar :: MonadSTM stm => a -> stm (TMVar stm a) newTMVar = newTMVarN "" @@ -47,6 +51,8 @@ -- -- Name conflicts are handled as usual for 'TVar's. The name is -- prefixed with \"ctmvar-\".+--+-- @since 1.0.0.0 newTMVarN :: MonadSTM stm => String -> a -> stm (TMVar stm a) newTMVarN n a = do let n' = if null n then "ctmvar" else "ctmvar-" ++ n@@ -54,6 +60,8 @@ return $ TMVar ctvar -- | Create a new empty 'TMVar'.+--+-- @since 1.0.0.0 newEmptyTMVar :: MonadSTM stm => stm (TMVar stm a) newEmptyTMVar = newEmptyTMVarN "" @@ -61,6 +69,8 @@ -- -- Name conflicts are handled as usual for 'TVar's. The name is -- prefixed with \"ctmvar-\".+--+-- @since 1.0.0.0 newEmptyTMVarN :: MonadSTM stm => String -> stm (TMVar stm a) newEmptyTMVarN n = do let n' = if null n then "ctmvar" else "ctmvar-" ++ n@@ -68,18 +78,24 @@ return $ TMVar ctvar -- | Take the contents of a 'TMVar', or 'retry' if it is empty.+--+-- @since 1.0.0.0 takeTMVar :: MonadSTM stm => TMVar stm a -> stm a takeTMVar ctmvar = do taken <- tryTakeTMVar ctmvar maybe retry return taken -- | Write to a 'TMVar', or 'retry' if it is full.+--+-- @since 1.0.0.0 putTMVar :: MonadSTM stm => TMVar stm a -> a -> stm () putTMVar ctmvar a = do putted <- tryPutTMVar ctmvar a unless putted retry -- | Read from a 'TMVar' without emptying, or 'retry' if it is empty.+--+-- @since 1.0.0.0 readTMVar :: MonadSTM stm => TMVar stm a -> stm a readTMVar ctmvar = do readed <- tryReadTMVar ctmvar@@ -87,6 +103,8 @@ -- | Try to take the contents of a 'TMVar', returning 'Nothing' if it -- is empty.+--+-- @since 1.0.0.0 tryTakeTMVar :: MonadSTM stm => TMVar stm a -> stm (Maybe a) tryTakeTMVar (TMVar ctvar) = do val <- readTVar ctvar@@ -94,6 +112,8 @@ return val -- | Try to write to a 'TMVar', returning 'False' if it is full.+--+-- @since 1.0.0.0 tryPutTMVar :: MonadSTM stm => TMVar stm a -> a -> stm Bool tryPutTMVar (TMVar ctvar) a = do val <- readTVar ctvar@@ -102,15 +122,21 @@ -- | Try to read from a 'TMVar' without emptying, returning 'Nothing' -- if it is empty.+--+-- @since 1.0.0.0 tryReadTMVar :: MonadSTM stm => TMVar stm a -> stm (Maybe a) tryReadTMVar (TMVar ctvar) = readTVar ctvar -- | Check if a 'TMVar' is empty or not.+--+-- @since 1.0.0.0 isEmptyTMVar :: MonadSTM stm => TMVar stm a -> stm Bool isEmptyTMVar ctmvar = isNothing `liftM` tryReadTMVar ctmvar -- | Swap the contents of a 'TMVar' returning the old contents, or -- 'retry' if it is empty.+--+-- @since 1.0.0.0 swapTMVar :: MonadSTM stm => TMVar stm a -> a -> stm a swapTMVar ctmvar a = do val <- takeTMVar ctmvar
Control/Concurrent/Classy/STM/TQueue.hs view
@@ -39,10 +39,14 @@ import Control.Monad.STM.Class -- | 'TQueue' is an abstract type representing an unbounded FIFO channel.+--+-- @since 1.0.0.0 data TQueue stm a = TQueue (TVar stm [a]) (TVar stm [a]) -- | Build and returns a new instance of 'TQueue'+--+-- @since 1.0.0.0 newTQueue :: MonadSTM stm => stm (TQueue stm a) newTQueue = do readT <- newTVar []@@ -50,12 +54,16 @@ pure (TQueue readT writeT) -- | Write a value to a 'TQueue'.+--+-- @since 1.0.0.0 writeTQueue :: MonadSTM stm => TQueue stm a -> a -> stm () writeTQueue (TQueue _ writeT) a = do listend <- readTVar writeT writeTVar writeT (a:listend) -- | Read the next value from the 'TQueue'.+--+-- @since 1.0.0.0 readTQueue :: MonadSTM stm => TQueue stm a -> stm a readTQueue (TQueue readT writeT) = do xs <- readTVar readT@@ -76,11 +84,15 @@ -- | A version of 'readTQueue' which does not retry. Instead it -- returns @Nothing@ if no value is available.+--+-- @since 1.0.0.0 tryReadTQueue :: MonadSTM stm => TQueue stm a -> stm (Maybe a) tryReadTQueue c = (Just <$> readTQueue c) `orElse` pure Nothing -- | Get the next value from the @TQueue@ without removing it, -- retrying if the channel is empty.+--+-- @since 1.0.0.0 peekTQueue :: MonadSTM stm => TQueue stm a -> stm a peekTQueue c = do x <- readTQueue c@@ -89,6 +101,8 @@ -- | A version of 'peekTQueue' which does not retry. Instead it -- returns @Nothing@ if no value is available.+--+-- @since 1.0.0.0 tryPeekTQueue :: MonadSTM stm => TQueue stm a -> stm (Maybe a) tryPeekTQueue c = do m <- tryReadTQueue c@@ -99,12 +113,16 @@ pure m -- |Put a data item back onto a channel, where it will be the next item read.+--+-- @since 1.0.0.0 unGetTQueue :: MonadSTM stm => TQueue stm a -> a -> stm () unGetTQueue (TQueue readT _) a = do xs <- readTVar readT writeTVar readT (a:xs) -- |Returns 'True' if the supplied 'TQueue' is empty.+--+-- @since 1.0.0.0 isEmptyTQueue :: MonadSTM stm => TQueue stm a -> stm Bool isEmptyTQueue (TQueue readT writeT) = do xs <- readTVar readT
Control/Concurrent/Classy/STM/TVar.hs view
@@ -32,18 +32,24 @@ -- * @TVar@s -- | Mutate the contents of a 'TVar'. This is non-strict.+--+-- @since 1.0.0.0 modifyTVar :: MonadSTM stm => TVar stm a -> (a -> a) -> stm () modifyTVar ctvar f = do a <- readTVar ctvar writeTVar ctvar $ f a -- | Mutate the contents of a 'TVar' strictly.+--+-- @since 1.0.0.0 modifyTVar' :: MonadSTM stm => TVar stm a -> (a -> a) -> stm () modifyTVar' ctvar f = do a <- readTVar ctvar writeTVar ctvar $! f a -- | Swap the contents of a 'TVar', returning the old value.+--+-- @since 1.0.0.0 swapTVar :: MonadSTM stm => TVar stm a -> a -> stm a swapTVar ctvar a = do old <- readTVar ctvar@@ -53,6 +59,8 @@ -- | Set the value of returned 'TVar' to @True@ after a given number -- of microseconds. The caveats associated with 'threadDelay' also -- apply.+--+-- @since 1.0.0.0 registerDelay :: MonadConc m => Int -> m (TVar (STM m) Bool) registerDelay delay = do var <- atomically (newTVar False)
Control/Monad/Conc/Class.hs view
@@ -50,7 +50,9 @@ , throw , catch , mask+ , Ca.mask_ , uninterruptibleMask+ , Ca.uninterruptibleMask_ -- * Mutable State , newMVar@@ -98,6 +100,8 @@ -- -- Every @MonadConc@ has an associated 'MonadSTM', transactions of -- which can be run atomically.+--+-- @since 1.0.0.0 class ( Applicative m, Monad m , MonadCatch m, MonadThrow m, MonadMask m , MonadSTM (STM m)@@ -129,31 +133,43 @@ #-} -- | The associated 'MonadSTM' for this class.+ --+ -- @since 1.0.0.0 type STM m :: * -> * -- | The mutable reference type, like 'MVar's. This may contain one -- value at a time, attempting to read or take from an \"empty\" -- @MVar@ will block until it is full, and attempting to put to a -- \"full\" @MVar@ will block until it is empty.+ --+ -- @since 1.0.0.0 type MVar m :: * -> * -- | The mutable non-blocking reference type. These may suffer from -- relaxed memory effects if functions outside the set @newCRef@, -- @readCRef@, @atomicModifyCRef@, and @atomicWriteCRef@ are used.+ --+ -- @since 1.0.0.0 type CRef m :: * -> * -- | When performing compare-and-swap operations on @CRef@s, a -- @Ticket@ is a proof that a thread observed a specific previous -- value.+ --+ -- @since 1.0.0.0 type Ticket m :: * -> * -- | An abstract handle to a thread.+ --+ -- @since 1.0.0.0 type ThreadId m :: * -- | Fork a computation to happen concurrently. Communication may -- happen over @MVar@s. -- -- > fork ma = forkWithUnmask (\_ -> ma)+ --+ -- @since 1.0.0.0 fork :: m () -> m (ThreadId m) fork ma = forkWithUnmask (\_ -> ma) @@ -162,6 +178,8 @@ -- not be used within a 'mask' or 'uninterruptibleMask'. -- -- > forkWithUnmask = forkWithUnmaskN ""+ --+ -- @since 1.0.0.0 forkWithUnmask :: ((forall a. m a -> m a) -> m ()) -> m (ThreadId m) forkWithUnmask = forkWithUnmaskN "" @@ -173,6 +191,8 @@ -- numeric suffix, counting up from 1. -- -- > forkWithUnmaskN _ = forkWithUnmask+ --+ -- @since 1.0.0.0 forkWithUnmaskN :: String -> ((forall a. m a -> m a) -> m ()) -> m (ThreadId m) forkWithUnmaskN _ = forkWithUnmask @@ -183,6 +203,8 @@ -- total number of capabilities as returned by 'getNumCapabilities'. -- -- > forkOn c ma = forkOnWithUnmask c (\_ -> ma)+ --+ -- @since 1.0.0.0 forkOn :: Int -> m () -> m (ThreadId m) forkOn c ma = forkOnWithUnmask c (\_ -> ma) @@ -190,6 +212,8 @@ -- given CPU, as with 'forkOn'. -- -- > forkOnWithUnmask = forkOnWithUnmaskN ""+ --+ -- @since 1.0.0.0 forkOnWithUnmask :: Int -> ((forall a. m a -> m a) -> m ()) -> m (ThreadId m) forkOnWithUnmask = forkOnWithUnmaskN "" @@ -197,20 +221,30 @@ -- given CPU, as with 'forkOn'. -- -- > forkOnWithUnmaskN _ = forkOnWithUnmask+ --+ -- @since 1.0.0.0 forkOnWithUnmaskN :: String -> Int -> ((forall a. m a -> m a) -> m ()) -> m (ThreadId m) forkOnWithUnmaskN _ = forkOnWithUnmask -- | Get the number of Haskell threads that can run simultaneously.+ --+ -- @since 1.0.0.0 getNumCapabilities :: m Int -- | Set the number of Haskell threads that can run simultaneously.+ --+ -- @since 1.0.0.0 setNumCapabilities :: Int -> m () -- | Get the @ThreadId@ of the current thread.+ --+ -- @since 1.0.0.0 myThreadId :: m (ThreadId m) -- | Allows a context-switch to any other currently runnable thread -- (if any).+ --+ -- @since 1.0.0.0 yield :: m () -- | Yields the current thread, and optionally suspends the current@@ -221,12 +255,16 @@ -- will never continue to run earlier than specified. -- -- > threadDelay _ = yield+ --+ -- @since 1.0.0.0 threadDelay :: Int -> m () threadDelay _ = yield -- | Create a new empty @MVar@. -- -- > newEmptyMVar = newEmptyMVarN ""+ --+ -- @since 1.0.0.0 newEmptyMVar :: m (MVar m a) newEmptyMVar = newEmptyMVarN "" @@ -238,43 +276,59 @@ -- numeric suffix, counting up from 1. -- -- > newEmptyMVarN _ = newEmptyMVar+ --+ -- @since 1.0.0.0 newEmptyMVarN :: String -> m (MVar m a) newEmptyMVarN _ = newEmptyMVar -- | Put a value into a @MVar@. If there is already a value there, -- this will block until that value has been taken, at which point -- the value will be stored.+ --+ -- @since 1.0.0.0 putMVar :: MVar m a -> a -> m () -- | Attempt to put a value in a @MVar@ non-blockingly, returning -- 'True' (and filling the @MVar@) if there was nothing there, -- otherwise returning 'False'.+ --+ -- @since 1.0.0.0 tryPutMVar :: MVar m a -> a -> m Bool -- | Block until a value is present in the @MVar@, and then return -- it. This does not \"remove\" the value, multiple reads are -- possible.+ --+ -- @since 1.0.0.0 readMVar :: MVar m a -> m a -- | Attempt to read a value from a @MVar@ non-blockingly, returning -- a 'Just' (and emptying the @MVar@) if there is something there, -- otherwise returning 'Nothing'. As with 'readMVar', this does not -- \"remove\" the value.+ --+ -- @since 1.1.0.0 tryReadMVar :: MVar m a -> m (Maybe a) -- | Take a value from a @MVar@. This \"empties\" the @MVar@, -- allowing a new value to be put in. This will block if there is no -- value in the @MVar@ already, until one has been put.+ --+ -- @since 1.0.0.0 takeMVar :: MVar m a -> m a -- | Attempt to take a value from a @MVar@ non-blockingly, returning -- a 'Just' (and emptying the @MVar@) if there was something there, -- otherwise returning 'Nothing'.+ --+ -- @since 1.0.0.0 tryTakeMVar :: MVar m a -> m (Maybe a) -- | Create a new reference. -- -- > newCRef = newCRefN ""+ --+ -- @since 1.0.0.0 newCRef :: a -> m (CRef m a) newCRef = newCRefN "" @@ -286,37 +340,51 @@ -- numeric suffix, counting up from 1. -- -- > newCRefN _ = newCRef+ --+ -- @since 1.0.0.0 newCRefN :: String -> a -> m (CRef m a) newCRefN _ = newCRef -- | Read the current value stored in a reference. -- -- > readCRef cref = readForCAS cref >>= peekTicket+ --+ -- @since 1.0.0.0 readCRef :: CRef m a -> m a readCRef cref = readForCAS cref >>= peekTicket -- | Atomically modify the value stored in a reference. This imposes -- a full memory barrier.+ --+ -- @since 1.0.0.0 atomicModifyCRef :: CRef m a -> (a -> (a, b)) -> m b -- | Write a new value into an @CRef@, without imposing a memory -- barrier. This means that relaxed memory effects can be observed.+ --+ -- @since 1.0.0.0 writeCRef :: CRef m a -> a -> m () -- | Replace the value stored in a reference, with the -- barrier-to-reordering property that 'atomicModifyCRef' has. -- -- > atomicWriteCRef r a = atomicModifyCRef r $ const (a, ())+ --+ -- @since 1.0.0.0 atomicWriteCRef :: CRef m a -> a -> m () atomicWriteCRef r a = atomicModifyCRef r $ const (a, ()) -- | Read the current value stored in a reference, returning a -- @Ticket@, for use in future compare-and-swap operations.+ --+ -- @since 1.0.0.0 readForCAS :: CRef m a -> m (Ticket m a) -- | Extract the actual Haskell value from a @Ticket@. -- -- The @proxy m@ is to determine the @m@ in the @Ticket@ type.+ --+ -- @since 1.0.0.0 peekTicket' :: proxy m -> Ticket m a -> a -- | Perform a machine-level compare-and-swap (CAS) operation on a@@ -324,32 +392,44 @@ -- most current value in the @CRef@. -- -- This is strict in the \"new\" value argument.+ --+ -- @since 1.0.0.0 casCRef :: CRef m a -> Ticket m a -> a -> m (Bool, Ticket m a) -- | A replacement for 'atomicModifyCRef' using a compare-and-swap. -- -- This is strict in the \"new\" value argument.+ --+ -- @since 1.0.0.0 modifyCRefCAS :: CRef m a -> (a -> (a, b)) -> m b -- | A variant of 'modifyCRefCAS' which doesn't return a result. -- -- > modifyCRefCAS_ cref f = modifyCRefCAS cref (\a -> (f a, ()))+ --+ -- @since 1.0.0.0 modifyCRefCAS_ :: CRef m a -> (a -> a) -> m () modifyCRefCAS_ cref f = modifyCRefCAS cref (\a -> (f a, ())) -- | Perform an STM transaction atomically.+ --+ -- @since 1.0.0.0 atomically :: STM m a -> m a -- | Read the current value stored in a @TVar@. This may be -- implemented differently for speed. -- -- > readTVarConc = atomically . readTVar+ --+ -- @since 1.0.0.0 readTVarConc :: TVar (STM m) a -> m a readTVarConc = atomically . readTVar -- | Throw an exception to the target thread. This blocks until the -- exception is delivered, and it is just as if the target thread -- had raised it with 'throw'. This can interrupt a blocked action.+ --+ -- @since 1.0.0.0 throwTo :: Exception e => ThreadId m -> e -> m () -------------------------------------------------------------------------------@@ -359,6 +439,8 @@ -- | Create a concurrent computation for the provided action, and -- return a @MVar@ which can be used to query the result.+--+-- @since 1.0.0.0 spawn :: MonadConc m => m a -> m (MVar m a) spawn ma = do cvar <- newEmptyMVar@@ -371,6 +453,8 @@ -- -- This function is useful for informing the parent when a child -- terminates, for example.+--+-- @since 1.0.0.0 forkFinally :: MonadConc m => m a -> (Either SomeException a -> m ()) -> m (ThreadId m) forkFinally action and_then = mask $ \restore ->@@ -379,6 +463,8 @@ -- | Raise the 'ThreadKilled' exception in the target thread. Note -- that if the thread is prepared to catch this exception, it won't -- actually kill it.+--+-- @since 1.0.0.0 killThread :: MonadConc m => ThreadId m -> m () killThread tid = throwTo tid ThreadKilled @@ -388,6 +474,8 @@ -- If no name is given, the @ThreadId@ is used. If names conflict, -- successive threads with the same name are given a numeric suffix, -- counting up from 1.+--+-- @since 1.0.0.0 forkN :: MonadConc m => String -> m () -> m (ThreadId m) forkN name ma = forkWithUnmaskN name (\_ -> ma) @@ -397,16 +485,22 @@ -- If no name is given, the @ThreadId@ is used. If names conflict, -- successive threads with the same name are given a numeric suffix, -- counting up from 1.+--+-- @since 1.0.0.0 forkOnN :: MonadConc m => String -> Int -> m () -> m (ThreadId m) forkOnN name i ma = forkOnWithUnmaskN name i (\_ -> ma) -- Bound Threads -- | Provided for compatibility, always returns 'False'.+--+-- @since 1.0.0.0 rtsSupportsBoundThreads :: Bool rtsSupportsBoundThreads = False -- | Provided for compatibility, always returns 'False'.+--+-- @since 1.0.0.0 isCurrentThreadBound :: MonadConc m => m Bool isCurrentThreadBound = pure False @@ -415,6 +509,8 @@ -- | Throw an exception. This will \"bubble up\" looking for an -- exception handler capable of dealing with it and, if one is not -- found, the thread is killed.+--+-- @since 1.0.0.0 throw :: (MonadConc m, Exception e) => e -> m a throw = Ca.throwM @@ -422,6 +518,8 @@ -- exceptions raised by 'throw', unlike the more general -- Control.Exception.catch function. If you need to be able to catch -- /all/ errors, you will have to use 'IO'.+--+-- @since 1.0.0.0 catch :: (MonadConc m, Exception e) => m a -> (e -> m a) -> m a catch = Ca.catch @@ -435,6 +533,8 @@ -- prevailing masking state within the context of the masked -- computation. This function should not be used within an -- 'uninterruptibleMask'.+--+-- @since 1.0.0.0 mask :: MonadConc m => ((forall a. m a -> m a) -> m b) -> m b mask = Ca.mask @@ -448,12 +548,16 @@ -- interruptible operation will only block for a short period of -- time. The supplied unmasking function should not be used within a -- 'mask'.+--+-- @since 1.0.0.0 uninterruptibleMask :: MonadConc m => ((forall a. m a -> m a) -> m b) -> m b uninterruptibleMask = Ca.uninterruptibleMask -- Mutable Variables -- | Create a new @MVar@ containing a value.+--+-- @since 1.0.0.0 newMVar :: MonadConc m => a -> m (MVar m a) newMVar a = do cvar <- newEmptyMVar@@ -466,6 +570,8 @@ -- If no name is given, a counter starting from 0 is used. If names -- conflict, successive @MVar@s with the same name are given a numeric -- suffix, counting up from 1.+--+-- @since 1.0.0.0 newMVarN :: MonadConc m => String -> a -> m (MVar m a) newMVarN n a = do cvar <- newEmptyMVarN n@@ -476,11 +582,15 @@ -- -- This doesn't do do any monadic computation, the @m@ appears in the -- result type to determine the @m@ in the @Ticket@ type.+--+-- @since 1.0.0.0 peekTicket :: forall m a. MonadConc m => Ticket m a -> m a peekTicket t = pure $ peekTicket' (Proxy :: Proxy m) (t :: Ticket m a) -- | Compare-and-swap a value in a @CRef@, returning an indication of -- success and the new value.+--+-- @since 1.0.0.0 cas :: MonadConc m => CRef m a -> a -> m (Bool, a) cas cref a = do tick <- readForCAS cref@@ -492,6 +602,7 @@ ------------------------------------------------------------------------------- -- Concrete instances +-- | @since 1.0.0.0 instance MonadConc IO where type STM IO = IO.STM type MVar IO = IO.MVar@@ -578,29 +689,47 @@ -- | New threads inherit the reader state of their parent, but do not -- communicate results back.+--+-- @since 1.0.0.0 INSTANCE(ReaderT r, MonadConc m, id) +-- | @since 1.0.0.0 INSTANCE(IdentityT, MonadConc m, id) -- | New threads inherit the writer state of their parent, but do not -- communicate results back.+--+-- @since 1.0.0.0 INSTANCE(WL.WriterT w, (MonadConc m, Monoid w), fst)+ -- | New threads inherit the writer state of their parent, but do not -- communicate results back.+--+-- @since 1.0.0.0 INSTANCE(WS.WriterT w, (MonadConc m, Monoid w), fst) -- | New threads inherit the state of their parent, but do not -- communicate results back.+--+-- @since 1.0.0.0 INSTANCE(SL.StateT s, MonadConc m, fst)+ -- | New threads inherit the state of their parent, but do not -- communicate results back.+--+-- @since 1.0.0.0 INSTANCE(SS.StateT s, MonadConc m, fst) -- | New threads inherit the states of their parent, but do not -- communicate results back.+--+-- @since 1.0.0.0 INSTANCE(RL.RWST r w s, (MonadConc m, Monoid w), (\(a,_,_) -> a))+ -- | New threads inherit the states of their parent, but do not -- communicate results back.+--+-- @since 1.0.0.0 INSTANCE(RS.RWST r w s, (MonadConc m, Monoid w), (\(a,_,_) -> a)) #undef INSTANCE@@ -609,6 +738,8 @@ -- | Given a function to remove the transformer-specific state, lift -- a function invocation.+--+-- @since 1.0.0.0 liftedF :: (MonadTransControl t, MonadConc m) => (forall x. StT t x -> x) -> (m a -> m b)@@ -618,6 +749,8 @@ -- | Given a function to remove the transformer-specific state, lift -- a @fork(on)WithUnmask@ invocation.+--+-- @since 1.0.0.0 liftedFork :: (MonadTransControl t, MonadConc m) => (forall x. StT t x -> x) -> (((forall x. m x -> m x) -> m a) -> m b)
Control/Monad/STM/Class.hs view
@@ -52,6 +52,8 @@ -- This class does not provide any way to run transactions, rather -- each 'MonadConc' has an associated @MonadSTM@ from which it can -- atomically run a transaction.+--+-- @since 1.0.0.0 class Ca.MonadCatch stm => MonadSTM stm where {-# MINIMAL retry@@ -64,23 +66,31 @@ -- | The mutable reference type. These behave like 'TVar's, in that -- they always contain a value and updates are non-blocking and -- synchronised.+ --+ -- @since 1.0.0.0 type TVar stm :: * -> * -- | Retry execution of this transaction because it has seen values -- in @TVar@s that it shouldn't have. This will result in the -- thread running the transaction being blocked until any @TVar@s -- referenced in it have been mutated.+ --+ -- @since 1.0.0.0 retry :: stm a -- | Run the first transaction and, if it @retry@s, run the second -- instead. If the monad is an instance of -- 'Alternative'/'MonadPlus', 'orElse' should be the '(<|>)'/'mplus' -- function.+ --+ -- @since 1.0.0.0 orElse :: stm a -> stm a -> stm a -- | Create a new @TVar@ containing the given value. -- -- > newTVar = newTVarN ""+ --+ -- @since 1.0.0.0 newTVar :: a -> stm (TVar stm a) newTVar = newTVarN "" @@ -93,28 +103,41 @@ -- a numeric suffix, counting up from 1. -- -- > newTVarN _ = newTVar+ --+ -- @since 1.0.0.0 newTVarN :: String -> a -> stm (TVar stm a) newTVarN _ = newTVar -- | Return the current value stored in a @TVar@.+ --+ -- @since 1.0.0.0 readTVar :: TVar stm a -> stm a -- | Write the supplied value into the @TVar@.+ --+ -- @since 1.0.0.0 writeTVar :: TVar stm a -> a -> stm () -- | Check whether a condition is true and, if not, call @retry@.+--+-- @since 1.0.0.0 check :: MonadSTM stm => Bool -> stm () check b = unless b retry -- | Throw an exception. This aborts the transaction and propagates -- the exception.+--+-- @since 1.0.0.0 throwSTM :: (MonadSTM stm, Exception e) => e -> stm a throwSTM = Ca.throwM -- | Handling exceptions from 'throwSTM'.+--+-- @since 1.0.0.0 catchSTM :: (MonadSTM stm, Exception e) => stm a -> (e -> stm a) -> stm a catchSTM = Ca.catch +-- | @since 1.0.0.0 instance MonadSTM STM.STM where type TVar STM.STM = STM.TVar @@ -138,17 +161,28 @@ readTVar = lift . readTVar ; \ writeTVar v = lift . writeTVar v } +-- | @since 1.0.0.0 INSTANCE(ReaderT r, MonadSTM stm, id) +-- | @since 1.0.0.0 INSTANCE(IdentityT, MonadSTM stm, id) +-- | @since 1.0.0.0 INSTANCE(WL.WriterT w, (MonadSTM stm, Monoid w), fst)++-- | @since 1.0.0.0 INSTANCE(WS.WriterT w, (MonadSTM stm, Monoid w), fst) +-- | @since 1.0.0.0 INSTANCE(SL.StateT s, MonadSTM stm, fst)++-- | @since 1.0.0.0 INSTANCE(SS.StateT s, MonadSTM stm, fst) +-- | @since 1.0.0.0 INSTANCE(RL.RWST r w s, (MonadSTM stm, Monoid w), (\(a,_,_) -> a))++-- | @since 1.0.0.0 INSTANCE(RS.RWST r w s, (MonadSTM stm, Monoid w), (\(a,_,_) -> a)) #undef INSTANCE@@ -157,6 +191,8 @@ -- | Given a function to remove the transformer-specific state, lift -- an @orElse@ invocation.+--+-- @since 1.0.0.0 liftedOrElse :: (MonadTransControl t, MonadSTM stm) => (forall x. StT t x -> x) -> t stm a -> t stm a -> t stm a
concurrency.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/ name: concurrency-version: 1.1.1.0+version: 1.1.2.0 synopsis: Typeclasses, functions, and data types for concurrency and STM. description:@@ -84,7 +84,7 @@ source-repository this type: git location: https://github.com/barrucadu/dejafu.git- tag: concurrency-1.1.1.0+ tag: concurrency-1.1.2.0 library exposed-modules: Control.Monad.Conc.Class