From d6164a4e9b44c074435b27896ff254e8efcd10ee Mon Sep 17 00:00:00 2001 From: Michael Walker Date: Wed, 28 Nov 2018 19:08:08 +0000 Subject: [PATCH] concurrency-1.6.2.0 release --- README.markdown | 2 +- concurrency/CHANGELOG.rst | 16 ++++++++++ .../Control/Concurrent/Classy/BoundedChan.hs | 16 ++++++++++ concurrency/Control/Concurrent/Classy/Lock.hs | 20 ++++++++++++ .../Control/Concurrent/Classy/RWLock.hs | 32 +++++++++++++++++++ concurrency/concurrency.cabal | 4 +-- doc/getting_started.rst | 2 +- 7 files changed, 88 insertions(+), 4 deletions(-) diff --git a/README.markdown b/README.markdown index 9b6b97a..3dbfd41 100644 --- a/README.markdown +++ b/README.markdown @@ -45,7 +45,7 @@ There are a few different packages under the Déjà Fu umbrella: | | Version | Summary | | - | ------- | ------- | -| [concurrency][h:conc] | 1.6.1.0 | Typeclasses, functions, and data types for concurrency and STM. | +| [concurrency][h:conc] | 1.6.2.0 | Typeclasses, functions, and data types for concurrency and STM. | | [dejafu][h:dejafu] | 1.11.0.3 | Systematic testing for Haskell concurrency. | | [hunit-dejafu][h:hunit] | 1.2.0.6 | Deja Fu support for the HUnit test framework. | | [tasty-dejafu][h:tasty] | 1.2.0.7 | Deja Fu support for the Tasty test framework. | diff --git a/concurrency/CHANGELOG.rst b/concurrency/CHANGELOG.rst index d203118..f549cd2 100644 --- a/concurrency/CHANGELOG.rst +++ b/concurrency/CHANGELOG.rst @@ -7,6 +7,22 @@ standard Haskell versioning scheme. .. _PVP: https://pvp.haskell.org/ +1.6.2.0 (2018-11-28) +-------------------- + +* Git: :tag:`concurrency-1.6.2.0` +* Hackage: :hackage:`concurrency-1.6.2.0` + +**Contributors:** :u:`gip` (:pull:`289`). + +Added +~~~~~ + +* (:pull:`289`) The ``Control.Concurrent.Classy.BoundedChan`` module. +* (:pull:`289`) The ``Control.Concurrent.Classy.Lock`` module. +* (:pull:`289`) The ``Control.Concurrent.Classy.RWLock`` module. + + 1.6.1.0 (2018-09-23) -------------------- diff --git a/concurrency/Control/Concurrent/Classy/BoundedChan.hs b/concurrency/Control/Concurrent/Classy/BoundedChan.hs index 8993395..ff3dce5 100644 --- a/concurrency/Control/Concurrent/Classy/BoundedChan.hs +++ b/concurrency/Control/Concurrent/Classy/BoundedChan.hs @@ -84,6 +84,8 @@ import Control.Monad.Conc.Class (MonadConc(MVar)) -------------------------------------------------------------------------------- -- | A 'BoundedChan' is an abstract data type representing a bounded channel. +-- +-- @since 1.6.2.0 data BoundedChan m a = BoundedChan { _size :: Int @@ -132,6 +134,8 @@ withMVarMask m callback = -- | -- @newBoundedChan n@ returns a channel than can contain no more than @n@ -- elements. +-- +-- @since 1.6.2.0 newBoundedChan :: (MonadConc m) => Int -> m (BoundedChan m a) newBoundedChan x = do entls <- replicateM x MVar.newEmptyMVar @@ -143,6 +147,8 @@ newBoundedChan x = do -- | -- Write an element to the channel. If the channel is full, this routine will -- block until it is able to write. Blockers wait in a fair FIFO queue. +-- +-- @since 1.6.2.0 writeBoundedChan :: (MonadConc m) => BoundedChan m a -> a -> m () writeBoundedChan (BoundedChan size contents wposMV _) x = modifyMVarMask_ wposMV $ \wpos -> do @@ -153,6 +159,8 @@ writeBoundedChan (BoundedChan size contents wposMV _) x = -- A variant of 'writeBoundedChan' which, instead of blocking when the channel is -- full, simply aborts and does not write the element. Note that this routine -- can still block while waiting for write access to the channel. +-- +-- @since 1.6.2.0 trywriteBoundedChan :: (MonadConc m) => BoundedChan m a -> a -> m Bool trywriteBoundedChan (BoundedChan size contents wposMV _) x = modifyMVarMask wposMV $ \wpos -> do @@ -164,6 +172,8 @@ trywriteBoundedChan (BoundedChan size contents wposMV _) x = -- | -- Read an element from the channel. If the channel is empty, this routine -- will block until it is able to read. Blockers wait in a fair FIFO queue. +-- +-- @since 1.6.2.0 readBoundedChan :: (MonadConc m) => BoundedChan m a -> m a readBoundedChan (BoundedChan size contents _ rposMV) = modifyMVarMask rposMV $ \rpos -> do @@ -175,6 +185,8 @@ readBoundedChan (BoundedChan size contents _ rposMV) = -- empty, immediately returns 'Nothing'. Otherwise, 'tryreadBoundedChan' returns -- @'Just' a@ where @a@ is the element read from the channel. Note that this -- routine can still block while waiting for read access to the channel. +-- +-- @since 1.6.2.0 tryreadBoundedChan :: (MonadConc m) => BoundedChan m a -> m (Maybe a) tryreadBoundedChan (BoundedChan size contents _ rposMV) = modifyMVarMask rposMV $ \rpos -> do @@ -190,6 +202,8 @@ tryreadBoundedChan (BoundedChan size contents _ rposMV) = -- -- NOTE: This may block on an empty channel if there is a blocked reader. -- NOTE: This function is deprecated. +-- +-- @since 1.6.2.0 {-# DEPRECATED isEmptyBoundedChan "This isEmptyBoundedChan can block, no non-blocking substitute yet" #-} isEmptyBoundedChan :: (MonadConc m) => BoundedChan m a -> m Bool @@ -201,6 +215,8 @@ isEmptyBoundedChan (BoundedChan _ contents _ rposMV) = -- Write a list of elements to the channel. -- If the channel becomes full, this routine will block until it can write. -- Competing writers may interleave with this one. +-- +-- @since 1.6.2.0 writeList2BoundedChan :: (MonadConc m) => BoundedChan m a -> [a] -> m () writeList2BoundedChan = mapM_ . writeBoundedChan diff --git a/concurrency/Control/Concurrent/Classy/Lock.hs b/concurrency/Control/Concurrent/Classy/Lock.hs index 4dda1f5..1ff853c 100644 --- a/concurrency/Control/Concurrent/Classy/Lock.hs +++ b/concurrency/Control/Concurrent/Classy/Lock.hs @@ -104,6 +104,8 @@ import Control.Monad.Conc.Class (MonadConc(MVar)) -------------------------------------------------------------------------------- -- | A lock is in one of two states: \"locked\" or \"unlocked\". +-- +-- @since 1.6.2.0 newtype Lock m = Lock { _fromLock :: MVar m () @@ -116,10 +118,14 @@ instance (Eq (MVar m ())) => Eq (Lock m) where -------------------------------------------------------------------------------- -- | Create a lock in the \"unlocked\" state. +-- +-- @since 1.6.2.0 newLock :: (MonadConc m) => m (Lock m) newLock = Lock <$> MVar.newMVar () -- | Create a lock in the \"locked\" state. +-- +-- @since 1.6.2.0 newAcquired :: (MonadConc m) => m (Lock m) newAcquired = Lock <$> MVar.newEmptyMVar @@ -147,6 +153,8 @@ newAcquired = Lock <$> MVar.newEmptyMVar -- order. This is useful for providing fairness properties of abstractions -- built using locks. Note that this differs from the Python implementation -- where the wake-up order is undefined. +-- +-- @since 1.6.2.0 acquire :: (MonadConc m) => Lock m -> m () acquire = MVar.takeMVar . _fromLock @@ -158,6 +166,8 @@ acquire = MVar.takeMVar . _fromLock -- -- * When the state is \"locked\" @tryAcquire@ leaves the state unchanged and -- returns 'False'. +-- +-- @since 1.6.2.0 tryAcquire :: (MonadConc m) => Lock m -> m Bool tryAcquire = fmap isJust . MVar.tryTakeMVar . _fromLock @@ -168,6 +178,8 @@ tryAcquire = fmap isJust . MVar.tryTakeMVar . _fromLock -- -- If there are any threads blocked on 'acquire' the thread that first called -- @acquire@ will be woken up. +-- +-- @since 1.6.2.0 release :: (MonadConc m) => Lock m -> m () release (Lock mv) = do b <- MVar.tryPutMVar mv () @@ -182,6 +194,8 @@ release (Lock mv) = do -- exception, the lock is released. -- -- Note that: @with = 'bracket_' '<$>' 'acquire' '<*>' 'release'@. +-- +-- @since 1.6.2.0 with :: (MonadConc m) => Lock m -> m a -> m a with = bracket_ <$> acquire <*> release @@ -191,6 +205,8 @@ with = bracket_ <$> acquire <*> release -- the computation is performed. When the computation terminates, whether -- normally or by raising an exception, the lock is released and 'Just' the -- result of the computation is returned. +-- +-- @since 1.6.2.0 tryWith :: (MonadConc m) => Lock m -> m a -> m (Maybe a) tryWith l a = mask $ \restore -> do acquired <- tryAcquire l @@ -210,6 +226,8 @@ tryWith l a = mask $ \restore -> do -- * When the state is \"unlocked\" @wait@ returns immediately. -- -- @wait@ does not alter the state of the lock. +-- +-- @since 1.6.2.0 wait :: (MonadConc m) => Lock m -> m () wait (Lock mv) = MVar.readMVar mv @@ -220,6 +238,8 @@ wait (Lock mv) = MVar.readMVar mv -- -- Note that this is only a snapshot of the state. By the time a program reacts -- on its result it may already be out of date. +-- +-- @since 1.6.2.0 locked :: (MonadConc m) => Lock m -> m Bool locked = MVar.isEmptyMVar . _fromLock diff --git a/concurrency/Control/Concurrent/Classy/RWLock.hs b/concurrency/Control/Concurrent/Classy/RWLock.hs index fd894ba..f549728 100644 --- a/concurrency/Control/Concurrent/Classy/RWLock.hs +++ b/concurrency/Control/Concurrent/Classy/RWLock.hs @@ -130,6 +130,8 @@ import qualified Control.Concurrent.Classy.Lock as Lock -- -- * \"Write\": A single thread has acquired write access. -- Blocks other threads from acquiring both read and write access. +-- +-- @since 1.6.2.0 data RWLock m = RWLock { _state :: MVar m State @@ -158,6 +160,8 @@ data State -- | -- Create a new 'RWLock' in the \"free\" state; either read or write access -- can be acquired without blocking. +-- +-- @since 1.6.2.0 newRWLock :: (MonadConc m) => m (RWLock m) newRWLock = do state <- MVar.newMVar Free @@ -167,6 +171,8 @@ newRWLock = do -- | -- Create a new 'RWLock' in the \"read\" state; only read can be acquired -- without blocking. +-- +-- @since 1.6.2.0 newAcquiredRead :: (MonadConc m) => m (RWLock m) newAcquiredRead = do state <- MVar.newMVar (Read 1) @@ -176,6 +182,8 @@ newAcquiredRead = do -- | -- Create a new 'RWLock' in the \"write\" state; either acquiring read or -- write will block. +-- +-- @since 1.6.2.0 newAcquiredWrite :: (MonadConc m) => m (RWLock m) newAcquiredWrite = do state <- MVar.newMVar Write @@ -193,6 +201,8 @@ newAcquiredWrite = do -- -- Implementation note: throws an exception when more than @'maxBound' :: 'Int'@ -- simultaneous threads acquire the read lock. But that is unlikely. +-- +-- @since 1.6.2.0 acquireRead :: (MonadConc m) => RWLock m -> m () acquireRead RWLock { _state, _readLock, _writeLock } = mask_ go where @@ -211,6 +221,8 @@ acquireRead RWLock { _state, _readLock, _writeLock } = mask_ go -- -- Like 'acquireRead', but doesn't block. Returns 'True' if the resulting -- state is \"read\", 'False' otherwise. +-- +-- @since 1.6.2.0 tryAcquireRead :: (MonadConc m) => RWLock m -> m Bool tryAcquireRead RWLock { _state, _readLock } = mask_ $ do st <- MVar.takeMVar _state @@ -231,6 +243,8 @@ tryAcquireRead RWLock { _state, _readLock } = mask_ $ do -- -- It is an error to release read access to an 'RWLock' which is not in -- the \"read\" state. +-- +-- @since 1.6.2.0 releaseRead :: (MonadConc m) => RWLock m -> m () releaseRead RWLock { _state, _readLock } = mask_ $ do st <- MVar.takeMVar _state @@ -245,6 +259,8 @@ releaseRead RWLock { _state, _readLock } = mask_ $ do -- A convenience function wich first acquires read access and then performs the -- computation. When the computation terminates, whether normally or by raising -- an exception, the read lock is released. +-- +-- @since 1.6.2.0 withRead :: (MonadConc m) => RWLock m -> m a -> m a withRead = bracket_ <$> acquireRead <*> releaseRead @@ -253,6 +269,8 @@ withRead = bracket_ <$> acquireRead <*> releaseRead -- 'Nothing' is returned. If it succeeds, the computation is performed. -- When the computation terminates, whether normally or by raising an exception, -- the lock is released and 'Just' the result of the computation is returned. +-- +-- @since 1.6.2.0 tryWithRead :: (MonadConc m) => RWLock m -> m a -> m (Maybe a) tryWithRead l a = mask $ \restore -> do acquired <- tryAcquireRead l @@ -273,6 +291,8 @@ tryWithRead l a = mask $ \restore -> do -- Note that @waitRead@ is just a convenience function defined as: -- -- @waitRead l = 'mask_' '$' 'acquireRead' l '>>' 'releaseRead' l@ +-- +-- @since 1.6.2.0 waitRead :: (MonadConc m) => RWLock m -> m () waitRead l = mask_ (acquireRead l >> releaseRead l) @@ -284,6 +304,8 @@ waitRead l = mask_ (acquireRead l >> releaseRead l) -- Blocks if another thread has acquired either read or write access. -- If @acquireWrite@ terminates without throwing an exception the state of -- the 'RWLock' will be \"write\". +-- +-- @since 1.6.2.0 acquireWrite :: (MonadConc m) => RWLock m -> m () acquireWrite RWLock { _state, _readLock, _writeLock } = mask_ go' where @@ -304,6 +326,8 @@ acquireWrite RWLock { _state, _readLock, _writeLock } = mask_ go' -- -- Like 'acquireWrite', but doesn't block. -- Returns 'True' if the resulting state is \"write\", 'False' otherwise. +-- +-- @since 1.6.2.0 tryAcquireWrite :: (MonadConc m) => RWLock m -> m Bool tryAcquireWrite RWLock { _state, _writeLock } = mask_ $ do st <- MVar.takeMVar _state @@ -322,6 +346,8 @@ tryAcquireWrite RWLock { _state, _writeLock } = mask_ $ do -- -- It is an error to release write access to an 'RWLock' which is not -- in the \"write\" state. +-- +-- @since 1.6.2.0 releaseWrite :: (MonadConc m) => RWLock m -> m () releaseWrite RWLock { _state, _writeLock } = mask_ $ do st <- MVar.takeMVar _state @@ -335,6 +361,8 @@ releaseWrite RWLock { _state, _writeLock } = mask_ $ do -- A convenience function wich first acquires write access and then performs -- the computation. When the computation terminates, whether normally or by -- raising an exception, the write lock is released. +-- +-- @since 1.6.2.0 withWrite :: (MonadConc m) => RWLock m -> m a -> m a withWrite = bracket_ <$> acquireWrite <*> releaseWrite @@ -343,6 +371,8 @@ withWrite = bracket_ <$> acquireWrite <*> releaseWrite -- 'Nothing' is returned. If it succeeds, the computation is performed. -- When the computation terminates, whether normally or by raising an exception, -- the lock is released and 'Just' the result of the computation is returned. +-- +-- @since 1.6.2.0 tryWithWrite :: (MonadConc m) => RWLock m -> m a -> m (Maybe a) tryWithWrite l a = mask $ \restore -> do acquired <- tryAcquireWrite l @@ -364,6 +394,8 @@ tryWithWrite l a = mask $ \restore -> do -- Note that @waitWrite@ is just a convenience function defined as: -- -- @waitWrite l = 'mask_' '$' 'acquireWrite' l '>>' 'releaseWrite' l@ +-- +-- @since 1.6.2.0 waitWrite :: (MonadConc m) => RWLock m -> m () waitWrite l = mask_ (acquireWrite l >> releaseWrite l) diff --git a/concurrency/concurrency.cabal b/concurrency/concurrency.cabal index a4d35d4..408ac3a 100755 --- a/concurrency/concurrency.cabal +++ b/concurrency/concurrency.cabal @@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/ name: concurrency -version: 1.6.1.0 +version: 1.6.2.0 synopsis: Typeclasses, functions, and data types for concurrency and STM. description: @@ -32,7 +32,7 @@ source-repository head source-repository this type: git location: https://github.com/barrucadu/dejafu.git - tag: concurrency-1.6.1.0 + tag: concurrency-1.6.2.0 library exposed-modules: Control.Monad.Conc.Class diff --git a/doc/getting_started.rst b/doc/getting_started.rst index b8a5dd0..96fe758 100644 --- a/doc/getting_started.rst +++ b/doc/getting_started.rst @@ -27,7 +27,7 @@ There are a few different packages under the Déjà Fu umbrella: .. csv-table:: :header: "Package", "Version", "Summary" - ":hackage:`concurrency`", "1.6.1.0", "Typeclasses, functions, and data types for concurrency and STM" + ":hackage:`concurrency`", "1.6.2.0", "Typeclasses, functions, and data types for concurrency and STM" ":hackage:`dejafu`", "1.11.0.3", "Systematic testing for Haskell concurrency" ":hackage:`hunit-dejafu`", "1.2.0.6", "Déjà Fu support for the HUnit test framework" ":hackage:`tasty-dejafu`", "1.2.0.7", "Déjà Fu support for the tasty test framework"