mirror of
https://github.com/barrucadu/dejafu.git
synced 2024-11-26 09:20:36 +03:00
concurrency-1.6.2.0 release
This commit is contained in:
parent
88278ca471
commit
d6164a4e9b
@ -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. |
|
||||
|
@ -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)
|
||||
--------------------
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user