concurrency-1.6.2.0 release

This commit is contained in:
Michael Walker 2018-11-28 19:08:08 +00:00
parent 88278ca471
commit d6164a4e9b
7 changed files with 88 additions and 4 deletions

View File

@ -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. |

View File

@ -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)
--------------------

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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"