Merge pull request #276 from barrucadu/274-ioref

Rename CRef to IORef
This commit is contained in:
Michael Walker 2018-07-01 14:02:53 +01:00 committed by GitHub
commit fb43e90097
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 1011 additions and 793 deletions

View File

@ -45,10 +45,10 @@ There are a few different packages under the Déjà Fu umbrella:
| | Version | Summary | | | Version | Summary |
| - | ------- | ------- | | - | ------- | ------- |
| [concurrency][h:conc] | 1.5.0.0 | Typeclasses, functions, and data types for concurrency and STM. | | [concurrency][h:conc] | 1.6.0.0 | Typeclasses, functions, and data types for concurrency and STM. |
| [dejafu][h:dejafu] | 1.10.1.0 | Systematic testing for Haskell concurrency. | | [dejafu][h:dejafu] | 1.11.0.0 | Systematic testing for Haskell concurrency. |
| [hunit-dejafu][h:hunit] | 1.2.0.5 | Deja Fu support for the HUnit test framework. | | [hunit-dejafu][h:hunit] | 1.2.0.6 | Deja Fu support for the HUnit test framework. |
| [tasty-dejafu][h:tasty] | 1.2.0.6 | Deja Fu support for the Tasty test framework. | | [tasty-dejafu][h:tasty] | 1.2.0.7 | Deja Fu support for the Tasty test framework. |
Each package has its own README and CHANGELOG in its subdirectory. Each package has its own README and CHANGELOG in its subdirectory.

View File

@ -7,6 +7,25 @@ standard Haskell versioning scheme.
.. _PVP: https://pvp.haskell.org/ .. _PVP: https://pvp.haskell.org/
1.6.0.0 - IORefs (2018-07-01)
-----------------------------
* Git: :tag:`concurrency-1.6.0.0`
* Hackage: :hackage:`concurrency-1.6.0.0`
Added
~~~~~
* ``Control.Concurrent.Classy.CRef``, deprecated ``*CRef`` functions
and a ``CRef`` alias.
Changed
~~~~~~~
* (:issue:`274`) ``CRef`` is now ``IORef``: all functions, modules,
and types have been renamed.
1.5.0.0 - No More 7.10 (2018-03-28) 1.5.0.0 - No More 7.10 (2018-03-28)
----------------------------------- -----------------------------------

View File

@ -1,3 +1,5 @@
{-# OPTIONS_GHC -Wno-deprecations #-}
-- | -- |
-- Module : Control.Concurrent.Classy -- Module : Control.Concurrent.Classy
-- Copyright : (c) 2016 Michael Walker -- Copyright : (c) 2016 Michael Walker
@ -23,6 +25,7 @@ module Control.Concurrent.Classy
( module Control.Monad.Conc.Class ( module Control.Monad.Conc.Class
, module Control.Concurrent.Classy.Chan , module Control.Concurrent.Classy.Chan
, module Control.Concurrent.Classy.CRef , module Control.Concurrent.Classy.CRef
, module Control.Concurrent.Classy.IORef
, module Control.Concurrent.Classy.MVar , module Control.Concurrent.Classy.MVar
, module Control.Concurrent.Classy.STM , module Control.Concurrent.Classy.STM
, module Control.Concurrent.Classy.QSem , module Control.Concurrent.Classy.QSem
@ -31,6 +34,7 @@ module Control.Concurrent.Classy
import Control.Concurrent.Classy.Chan import Control.Concurrent.Classy.Chan
import Control.Concurrent.Classy.CRef import Control.Concurrent.Classy.CRef
import Control.Concurrent.Classy.IORef
import Control.Concurrent.Classy.MVar import Control.Concurrent.Classy.MVar
import Control.Concurrent.Classy.QSem import Control.Concurrent.Classy.QSem
import Control.Concurrent.Classy.QSemN import Control.Concurrent.Classy.QSemN

View File

@ -1,19 +1,18 @@
-- | -- |
-- Module : Control.Concurrent.Classy.CRef -- Module : Control.Concurrent.Classy.CRef
-- Copyright : (c) 2016 Michael Walker -- Copyright : (c) 2016--2018 Michael Walker
-- License : MIT -- License : MIT
-- Maintainer : Michael Walker <mike@barrucadu.co.uk> -- Maintainer : Michael Walker <mike@barrucadu.co.uk>
-- Stability : stable -- Stability : experimental
-- Portability : portable -- Portability : portable
-- --
-- Mutable references in a concurrency monad. -- Deprecated re-exports of @IORef@ functions under the old @CRef@
-- -- names.
-- __Deviations:__ There is no @Eq@ instance for @MonadConc@ the module Control.Concurrent.Classy.CRef {-# DEPRECATED "Import Control.Concurrent.Classy.IORef instead" #-}
-- @CRef@ type. Furthermore, the @mkWeakIORef@ function is not
-- provided.
module Control.Concurrent.Classy.CRef
( -- * CRefs ( -- * CRefs
newCRef CRef
, newCRef
, newCRefN
, readCRef , readCRef
, writeCRef , writeCRef
, modifyCRef , modifyCRef
@ -22,6 +21,11 @@ module Control.Concurrent.Classy.CRef
, atomicModifyCRef' , atomicModifyCRef'
, atomicWriteCRef , atomicWriteCRef
-- ** Compare-and-swap
, casCRef
, modifyCRefCAS
, modifyCRefCAS_
-- * Memory Model -- * Memory Model
-- | In a concurrent program, @CRef@ operations may appear -- | In a concurrent program, @CRef@ operations may appear
@ -80,41 +84,85 @@ module Control.Concurrent.Classy.CRef
-- memory barrier. -- memory barrier.
) where ) where
import Control.Monad.Conc.Class import qualified Control.Concurrent.Classy.IORef as IORef
import Control.Monad.Conc.Class (IORef, MonadConc, Ticket)
import qualified Control.Monad.Conc.Class as IORef
-- | Type alias for 'IORef'.
type CRef m a = IORef m a
{-# DEPRECATED CRef "Use IORef instead" #-}
-- | Create a new reference.
newCRef :: MonadConc m => a -> m (CRef m a)
newCRef = IORef.newIORef
{-# DEPRECATED newCRef "Use newIORef instead" #-}
-- | Create a new reference, but it is given a name which may be used
-- to present more useful debugging information.
newCRefN :: MonadConc m => String -> a -> m (CRef m a)
newCRefN = IORef.newIORefN
{-# DEPRECATED newCRefN "Use newIORefN instead" #-}
-- | Read the current value stored in a reference.
readCRef :: MonadConc m => CRef m a -> m a
readCRef = IORef.readIORef
{-# DEPRECATED readCRef "Use readIORef instead" #-}
-- | Write a new value into an @CRef@, without imposing a memory
-- barrier. This means that relaxed memory effects can be observed.
writeCRef :: MonadConc m => CRef m a -> a -> m ()
writeCRef = IORef.writeIORef
{-# DEPRECATED writeCRef "Use writeIORef instead" #-}
-- | Mutate the contents of a @CRef@. -- | Mutate the contents of a @CRef@.
-- --
-- Be warned that 'modifyCRef' does not apply the function strictly. -- Be warned that 'modifyCRef' does not apply the function strictly.
-- This means if the program calls 'modifyCRef' many times, but -- This means if the program calls 'modifyCRef' many times, but
-- seldomly uses the value, thunks will pile up in memory resulting in -- seldomly uses the value, thunks will pile up in memory resulting in
-- a space leak. This is a common mistake made when using a @CRef@ as -- a space leak.
-- a counter. For example, the following will likely produce a stack
-- overflow:
--
-- >ref <- newCRef 0
-- >replicateM_ 1000000 $ modifyCRef ref (+1)
-- >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 :: MonadConc m => CRef m a -> (a -> a) -> m ()
modifyCRef ref f = readCRef ref >>= writeCRef ref . f modifyCRef = IORef.modifyIORef
{-# DEPRECATED modifyCRef "Use modifyIORef instead" #-}
-- | Strict version of 'modifyCRef' -- | Strict version of 'modifyCRef'
--
-- @since 1.0.0.0
modifyCRef' :: MonadConc m => CRef m a -> (a -> a) -> m () modifyCRef' :: MonadConc m => CRef m a -> (a -> a) -> m ()
modifyCRef' ref f = do modifyCRef' = IORef.modifyIORef'
x <- readCRef ref {-# DEPRECATED modifyCRef' "Use modifyIORef' instead" #-}
writeCRef ref $! f x
-- | Atomically modify the value stored in a reference. This imposes
-- a full memory barrier.
atomicModifyCRef :: MonadConc m => CRef m a -> (a -> (a, b)) -> m b
atomicModifyCRef = IORef.atomicModifyIORef
{-# DEPRECATED atomicModifyCRef "Use atomicModifyIORef instead" #-}
-- | Strict version of 'atomicModifyCRef'. This forces both the value -- | Strict version of 'atomicModifyCRef'. This forces both the value
-- stored in the @CRef@ as well as the value returned. -- 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' :: MonadConc m => CRef m a -> (a -> (a,b)) -> m b
atomicModifyCRef' ref f = do atomicModifyCRef' = IORef.atomicModifyIORef'
b <- atomicModifyCRef ref $ \a -> case f a of {-# DEPRECATED atomicModifyCRef' "Use atomicModifyIORef' instead" #-}
v@(a',_) -> a' `seq` v
pure $! b -- | Replace the value stored in a reference, with the
-- barrier-to-reordering property that 'atomicModifyIORef' has.
atomicWriteCRef :: MonadConc m => CRef m a -> a -> m ()
atomicWriteCRef = IORef.atomicWriteIORef
{-# DEPRECATED atomicWriteCRef "Use atomicWriteIORef instead" #-}
-- | Perform a machine-level compare-and-swap (CAS) operation on a
-- @CRef@. Returns an indication of success and a @Ticket@ for the
-- most current value in the @CRef@.
-- This is strict in the \"new\" value argument.
casCRef :: MonadConc m => CRef m a -> Ticket m a -> a -> m (Bool, Ticket m a)
casCRef = IORef.casIORef
{-# DEPRECATED casCRef "Use casIORef instead" #-}
-- | A replacement for 'atomicModifyCRef' using a compare-and-swap.
--
-- This is strict in the \"new\" value argument.
modifyCRefCAS :: MonadConc m => CRef m a -> (a -> (a, b)) -> m b
modifyCRefCAS = IORef.modifyIORefCAS
{-# DEPRECATED modifyCRefCAS "Use modifyIORefCAS instead" #-}
-- | A variant of 'modifyCRefCAS' which doesn't return a result.
modifyCRefCAS_ :: MonadConc m => CRef m a -> (a -> a) -> m ()
modifyCRefCAS_ = IORef.modifyIORefCAS_
{-# DEPRECATED modifyCRefCAS_ "Use modifyIORefCAS_ instead" #-}

View File

@ -0,0 +1,120 @@
-- |
-- Module : Control.Concurrent.Classy.IORef
-- Copyright : (c) 2018 Michael Walker
-- License : MIT
-- Maintainer : Michael Walker <mike@barrucadu.co.uk>
-- Stability : stable
-- Portability : portable
--
-- Mutable references in a concurrency monad.
--
-- __Deviations:__ There is no @Eq@ instance for @MonadConc@ the
-- @IORef@ type. Furthermore, the @mkWeakIORef@ function is not
-- provided.
module Control.Concurrent.Classy.IORef
( -- * IORefs
newIORef
, readIORef
, writeIORef
, modifyIORef
, modifyIORef'
, atomicModifyIORef
, atomicModifyIORef'
, atomicWriteIORef
-- * Memory Model
-- | In a concurrent program, @IORef@ operations may appear
-- out-of-order to another thread, depending on the memory model of
-- the underlying processor architecture. For example, on x86 (which
-- uses total store order), loads can move ahead of stores. Consider
-- this example:
--
-- > iorefs :: MonadConc m => m (Bool, Bool)
-- > iorefs = do
-- > r1 <- newIORef False
-- > r2 <- newIORef False
-- >
-- > x <- spawn $ writeIORef r1 True >> readIORef r2
-- > y <- spawn $ writeIORef r2 True >> readIORef r1
-- >
-- > (,) <$> readMVar x <*> readMVar y
--
-- Under a sequentially consistent memory model the possible results
-- are @(True, True)@, @(True, False)@, and @(False, True)@. Under
-- total or partial store order, @(False, False)@ is also a possible
-- result, even though there is no interleaving of the threads which
-- can lead to this.
--
-- We can see this by testing with different memory models:
--
-- > > autocheckWay defaultWay SequentialConsistency relaxed
-- > [pass] Never Deadlocks
-- > [pass] No Exceptions
-- > [fail] Consistent Result
-- > (False,True) S0---------S1----S0--S2----S0--
-- >
-- > (True,True) S0---------S1-P2----S1---S0---
-- >
-- > (True,False) S0---------S2----S1----S0---
-- > False
--
-- > > autocheckWay defaultWay TotalStoreOrder relaxed
-- > [pass] Never Deadlocks
-- > [pass] No Exceptions
-- > [fail] Consistent Result
-- > (False,True) S0---------S1----S0--S2----S0--
-- >
-- > (False,False) S0---------S1--P2----S1--S0---
-- >
-- > (True,False) S0---------S2----S1----S0---
-- >
-- > (True,True) S0---------S1-C-S2----S1---S0---
-- > False
--
-- Traces for non-sequentially-consistent memory models show where
-- writes to @IORef@s are /committed/, which makes a write visible to
-- all threads rather than just the one which performed the
-- write. Only 'writeIORef' is broken up into separate write and
-- commit steps, 'atomicModifyIORef' is still atomic and imposes a
-- memory barrier.
) where
import Control.Monad.Conc.Class
-- | Mutate the contents of a @IORef@.
--
-- Be warned that 'modifyIORef' does not apply the function strictly.
-- This means if the program calls 'modifyIORef' many times, but
-- seldomly uses the value, thunks will pile up in memory resulting in
-- a space leak. This is a common mistake made when using a @IORef@ as
-- a counter. For example, the following will likely produce a stack
-- overflow:
--
-- >ref <- newIORef 0
-- >replicateM_ 1000000 $ modifyIORef ref (+1)
-- >readIORef ref >>= print
--
-- To avoid this problem, use 'modifyIORef'' instead.
--
-- @since 1.6.0.0
modifyIORef :: MonadConc m => IORef m a -> (a -> a) -> m ()
modifyIORef ref f = readIORef ref >>= writeIORef ref . f
-- | Strict version of 'modifyIORef'
--
-- @since 1.6.0.0
modifyIORef' :: MonadConc m => IORef m a -> (a -> a) -> m ()
modifyIORef' ref f = do
x <- readIORef ref
writeIORef ref $! f x
-- | Strict version of 'atomicModifyIORef'. This forces both the value
-- stored in the @IORef@ as well as the value returned.
--
-- @since 1.6.0.0
atomicModifyIORef' :: MonadConc m => IORef m a -> (a -> (a,b)) -> m b
atomicModifyIORef' ref f = do
b <- atomicModifyIORef ref $ \a -> case f a of
v@(a',_) -> a' `seq` v
pure $! b

View File

@ -8,7 +8,7 @@
-- | -- |
-- Module : Control.Monad.Conc.Class -- Module : Control.Monad.Conc.Class
-- Copyright : (c) 2016--2017 Michael Walker -- Copyright : (c) 2016--2018 Michael Walker
-- License : MIT -- License : MIT
-- Maintainer : Michael Walker <mike@barrucadu.co.uk> -- Maintainer : Michael Walker <mike@barrucadu.co.uk>
-- Stability : experimental -- Stability : experimental
@ -18,7 +18,7 @@
-- monads. -- monads.
-- --
-- __Deviations:__ An instance of @MonadConc@ is not required to be an -- __Deviations:__ An instance of @MonadConc@ is not required to be an
-- instance of @MonadFix@, unlike @IO@. The @CRef@, @MVar@, and -- instance of @MonadFix@, unlike @IO@. The @IORef@, @MVar@, and
-- @Ticket@ types are not required to be instances of @Show@ or @Eq@, -- @Ticket@ types are not required to be instances of @Show@ or @Eq@,
-- unlike their normal counterparts. The @threadCapability@, -- unlike their normal counterparts. The @threadCapability@,
-- @threadWaitRead@, @threadWaitWrite@, @threadWaitReadSTM@, -- @threadWaitRead@, @threadWaitWrite@, @threadWaitReadSTM@,
@ -150,7 +150,7 @@ import qualified Control.Monad.Writer.Strict as WS
-- Do not be put off by the use of @UndecidableInstances@, it is safe -- Do not be put off by the use of @UndecidableInstances@, it is safe
-- here. -- here.
-- --
-- @since 1.5.0.0 -- @since 1.6.0.0
class ( Monad m class ( Monad m
, MonadCatch m, MonadThrow m, MonadMask m , MonadCatch m, MonadThrow m, MonadMask m
, MonadSTM (STM m) , MonadSTM (STM m)
@ -172,13 +172,13 @@ class ( Monad m
, tryReadMVar , tryReadMVar
, takeMVar , takeMVar
, tryTakeMVar , tryTakeMVar
, (newCRef | newCRefN) , (newIORef | newIORefN)
, atomicModifyCRef , atomicModifyIORef
, writeCRef , writeIORef
, readForCAS , readForCAS
, peekTicket' , peekTicket'
, casCRef , casIORef
, modifyCRefCAS , modifyIORefCAS
, atomically , atomically
, throwTo , throwTo
#-} #-}
@ -197,13 +197,13 @@ class ( Monad m
type MVar m :: * -> * type MVar m :: * -> *
-- | The mutable non-blocking reference type. These may suffer from -- | The mutable non-blocking reference type. These may suffer from
-- relaxed memory effects if functions outside the set @newCRef@, -- relaxed memory effects if functions outside the set @newIORef@,
-- @readCRef@, @atomicModifyCRef@, and @atomicWriteCRef@ are used. -- @readIORef@, @atomicModifyIORef@, and @atomicWriteIORef@ are used.
-- --
-- @since 1.0.0.0 -- @since 1.6.0.0
type CRef m :: * -> * type IORef m :: * -> *
-- | When performing compare-and-swap operations on @CRef@s, a -- | When performing compare-and-swap operations on @IORef@s, a
-- @Ticket@ is a proof that a thread observed a specific previous -- @Ticket@ is a proof that a thread observed a specific previous
-- value. -- value.
-- --
@ -376,55 +376,55 @@ class ( Monad m
-- | Create a new reference. -- | Create a new reference.
-- --
-- > newCRef = newCRefN "" -- > newIORef = newIORefN ""
-- --
-- @since 1.0.0.0 -- @since 1.6.0.0
newCRef :: a -> m (CRef m a) newIORef :: a -> m (IORef m a)
newCRef = newCRefN "" newIORef = newIORefN ""
-- | Create a new reference, but it is given a name which may be -- | Create a new reference, but it is given a name which may be
-- used to present more useful debugging information. -- used to present more useful debugging information.
-- --
-- > newCRefN _ = newCRef -- > newIORefN _ = newIORef
-- --
-- @since 1.0.0.0 -- @since 1.6.0.0
newCRefN :: String -> a -> m (CRef m a) newIORefN :: String -> a -> m (IORef m a)
newCRefN _ = newCRef newIORefN _ = newIORef
-- | Read the current value stored in a reference. -- | Read the current value stored in a reference.
-- --
-- > readCRef cref = readForCAS cref >>= peekTicket -- > readIORef ioref = readForCAS ioref >>= peekTicket
-- --
-- @since 1.0.0.0 -- @since 1.6.0.0
readCRef :: CRef m a -> m a readIORef :: IORef m a -> m a
readCRef cref = readForCAS cref >>= peekTicket readIORef ioref = readForCAS ioref >>= peekTicket
-- | Atomically modify the value stored in a reference. This imposes -- | Atomically modify the value stored in a reference. This imposes
-- a full memory barrier. -- a full memory barrier.
-- --
-- @since 1.0.0.0 -- @since 1.6.0.0
atomicModifyCRef :: CRef m a -> (a -> (a, b)) -> m b atomicModifyIORef :: IORef m a -> (a -> (a, b)) -> m b
-- | Write a new value into an @CRef@, without imposing a memory -- | Write a new value into an @IORef@, without imposing a memory
-- barrier. This means that relaxed memory effects can be observed. -- barrier. This means that relaxed memory effects can be observed.
-- --
-- @since 1.0.0.0 -- @since 1.6.0.0
writeCRef :: CRef m a -> a -> m () writeIORef :: IORef m a -> a -> m ()
-- | Replace the value stored in a reference, with the -- | Replace the value stored in a reference, with the
-- barrier-to-reordering property that 'atomicModifyCRef' has. -- barrier-to-reordering property that 'atomicModifyIORef' has.
-- --
-- > atomicWriteCRef r a = atomicModifyCRef r $ const (a, ()) -- > atomicWriteIORef r a = atomicModifyIORef r $ const (a, ())
-- --
-- @since 1.0.0.0 -- @since 1.6.0.0
atomicWriteCRef :: CRef m a -> a -> m () atomicWriteIORef :: IORef m a -> a -> m ()
atomicWriteCRef r a = atomicModifyCRef r $ const (a, ()) atomicWriteIORef r a = atomicModifyIORef r $ const (a, ())
-- | Read the current value stored in a reference, returning a -- | Read the current value stored in a reference, returning a
-- @Ticket@, for use in future compare-and-swap operations. -- @Ticket@, for use in future compare-and-swap operations.
-- --
-- @since 1.0.0.0 -- @since 1.6.0.0
readForCAS :: CRef m a -> m (Ticket m a) readForCAS :: IORef m a -> m (Ticket m a)
-- | Extract the actual Haskell value from a @Ticket@. -- | Extract the actual Haskell value from a @Ticket@.
-- --
@ -434,28 +434,28 @@ class ( Monad m
peekTicket' :: Proxy m -> Ticket m a -> a peekTicket' :: Proxy m -> Ticket m a -> a
-- | Perform a machine-level compare-and-swap (CAS) operation on a -- | Perform a machine-level compare-and-swap (CAS) operation on a
-- @CRef@. Returns an indication of success and a @Ticket@ for the -- @IORef@. Returns an indication of success and a @Ticket@ for the
-- most current value in the @CRef@. -- most current value in the @IORef@.
-- --
-- This is strict in the \"new\" value argument. -- This is strict in the \"new\" value argument.
-- --
-- @since 1.0.0.0 -- @since 1.6.0.0
casCRef :: CRef m a -> Ticket m a -> a -> m (Bool, Ticket m a) casIORef :: IORef m a -> Ticket m a -> a -> m (Bool, Ticket m a)
-- | A replacement for 'atomicModifyCRef' using a compare-and-swap. -- | A replacement for 'atomicModifyIORef' using a compare-and-swap.
-- --
-- This is strict in the \"new\" value argument. -- This is strict in the \"new\" value argument.
-- --
-- @since 1.0.0.0 -- @since 1.6.0.0
modifyCRefCAS :: CRef m a -> (a -> (a, b)) -> m b modifyIORefCAS :: IORef m a -> (a -> (a, b)) -> m b
-- | A variant of 'modifyCRefCAS' which doesn't return a result. -- | A variant of 'modifyIORefCAS' which doesn't return a result.
-- --
-- > modifyCRefCAS_ cref f = modifyCRefCAS cref (\a -> (f a, ())) -- > modifyIORefCAS_ ioref f = modifyIORefCAS ioref (\a -> (f a, ()))
-- --
-- @since 1.0.0.0 -- @since 1.6.0.0
modifyCRefCAS_ :: CRef m a -> (a -> a) -> m () modifyIORefCAS_ :: IORef m a -> (a -> a) -> m ()
modifyCRefCAS_ cref f = modifyCRefCAS cref (\a -> (f a, ())) modifyIORefCAS_ ioref f = modifyIORefCAS ioref (\a -> (f a, ()))
-- | Perform an STM transaction atomically. -- | Perform an STM transaction atomically.
-- --
@ -687,14 +687,14 @@ newMVarN n a = do
peekTicket :: forall m a. MonadConc m => Ticket m a -> m a peekTicket :: forall m a. MonadConc m => Ticket m a -> m a
peekTicket t = pure $ peekTicket' (Proxy :: Proxy m) (t :: Ticket 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 -- | Compare-and-swap a value in a @IORef@, returning an indication of
-- success and the new value. -- success and the new value.
-- --
-- @since 1.0.0.0 -- @since 1.6.0.0
cas :: MonadConc m => CRef m a -> a -> m (Bool, a) cas :: MonadConc m => IORef m a -> a -> m (Bool, a)
cas cref a = do cas ioref a = do
tick <- readForCAS cref tick <- readForCAS ioref
(suc, tick') <- casCRef cref tick a (suc, tick') <- casIORef ioref tick a
a' <- peekTicket tick' a' <- peekTicket tick'
pure (suc, a') pure (suc, a')
@ -706,7 +706,7 @@ cas cref a = do
instance MonadConc IO where instance MonadConc IO where
type STM IO = IO.STM type STM IO = IO.STM
type MVar IO = IO.MVar type MVar IO = IO.MVar
type CRef IO = IO.IORef type IORef IO = IO.IORef
type Ticket IO = IO.Ticket type Ticket IO = IO.Ticket
type ThreadId IO = IO.ThreadId type ThreadId IO = IO.ThreadId
@ -728,30 +728,30 @@ instance MonadConc IO where
isCurrentThreadBound = IO.isCurrentThreadBound isCurrentThreadBound = IO.isCurrentThreadBound
getNumCapabilities = IO.getNumCapabilities getNumCapabilities = IO.getNumCapabilities
setNumCapabilities = IO.setNumCapabilities setNumCapabilities = IO.setNumCapabilities
readMVar = IO.readMVar readMVar = IO.readMVar
tryReadMVar = IO.tryReadMVar tryReadMVar = IO.tryReadMVar
myThreadId = IO.myThreadId myThreadId = IO.myThreadId
yield = IO.yield yield = IO.yield
threadDelay = IO.threadDelay threadDelay = IO.threadDelay
throwTo = IO.throwTo throwTo = IO.throwTo
newEmptyMVar = IO.newEmptyMVar newEmptyMVar = IO.newEmptyMVar
putMVar = IO.putMVar putMVar = IO.putMVar
tryPutMVar = IO.tryPutMVar tryPutMVar = IO.tryPutMVar
takeMVar = IO.takeMVar takeMVar = IO.takeMVar
tryTakeMVar = IO.tryTakeMVar tryTakeMVar = IO.tryTakeMVar
newCRef = IO.newIORef newIORef = IO.newIORef
readCRef = IO.readIORef readIORef = IO.readIORef
atomicModifyCRef = IO.atomicModifyIORef atomicModifyIORef = IO.atomicModifyIORef
writeCRef = IO.writeIORef writeIORef = IO.writeIORef
atomicWriteCRef = IO.atomicWriteIORef atomicWriteIORef = IO.atomicWriteIORef
readForCAS = IO.readForCAS readForCAS = IO.readForCAS
peekTicket' _ = IO.peekTicket peekTicket' _ = IO.peekTicket
casCRef = IO.casIORef casIORef = IO.casIORef
modifyCRefCAS = IO.atomicModifyIORefCAS modifyIORefCAS = IO.atomicModifyIORefCAS
atomically = IO.atomically atomically = IO.atomically
readTVarConc = IO.readTVarIO readTVarConc = IO.readTVarIO
-- | Label the current thread, if the given label is nonempty. -- | Label the current thread, if the given label is nonempty.
labelMe :: String -> IO () labelMe :: String -> IO ()
@ -786,7 +786,7 @@ fromIsConc = unIsConc
instance MonadConc m => MonadConc (IsConc m) where instance MonadConc m => MonadConc (IsConc m) where
type STM (IsConc m) = IsSTM (STM m) type STM (IsConc m) = IsSTM (STM m)
type MVar (IsConc m) = MVar m type MVar (IsConc m) = MVar m
type CRef (IsConc m) = CRef m type IORef (IsConc m) = IORef m
type Ticket (IsConc m) = Ticket m type Ticket (IsConc m) = Ticket m
type ThreadId (IsConc m) = ThreadId m type ThreadId (IsConc m) = ThreadId m
@ -799,33 +799,33 @@ instance MonadConc m => MonadConc (IsConc m) where
isCurrentThreadBound = toIsConc isCurrentThreadBound isCurrentThreadBound = toIsConc isCurrentThreadBound
getNumCapabilities = toIsConc getNumCapabilities getNumCapabilities = toIsConc getNumCapabilities
setNumCapabilities = toIsConc . setNumCapabilities setNumCapabilities = toIsConc . setNumCapabilities
myThreadId = toIsConc myThreadId myThreadId = toIsConc myThreadId
yield = toIsConc yield yield = toIsConc yield
threadDelay = toIsConc . threadDelay threadDelay = toIsConc . threadDelay
throwTo t = toIsConc . throwTo t throwTo t = toIsConc . throwTo t
newEmptyMVar = toIsConc newEmptyMVar newEmptyMVar = toIsConc newEmptyMVar
newEmptyMVarN = toIsConc . newEmptyMVarN newEmptyMVarN = toIsConc . newEmptyMVarN
readMVar = toIsConc . readMVar readMVar = toIsConc . readMVar
tryReadMVar = toIsConc . tryReadMVar tryReadMVar = toIsConc . tryReadMVar
putMVar v = toIsConc . putMVar v putMVar v = toIsConc . putMVar v
tryPutMVar v = toIsConc . tryPutMVar v tryPutMVar v = toIsConc . tryPutMVar v
takeMVar = toIsConc . takeMVar takeMVar = toIsConc . takeMVar
tryTakeMVar = toIsConc . tryTakeMVar tryTakeMVar = toIsConc . tryTakeMVar
newCRef = toIsConc . newCRef newIORef = toIsConc . newIORef
newCRefN n = toIsConc . newCRefN n newIORefN n = toIsConc . newIORefN n
readCRef = toIsConc . readCRef readIORef = toIsConc . readIORef
atomicModifyCRef r = toIsConc . atomicModifyCRef r atomicModifyIORef r = toIsConc . atomicModifyIORef r
writeCRef r = toIsConc . writeCRef r writeIORef r = toIsConc . writeIORef r
atomicWriteCRef r = toIsConc . atomicWriteCRef r atomicWriteIORef r = toIsConc . atomicWriteIORef r
readForCAS = toIsConc . readForCAS readForCAS = toIsConc . readForCAS
peekTicket' _ = peekTicket' (Proxy :: Proxy m) peekTicket' _ = peekTicket' (Proxy :: Proxy m)
casCRef r t = toIsConc . casCRef r t casIORef r t = toIsConc . casIORef r t
modifyCRefCAS r = toIsConc . modifyCRefCAS r modifyIORefCAS r = toIsConc . modifyIORefCAS r
modifyCRefCAS_ r = toIsConc . modifyCRefCAS_ r modifyIORefCAS_ r = toIsConc . modifyIORefCAS_ r
atomically = toIsConc . atomically . fromIsSTM atomically = toIsConc . atomically . fromIsSTM
readTVarConc = toIsConc . readTVarConc readTVarConc = toIsConc . readTVarConc
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- Transformer instances -- Transformer instances
@ -834,7 +834,7 @@ instance MonadConc m => MonadConc (IsConc m) where
instance C => MonadConc (T m) where { \ instance C => MonadConc (T m) where { \
type STM (T m) = STM m ; \ type STM (T m) = STM m ; \
type MVar (T m) = MVar m ; \ type MVar (T m) = MVar m ; \
type CRef (T m) = CRef m ; \ type IORef (T m) = IORef m ; \
type Ticket (T m) = Ticket m ; \ type Ticket (T m) = Ticket m ; \
type ThreadId (T m) = ThreadId m ; \ type ThreadId (T m) = ThreadId m ; \
\ \
@ -847,33 +847,33 @@ instance C => MonadConc (T m) where { \
\ \
isCurrentThreadBound = lift isCurrentThreadBound ; \ isCurrentThreadBound = lift isCurrentThreadBound ; \
\ \
getNumCapabilities = lift getNumCapabilities ; \ getNumCapabilities = lift getNumCapabilities ; \
setNumCapabilities = lift . setNumCapabilities ; \ setNumCapabilities = lift . setNumCapabilities ; \
myThreadId = lift myThreadId ; \ myThreadId = lift myThreadId ; \
yield = lift yield ; \ yield = lift yield ; \
threadDelay = lift . threadDelay ; \ threadDelay = lift . threadDelay ; \
throwTo t = lift . throwTo t ; \ throwTo t = lift . throwTo t ; \
newEmptyMVar = lift newEmptyMVar ; \ newEmptyMVar = lift newEmptyMVar ; \
newEmptyMVarN = lift . newEmptyMVarN ; \ newEmptyMVarN = lift . newEmptyMVarN ; \
readMVar = lift . readMVar ; \ readMVar = lift . readMVar ; \
tryReadMVar = lift . tryReadMVar ; \ tryReadMVar = lift . tryReadMVar ; \
putMVar v = lift . putMVar v ; \ putMVar v = lift . putMVar v ; \
tryPutMVar v = lift . tryPutMVar v ; \ tryPutMVar v = lift . tryPutMVar v ; \
takeMVar = lift . takeMVar ; \ takeMVar = lift . takeMVar ; \
tryTakeMVar = lift . tryTakeMVar ; \ tryTakeMVar = lift . tryTakeMVar ; \
newCRef = lift . newCRef ; \ newIORef = lift . newIORef ; \
newCRefN n = lift . newCRefN n ; \ newIORefN n = lift . newIORefN n ; \
readCRef = lift . readCRef ; \ readIORef = lift . readIORef ; \
atomicModifyCRef r = lift . atomicModifyCRef r ; \ atomicModifyIORef r = lift . atomicModifyIORef r ; \
writeCRef r = lift . writeCRef r ; \ writeIORef r = lift . writeIORef r ; \
atomicWriteCRef r = lift . atomicWriteCRef r ; \ atomicWriteIORef r = lift . atomicWriteIORef r ; \
readForCAS = lift . readForCAS ; \ readForCAS = lift . readForCAS ; \
peekTicket' _ = peekTicket' (Proxy :: Proxy m) ; \ peekTicket' _ = peekTicket' (Proxy :: Proxy m) ; \
casCRef r t = lift . casCRef r t ; \ casIORef r t = lift . casIORef r t ; \
modifyCRefCAS r = lift . modifyCRefCAS r ; \ modifyIORefCAS r = lift . modifyIORefCAS r ; \
modifyCRefCAS_ r = lift . modifyCRefCAS_ r ; \ modifyIORefCAS_ r = lift . modifyIORefCAS_ r ; \
atomically = lift . atomically ; \ atomically = lift . atomically ; \
readTVarConc = lift . readTVarConc } readTVarConc = lift . readTVarConc }
-- | New threads inherit the reader state of their parent, but do not -- | New threads inherit the reader state of their parent, but do not
-- communicate results back. -- communicate results back.

View File

@ -2,7 +2,7 @@
-- documentation, see http://haskell.org/cabal/users-guide/ -- documentation, see http://haskell.org/cabal/users-guide/
name: concurrency name: concurrency
version: 1.5.0.0 version: 1.6.0.0
synopsis: Typeclasses, functions, and data types for concurrency and STM. synopsis: Typeclasses, functions, and data types for concurrency and STM.
description: description:
@ -32,7 +32,7 @@ source-repository head
source-repository this source-repository this
type: git type: git
location: https://github.com/barrucadu/dejafu.git location: https://github.com/barrucadu/dejafu.git
tag: concurrency-1.5.0.0 tag: concurrency-1.6.0.0
library library
exposed-modules: Control.Monad.Conc.Class exposed-modules: Control.Monad.Conc.Class
@ -42,6 +42,7 @@ library
, Control.Concurrent.Classy.Async , Control.Concurrent.Classy.Async
, Control.Concurrent.Classy.Chan , Control.Concurrent.Classy.Chan
, Control.Concurrent.Classy.CRef , Control.Concurrent.Classy.CRef
, Control.Concurrent.Classy.IORef
, Control.Concurrent.Classy.MVar , Control.Concurrent.Classy.MVar
, Control.Concurrent.Classy.QSem , Control.Concurrent.Classy.QSem
, Control.Concurrent.Classy.QSemN , Control.Concurrent.Classy.QSemN

View File

@ -213,9 +213,9 @@ newEmptyMVarInt = newEmptyMVar
newMVarInt :: MonadConc m => Int -> m (MVar m Int) newMVarInt :: MonadConc m => Int -> m (MVar m Int)
newMVarInt = newMVar newMVarInt = newMVar
-- | Create a monomorphic @CRef@. -- | Create a monomorphic @IORef@.
newCRefInt :: MonadConc m => Int -> m (CRef m Int) newIORefInt :: MonadConc m => Int -> m (IORef m Int)
newCRefInt = newCRef newIORefInt = newIORef
-- | Create a monomorphic @TVar@. -- | Create a monomorphic @TVar@.
newTVarInt :: MonadSTM stm => Int -> stm (TVar stm Int) newTVarInt :: MonadSTM stm => Int -> stm (TVar stm Int)

View File

@ -60,9 +60,9 @@ deadlocks = join (mkAutoUpdate defaultUpdateSettings)
-- the program explicitly yields, the bounds don't need changing. -- the program explicitly yields, the bounds don't need changing.
nondeterministic :: forall m. MonadConc m => m Int nondeterministic :: forall m. MonadConc m => m Int
nondeterministic = do nondeterministic = do
var <- newCRef 0 var <- newIORef 0
let settings = (defaultUpdateSettings :: UpdateSettings m ()) let settings = (defaultUpdateSettings :: UpdateSettings m ())
{ updateAction = atomicModifyCRef var (\x -> (x+1, x)) } { updateAction = atomicModifyIORef var (\x -> (x+1, x)) }
auto <- mkAutoUpdate settings auto <- mkAutoUpdate settings
void auto void auto
auto auto
@ -84,7 +84,7 @@ defaultUpdateSettings = UpdateSettings
mkAutoUpdate :: MonadConc m => UpdateSettings m a -> m (m a) mkAutoUpdate :: MonadConc m => UpdateSettings m a -> m (m a)
mkAutoUpdate us = do mkAutoUpdate us = do
currRef <- newCRef Nothing currRef <- newIORef Nothing
needsRunning <- newEmptyMVar needsRunning <- newEmptyMVar
lastValue <- newEmptyMVar lastValue <- newEmptyMVar
@ -93,17 +93,17 @@ mkAutoUpdate us = do
a <- catchSome $ updateAction us a <- catchSome $ updateAction us
writeCRef currRef $ Just a writeIORef currRef $ Just a
void $ tryTakeMVar lastValue void $ tryTakeMVar lastValue
putMVar lastValue a putMVar lastValue a
threadDelay $ updateFreq us threadDelay $ updateFreq us
writeCRef currRef Nothing writeIORef currRef Nothing
void $ takeMVar lastValue void $ takeMVar lastValue
pure $ do pure $ do
mval <- readCRef currRef mval <- readIORef currRef
case mval of case mval of
Just val -> pure val Just val -> pure val
Nothing -> do Nothing -> do

View File

@ -119,7 +119,7 @@ _IDLING_ON = True
type ROnly m = RD.ReaderT (Sched m) m type ROnly m = RD.ReaderT (Sched m) m
newtype IVar m a = IVar (CRef m (IVarContents m a)) newtype IVar m a = IVar (IORef m (IVarContents m a))
data IVarContents m a = Full a | Empty | Blocked [a -> m ()] data IVarContents m a = Full a | Empty | Blocked [a -> m ()]
@ -205,7 +205,7 @@ runNewSessionAndWait name sched userComp = do
_ <- modifyHotVar (activeSessions sched) (\ set -> (S.insert sid set, ())) _ <- modifyHotVar (activeSessions sched) (\ set -> (S.insert sid set, ()))
-- Here we have an extra IORef... ugly. -- Here we have an extra IORef... ugly.
ref <- newCRef (error$ "Empty session-result ref ("++name++") should never be touched (sid "++ show sid++", "++show tid ++")") ref <- newIORef (error$ "Empty session-result ref ("++name++") should never be touched (sid "++ show sid++", "++show tid ++")")
newFlag <- newHotVar False newFlag <- newHotVar False
-- Push the new session: -- Push the new session:
_ <- modifyHotVar (sessions sched) (\ ls -> (Session sid newFlag : ls, ())) _ <- modifyHotVar (sessions sched) (\ ls -> (Session sid newFlag : ls, ()))
@ -213,11 +213,11 @@ runNewSessionAndWait name sched userComp = do
let userComp' = do ans <- userComp let userComp' = do ans <- userComp
-- This add-on to userComp will run only after userComp has completed successfully, -- This add-on to userComp will run only after userComp has completed successfully,
-- but that does NOT guarantee that userComp-forked computations have terminated: -- but that does NOT guarantee that userComp-forked computations have terminated:
io$ do writeCRef ref ans io$ do writeIORef ref ans
writeHotVarRaw newFlag True writeHotVarRaw newFlag True
modifyHotVar (activeSessions sched) (\ set -> (S.delete sid set, ())) modifyHotVar (activeSessions sched) (\ set -> (S.delete sid set, ()))
kont n = trivialCont$ "("++name++", sid "++show sid++", round "++show n++")" kont n = trivialCont$ "("++name++", sid "++show sid++", round "++show n++")"
loop n = do flg <- readCRef newFlag loop n = do flg <- readIORef newFlag
unless flg $ do unless flg $ do
rescheduleR 0 $ trivialCont$ "("++name++", sid "++show sid++")" rescheduleR 0 $ trivialCont$ "("++name++", sid "++show sid++")"
loop (n+1) loop (n+1)
@ -238,7 +238,7 @@ runNewSessionAndWait name sched userComp = do
-- By returning here we ARE implicitly reengaging the scheduler, since we -- By returning here we ARE implicitly reengaging the scheduler, since we
-- are already inside the rescheduleR loop on this thread -- are already inside the rescheduleR loop on this thread
-- (before runParIO was called in a nested fashion). -- (before runParIO was called in a nested fashion).
readCRef ref readIORef ref
{-# NOINLINE runParIO #-} {-# NOINLINE runParIO #-}
@ -285,7 +285,7 @@ runParIO userComp = do
putMVar workerDone cpu putMVar workerDone cpu
else do x <- runNewSessionAndWait "top-lvl main worker" sched userComp else do x <- runNewSessionAndWait "top-lvl main worker" sched userComp
-- When the main worker finishes we can tell the anonymous "system" workers: -- When the main worker finishes we can tell the anonymous "system" workers:
writeCRef topSessFlag True writeIORef topSessFlag True
putMVar mfin x putMVar mfin x
unregisterWorker tid unregisterWorker tid
@ -333,7 +333,7 @@ baseSessionID = 1000
{-# INLINE new #-} {-# INLINE new #-}
-- | Creates a new @IVar@ -- | Creates a new @IVar@
new :: MonadConc m => Par m (IVar m a) new :: MonadConc m => Par m (IVar m a)
new = io$ IVar <$> newCRef Empty new = io$ IVar <$> newIORef Empty
{-# INLINE get #-} {-# INLINE get #-}
-- | Read the value in an @IVar@. The 'get' operation can only return when the -- | Read the value in an @IVar@. The 'get' operation can only return when the
@ -342,7 +342,7 @@ new = io$ IVar <$> newCRef Empty
get (IVar vr) = get (IVar vr) =
callCC $ \kont -> callCC $ \kont ->
do do
e <- io$ readCRef vr e <- io$ readIORef vr
case e of case e of
Full a -> pure a Full a -> pure a
_ -> do _ -> do
@ -351,7 +351,7 @@ get (IVar vr) =
let resched = longjmpSched -- Invariant: kont must not be lost. let resched = longjmpSched -- Invariant: kont must not be lost.
-- Because we continue on the same processor the Sched stays the same: -- Because we continue on the same processor the Sched stays the same:
-- TODO: Try NOT using monadic values as first class. Check for performance effect: -- TODO: Try NOT using monadic values as first class. Check for performance effect:
join . io$ atomicModifyCRef vr $ \case join . io$ atomicModifyIORef vr $ \case
Empty -> (Blocked [pushWork sch . kont], resched) Empty -> (Blocked [pushWork sch . kont], resched)
Full a -> (Full a, pure a) -- kont is implicit here. Full a -> (Full a, pure a) -- kont is implicit here.
Blocked ks -> (Blocked (pushWork sch . kont:ks), resched) Blocked ks -> (Blocked (pushWork sch . kont:ks), resched)
@ -362,7 +362,7 @@ get (IVar vr) =
-- In this scheduler, puts immediately execute woken work in the current thread. -- In this scheduler, puts immediately execute woken work in the current thread.
put_ (IVar vr) !content = do put_ (IVar vr) !content = do
sched <- RD.ask sched <- RD.ask
ks <- io$ atomicModifyCRef vr $ \case ks <- io$ atomicModifyIORef vr $ \case
Empty -> (Full content, []) Empty -> (Full content, [])
Full _ -> error "multiple put" Full _ -> error "multiple put"
Blocked ks -> (Full content, ks) Blocked ks -> (Full content, ks)
@ -445,8 +445,8 @@ rescheduleR cnt kont = do
mtask <- lift $ popWork mysched mtask <- lift $ popWork mysched
case mtask of case mtask of
Nothing -> do Nothing -> do
Session _ finRef:_ <- lift $ readCRef $ sessions mysched Session _ finRef:_ <- lift $ readIORef $ sessions mysched
fin <- lift $ readCRef finRef fin <- lift $ readIORef finRef
if fin if fin
then kont (error "Direct.hs: The result value from rescheduleR should not be used.") then kont (error "Direct.hs: The result value from rescheduleR should not be used.")
else do else do

View File

@ -132,12 +132,12 @@ writeHotVarRaw :: MonadConc m => HotVar m a -> a -> m ()
{-# INLINE readHotVar #-} {-# INLINE readHotVar #-}
{-# INLINE writeHotVar #-} {-# INLINE writeHotVar #-}
type HotVar m a = CRef m a type HotVar m a = IORef m a
newHotVar = newCRef newHotVar = newIORef
modifyHotVar = atomicModifyCRef modifyHotVar = atomicModifyIORef
modifyHotVar_ v fn = atomicModifyCRef v (\a -> (fn a, ())) modifyHotVar_ v fn = atomicModifyIORef v (\a -> (fn a, ()))
readHotVar = readCRef readHotVar = readIORef
writeHotVar = writeCRef writeHotVar = writeIORef
readHotVarRaw = readHotVar readHotVarRaw = readHotVar
writeHotVarRaw = writeHotVar writeHotVarRaw = writeHotVar

View File

@ -215,13 +215,13 @@ work shortcircuit workitems = do
-- If there's only one capability don't bother with threads. -- If there's only one capability don't bother with threads.
driver 1 res kill = do driver 1 res kill = do
atomically . putTMVar kill $ failit res atomically . putTMVar kill $ failit res
remaining <- newCRef workitems remaining <- newIORef workitems
process remaining res process remaining res
-- Fork off as many threads as there are capabilities, and queue -- Fork off as many threads as there are capabilities, and queue
-- up the remaining work. -- up the remaining work.
driver caps res kill = do driver caps res kill = do
remaining <- newCRef workitems remaining <- newIORef workitems
tids <- mapM (\cap -> forkOn cap $ process remaining res) [0..caps-1] tids <- mapM (\cap -> forkOn cap $ process remaining res) [0..caps-1]
-- Construct an action to short-circuit the computation. -- Construct an action to short-circuit the computation.
@ -236,7 +236,7 @@ work shortcircuit workitems = do
-- Process a work item and store the result if it is a success, -- Process a work item and store the result if it is a success,
-- otherwise continue. -- otherwise continue.
process remaining res = do process remaining res = do
mitem <- atomicModifyCRef remaining $ \rs -> if null rs then ([], Nothing) else (tail rs, Just $ head rs) mitem <- atomicModifyIORef remaining $ \rs -> if null rs then ([], Nothing) else (tail rs, Just $ head rs)
case mitem of case mitem of
Just item -> do Just item -> do
fwrap <- item fwrap <- item

View File

@ -4,7 +4,7 @@
module Integration.Async where module Integration.Async where
import Control.Concurrent.Classy.Async import Control.Concurrent.Classy.Async
import Control.Concurrent.Classy.CRef import Control.Concurrent.Classy.IORef
import Control.Exception (AsyncException(..), Exception, import Control.Exception (AsyncException(..), Exception,
SomeException, fromException) SomeException, fromException)
import Control.Monad (when) import Control.Monad (when)
@ -132,28 +132,28 @@ async_poll2 = do
case_concurrently_ :: MonadConc m => m () case_concurrently_ :: MonadConc m => m ()
case_concurrently_ = do case_concurrently_ = do
ref <- newCRefInt 0 ref <- newIORefInt 0
() <- concurrently_ () <- concurrently_
(atomicModifyCRef ref (\x -> (x + 1, True))) (atomicModifyIORef ref (\x -> (x + 1, True)))
(atomicModifyCRef ref (\x -> (x + 2, 'x'))) (atomicModifyIORef ref (\x -> (x + 2, 'x')))
res <- readCRef ref res <- readIORef ref
res @?= 3 res @?= 3
case_replicateConcurrently :: MonadConc m => m () case_replicateConcurrently :: MonadConc m => m ()
case_replicateConcurrently = do case_replicateConcurrently = do
ref <- newCRefInt 0 ref <- newIORefInt 0
let action = atomicModifyCRef ref (\x -> (x + 1, x + 1)) let action = atomicModifyIORef ref (\x -> (x + 1, x + 1))
resList <- replicateConcurrently 4 action resList <- replicateConcurrently 4 action
resVal <- readCRef ref resVal <- readIORef ref
resVal @?= 4 resVal @?= 4
sort resList @?= [1..4] sort resList @?= [1..4]
case_replicateConcurrently_ :: MonadConc m => m () case_replicateConcurrently_ :: MonadConc m => m ()
case_replicateConcurrently_ = do case_replicateConcurrently_ = do
ref <- newCRefInt 0 ref <- newIORefInt 0
let action = atomicModifyCRef ref (\x -> (x + 1, x + 1)) let action = atomicModifyIORef ref (\x -> (x + 1, x + 1))
() <- replicateConcurrently_ 4 action () <- replicateConcurrently_ 4 action
resVal <- readCRef ref resVal <- readIORef ref
resVal @?= 4 resVal @?= 4
------------------------------------------------------------------------------- -------------------------------------------------------------------------------

View File

@ -81,51 +81,51 @@ compareTest act = do
-- reordered with other stores. -- reordered with other stores.
intelWP21 :: MonadConc m => m (Int, Int) intelWP21 :: MonadConc m => m (Int, Int)
intelWP21 = snd <$> litmus2 intelWP21 = snd <$> litmus2
(\x y -> writeCRef x 1 >> writeCRef y 1) (\x y -> writeIORef x 1 >> writeIORef y 1)
(\x y -> (,) <$> readCRef y <*> readCRef x) (\x y -> (,) <$> readIORef y <*> readIORef x)
-- | Stores are not reordered with older loads. -- | Stores are not reordered with older loads.
intelWP22 :: MonadConc m => m (Int, Int) intelWP22 :: MonadConc m => m (Int, Int)
intelWP22 = litmus2 intelWP22 = litmus2
(\x y -> do r1 <- readCRef x; writeCRef y 1; pure r1) (\x y -> do r1 <- readIORef x; writeIORef y 1; pure r1)
(\x y -> do r2 <- readCRef y; writeCRef x 1; pure r2) (\x y -> do r2 <- readIORef y; writeIORef x 1; pure r2)
-- | Loads may be reordered with older stores to different locations. -- | Loads may be reordered with older stores to different locations.
intelWP23 :: MonadConc m => m (Int, Int) intelWP23 :: MonadConc m => m (Int, Int)
intelWP23 = litmus2 intelWP23 = litmus2
(\x y -> writeCRef x 1 >> readCRef y) (\x y -> writeIORef x 1 >> readIORef y)
(\x y -> writeCRef y 1 >> readCRef x) (\x y -> writeIORef y 1 >> readIORef x)
-- | Loads are not reordered with older stores to the same location. -- | Loads are not reordered with older stores to the same location.
intelWP24 :: MonadConc m => m (Int, Int) intelWP24 :: MonadConc m => m (Int, Int)
intelWP24 = litmus2 intelWP24 = litmus2
(\x _ -> writeCRef x 1 >> readCRef x) (\x _ -> writeIORef x 1 >> readIORef x)
(\_ y -> writeCRef y 1 >> readCRef y) (\_ y -> writeIORef y 1 >> readIORef y)
-- | Intra-processor forwarding is allowed -- | Intra-processor forwarding is allowed
intelWP25 :: MonadConc m => m ((Int, Int), (Int, Int)) intelWP25 :: MonadConc m => m ((Int, Int), (Int, Int))
intelWP25 = litmus2 intelWP25 = litmus2
(\x y -> do writeCRef x 1; r1 <- readCRef x; r2 <- readCRef y; pure (r1, r2)) (\x y -> do writeIORef x 1; r1 <- readIORef x; r2 <- readIORef y; pure (r1, r2))
(\x y -> do writeCRef y 1; r3 <- readCRef y; r4 <- readCRef x; pure (r3, r4)) (\x y -> do writeIORef y 1; r3 <- readIORef y; r4 <- readIORef x; pure (r3, r4))
-- | Stores are transitively visible. -- | Stores are transitively visible.
intelWP26 :: MonadConc m => m (Int, Int, Int) intelWP26 :: MonadConc m => m (Int, Int, Int)
intelWP26 = do intelWP26 = do
x <- newCRef 0 x <- newIORef 0
y <- newCRef 0 y <- newIORef 0
j1 <- spawn (writeCRef x 1) j1 <- spawn (writeIORef x 1)
j2 <- spawn (do r1 <- readCRef x; writeCRef x 1; pure r1) j2 <- spawn (do r1 <- readIORef x; writeIORef x 1; pure r1)
j3 <- spawn (do r2 <- readCRef y; r3 <- readCRef x; pure (r2,r3)) j3 <- spawn (do r2 <- readIORef y; r3 <- readIORef x; pure (r2,r3))
(\() r1 (r2,r3) -> (r1,r2,r3)) <$> readMVar j1 <*> readMVar j2 <*> readMVar j3 (\() r1 (r2,r3) -> (r1,r2,r3)) <$> readMVar j1 <*> readMVar j2 <*> readMVar j3
-- | Total order on stores to the same location. -- | Total order on stores to the same location.
intelWP27 :: MonadConc m => m ((Int, Int), (Int, Int)) intelWP27 :: MonadConc m => m ((Int, Int), (Int, Int))
intelWP27 = do intelWP27 = do
x <- newCRef 0 x <- newIORef 0
j1 <- spawn (writeCRef x 1) j1 <- spawn (writeIORef x 1)
j2 <- spawn (writeCRef x 2) j2 <- spawn (writeIORef x 2)
j3 <- spawn (do r1 <- readCRef x; r2 <- readCRef x; pure (r1, r2)) j3 <- spawn (do r1 <- readIORef x; r2 <- readIORef x; pure (r1, r2))
j4 <- spawn (do r3 <- readCRef x; r4 <- readCRef x; pure (r3, r4)) j4 <- spawn (do r3 <- readIORef x; r4 <- readIORef x; pure (r3, r4))
(\() () r12 r23 -> (r12, r23)) <$> readMVar j1 <*> readMVar j2 <*> readMVar j3 <*> readMVar j4 (\() () r12 r23 -> (r12, r23)) <$> readMVar j1 <*> readMVar j2 <*> readMVar j3 <*> readMVar j4
-- | Independent Read Independent Write. -- | Independent Read Independent Write.
@ -134,24 +134,24 @@ intelWP27 = do
-- ((1,0),(1,0)). Intel (and TSO/PSO) forbid it. -- ((1,0),(1,0)). Intel (and TSO/PSO) forbid it.
intelWP28 :: MonadConc m => m ((Int, Int), (Int, Int)) intelWP28 :: MonadConc m => m ((Int, Int), (Int, Int))
intelWP28 = do intelWP28 = do
x <- newCRef 0 x <- newIORef 0
y <- newCRef 0 y <- newIORef 0
j1 <- spawn (writeCRef x 1) j1 <- spawn (writeIORef x 1)
j2 <- spawn (writeCRef y 1) j2 <- spawn (writeIORef y 1)
j3 <- spawn (do r1 <- readCRef x; r2 <- readCRef y; pure (r1, r2)) j3 <- spawn (do r1 <- readIORef x; r2 <- readIORef y; pure (r1, r2))
j4 <- spawn (do r3 <- readCRef y; r4 <- readCRef x; pure (r3, r4)) j4 <- spawn (do r3 <- readIORef y; r4 <- readIORef x; pure (r3, r4))
(\() () r12 r23 -> (r12, r23)) <$> readMVar j1 <*> readMVar j2 <*> readMVar j3 <*> readMVar j4 (\() () r12 r23 -> (r12, r23)) <$> readMVar j1 <*> readMVar j2 <*> readMVar j3 <*> readMVar j4
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- | Create two @CRef@s, fork the two threads, and return the result. -- | Create two @IORef@s, fork the two threads, and return the result.
litmus2 :: MonadConc m litmus2 :: MonadConc m
=> (CRef m Int -> CRef m Int -> m b) => (IORef m Int -> IORef m Int -> m b)
-> (CRef m Int -> CRef m Int -> m c) -> (IORef m Int -> IORef m Int -> m c)
-> m (b, c) -> m (b, c)
litmus2 thread1 thread2 = do litmus2 thread1 thread2 = do
x <- newCRef 0 x <- newIORef 0
y <- newCRef 0 y <- newIORef 0
j1 <- spawn (thread1 x y) j1 <- spawn (thread1 x y)
j2 <- spawn (thread2 x y) j2 <- spawn (thread2 x y)
(,) <$> readMVar j1 <*> readMVar j2 (,) <$> readMVar j1 <*> readMVar j2

View File

@ -18,7 +18,7 @@ tests :: [TestTree]
tests = tests =
[ testGroup "Threading" threadingTests [ testGroup "Threading" threadingTests
, testGroup "MVar" mvarTests , testGroup "MVar" mvarTests
, testGroup "CRef" crefTests , testGroup "IORef" iorefTests
, testGroup "STM" stmTests , testGroup "STM" stmTests
, testGroup "Exceptions" exceptionTests , testGroup "Exceptions" exceptionTests
, testGroup "Capabilities" capabilityTests , testGroup "Capabilities" capabilityTests
@ -40,9 +40,9 @@ threadingTests = toTestList
(/=) <$> myThreadId <*> readMVar tid (/=) <$> myThreadId <*> readMVar tid
, djfuT "A thread doesn't wait for its children before terminating" (gives' [Nothing, Just ()]) $ do , djfuT "A thread doesn't wait for its children before terminating" (gives' [Nothing, Just ()]) $ do
x <- newCRef Nothing x <- newIORef Nothing
_ <- fork . writeCRef x $ Just () _ <- fork . writeIORef x $ Just ()
readCRef x readIORef x
, djfuT "The main thread is bound" (gives' [(True, True)]) $ do , djfuT "The main thread is bound" (gives' [(True, True)]) $ do
b1 <- isCurrentThreadBound b1 <- isCurrentThreadBound
@ -117,58 +117,58 @@ mvarTests = toTestList
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
crefTests :: [TestTree] iorefTests :: [TestTree]
crefTests = toTestList iorefTests = toTestList
[ djfuT "Racey CRef computations are nondeterministic" (gives' [0,1]) $ do [ djfuT "Racey IORef computations are nondeterministic" (gives' [0,1]) $ do
x <- newCRefInt 0 x <- newIORefInt 0
j1 <- spawn $ writeCRef x 0 j1 <- spawn $ writeIORef x 0
j2 <- spawn $ writeCRef x 1 j2 <- spawn $ writeIORef x 1
takeMVar j1 takeMVar j1
takeMVar j2 takeMVar j2
readCRef x readIORef x
, djfuT "CASing CRef changes its value" (gives' [0,1]) $ do , djfuT "CASing IORef changes its value" (gives' [0,1]) $ do
x <- newCRefInt 0 x <- newIORefInt 0
_ <- fork $ modifyCRefCAS x (const (1, ())) _ <- fork $ modifyIORefCAS x (const (1, ()))
readCRef x readIORef x
, djfuT "Racey CAS computations are nondeterministic" (gives' [(True, 2), (False, 2)]) $ do , djfuT "Racey CAS computations are nondeterministic" (gives' [(True, 2), (False, 2)]) $ do
x <- newCRefInt 0 x <- newIORefInt 0
t <- readForCAS x t <- readForCAS x
j <- spawn $ casCRef x t 1 j <- spawn $ casIORef x t 1
writeCRef x 2 writeIORef x 2
b <- fst <$> readMVar j b <- fst <$> readMVar j
v <- readCRef x v <- readIORef x
pure (b, v) pure (b, v)
, djfuT "A failed CAS gives an updated ticket" (gives' [(True, 1), (True, 2)]) $ do , djfuT "A failed CAS gives an updated ticket" (gives' [(True, 1), (True, 2)]) $ do
x <- newCRefInt 0 x <- newIORefInt 0
t <- readForCAS x t <- readForCAS x
v <- newEmptyMVar v <- newEmptyMVar
j <- spawn $ do j <- spawn $ do
o@(f, t') <- casCRef x t 1 o@(f, t') <- casIORef x t 1
takeMVar v takeMVar v
if f then pure o else casCRef x t' 1 if f then pure o else casIORef x t' 1
writeCRef x 2 writeIORef x 2
putMVar v () putMVar v ()
b <- fst <$> readMVar j b <- fst <$> readMVar j
o <- readCRef x o <- readIORef x
pure (b, o) pure (b, o)
, djfuT "A ticket is only good for one CAS" (gives' [(True, False, 1), (False, True, 2)]) $ do , djfuT "A ticket is only good for one CAS" (gives' [(True, False, 1), (False, True, 2)]) $ do
x <- newCRefInt 0 x <- newIORefInt 0
t <- readForCAS x t <- readForCAS x
j1 <- spawn $ casCRef x t 1 j1 <- spawn $ casIORef x t 1
j2 <- spawn $ casCRef x t 2 j2 <- spawn $ casIORef x t 2
b1 <- fst <$> readMVar j1 b1 <- fst <$> readMVar j1
b2 <- fst <$> readMVar j2 b2 <- fst <$> readMVar j2
v <- readCRef x v <- readIORef x
pure (b1, b2, v) pure (b1, b2, v)
, djfuT "CRef writes may be delayed" (gives' [0,1]) $ do , djfuT "IORef writes may be delayed" (gives' [0,1]) $ do
x <- newCRefInt 0 x <- newIORefInt 0
writeCRef x 1 writeIORef x 1
takeMVar =<< spawn (readCRef x) takeMVar =<< spawn (readIORef x)
] ]
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
@ -312,18 +312,18 @@ hacksTests = toTestList
, testGroup "DontCheck" , testGroup "DontCheck"
[ djfuT "Inner action is run with a deterministic scheduler" (gives' [1]) $ [ djfuT "Inner action is run with a deterministic scheduler" (gives' [1]) $
dontCheck Nothing $ do dontCheck Nothing $ do
r <- newCRefInt 1 r <- newIORefInt 1
_ <- fork (atomicWriteCRef r 2) _ <- fork (atomicWriteIORef r 2)
readCRef r readIORef r
, djfuT "Threads created by the inner action persist in the outside" (gives' [1,2]) $ do , djfuT "Threads created by the inner action persist in the outside" (gives' [1,2]) $ do
(ref, trigger) <- dontCheck Nothing $ do (ref, trigger) <- dontCheck Nothing $ do
r <- newCRefInt 1 r <- newIORefInt 1
v <- newEmptyMVar v <- newEmptyMVar
_ <- fork (takeMVar v >> atomicWriteCRef r 2) _ <- fork (takeMVar v >> atomicWriteIORef r 2)
pure (r, v) pure (r, v)
putMVar trigger () putMVar trigger ()
readCRef ref readIORef ref
, djfuT "Bound threads created on the inside are bound on the outside" (gives' [True]) $ do , djfuT "Bound threads created on the inside are bound on the outside" (gives' [True]) $ do
(out, trigger) <- dontCheck Nothing $ do (out, trigger) <- dontCheck Nothing $ do
@ -344,10 +344,10 @@ hacksTests = toTestList
, djfuT "Inner action is run under sequential consistency" (gives' [1]) $ do , djfuT "Inner action is run under sequential consistency" (gives' [1]) $ do
x <- dontCheck Nothing $ do x <- dontCheck Nothing $ do
x <- newCRefInt 0 x <- newIORefInt 0
writeCRef x 1 writeIORef x 1
pure x pure x
takeMVar =<< spawn (readCRef x) takeMVar =<< spawn (readIORef x)
] ]
] ]

View File

@ -3,7 +3,7 @@ module Integration.Names where
import Control.Concurrent.Classy hiding (check) import Control.Concurrent.Classy hiding (check)
import Data.Maybe (mapMaybe) import Data.Maybe (mapMaybe)
import Test.DejaFu.Conc (ConcIO) import Test.DejaFu.Conc (ConcIO)
import Test.DejaFu.Internal (crefOf, mvarOf, simplifyAction, import Test.DejaFu.Internal (iorefOf, mvarOf, simplifyAction,
tidsOf, tvarsOf) tidsOf, tvarsOf)
import Test.DejaFu.SCT (runSCT) import Test.DejaFu.SCT (runSCT)
import Test.DejaFu.Types import Test.DejaFu.Types
@ -15,7 +15,7 @@ tests :: [TestTree]
tests = tests =
toTestList toTestList
[ testCase "MVar names" testMVarNames [ testCase "MVar names" testMVarNames
, testCase "CRef names" testCRefNames , testCase "IORef names" testIORefNames
, testCase "TVar names" testTVarNames , testCase "TVar names" testTVarNames
, testCase "Thread names" testThreadNames , testCase "Thread names" testThreadNames
] ]
@ -52,24 +52,24 @@ testMVarNames =
let validMVid = maybe False (`elem` [mvarName1, mvarName2]) . mvarName let validMVid = maybe False (`elem` [mvarName1, mvarName2]) . mvarName
in all validMVid . mapMaybe mvar in all validMVid . mapMaybe mvar
testCRefNames :: Assertion testIORefNames :: Assertion
testCRefNames = testIORefNames =
check "All traces should use only required CRef names" checkCRefs $ do check "All traces should use only required IORef names" checkIORefs $ do
x <- newCRefN crefName1 (0::Int) x <- newIORefN iorefName1 (0::Int)
y <- newCRefN crefName2 (0::Int) y <- newIORefN iorefName2 (0::Int)
_ <- fork $ modifyCRefCAS x (const (1, ())) _ <- fork $ modifyIORefCAS x (const (1, ()))
_ <- fork $ writeCRef y 2 _ <- fork $ writeIORef y 2
(,) <$> readCRef x <*> readCRef y (,) <$> readIORef x <*> readIORef y
where where
crefName1 = "cref-one" iorefName1 = "ioref-one"
crefName2 = "cref-two" iorefName2 = "ioref-two"
crefName (CRefId (Id (Just n) _)) = Just n iorefName (IORefId (Id (Just n) _)) = Just n
crefName _ = Nothing iorefName _ = Nothing
cref (NewCRef ref) = Just ref ioref (NewIORef ref) = Just ref
cref a = crefOf (simplifyAction a) ioref a = iorefOf (simplifyAction a)
checkCRefs = checkIORefs =
let validCRef = maybe False (`elem` [crefName1, crefName2]) . crefName let validIORef = maybe False (`elem` [iorefName1, iorefName2]) . iorefName
in all validCRef . mapMaybe cref in all validIORef . mapMaybe ioref
testTVarNames :: Assertion testTVarNames :: Assertion
testTVarNames = testTVarNames =

View File

@ -16,9 +16,9 @@ import QSemN
tests :: [TestTree] tests :: [TestTree]
tests = toTestList tests = toTestList
[ djfu "https://github.com/barrucadu/dejafu/issues/40" (gives' [0,1]) $ do [ djfu "https://github.com/barrucadu/dejafu/issues/40" (gives' [0,1]) $ do
x <- newCRefInt 0 x <- newIORefInt 0
_ <- fork $ myThreadId >> writeCRef x 1 _ <- fork $ myThreadId >> writeIORef x 1
readCRef x readIORef x
, djfu "https://github.com/barrucadu/dejafu/issues/55" (gives' [True]) $ do , djfu "https://github.com/barrucadu/dejafu/issues/55" (gives' [True]) $ do
a <- atomically newTQueue a <- atomically newTQueue

View File

@ -21,7 +21,7 @@ import Common
tests :: [TestTree] tests :: [TestTree]
tests = tests =
[ testGroup "MVar" mvarTests [ testGroup "MVar" mvarTests
, testGroup "CRef" crefTests , testGroup "IORef" iorefTests
, testGroup "STM" stmTests , testGroup "STM" stmTests
, testGroup "Exceptions" exceptionTests , testGroup "Exceptions" exceptionTests
, testGroup "Capabilities" capabilityTests , testGroup "Capabilities" capabilityTests
@ -86,47 +86,47 @@ mvarTests = toTestList
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
crefTests :: [TestTree] iorefTests :: [TestTree]
crefTests = toTestList iorefTests = toTestList
[ djfu "Reading a non-updated CRef gives its initial value" (gives' [True]) $ do [ djfu "Reading a non-updated IORef gives its initial value" (gives' [True]) $ do
ref <- newCRefInt 5 ref <- newIORefInt 5
(5==) <$> readCRef ref (5==) <$> readIORef ref
, djfu "Reading an updated CRef gives its new value" (gives' [True]) $ do , djfu "Reading an updated IORef gives its new value" (gives' [True]) $ do
ref <- newCRefInt 5 ref <- newIORefInt 5
writeCRef ref 6 writeIORef ref 6
(6==) <$> readCRef ref (6==) <$> readIORef ref
, djfu "Updating a CRef by a function changes its value" (gives' [True]) $ do , djfu "Updating a IORef by a function changes its value" (gives' [True]) $ do
ref <- newCRefInt 5 ref <- newIORefInt 5
atomicModifyCRef ref (\i -> (i+1, ())) atomicModifyIORef ref (\i -> (i+1, ()))
(6==) <$> readCRef ref (6==) <$> readIORef ref
, djfu "A ticket contains the value of the CRef at the time of its creation" (gives' [True]) $ do , djfu "A ticket contains the value of the IORef at the time of its creation" (gives' [True]) $ do
ref <- newCRefInt 5 ref <- newIORefInt 5
tick <- readForCAS ref tick <- readForCAS ref
writeCRef ref 6 writeIORef ref 6
(5==) <$> peekTicket tick (5==) <$> peekTicket tick
, djfu "Compare-and-swap returns a ticket containing the new value" (gives' [True]) $ do , djfu "Compare-and-swap returns a ticket containing the new value" (gives' [True]) $ do
ref <- newCRefInt 5 ref <- newIORefInt 5
tick <- readForCAS ref tick <- readForCAS ref
(_, tick') <- casCRef ref tick 6 (_, tick') <- casIORef ref tick 6
(6==) <$> peekTicket tick' (6==) <$> peekTicket tick'
, djfu "Compare-and-swap on an unmodified CRef succeeds" (gives' [True]) $ do , djfu "Compare-and-swap on an unmodified IORef succeeds" (gives' [True]) $ do
ref <- newCRefInt 5 ref <- newIORefInt 5
tick <- readForCAS ref tick <- readForCAS ref
(suc, _) <- casCRef ref tick 6 (suc, _) <- casIORef ref tick 6
val <- readCRef ref val <- readIORef ref
pure (suc && (6 == val)) pure (suc && (6 == val))
, djfu "Compare-and-swap on a modified CRef fails" (gives' [True]) $ do , djfu "Compare-and-swap on a modified IORef fails" (gives' [True]) $ do
ref <- newCRefInt 5 ref <- newIORefInt 5
tick <- readForCAS ref tick <- readForCAS ref
writeCRef ref 6 writeIORef ref 6
(suc, _) <- casCRef ref tick 7 (suc, _) <- casIORef ref tick 7
val <- readCRef ref val <- readIORef ref
pure (not suc && 7 /= val) pure (not suc && 7 /= val)
] ]
@ -292,11 +292,11 @@ hacksTests = toTestList
, toTestList . testGroup "Snapshotting" $ let snapshotTest n p conc = W n conc p ("randomly", randomly (mkStdGen 0) 150) in , toTestList . testGroup "Snapshotting" $ let snapshotTest n p conc = W n conc p ("randomly", randomly (mkStdGen 0) 150) in
[ snapshotTest "State updates are applied correctly" (gives' [2]) $ do [ snapshotTest "State updates are applied correctly" (gives' [2]) $ do
r <- dontCheck Nothing $ do r <- dontCheck Nothing $ do
r <- newCRefInt 0 r <- newIORefInt 0
writeCRef r 1 writeIORef r 1
writeCRef r 2 writeIORef r 2
pure r pure r
readCRef r readIORef r
, snapshotTest "Lifted IO is re-run (1)" (gives' [2..151]) $ do , snapshotTest "Lifted IO is re-run (1)" (gives' [2..151]) $ do
r <- dontCheck Nothing $ do r <- dontCheck Nothing $ do

View File

@ -162,12 +162,12 @@ commonProps = toTestList
, testProperty "isBarrier a ==> synchronises a r" $ do , testProperty "isBarrier a ==> synchronises a r" $ do
a <- H.forAll (HGen.filter D.isBarrier genActionType) a <- H.forAll (HGen.filter D.isBarrier genActionType)
r <- H.forAll genCRefId r <- H.forAll genIORefId
H.assert (D.synchronises a r) H.assert (D.synchronises a r)
, testProperty "isCommit a r ==> synchronises a r" $ do , testProperty "isCommit a r ==> synchronises a r" $ do
a <- H.forAll genPartiallySynchronisedActionType a <- H.forAll genPartiallySynchronisedActionType
case D.crefOf a of case D.iorefOf a of
Just r -> H.assert (D.synchronises a r) Just r -> H.assert (D.synchronises a r)
_ -> H.discard _ -> H.discard
] ]
@ -179,8 +179,8 @@ memoryProps = toTestList
[ testProperty "bufferWrite emptyBuffer k c a /= emptyBuffer" $ do [ testProperty "bufferWrite emptyBuffer k c a /= emptyBuffer" $ do
k <- H.forAll genWBKey k <- H.forAll genWBKey
a <- H.forAll genInt a <- H.forAll genInt
res <- crefProp $ \cref -> do res <- iorefProp $ \ioref -> do
wb <- Mem.bufferWrite Mem.emptyBuffer k cref a wb <- Mem.bufferWrite Mem.emptyBuffer k ioref a
wb `eqWB` Mem.emptyBuffer wb `eqWB` Mem.emptyBuffer
H.assert (not res) H.assert (not res)
@ -194,8 +194,8 @@ memoryProps = toTestList
, testProperty "commitWrite (bufferWrite emptyBuffer k a) k == emptyBuffer" $ do , testProperty "commitWrite (bufferWrite emptyBuffer k a) k == emptyBuffer" $ do
k <- H.forAll genWBKey k <- H.forAll genWBKey
a <- H.forAll genInt a <- H.forAll genInt
res <- crefProp $ \cref -> do res <- iorefProp $ \ioref -> do
wb1 <- Mem.bufferWrite Mem.emptyBuffer k cref a wb1 <- Mem.bufferWrite Mem.emptyBuffer k ioref a
wb2 <- Mem.commitWrite wb1 k wb2 <- Mem.commitWrite wb1 k
wb2 `eqWB` Mem.emptyBuffer wb2 `eqWB` Mem.emptyBuffer
H.assert res H.assert res
@ -203,19 +203,19 @@ memoryProps = toTestList
, testProperty "Single buffered write/read from same thread" $ do , testProperty "Single buffered write/read from same thread" $ do
k@(tid, _) <- H.forAll genWBKey k@(tid, _) <- H.forAll genWBKey
a <- H.forAll genInt a <- H.forAll genInt
res <- crefProp $ \cref -> do res <- iorefProp $ \ioref -> do
_ <- Mem.bufferWrite Mem.emptyBuffer k cref a _ <- Mem.bufferWrite Mem.emptyBuffer k ioref a
Mem.readCRef cref tid Mem.readIORef ioref tid
a H.=== res a H.=== res
, testProperty "Overriding buffered write/read from same thread" $ do , testProperty "Overriding buffered write/read from same thread" $ do
k@(tid, _) <- H.forAll genWBKey k@(tid, _) <- H.forAll genWBKey
a1 <- H.forAll genInt a1 <- H.forAll genInt
a2 <- H.forAll genInt a2 <- H.forAll genInt
res <- crefProp $ \cref -> do res <- iorefProp $ \ioref -> do
_ <- Mem.bufferWrite Mem.emptyBuffer k cref a1 _ <- Mem.bufferWrite Mem.emptyBuffer k ioref a1
_ <- Mem.bufferWrite Mem.emptyBuffer k cref a2 _ <- Mem.bufferWrite Mem.emptyBuffer k ioref a2
Mem.readCRef cref tid Mem.readIORef ioref tid
a2 H.=== res a2 H.=== res
, testProperty "Buffered write/read from different thread" $ do , testProperty "Buffered write/read from different thread" $ do
@ -223,22 +223,22 @@ memoryProps = toTestList
k2 <- H.forAll (HGen.filter ((/=tid) . fst) genWBKey) k2 <- H.forAll (HGen.filter ((/=tid) . fst) genWBKey)
a1 <- H.forAll genInt a1 <- H.forAll genInt
a2 <- H.forAll genInt a2 <- H.forAll genInt
res <- crefProp $ \cref -> do res <- iorefProp $ \ioref -> do
_ <- Mem.bufferWrite Mem.emptyBuffer k1 cref a1 _ <- Mem.bufferWrite Mem.emptyBuffer k1 ioref a1
_ <- Mem.bufferWrite Mem.emptyBuffer k2 cref a2 _ <- Mem.bufferWrite Mem.emptyBuffer k2 ioref a2
Mem.readCRef cref tid Mem.readIORef ioref tid
a1 H.=== res a1 H.=== res
] ]
where where
crefProp iorefProp
:: Show a :: Show a
=> (D.ModelCRef IO Int -> IO a) => (D.ModelIORef IO Int -> IO a)
-> H.PropertyT IO a -> H.PropertyT IO a
crefProp p = do iorefProp p = do
crefId <- H.forAll genCRefId iorefId <- H.forAll genIORefId
liftIO $ do liftIO $ do
cref <- makeCRef crefId ioref <- makeIORef iorefId
p cref p ioref
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
@ -278,8 +278,8 @@ sctProps = toTestList
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- Utils -- Utils
makeCRef :: D.CRefId -> IO (D.ModelCRef IO Int) makeIORef :: D.IORefId -> IO (D.ModelIORef IO Int)
makeCRef crid = D.ModelCRef crid <$> C.newCRef (M.empty, 0, 42) makeIORef iorid = D.ModelIORef iorid <$> C.newIORef (M.empty, 0, 42)
-- equality for writebuffers is a little tricky as we can't directly -- equality for writebuffers is a little tricky as we can't directly
-- compare the buffered values, so we compare everything else: -- compare the buffered values, so we compare everything else:
@ -288,7 +288,7 @@ makeCRef crid = D.ModelCRef crid <$> C.newCRef (M.empty, 0, 42)
-- - each pair of buffers for the same key must have an equal sequence of writes -- - each pair of buffers for the same key must have an equal sequence of writes
-- --
-- individual writes are compared like so: -- individual writes are compared like so:
-- - the threadid and crefid must be the same -- - the threadid and iorefid must be the same
-- - the cache and number of writes inside the ref must be the same -- - the cache and number of writes inside the ref must be the same
eqWB :: Mem.WriteBuffer IO -> Mem.WriteBuffer IO -> IO Bool eqWB :: Mem.WriteBuffer IO -> Mem.WriteBuffer IO -> IO Bool
eqWB (Mem.WriteBuffer wb1) (Mem.WriteBuffer wb2) = andM (pure (ks1 == ks2) : eqWB (Mem.WriteBuffer wb1) (Mem.WriteBuffer wb2) = andM (pure (ks1 == ks2) :
@ -301,10 +301,10 @@ eqWB (Mem.WriteBuffer wb1) (Mem.WriteBuffer wb2) = andM (pure (ks1 == ks2) :
ks1 = M.keys $ M.filter (not . S.null) wb1 ks1 = M.keys $ M.filter (not . S.null) wb1
ks2 = M.keys $ M.filter (not . S.null) wb2 ks2 = M.keys $ M.filter (not . S.null) wb2
eqBW (Mem.BufferedWrite t1 (D.ModelCRef crid1 ref1) _) (Mem.BufferedWrite t2 (D.ModelCRef crid2 ref2) _) = do eqBW (Mem.BufferedWrite t1 (D.ModelIORef iorid1 ref1) _) (Mem.BufferedWrite t2 (D.ModelIORef iorid2 ref2) _) = do
d1 <- (\(m,i,_) -> (M.keys m, i)) <$> C.readCRef ref1 d1 <- (\(m,i,_) -> (M.keys m, i)) <$> C.readIORef ref1
d2 <- (\(m,i,_) -> (M.keys m, i)) <$> C.readCRef ref2 d2 <- (\(m,i,_) -> (M.keys m, i)) <$> C.readIORef ref2
pure (t1 == t2 && crid1 == crid2 && d1 == d2) pure (t1 == t2 && iorid1 == iorid2 && d1 == d2)
andM [] = pure True andM [] = pure True
andM (p:ps) = do andM (p:ps) = do
@ -322,8 +322,8 @@ infixr 0 ==>
genThreadId :: H.Gen D.ThreadId genThreadId :: H.Gen D.ThreadId
genThreadId = D.ThreadId <$> genId genThreadId = D.ThreadId <$> genId
genCRefId :: H.Gen D.CRefId genIORefId :: H.Gen D.IORefId
genCRefId = D.CRefId <$> genId genIORefId = D.IORefId <$> genId
genMVarId :: H.Gen D.MVarId genMVarId :: H.Gen D.MVarId
genMVarId = D.MVarId <$> genId genMVarId = D.MVarId <$> genId
@ -347,8 +347,8 @@ genFailure = HGen.element $
, E.toException E.NonTermination , E.toException E.NonTermination
] ]
genWBKey :: H.Gen (D.ThreadId, Maybe D.CRefId) genWBKey :: H.Gen (D.ThreadId, Maybe D.IORefId)
genWBKey = (,) <$> genThreadId <*> HGen.maybe genCRefId genWBKey = (,) <$> genThreadId <*> HGen.maybe genIORefId
genThreadAction :: H.Gen D.ThreadAction genThreadAction :: H.Gen D.ThreadAction
genThreadAction = HGen.choice genThreadAction = HGen.choice
@ -368,14 +368,14 @@ genThreadAction = HGen.choice
, D.TakeMVar <$> genMVarId <*> genSmallList genThreadId , D.TakeMVar <$> genMVarId <*> genSmallList genThreadId
, D.BlockedTakeMVar <$> genMVarId , D.BlockedTakeMVar <$> genMVarId
, D.TryTakeMVar <$> genMVarId <*> HGen.bool <*> genSmallList genThreadId , D.TryTakeMVar <$> genMVarId <*> HGen.bool <*> genSmallList genThreadId
, D.NewCRef <$> genCRefId , D.NewIORef <$> genIORefId
, D.ReadCRef <$> genCRefId , D.ReadIORef <$> genIORefId
, D.ReadCRefCas <$> genCRefId , D.ReadIORefCas <$> genIORefId
, D.ModCRef <$> genCRefId , D.ModIORef <$> genIORefId
, D.ModCRefCas <$> genCRefId , D.ModIORefCas <$> genIORefId
, D.WriteCRef <$> genCRefId , D.WriteIORef <$> genIORefId
, D.CasCRef <$> genCRefId <*> HGen.bool , D.CasIORef <$> genIORefId <*> HGen.bool
, D.CommitCRef <$> genThreadId <*> genCRefId , D.CommitIORef <$> genThreadId <*> genIORefId
, D.STM <$> genSmallList genTAction <*> genSmallList genThreadId , D.STM <$> genSmallList genTAction <*> genSmallList genThreadId
, D.BlockedSTM <$> genSmallList genTAction , D.BlockedSTM <$> genSmallList genTAction
, pure D.Catching , pure D.Catching
@ -420,21 +420,21 @@ genActionType = HGen.choice
genUnsynchronisedActionType :: H.Gen D.ActionType genUnsynchronisedActionType :: H.Gen D.ActionType
genUnsynchronisedActionType = HGen.choice genUnsynchronisedActionType = HGen.choice
[ D.UnsynchronisedRead <$> genCRefId [ D.UnsynchronisedRead <$> genIORefId
, D.UnsynchronisedWrite <$> genCRefId , D.UnsynchronisedWrite <$> genIORefId
, pure D.UnsynchronisedOther , pure D.UnsynchronisedOther
] ]
genPartiallySynchronisedActionType :: H.Gen D.ActionType genPartiallySynchronisedActionType :: H.Gen D.ActionType
genPartiallySynchronisedActionType = HGen.choice genPartiallySynchronisedActionType = HGen.choice
[ D.PartiallySynchronisedCommit <$> genCRefId [ D.PartiallySynchronisedCommit <$> genIORefId
, D.PartiallySynchronisedWrite <$> genCRefId , D.PartiallySynchronisedWrite <$> genIORefId
, D.PartiallySynchronisedModify <$> genCRefId , D.PartiallySynchronisedModify <$> genIORefId
] ]
genSynchronisedActionType :: H.Gen D.ActionType genSynchronisedActionType :: H.Gen D.ActionType
genSynchronisedActionType = HGen.choice genSynchronisedActionType = HGen.choice
[ D.SynchronisedModify <$> genCRefId [ D.SynchronisedModify <$> genIORefId
, D.SynchronisedRead <$> genMVarId , D.SynchronisedRead <$> genMVarId
, D.SynchronisedWrite <$> genMVarId , D.SynchronisedWrite <$> genMVarId
, pure D.SynchronisedOther , pure D.SynchronisedOther
@ -442,7 +442,7 @@ genSynchronisedActionType = HGen.choice
genDepState :: H.Gen SCT.DepState genDepState :: H.Gen SCT.DepState
genDepState = SCT.DepState genDepState = SCT.DepState
<$> genSmallMap genCRefId HGen.bool <$> genSmallMap genIORefId HGen.bool
<*> genSmallSet genMVarId <*> genSmallSet genMVarId
<*> genSmallMap genThreadId genMaskingState <*> genSmallMap genThreadId genMaskingState

View File

@ -7,6 +7,21 @@ standard Haskell versioning scheme.
.. _PVP: https://pvp.haskell.org/ .. _PVP: https://pvp.haskell.org/
1.11.0.0 - IORefs (2018-07-01)
------------------------------
* Git: :tag:`dejafu-1.11.0.0`
* Hackage: :hackage:`dejafu-1.11.0.0`
Changed
~~~~~~~
* (:issue:`274`) ``CRef`` is now ``IORef``: all functions, data
constructors, and types have been renamed.
* The lower bound on :hackage:`concurrency` is 1.6.
1.10.1.0 (2018-06-17) 1.10.1.0 (2018-06-17)
--------------------- ---------------------

View File

@ -102,7 +102,7 @@ There are a few knobs to tweak to control the behaviour of dejafu.
The defaults should generally be good enough, but if not you have a The defaults should generally be good enough, but if not you have a
few tricks available. The main two are: the 'Way', which controls how few tricks available. The main two are: the 'Way', which controls how
schedules are explored; and the 'MemType', which controls how reads schedules are explored; and the 'MemType', which controls how reads
and writes to @CRef@s behave; see "Test.DejaFu.Settings" for a and writes to @IORef@s behave; see "Test.DejaFu.Settings" for a
complete listing. complete listing.
-} -}
@ -301,10 +301,10 @@ let example = do
>>> :{ >>> :{
let relaxed = do let relaxed = do
r1 <- newCRef False r1 <- newIORef False
r2 <- newCRef False r2 <- newIORef False
x <- spawn $ writeCRef r1 True >> readCRef r2 x <- spawn $ writeIORef r1 True >> readIORef r2
y <- spawn $ writeCRef r2 True >> readCRef r1 y <- spawn $ writeIORef r2 True >> readIORef r1
(,) <$> readMVar x <*> readMVar y (,) <$> readMVar x <*> readMVar y
:} :}
@ -363,7 +363,7 @@ autocheckWay :: (MonadConc n, MonadIO n, Eq a, Show a)
=> Way => Way
-- ^ How to run the concurrent program. -- ^ How to run the concurrent program.
-> MemType -> MemType
-- ^ The memory model to use for non-synchronised @CRef@ operations. -- ^ The memory model to use for non-synchronised @IORef@ operations.
-> ConcT n a -> ConcT n a
-- ^ The computation to test. -- ^ The computation to test.
-> n Bool -> n Bool
@ -454,7 +454,7 @@ dejafuWay :: (MonadConc n, MonadIO n, Show b)
=> Way => Way
-- ^ How to run the concurrent program. -- ^ How to run the concurrent program.
-> MemType -> MemType
-- ^ The memory model to use for non-synchronised @CRef@ operations. -- ^ The memory model to use for non-synchronised @IORef@ operations.
-> String -> String
-- ^ The name of the test. -- ^ The name of the test.
-> ProPredicate a b -> ProPredicate a b
@ -505,7 +505,7 @@ dejafuDiscard :: (MonadConc n, MonadIO n, Show b)
-> Way -> Way
-- ^ How to run the concurrent program. -- ^ How to run the concurrent program.
-> MemType -> MemType
-- ^ The memory model to use for non-synchronised @CRef@ operations. -- ^ The memory model to use for non-synchronised @IORef@ operations.
-> String -> String
-- ^ The name of the test. -- ^ The name of the test.
-> ProPredicate a b -> ProPredicate a b
@ -555,7 +555,7 @@ dejafusWay :: (MonadConc n, MonadIO n, Show b)
=> Way => Way
-- ^ How to run the concurrent program. -- ^ How to run the concurrent program.
-> MemType -> MemType
-- ^ The memory model to use for non-synchronised @CRef@ operations. -- ^ The memory model to use for non-synchronised @IORef@ operations.
-> [(String, ProPredicate a b)] -> [(String, ProPredicate a b)]
-- ^ The list of predicates (with names) to check. -- ^ The list of predicates (with names) to check.
-> ConcT n a -> ConcT n a
@ -672,7 +672,7 @@ runTestWay :: MonadConc n
=> Way => Way
-- ^ How to run the concurrent program. -- ^ How to run the concurrent program.
-> MemType -> MemType
-- ^ The memory model to use for non-synchronised @CRef@ operations. -- ^ The memory model to use for non-synchronised @IORef@ operations.
-> ProPredicate a b -> ProPredicate a b
-- ^ The predicate to check -- ^ The predicate to check
-> ConcT n a -> ConcT n a

View File

@ -46,7 +46,7 @@ module Test.DejaFu.Conc
, ThreadAction(..) , ThreadAction(..)
, Lookahead(..) , Lookahead(..)
, MVarId , MVarId
, CRefId , IORefId
, MaskingState(..) , MaskingState(..)
, showTrace , showTrace
, showFail , showFail
@ -124,7 +124,7 @@ instance Ca.MonadMask (ConcT n) where
instance Monad n => C.MonadConc (ConcT n) where instance Monad n => C.MonadConc (ConcT n) where
type MVar (ConcT n) = ModelMVar n type MVar (ConcT n) = ModelMVar n
type CRef (ConcT n) = ModelCRef n type IORef (ConcT n) = ModelIORef n
type Ticket (ConcT n) = ModelTicket type Ticket (ConcT n) = ModelTicket
type STM (ConcT n) = ModelSTM n type STM (ConcT n) = ModelSTM n
type ThreadId (ConcT n) = ThreadId type ThreadId (ConcT n) = ThreadId
@ -153,18 +153,18 @@ instance Monad n => C.MonadConc (ConcT n) where
-- ---------- -- ----------
newCRefN n a = toConc (ANewCRef n a) newIORefN n a = toConc (ANewIORef n a)
readCRef ref = toConc (AReadCRef ref) readIORef ref = toConc (AReadIORef ref)
readForCAS ref = toConc (AReadCRefCas ref) readForCAS ref = toConc (AReadIORefCas ref)
peekTicket' _ = ticketVal peekTicket' _ = ticketVal
writeCRef ref a = toConc (\c -> AWriteCRef ref a (c ())) writeIORef ref a = toConc (\c -> AWriteIORef ref a (c ()))
casCRef ref tick a = toConc (ACasCRef ref tick a) casIORef ref tick a = toConc (ACasIORef ref tick a)
atomicModifyCRef ref f = toConc (AModCRef ref f) atomicModifyIORef ref f = toConc (AModIORef ref f)
modifyCRefCAS ref f = toConc (AModCRefCas ref f) modifyIORefCAS ref f = toConc (AModIORefCas ref f)
-- ---------- -- ----------
@ -218,7 +218,7 @@ runConcurrent :: C.MonadConc n
-> n (Either Failure a, s, Trace) -> n (Either Failure a, s, Trace)
runConcurrent sched memtype s ma = do runConcurrent sched memtype s ma = do
res <- runConcurrency False sched memtype s initialIdSource 2 (unC ma) res <- runConcurrency False sched memtype s initialIdSource 2 (unC ma)
out <- efromJust <$> C.readCRef (finalRef res) out <- efromJust <$> C.readIORef (finalRef res)
pure ( out pure ( out
, cSchedState (finalContext res) , cSchedState (finalContext res)
, F.toList (finalTrace res) , F.toList (finalTrace res)
@ -284,7 +284,7 @@ dontCheck lb ma = toConc (ADontCheck lb (unC ma))
-- --
-- __Snapshotting @IO@:__ A snapshot captures entire state of your -- __Snapshotting @IO@:__ A snapshot captures entire state of your
-- concurrent program: the state of every thread, the number of -- concurrent program: the state of every thread, the number of
-- capabilities, the values of any @CRef@s, @MVar@s, and @TVar@s, and -- capabilities, the values of any @IORef@s, @MVar@s, and @TVar@s, and
-- records any @IO@ that you performed. -- records any @IO@ that you performed.
-- --
-- When restoring a snapshot this @IO@ is replayed, in order. But the -- When restoring a snapshot this @IO@ is replayed, in order. But the
@ -311,7 +311,7 @@ dontCheck lb ma = toConc (ADontCheck lb (unC ma))
-- To safely use @IO@ in a snapshotted computation, __the combined effect must be idempotent__. -- To safely use @IO@ in a snapshotted computation, __the combined effect must be idempotent__.
-- You should either use actions which set the state to the final -- You should either use actions which set the state to the final
-- value directly, rather than modifying it (eg, using a combination -- value directly, rather than modifying it (eg, using a combination
-- of @liftIO . readCRef@ and @liftIO . writeIORef@ here), or reset -- of @liftIO . readIORef@ and @liftIO . writeIORef@ here), or reset
-- the state to a known value. Both of these approaches will work: -- the state to a known value. Both of these approaches will work:
-- --
-- @ -- @
@ -349,7 +349,7 @@ runForDCSnapshot :: C.MonadConc n
-> n (Maybe (Either Failure (DCSnapshot n a), Trace)) -> n (Maybe (Either Failure (DCSnapshot n a), Trace))
runForDCSnapshot ma = do runForDCSnapshot ma = do
res <- runConcurrency True roundRobinSchedNP SequentialConsistency () initialIdSource 2 (unC ma) res <- runConcurrency True roundRobinSchedNP SequentialConsistency () initialIdSource 2 (unC ma)
out <- C.readCRef (finalRef res) out <- C.readIORef (finalRef res)
pure $ case (finalRestore res, out) of pure $ case (finalRestore res, out) of
(Just _, Just (Left f)) -> Just (Left f, F.toList (finalTrace res)) (Just _, Just (Left f)) -> Just (Left f, F.toList (finalTrace res))
(Just restore, _) -> Just (Right (DCSnapshot (finalContext res) restore (finalRef res)), F.toList (finalTrace res)) (Just restore, _) -> Just (Right (DCSnapshot (finalContext res) restore (finalRef res)), F.toList (finalTrace res))
@ -374,7 +374,7 @@ runWithDCSnapshot sched memtype s snapshot = do
let restore = dcsRestore snapshot let restore = dcsRestore snapshot
let ref = dcsRef snapshot let ref = dcsRef snapshot
res <- runConcurrencyWithSnapshot sched memtype context restore ref res <- runConcurrencyWithSnapshot sched memtype context restore ref
out <- efromJust <$> C.readCRef (finalRef res) out <- efromJust <$> C.readIORef (finalRef res)
pure ( out pure ( out
, cSchedState (finalContext res) , cSchedState (finalContext res)
, F.toList (finalTrace res) , F.toList (finalTrace res)

View File

@ -49,7 +49,7 @@ type SeqTrace
-- | The result of running a concurrent program. -- | The result of running a concurrent program.
data CResult n g a = CResult data CResult n g a = CResult
{ finalContext :: Context n g { finalContext :: Context n g
, finalRef :: C.CRef n (Maybe (Either Failure a)) , finalRef :: C.IORef n (Maybe (Either Failure a))
, finalRestore :: Maybe (Threads n -> n ()) , finalRestore :: Maybe (Threads n -> n ())
-- ^ Meaningless if this result doesn't come from a snapshotting -- ^ Meaningless if this result doesn't come from a snapshotting
-- execution. -- execution.
@ -66,8 +66,8 @@ data DCSnapshot n a = DCSnapshot
-- ^ The execution context. The scheduler state is ignored when -- ^ The execution context. The scheduler state is ignored when
-- restoring. -- restoring.
, dcsRestore :: Threads n -> n () , dcsRestore :: Threads n -> n ()
-- ^ Action to restore CRef, MVar, and TVar values. -- ^ Action to restore IORef, MVar, and TVar values.
, dcsRef :: C.CRef n (Maybe (Either Failure a)) , dcsRef :: C.IORef n (Maybe (Either Failure a))
-- ^ Reference where the result will be written. -- ^ Reference where the result will be written.
} }
@ -118,7 +118,7 @@ runConcurrencyWithSnapshot :: (C.MonadConc n, HasCallStack)
-> MemType -> MemType
-> Context n g -> Context n g
-> (Threads n -> n ()) -> (Threads n -> n ())
-> C.CRef n (Maybe (Either Failure a)) -> C.IORef n (Maybe (Either Failure a))
-> n (CResult n g a) -> n (CResult n g a)
runConcurrencyWithSnapshot sched memtype ctx restore ref = do runConcurrencyWithSnapshot sched memtype ctx restore ref = do
let boundThreads = M.filter (isJust . _bound) (cThreads ctx) let boundThreads = M.filter (isJust . _bound) (cThreads ctx)
@ -151,13 +151,13 @@ runThreads :: (C.MonadConc n, HasCallStack)
=> Bool => Bool
-> Scheduler g -> Scheduler g
-> MemType -> MemType
-> C.CRef n (Maybe (Either Failure a)) -> C.IORef n (Maybe (Either Failure a))
-> Context n g -> Context n g
-> n (CResult n g a) -> n (CResult n g a)
runThreads forSnapshot sched memtype ref = schedule (const $ pure ()) Seq.empty Nothing where runThreads forSnapshot sched memtype ref = schedule (const $ pure ()) Seq.empty Nothing where
-- signal failure & terminate -- signal failure & terminate
die reason finalR finalT finalD finalC = do die reason finalR finalT finalD finalC = do
C.writeCRef ref (Just $ Left reason) C.writeIORef ref (Just $ Left reason)
stop finalR finalT finalD finalC stop finalR finalT finalD finalC
-- just terminate; 'ref' must have been written to before calling -- just terminate; 'ref' must have been written to before calling
@ -367,11 +367,11 @@ stepThread _ _ _ _ tid (ADelay n c) = \ctx@Context{..} ->
-- create a new @MVar@, using the next 'MVarId'. -- create a new @MVar@, using the next 'MVarId'.
stepThread _ _ _ _ tid (ANewMVar n c) = \ctx@Context{..} -> do stepThread _ _ _ _ tid (ANewMVar n c) = \ctx@Context{..} -> do
let (idSource', newmvid) = nextMVId n cIdSource let (idSource', newmvid) = nextMVId n cIdSource
ref <- C.newCRef Nothing ref <- C.newIORef Nothing
let mvar = ModelMVar newmvid ref let mvar = ModelMVar newmvid ref
pure ( Succeeded ctx { cThreads = goto (c mvar) tid cThreads, cIdSource = idSource' } pure ( Succeeded ctx { cThreads = goto (c mvar) tid cThreads, cIdSource = idSource' }
, Single (NewMVar newmvid) , Single (NewMVar newmvid)
, const (C.writeCRef ref Nothing) , const (C.writeIORef ref Nothing)
) )
-- put a value into a @MVar@, blocking the thread until it's empty. -- put a value into a @MVar@, blocking the thread until it's empty.
@ -424,85 +424,85 @@ stepThread _ _ _ _ tid (ATryTakeMVar mvar@ModelMVar{..} c) = synchronised $ \ctx
, const effect , const effect
) )
-- create a new @CRef@, using the next 'CRefId'. -- create a new @IORef@, using the next 'IORefId'.
stepThread _ _ _ _ tid (ANewCRef n a c) = \ctx@Context{..} -> do stepThread _ _ _ _ tid (ANewIORef n a c) = \ctx@Context{..} -> do
let (idSource', newcrid) = nextCRId n cIdSource let (idSource', newiorid) = nextIORId n cIdSource
let val = (M.empty, 0, a) let val = (M.empty, 0, a)
ref <- C.newCRef val ioref <- C.newIORef val
let cref = ModelCRef newcrid ref let ref = ModelIORef newiorid ioref
pure ( Succeeded ctx { cThreads = goto (c cref) tid cThreads, cIdSource = idSource' } pure ( Succeeded ctx { cThreads = goto (c ref) tid cThreads, cIdSource = idSource' }
, Single (NewCRef newcrid) , Single (NewIORef newiorid)
, const (C.writeCRef ref val) , const (C.writeIORef ioref val)
) )
-- read from a @CRef@. -- read from a @IORef@.
stepThread _ _ _ _ tid (AReadCRef cref@ModelCRef{..} c) = \ctx@Context{..} -> do stepThread _ _ _ _ tid (AReadIORef ref@ModelIORef{..} c) = \ctx@Context{..} -> do
val <- readCRef cref tid val <- readIORef ref tid
pure ( Succeeded ctx { cThreads = goto (c val) tid cThreads } pure ( Succeeded ctx { cThreads = goto (c val) tid cThreads }
, Single (ReadCRef crefId) , Single (ReadIORef iorefId)
, const (pure ()) , const (pure ())
) )
-- read from a @CRef@ for future compare-and-swap operations. -- read from a @IORef@ for future compare-and-swap operations.
stepThread _ _ _ _ tid (AReadCRefCas cref@ModelCRef{..} c) = \ctx@Context{..} -> do stepThread _ _ _ _ tid (AReadIORefCas ref@ModelIORef{..} c) = \ctx@Context{..} -> do
tick <- readForTicket cref tid tick <- readForTicket ref tid
pure ( Succeeded ctx { cThreads = goto (c tick) tid cThreads } pure ( Succeeded ctx { cThreads = goto (c tick) tid cThreads }
, Single (ReadCRefCas crefId) , Single (ReadIORefCas iorefId)
, const (pure ()) , const (pure ())
) )
-- modify a @CRef@. -- modify a @IORef@.
stepThread _ _ _ _ tid (AModCRef cref@ModelCRef{..} f c) = synchronised $ \ctx@Context{..} -> do stepThread _ _ _ _ tid (AModIORef ref@ModelIORef{..} f c) = synchronised $ \ctx@Context{..} -> do
(new, val) <- f <$> readCRef cref tid (new, val) <- f <$> readIORef ref tid
effect <- writeImmediate cref new effect <- writeImmediate ref new
pure ( Succeeded ctx { cThreads = goto (c val) tid cThreads } pure ( Succeeded ctx { cThreads = goto (c val) tid cThreads }
, Single (ModCRef crefId) , Single (ModIORef iorefId)
, const effect , const effect
) )
-- modify a @CRef@ using a compare-and-swap. -- modify a @IORef@ using a compare-and-swap.
stepThread _ _ _ _ tid (AModCRefCas cref@ModelCRef{..} f c) = synchronised $ \ctx@Context{..} -> do stepThread _ _ _ _ tid (AModIORefCas ref@ModelIORef{..} f c) = synchronised $ \ctx@Context{..} -> do
tick@(ModelTicket _ _ old) <- readForTicket cref tid tick@(ModelTicket _ _ old) <- readForTicket ref tid
let (new, val) = f old let (new, val) = f old
(_, _, effect) <- casCRef cref tid tick new (_, _, effect) <- casIORef ref tid tick new
pure ( Succeeded ctx { cThreads = goto (c val) tid cThreads } pure ( Succeeded ctx { cThreads = goto (c val) tid cThreads }
, Single (ModCRefCas crefId) , Single (ModIORefCas iorefId)
, const effect , const effect
) )
-- write to a @CRef@ without synchronising. -- write to a @IORef@ without synchronising.
stepThread _ _ _ memtype tid (AWriteCRef cref@ModelCRef{..} a c) = \ctx@Context{..} -> case memtype of stepThread _ _ _ memtype tid (AWriteIORef ref@ModelIORef{..} a c) = \ctx@Context{..} -> case memtype of
-- write immediately. -- write immediately.
SequentialConsistency -> do SequentialConsistency -> do
effect <- writeImmediate cref a effect <- writeImmediate ref a
pure ( Succeeded ctx { cThreads = goto c tid cThreads } pure ( Succeeded ctx { cThreads = goto c tid cThreads }
, Single (WriteCRef crefId) , Single (WriteIORef iorefId)
, const effect , const effect
) )
-- add to buffer using thread id. -- add to buffer using thread id.
TotalStoreOrder -> do TotalStoreOrder -> do
wb' <- bufferWrite cWriteBuf (tid, Nothing) cref a wb' <- bufferWrite cWriteBuf (tid, Nothing) ref a
pure ( Succeeded ctx { cThreads = goto c tid cThreads, cWriteBuf = wb' } pure ( Succeeded ctx { cThreads = goto c tid cThreads, cWriteBuf = wb' }
, Single (WriteCRef crefId) , Single (WriteIORef iorefId)
, const (pure ()) , const (pure ())
) )
-- add to buffer using both thread id and cref id -- add to buffer using both thread id and IORef id
PartialStoreOrder -> do PartialStoreOrder -> do
wb' <- bufferWrite cWriteBuf (tid, Just crefId) cref a wb' <- bufferWrite cWriteBuf (tid, Just iorefId) ref a
pure ( Succeeded ctx { cThreads = goto c tid cThreads, cWriteBuf = wb' } pure ( Succeeded ctx { cThreads = goto c tid cThreads, cWriteBuf = wb' }
, Single (WriteCRef crefId) , Single (WriteIORef iorefId)
, const (pure ()) , const (pure ())
) )
-- perform a compare-and-swap on a @CRef@. -- perform a compare-and-swap on a @IORef@.
stepThread _ _ _ _ tid (ACasCRef cref@ModelCRef{..} tick a c) = synchronised $ \ctx@Context{..} -> do stepThread _ _ _ _ tid (ACasIORef ref@ModelIORef{..} tick a c) = synchronised $ \ctx@Context{..} -> do
(suc, tick', effect) <- casCRef cref tid tick a (suc, tick', effect) <- casIORef ref tid tick a
pure ( Succeeded ctx { cThreads = goto (c (suc, tick')) tid cThreads } pure ( Succeeded ctx { cThreads = goto (c (suc, tick')) tid cThreads }
, Single (CasCRef crefId suc) , Single (CasIORef iorefId suc)
, const effect , const effect
) )
-- commit a @CRef@ write -- commit a @IORef@ write
stepThread _ _ _ memtype _ (ACommit t c) = \ctx@Context{..} -> do stepThread _ _ _ memtype _ (ACommit t c) = \ctx@Context{..} -> do
wb' <- case memtype of wb' <- case memtype of
-- shouldn't ever get here -- shouldn't ever get here
@ -511,11 +511,11 @@ stepThread _ _ _ memtype _ (ACommit t c) = \ctx@Context{..} -> do
-- commit using the thread id. -- commit using the thread id.
TotalStoreOrder -> TotalStoreOrder ->
commitWrite cWriteBuf (t, Nothing) commitWrite cWriteBuf (t, Nothing)
-- commit using the cref id. -- commit using the IORef id.
PartialStoreOrder -> PartialStoreOrder ->
commitWrite cWriteBuf (t, Just c) commitWrite cWriteBuf (t, Just c)
pure ( Succeeded ctx { cWriteBuf = wb' } pure ( Succeeded ctx { cWriteBuf = wb' }
, Single (CommitCRef t c) , Single (CommitIORef t c)
, const (pure ()) , const (pure ())
) )
@ -634,7 +634,7 @@ stepThread forSnapshot _ sched memtype tid (ASub ma c) = \ctx ->
| M.size (cThreads ctx) > 1 -> pure (Failed IllegalSubconcurrency, Single Subconcurrency, const (pure ())) | M.size (cThreads ctx) > 1 -> pure (Failed IllegalSubconcurrency, Single Subconcurrency, const (pure ()))
| otherwise -> do | otherwise -> do
res <- runConcurrency False sched memtype (cSchedState ctx) (cIdSource ctx) (cCaps ctx) ma res <- runConcurrency False sched memtype (cSchedState ctx) (cIdSource ctx) (cCaps ctx) ma
out <- efromJust <$> C.readCRef (finalRef res) out <- efromJust <$> C.readIORef (finalRef res)
pure ( Succeeded ctx pure ( Succeeded ctx
{ cThreads = goto (AStopSub (c out)) tid (cThreads ctx) { cThreads = goto (AStopSub (c out)) tid (cThreads ctx)
, cIdSource = cIdSource (finalContext res) , cIdSource = cIdSource (finalContext res)
@ -662,7 +662,7 @@ stepThread forSnapshot isFirst _ _ tid (ADontCheck lb ma c) = \ctx ->
threads' <- kill tid (cThreads ctx) threads' <- kill tid (cThreads ctx)
let dcCtx = ctx { cThreads = threads', cSchedState = lb } let dcCtx = ctx { cThreads = threads', cSchedState = lb }
res <- runConcurrency' forSnapshot dcSched SequentialConsistency dcCtx ma res <- runConcurrency' forSnapshot dcSched SequentialConsistency dcCtx ma
out <- efromJust <$> C.readCRef (finalRef res) out <- efromJust <$> C.readIORef (finalRef res)
case out of case out of
Right a -> do Right a -> do
let threads'' = launch' Unmasked tid (const (c a)) (cThreads (finalContext res)) let threads'' = launch' Unmasked tid (const (c a)) (cThreads (finalContext res))

View File

@ -56,22 +56,22 @@ instance Fail.MonadFail (ModelConc n) where
-- @Maybe@ value. -- @Maybe@ value.
data ModelMVar n a = ModelMVar data ModelMVar n a = ModelMVar
{ mvarId :: MVarId { mvarId :: MVarId
, mvarRef :: C.CRef n (Maybe a) , mvarRef :: C.IORef n (Maybe a)
} }
-- | A @CRef@ is modelled as a unique ID and a reference holding -- | A @IORef@ is modelled as a unique ID and a reference holding
-- thread-local values, the number of commits, and the most recent -- thread-local values, the number of commits, and the most recent
-- committed value. -- committed value.
data ModelCRef n a = ModelCRef data ModelIORef n a = ModelIORef
{ crefId :: CRefId { iorefId :: IORefId
, crefRef :: C.CRef n (Map ThreadId a, Integer, a) , iorefRef :: C.IORef n (Map ThreadId a, Integer, a)
} }
-- | A @Ticket@ is modelled as the ID of the @ModelCRef@ it came from, -- | A @Ticket@ is modelled as the ID of the @ModelIORef@ it came from,
-- the commits to the @ModelCRef@ at the time it was produced, and the -- the commits to the @ModelIORef@ at the time it was produced, and the
-- value observed. -- value observed.
data ModelTicket a = ModelTicket data ModelTicket a = ModelTicket
{ ticketCRef :: CRefId { ticketIORef :: IORefId
, ticketWrites :: Integer , ticketWrites :: Integer
, ticketVal :: a , ticketVal :: a
} }
@ -100,13 +100,13 @@ data Action n =
| forall a. ATakeMVar (ModelMVar n a) (a -> Action n) | forall a. ATakeMVar (ModelMVar n a) (a -> Action n)
| forall a. ATryTakeMVar (ModelMVar n a) (Maybe a -> Action n) | forall a. ATryTakeMVar (ModelMVar n a) (Maybe a -> Action n)
| forall a. ANewCRef String a (ModelCRef n a -> Action n) | forall a. ANewIORef String a (ModelIORef n a -> Action n)
| forall a. AReadCRef (ModelCRef n a) (a -> Action n) | forall a. AReadIORef (ModelIORef n a) (a -> Action n)
| forall a. AReadCRefCas (ModelCRef n a) (ModelTicket a -> Action n) | forall a. AReadIORefCas (ModelIORef n a) (ModelTicket a -> Action n)
| forall a b. AModCRef (ModelCRef n a) (a -> (a, b)) (b -> Action n) | forall a b. AModIORef (ModelIORef n a) (a -> (a, b)) (b -> Action n)
| forall a b. AModCRefCas (ModelCRef n a) (a -> (a, b)) (b -> Action n) | forall a b. AModIORefCas (ModelIORef n a) (a -> (a, b)) (b -> Action n)
| forall a. AWriteCRef (ModelCRef n a) a (Action n) | forall a. AWriteIORef (ModelIORef n a) a (Action n)
| forall a. ACasCRef (ModelCRef n a) (ModelTicket a) a ((Bool, ModelTicket a) -> Action n) | forall a. ACasIORef (ModelIORef n a) (ModelTicket a) a ((Bool, ModelTicket a) -> Action n)
| forall e. Exception e => AThrow e | forall e. Exception e => AThrow e
| forall e. Exception e => AThrowTo ThreadId e (Action n) | forall e. Exception e => AThrowTo ThreadId e (Action n)
@ -120,7 +120,7 @@ data Action n =
| AYield (Action n) | AYield (Action n)
| ADelay Int (Action n) | ADelay Int (Action n)
| AReturn (Action n) | AReturn (Action n)
| ACommit ThreadId CRefId | ACommit ThreadId IORefId
| AStop (n ()) | AStop (n ())
| forall a. ASub (ModelConc n a) (Either Failure a -> Action n) | forall a. ASub (ModelConc n a) (Either Failure a -> Action n)
@ -145,14 +145,14 @@ lookahead (AReadMVar (ModelMVar m _) _) = WillReadMVar m
lookahead (ATryReadMVar (ModelMVar m _) _) = WillTryReadMVar m lookahead (ATryReadMVar (ModelMVar m _) _) = WillTryReadMVar m
lookahead (ATakeMVar (ModelMVar m _) _) = WillTakeMVar m lookahead (ATakeMVar (ModelMVar m _) _) = WillTakeMVar m
lookahead (ATryTakeMVar (ModelMVar m _) _) = WillTryTakeMVar m lookahead (ATryTakeMVar (ModelMVar m _) _) = WillTryTakeMVar m
lookahead (ANewCRef _ _ _) = WillNewCRef lookahead (ANewIORef _ _ _) = WillNewIORef
lookahead (AReadCRef (ModelCRef r _) _) = WillReadCRef r lookahead (AReadIORef (ModelIORef r _) _) = WillReadIORef r
lookahead (AReadCRefCas (ModelCRef r _) _) = WillReadCRefCas r lookahead (AReadIORefCas (ModelIORef r _) _) = WillReadIORefCas r
lookahead (AModCRef (ModelCRef r _) _ _) = WillModCRef r lookahead (AModIORef (ModelIORef r _) _ _) = WillModIORef r
lookahead (AModCRefCas (ModelCRef r _) _ _) = WillModCRefCas r lookahead (AModIORefCas (ModelIORef r _) _ _) = WillModIORefCas r
lookahead (AWriteCRef (ModelCRef r _) _ _) = WillWriteCRef r lookahead (AWriteIORef (ModelIORef r _) _ _) = WillWriteIORef r
lookahead (ACasCRef (ModelCRef r _) _ _ _) = WillCasCRef r lookahead (ACasIORef (ModelIORef r _) _ _ _) = WillCasIORef r
lookahead (ACommit t c) = WillCommitCRef t c lookahead (ACommit t c) = WillCommitIORef t c
lookahead (AAtom _ _) = WillSTM lookahead (AAtom _ _) = WillSTM
lookahead (AThrow _) = WillThrow lookahead (AThrow _) = WillThrow
lookahead (AThrowTo tid _ _) = WillThrowTo tid lookahead (AThrowTo tid _ _) = WillThrowTo tid

View File

@ -12,14 +12,14 @@
-- Stability : experimental -- Stability : experimental
-- Portability : BangPatterns, GADTs, FlexibleContexts, LambdaCase, RecordWildCards -- Portability : BangPatterns, GADTs, FlexibleContexts, LambdaCase, RecordWildCards
-- --
-- Operations over @CRef@s and @MVar@s. This module is NOT considered -- Operations over @IORef@s and @MVar@s. This module is NOT considered
-- to form part of the public interface of this library. -- to form part of the public interface of this library.
-- --
-- Relaxed memory operations over @CRef@s are implemented with an -- Relaxed memory operations over @IORef@s are implemented with an
-- explicit write buffer: one per thread for TSO, and one per -- explicit write buffer: one per thread for TSO, and one per
-- thread/variable combination for PSO. Unsynchronised writes append -- thread/variable combination for PSO. Unsynchronised writes append
-- to this buffer, and periodically separate threads commit from these -- to this buffer, and periodically separate threads commit from these
-- buffers to the \"actual\" @CRef@. -- buffers to the \"actual\" @IORef@.
-- --
-- This model comes from /Dynamic Partial Order Reduction for Relaxed -- This model comes from /Dynamic Partial Order Reduction for Relaxed
-- Memory Models/, N. Zhang, M. Kusano, and C. Wang (2015). -- Memory Models/, N. Zhang, M. Kusano, and C. Wang (2015).
@ -40,93 +40,93 @@ import Test.DejaFu.Internal
import Test.DejaFu.Types import Test.DejaFu.Types
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
-- * Manipulating @CRef@s -- * Manipulating @IORef@s
-- | In non-sequentially-consistent memory models, non-synchronised -- | In non-sequentially-consistent memory models, non-synchronised
-- writes get buffered. -- writes get buffered.
-- --
-- The @CRefId@ parameter is only used under PSO. Under TSO each -- The @IORefId@ parameter is only used under PSO. Under TSO each
-- thread has a single buffer. -- thread has a single buffer.
newtype WriteBuffer n = WriteBuffer newtype WriteBuffer n = WriteBuffer
{ buffer :: Map (ThreadId, Maybe CRefId) (Seq (BufferedWrite n)) } { buffer :: Map (ThreadId, Maybe IORefId) (Seq (BufferedWrite n)) }
-- | A buffered write is a reference to the variable, and the value to -- | A buffered write is a reference to the variable, and the value to
-- write. Universally quantified over the value type so that the only -- write. Universally quantified over the value type so that the only
-- thing which can be done with it is to write it to the reference. -- thing which can be done with it is to write it to the reference.
data BufferedWrite n where data BufferedWrite n where
BufferedWrite :: ThreadId -> ModelCRef n a -> a -> BufferedWrite n BufferedWrite :: ThreadId -> ModelIORef n a -> a -> BufferedWrite n
-- | An empty write buffer. -- | An empty write buffer.
emptyBuffer :: WriteBuffer n emptyBuffer :: WriteBuffer n
emptyBuffer = WriteBuffer M.empty emptyBuffer = WriteBuffer M.empty
-- | Add a new write to the end of a buffer. -- | Add a new write to the end of a buffer.
bufferWrite :: C.MonadConc n => WriteBuffer n -> (ThreadId, Maybe CRefId) -> ModelCRef n a -> a -> n (WriteBuffer n) bufferWrite :: C.MonadConc n => WriteBuffer n -> (ThreadId, Maybe IORefId) -> ModelIORef n a -> a -> n (WriteBuffer n)
bufferWrite (WriteBuffer wb) k@(tid, _) cref@ModelCRef{..} new = do bufferWrite (WriteBuffer wb) k@(tid, _) ref@ModelIORef{..} new = do
-- Construct the new write buffer -- Construct the new write buffer
let write = singleton $ BufferedWrite tid cref new let write = singleton $ BufferedWrite tid ref new
let buffer' = M.insertWith (flip (><)) k write wb let buffer' = M.insertWith (flip (><)) k write wb
-- Write the thread-local value to the @CRef@'s update map. -- Write the thread-local value to the @IORef@'s update map.
(locals, count, def) <- C.readCRef crefRef (locals, count, def) <- C.readIORef iorefRef
C.writeCRef crefRef (M.insert tid new locals, count, def) C.writeIORef iorefRef (M.insert tid new locals, count, def)
pure (WriteBuffer buffer') pure (WriteBuffer buffer')
-- | Commit the write at the head of a buffer. -- | Commit the write at the head of a buffer.
commitWrite :: C.MonadConc n => WriteBuffer n -> (ThreadId, Maybe CRefId) -> n (WriteBuffer n) commitWrite :: C.MonadConc n => WriteBuffer n -> (ThreadId, Maybe IORefId) -> n (WriteBuffer n)
commitWrite w@(WriteBuffer wb) k = case maybe EmptyL viewl $ M.lookup k wb of commitWrite w@(WriteBuffer wb) k = case maybe EmptyL viewl $ M.lookup k wb of
BufferedWrite _ cref a :< rest -> do BufferedWrite _ ref a :< rest -> do
_ <- writeImmediate cref a _ <- writeImmediate ref a
pure . WriteBuffer $ M.insert k rest wb pure . WriteBuffer $ M.insert k rest wb
EmptyL -> pure w EmptyL -> pure w
-- | Read from a @CRef@, returning a newer thread-local non-committed -- | Read from a @IORef@, returning a newer thread-local non-committed
-- write if there is one. -- write if there is one.
readCRef :: C.MonadConc n => ModelCRef n a -> ThreadId -> n a readIORef :: C.MonadConc n => ModelIORef n a -> ThreadId -> n a
readCRef cref tid = do readIORef ref tid = do
(val, _) <- readCRefPrim cref tid (val, _) <- readIORefPrim ref tid
pure val pure val
-- | Read from a @CRef@, returning a @Ticket@ representing the current -- | Read from a @IORef@, returning a @Ticket@ representing the current
-- view of the thread. -- view of the thread.
readForTicket :: C.MonadConc n => ModelCRef n a -> ThreadId -> n (ModelTicket a) readForTicket :: C.MonadConc n => ModelIORef n a -> ThreadId -> n (ModelTicket a)
readForTicket cref@ModelCRef{..} tid = do readForTicket ref@ModelIORef{..} tid = do
(val, count) <- readCRefPrim cref tid (val, count) <- readIORefPrim ref tid
pure (ModelTicket crefId count val) pure (ModelTicket iorefId count val)
-- | Perform a compare-and-swap on a @CRef@ if the ticket is still -- | Perform a compare-and-swap on a @IORef@ if the ticket is still
-- valid. This is strict in the \"new\" value argument. -- valid. This is strict in the \"new\" value argument.
casCRef :: C.MonadConc n => ModelCRef n a -> ThreadId -> ModelTicket a -> a -> n (Bool, ModelTicket a, n ()) casIORef :: C.MonadConc n => ModelIORef n a -> ThreadId -> ModelTicket a -> a -> n (Bool, ModelTicket a, n ())
casCRef cref tid (ModelTicket _ cc _) !new = do casIORef ref tid (ModelTicket _ cc _) !new = do
tick'@(ModelTicket _ cc' _) <- readForTicket cref tid tick'@(ModelTicket _ cc' _) <- readForTicket ref tid
if cc == cc' if cc == cc'
then do then do
effect <- writeImmediate cref new effect <- writeImmediate ref new
tick'' <- readForTicket cref tid tick'' <- readForTicket ref tid
pure (True, tick'', effect) pure (True, tick'', effect)
else pure (False, tick', pure ()) else pure (False, tick', pure ())
-- | Read the local state of a @CRef@. -- | Read the local state of a @IORef@.
readCRefPrim :: C.MonadConc n => ModelCRef n a -> ThreadId -> n (a, Integer) readIORefPrim :: C.MonadConc n => ModelIORef n a -> ThreadId -> n (a, Integer)
readCRefPrim ModelCRef{..} tid = do readIORefPrim ModelIORef{..} tid = do
(vals, count, def) <- C.readCRef crefRef (vals, count, def) <- C.readIORef iorefRef
pure (M.findWithDefault def tid vals, count) pure (M.findWithDefault def tid vals, count)
-- | Write and commit to a @CRef@ immediately, clearing the update map -- | Write and commit to a @IORef@ immediately, clearing the update map
-- and incrementing the write count. -- and incrementing the write count.
writeImmediate :: C.MonadConc n => ModelCRef n a -> a -> n (n ()) writeImmediate :: C.MonadConc n => ModelIORef n a -> a -> n (n ())
writeImmediate ModelCRef{..} a = do writeImmediate ModelIORef{..} a = do
(_, count, _) <- C.readCRef crefRef (_, count, _) <- C.readIORef iorefRef
let effect = C.writeCRef crefRef (M.empty, count + 1, a) let effect = C.writeIORef iorefRef (M.empty, count + 1, a)
effect effect
pure effect pure effect
-- | Flush all writes in the buffer. -- | Flush all writes in the buffer.
writeBarrier :: C.MonadConc n => WriteBuffer n -> n () writeBarrier :: C.MonadConc n => WriteBuffer n -> n ()
writeBarrier (WriteBuffer wb) = mapM_ flush $ M.elems wb where writeBarrier (WriteBuffer wb) = mapM_ flush $ M.elems wb where
flush = mapM_ $ \(BufferedWrite _ cref a) -> writeImmediate cref a flush = mapM_ $ \(BufferedWrite _ ref a) -> writeImmediate ref a
-- | Add phantom threads to the thread list to commit pending writes. -- | Add phantom threads to the thread list to commit pending writes.
addCommitThreads :: WriteBuffer n -> Threads n -> Threads n addCommitThreads :: WriteBuffer n -> Threads n -> Threads n
@ -135,13 +135,13 @@ addCommitThreads (WriteBuffer wb) ts = ts <> M.fromList phantoms where
| (k, b) <- M.toList wb | (k, b) <- M.toList wb
, c <- maybeToList (go $ viewl b) , c <- maybeToList (go $ viewl b)
] ]
go (BufferedWrite tid ModelCRef{..} _ :< _) = Just $ ACommit tid crefId go (BufferedWrite tid ModelIORef{..} _ :< _) = Just $ ACommit tid iorefId
go EmptyL = Nothing go EmptyL = Nothing
-- | The ID of a commit thread. -- | The ID of a commit thread.
commitThreadId :: ThreadId -> Maybe CRefId -> ThreadId commitThreadId :: ThreadId -> Maybe IORefId -> ThreadId
commitThreadId (ThreadId (Id _ t)) = ThreadId . Id Nothing . negate . go where commitThreadId (ThreadId (Id _ t)) = ThreadId . Id Nothing . negate . go where
go (Just (CRefId (Id _ c))) = t + 1 + c * 10000 go (Just (IORefId (Id _ c))) = t + 1 + c * 10000
go Nothing = t + 1 go Nothing = t + 1
-- | Remove phantom threads. -- | Remove phantom threads.
@ -220,7 +220,7 @@ mutMVar :: C.MonadConc n
-> ThreadId -> ThreadId
-> Threads n -> Threads n
-> n (Bool, Threads n, [ThreadId], n ()) -> n (Bool, Threads n, [ThreadId], n ())
mutMVar blocking ModelMVar{..} a c threadid threads = C.readCRef mvarRef >>= \case mutMVar blocking ModelMVar{..} a c threadid threads = C.readIORef mvarRef >>= \case
Just _ -> case blocking of Just _ -> case blocking of
Blocking -> Blocking ->
let threads' = block (OnMVarEmpty mvarId) threadid threads let threads' = block (OnMVarEmpty mvarId) threadid threads
@ -228,7 +228,7 @@ mutMVar blocking ModelMVar{..} a c threadid threads = C.readCRef mvarRef >>= \ca
NonBlocking -> NonBlocking ->
pure (False, goto (c False) threadid threads, [], pure ()) pure (False, goto (c False) threadid threads, [], pure ())
Nothing -> do Nothing -> do
let effect = C.writeCRef mvarRef $ Just a let effect = C.writeIORef mvarRef $ Just a
let (threads', woken) = wake (OnMVarFull mvarId) threads let (threads', woken) = wake (OnMVarFull mvarId) threads
effect effect
pure (True, goto (c True) threadid threads', woken, effect) pure (True, goto (c True) threadid threads', woken, effect)
@ -243,10 +243,10 @@ seeMVar :: C.MonadConc n
-> ThreadId -> ThreadId
-> Threads n -> Threads n
-> n (Bool, Threads n, [ThreadId], n ()) -> n (Bool, Threads n, [ThreadId], n ())
seeMVar emptying blocking ModelMVar{..} c threadid threads = C.readCRef mvarRef >>= \case seeMVar emptying blocking ModelMVar{..} c threadid threads = C.readIORef mvarRef >>= \case
val@(Just _) -> do val@(Just _) -> do
let effect = case emptying of let effect = case emptying of
Emptying -> C.writeCRef mvarRef Nothing Emptying -> C.writeIORef mvarRef Nothing
NonEmptying -> pure () NonEmptying -> pure ()
let (threads', woken) = wake (OnMVarEmpty mvarId) threads let (threads', woken) = wake (OnMVarEmpty mvarId) threads
effect effect

View File

@ -100,7 +100,7 @@ data STMAction n
-- value. -- value.
data ModelTVar n a = ModelTVar data ModelTVar n a = ModelTVar
{ tvarId :: TVarId { tvarId :: TVarId
, tvarRef :: C.CRef n a , tvarRef :: C.IORef n a
} }
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
@ -145,7 +145,7 @@ doTransaction :: C.MonadConc n
doTransaction ma idsource = do doTransaction ma idsource = do
(c, ref) <- runRefCont SStop (Just . Right) (runModelSTM ma) (c, ref) <- runRefCont SStop (Just . Right) (runModelSTM ma)
(idsource', undo, readen, written, trace) <- go ref c (pure ()) idsource [] [] [] (idsource', undo, readen, written, trace) <- go ref c (pure ()) idsource [] [] []
res <- C.readCRef ref res <- C.readIORef ref
case res of case res of
Just (Right val) -> pure (Success (nub readen) (nub written) val, undo, idsource', reverse trace) Just (Right val) -> pure (Success (nub readen) (nub written) val, undo, idsource', reverse trace)
@ -166,10 +166,10 @@ doTransaction ma idsource = do
case tact of case tact of
TStop -> pure (newIDSource, newUndo, newReaden, newWritten, TStop:newSofar) TStop -> pure (newIDSource, newUndo, newReaden, newWritten, TStop:newSofar)
TRetry -> do TRetry -> do
C.writeCRef ref Nothing C.writeIORef ref Nothing
pure (newIDSource, newUndo, newReaden, newWritten, TRetry:newSofar) pure (newIDSource, newUndo, newReaden, newWritten, TRetry:newSofar)
TThrow -> do TThrow -> do
C.writeCRef ref (Just . Left $ case act of SThrow e -> toException e; _ -> undefined) C.writeIORef ref (Just . Left $ case act of SThrow e -> toException e; _ -> undefined)
pure (newIDSource, newUndo, newReaden, newWritten, TThrow:newSofar) pure (newIDSource, newUndo, newReaden, newWritten, TThrow:newSofar)
_ -> go ref newAct newUndo newIDSource newReaden newWritten newSofar _ -> go ref newAct newUndo newIDSource newReaden newWritten newSofar
@ -199,17 +199,17 @@ stepTrans act idsource = case act of
Nothing -> pure (SThrow exc, nothing, idsource, [], [], TCatch trace Nothing)) Nothing -> pure (SThrow exc, nothing, idsource, [], [], TCatch trace Nothing))
stepRead ModelTVar{..} c = do stepRead ModelTVar{..} c = do
val <- C.readCRef tvarRef val <- C.readIORef tvarRef
pure (c val, nothing, idsource, [tvarId], [], TRead tvarId) pure (c val, nothing, idsource, [tvarId], [], TRead tvarId)
stepWrite ModelTVar{..} a c = do stepWrite ModelTVar{..} a c = do
old <- C.readCRef tvarRef old <- C.readIORef tvarRef
C.writeCRef tvarRef a C.writeIORef tvarRef a
pure (c, C.writeCRef tvarRef old, idsource, [], [tvarId], TWrite tvarId) pure (c, C.writeIORef tvarRef old, idsource, [], [tvarId], TWrite tvarId)
stepNew n a c = do stepNew n a c = do
let (idsource', tvid) = nextTVId n idsource let (idsource', tvid) = nextTVId n idsource
ref <- C.newCRef a ref <- C.newIORef a
let tvar = ModelTVar tvid ref let tvar = ModelTVar tvid ref
pure (c tvar, nothing, idsource', [], [tvid], TNew tvid) pure (c tvar, nothing, idsource', [], [tvid], TNew tvid)

View File

@ -65,17 +65,17 @@ instance Show Way where
-- | The number of ID parameters was getting a bit unwieldy, so this -- | The number of ID parameters was getting a bit unwieldy, so this
-- hides them all away. -- hides them all away.
data IdSource = IdSource data IdSource = IdSource
{ _crids :: (Int, [String]) { _iorids :: (Int, [String])
, _mvids :: (Int, [String]) , _mvids :: (Int, [String])
, _tvids :: (Int, [String]) , _tvids :: (Int, [String])
, _tids :: (Int, [String]) , _tids :: (Int, [String])
} deriving (Eq, Ord, Show, Generic, NFData) } deriving (Eq, Ord, Show, Generic, NFData)
-- | Get the next free 'CRefId'. -- | Get the next free 'IORefId'.
nextCRId :: String -> IdSource -> (IdSource, CRefId) nextIORId :: String -> IdSource -> (IdSource, IORefId)
nextCRId name idsource = nextIORId name idsource =
let (crid, crids') = nextId name (_crids idsource) let (iorid, iorids') = nextId name (_iorids idsource)
in (idsource { _crids = crids' }, CRefId crid) in (idsource { _iorids = iorids' }, IORefId iorid)
-- | Get the next free 'MVarId'. -- | Get the next free 'MVarId'.
nextMVId :: String -> IdSource -> (IdSource, MVarId) nextMVId :: String -> IdSource -> (IdSource, MVarId)
@ -176,14 +176,14 @@ rewind (TryReadMVar c _) = WillTryReadMVar c
rewind (TakeMVar c _) = WillTakeMVar c rewind (TakeMVar c _) = WillTakeMVar c
rewind (BlockedTakeMVar c) = WillTakeMVar c rewind (BlockedTakeMVar c) = WillTakeMVar c
rewind (TryTakeMVar c _ _) = WillTryTakeMVar c rewind (TryTakeMVar c _ _) = WillTryTakeMVar c
rewind (NewCRef _) = WillNewCRef rewind (NewIORef _) = WillNewIORef
rewind (ReadCRef c) = WillReadCRef c rewind (ReadIORef c) = WillReadIORef c
rewind (ReadCRefCas c) = WillReadCRefCas c rewind (ReadIORefCas c) = WillReadIORefCas c
rewind (ModCRef c) = WillModCRef c rewind (ModIORef c) = WillModIORef c
rewind (ModCRefCas c) = WillModCRefCas c rewind (ModIORefCas c) = WillModIORefCas c
rewind (WriteCRef c) = WillWriteCRef c rewind (WriteIORef c) = WillWriteIORef c
rewind (CasCRef c _) = WillCasCRef c rewind (CasIORef c _) = WillCasIORef c
rewind (CommitCRef t c) = WillCommitCRef t c rewind (CommitIORef t c) = WillCommitIORef t c
rewind (STM _ _) = WillSTM rewind (STM _ _) = WillSTM
rewind (BlockedSTM _) = WillSTM rewind (BlockedSTM _) = WillSTM
rewind Catching = WillCatching rewind Catching = WillCatching
@ -224,21 +224,21 @@ willRelease _ = False
-- | A simplified view of the possible actions a thread can perform. -- | A simplified view of the possible actions a thread can perform.
data ActionType = data ActionType =
UnsynchronisedRead CRefId UnsynchronisedRead IORefId
-- ^ A 'readCRef' or a 'readForCAS'. -- ^ A 'readIORef' or a 'readForCAS'.
| UnsynchronisedWrite CRefId | UnsynchronisedWrite IORefId
-- ^ A 'writeCRef'. -- ^ A 'writeIORef'.
| UnsynchronisedOther | UnsynchronisedOther
-- ^ Some other action which doesn't require cross-thread -- ^ Some other action which doesn't require cross-thread
-- communication. -- communication.
| PartiallySynchronisedCommit CRefId | PartiallySynchronisedCommit IORefId
-- ^ A commit. -- ^ A commit.
| PartiallySynchronisedWrite CRefId | PartiallySynchronisedWrite IORefId
-- ^ A 'casCRef' -- ^ A 'casIORef'
| PartiallySynchronisedModify CRefId | PartiallySynchronisedModify IORefId
-- ^ A 'modifyCRefCAS' -- ^ A 'modifyIORefCAS'
| SynchronisedModify CRefId | SynchronisedModify IORefId
-- ^ An 'atomicModifyCRef'. -- ^ An 'atomicModifyIORef'.
| SynchronisedRead MVarId | SynchronisedRead MVarId
-- ^ A 'readMVar' or 'takeMVar' (or @try@/@blocked@ variants). -- ^ A 'readMVar' or 'takeMVar' (or @try@/@blocked@ variants).
| SynchronisedWrite MVarId | SynchronisedWrite MVarId
@ -256,26 +256,26 @@ isBarrier (SynchronisedWrite _) = True
isBarrier SynchronisedOther = True isBarrier SynchronisedOther = True
isBarrier _ = False isBarrier _ = False
-- | Check if an action commits a given 'CRef'. -- | Check if an action commits a given 'IORef'.
isCommit :: ActionType -> CRefId -> Bool isCommit :: ActionType -> IORefId -> Bool
isCommit (PartiallySynchronisedCommit c) r = c == r isCommit (PartiallySynchronisedCommit c) r = c == r
isCommit (PartiallySynchronisedWrite c) r = c == r isCommit (PartiallySynchronisedWrite c) r = c == r
isCommit (PartiallySynchronisedModify c) r = c == r isCommit (PartiallySynchronisedModify c) r = c == r
isCommit _ _ = False isCommit _ _ = False
-- | Check if an action synchronises a given 'CRef'. -- | Check if an action synchronises a given 'IORef'.
synchronises :: ActionType -> CRefId -> Bool synchronises :: ActionType -> IORefId -> Bool
synchronises a r = isCommit a r || isBarrier a synchronises a r = isCommit a r || isBarrier a
-- | Get the 'CRef' affected. -- | Get the 'IORef' affected.
crefOf :: ActionType -> Maybe CRefId iorefOf :: ActionType -> Maybe IORefId
crefOf (UnsynchronisedRead r) = Just r iorefOf (UnsynchronisedRead r) = Just r
crefOf (UnsynchronisedWrite r) = Just r iorefOf (UnsynchronisedWrite r) = Just r
crefOf (SynchronisedModify r) = Just r iorefOf (SynchronisedModify r) = Just r
crefOf (PartiallySynchronisedCommit r) = Just r iorefOf (PartiallySynchronisedCommit r) = Just r
crefOf (PartiallySynchronisedWrite r) = Just r iorefOf (PartiallySynchronisedWrite r) = Just r
crefOf (PartiallySynchronisedModify r) = Just r iorefOf (PartiallySynchronisedModify r) = Just r
crefOf _ = Nothing iorefOf _ = Nothing
-- | Get the 'MVar' affected. -- | Get the 'MVar' affected.
mvarOf :: ActionType -> Maybe MVarId mvarOf :: ActionType -> Maybe MVarId
@ -291,7 +291,7 @@ tidsOf (PutMVar _ tids) = S.fromList tids
tidsOf (TryPutMVar _ _ tids) = S.fromList tids tidsOf (TryPutMVar _ _ tids) = S.fromList tids
tidsOf (TakeMVar _ tids) = S.fromList tids tidsOf (TakeMVar _ tids) = S.fromList tids
tidsOf (TryTakeMVar _ _ tids) = S.fromList tids tidsOf (TryTakeMVar _ _ tids) = S.fromList tids
tidsOf (CommitCRef tid _) = S.singleton tid tidsOf (CommitIORef tid _) = S.singleton tid
tidsOf (STM _ tids) = S.fromList tids tidsOf (STM _ tids) = S.fromList tids
tidsOf (ThrowTo tid _) = S.singleton tid tidsOf (ThrowTo tid _) = S.singleton tid
tidsOf (BlockedThrowTo tid) = S.singleton tid tidsOf (BlockedThrowTo tid) = S.singleton tid
@ -313,13 +313,13 @@ simplifyLookahead (WillReadMVar c) = SynchronisedRead c
simplifyLookahead (WillTryReadMVar c) = SynchronisedRead c simplifyLookahead (WillTryReadMVar c) = SynchronisedRead c
simplifyLookahead (WillTakeMVar c) = SynchronisedRead c simplifyLookahead (WillTakeMVar c) = SynchronisedRead c
simplifyLookahead (WillTryTakeMVar c) = SynchronisedRead c simplifyLookahead (WillTryTakeMVar c) = SynchronisedRead c
simplifyLookahead (WillReadCRef r) = UnsynchronisedRead r simplifyLookahead (WillReadIORef r) = UnsynchronisedRead r
simplifyLookahead (WillReadCRefCas r) = UnsynchronisedRead r simplifyLookahead (WillReadIORefCas r) = UnsynchronisedRead r
simplifyLookahead (WillModCRef r) = SynchronisedModify r simplifyLookahead (WillModIORef r) = SynchronisedModify r
simplifyLookahead (WillModCRefCas r) = PartiallySynchronisedModify r simplifyLookahead (WillModIORefCas r) = PartiallySynchronisedModify r
simplifyLookahead (WillWriteCRef r) = UnsynchronisedWrite r simplifyLookahead (WillWriteIORef r) = UnsynchronisedWrite r
simplifyLookahead (WillCasCRef r) = PartiallySynchronisedWrite r simplifyLookahead (WillCasIORef r) = PartiallySynchronisedWrite r
simplifyLookahead (WillCommitCRef _ r) = PartiallySynchronisedCommit r simplifyLookahead (WillCommitIORef _ r) = PartiallySynchronisedCommit r
simplifyLookahead WillSTM = SynchronisedOther simplifyLookahead WillSTM = SynchronisedOther
simplifyLookahead (WillThrowTo _) = SynchronisedOther simplifyLookahead (WillThrowTo _) = SynchronisedOther
simplifyLookahead _ = UnsynchronisedOther simplifyLookahead _ = UnsynchronisedOther
@ -393,8 +393,8 @@ runRefCont :: C.MonadConc n
=> (n () -> x) => (n () -> x)
-> (a -> Maybe b) -> (a -> Maybe b)
-> ((a -> x) -> x) -> ((a -> x) -> x)
-> n (x, C.CRef n (Maybe b)) -> n (x, C.IORef n (Maybe b))
runRefCont act f k = do runRefCont act f k = do
ref <- C.newCRef Nothing ref <- C.newIORef Nothing
let c = k (act . C.writeCRef ref . f) let c = k (act . C.writeIORef ref . f)
pure (c, ref) pure (c, ref)

View File

@ -69,7 +69,7 @@ runSCT :: MonadConc n
=> Way => Way
-- ^ How to run the concurrent program. -- ^ How to run the concurrent program.
-> MemType -> MemType
-- ^ The memory model to use for non-synchronised @CRef@ operations. -- ^ The memory model to use for non-synchronised @IORef@ operations.
-> ConcT n a -> ConcT n a
-- ^ The computation to run many times. -- ^ The computation to run many times.
-> n [(Either Failure a, Trace)] -> n [(Either Failure a, Trace)]
@ -82,7 +82,7 @@ resultsSet :: (MonadConc n, Ord a)
=> Way => Way
-- ^ How to run the concurrent program. -- ^ How to run the concurrent program.
-> MemType -> MemType
-- ^ The memory model to use for non-synchronised @CRef@ operations. -- ^ The memory model to use for non-synchronised @IORef@ operations.
-> ConcT n a -> ConcT n a
-- ^ The computation to run many times. -- ^ The computation to run many times.
-> n (Set (Either Failure a)) -> n (Set (Either Failure a))
@ -100,7 +100,7 @@ runSCTDiscard :: MonadConc n
-> Way -> Way
-- ^ How to run the concurrent program. -- ^ How to run the concurrent program.
-> MemType -> MemType
-- ^ The memory model to use for non-synchronised @CRef@ operations. -- ^ The memory model to use for non-synchronised @IORef@ operations.
-> ConcT n a -> ConcT n a
-- ^ The computation to run many times. -- ^ The computation to run many times.
-> n [(Either Failure a, Trace)] -> n [(Either Failure a, Trace)]
@ -116,7 +116,7 @@ resultsSetDiscard :: (MonadConc n, Ord a)
-> Way -> Way
-- ^ How to run the concurrent program. -- ^ How to run the concurrent program.
-> MemType -> MemType
-- ^ The memory model to use for non-synchronised @CRef@ operations. -- ^ The memory model to use for non-synchronised @IORef@ operations.
-> ConcT n a -> ConcT n a
-- ^ The computation to run many times. -- ^ The computation to run many times.
-> n (Set (Either Failure a)) -> n (Set (Either Failure a))
@ -373,7 +373,7 @@ lBacktrack = backtrackAt (\_ _ -> False)
-- @since 1.0.0.0 -- @since 1.0.0.0
sctBound :: MonadConc n sctBound :: MonadConc n
=> MemType => MemType
-- ^ The memory model to use for non-synchronised @CRef@ operations. -- ^ The memory model to use for non-synchronised @IORef@ operations.
-> Bounds -> Bounds
-- ^ The combined bounds. -- ^ The combined bounds.
-> ConcT n a -> ConcT n a
@ -392,7 +392,7 @@ sctBoundDiscard :: MonadConc n
=> (Either Failure a -> Maybe Discard) => (Either Failure a -> Maybe Discard)
-- ^ Selectively discard results. -- ^ Selectively discard results.
-> MemType -> MemType
-- ^ The memory model to use for non-synchronised @CRef@ operations. -- ^ The memory model to use for non-synchronised @IORef@ operations.
-> Bounds -> Bounds
-- ^ The combined bounds. -- ^ The combined bounds.
-> ConcT n a -> ConcT n a
@ -412,7 +412,7 @@ sctBoundDiscard discard memtype cb = runSCTWithSettings $
-- @since 1.0.0.0 -- @since 1.0.0.0
sctUniformRandom :: (MonadConc n, RandomGen g) sctUniformRandom :: (MonadConc n, RandomGen g)
=> MemType => MemType
-- ^ The memory model to use for non-synchronised @CRef@ operations. -- ^ The memory model to use for non-synchronised @IORef@ operations.
-> g -> g
-- ^ The random number generator. -- ^ The random number generator.
-> Int -> Int
@ -433,7 +433,7 @@ sctUniformRandomDiscard :: (MonadConc n, RandomGen g)
=> (Either Failure a -> Maybe Discard) => (Either Failure a -> Maybe Discard)
-- ^ Selectively discard results. -- ^ Selectively discard results.
-> MemType -> MemType
-- ^ The memory model to use for non-synchronised @CRef@ operations. -- ^ The memory model to use for non-synchronised @IORef@ operations.
-> g -> g
-- ^ The random number generator. -- ^ The random number generator.
-> Int -> Int
@ -455,7 +455,7 @@ sctUniformRandomDiscard discard memtype g lim = runSCTWithSettings $
-- @since 1.7.0.0 -- @since 1.7.0.0
sctWeightedRandom :: (MonadConc n, RandomGen g) sctWeightedRandom :: (MonadConc n, RandomGen g)
=> MemType => MemType
-- ^ The memory model to use for non-synchronised @CRef@ operations. -- ^ The memory model to use for non-synchronised @IORef@ operations.
-> g -> g
-- ^ The random number generator. -- ^ The random number generator.
-> Int -> Int
@ -476,7 +476,7 @@ sctWeightedRandomDiscard :: (MonadConc n, RandomGen g)
=> (Either Failure a -> Maybe Discard) => (Either Failure a -> Maybe Discard)
-- ^ Selectively discard results. -- ^ Selectively discard results.
-> MemType -> MemType
-- ^ The memory model to use for non-synchronised @CRef@ operations. -- ^ The memory model to use for non-synchronised @IORef@ operations.
-> g -> g
-- ^ The random number generator. -- ^ The random number generator.
-> Int -> Int
@ -533,7 +533,7 @@ yieldCountInc sofar prior (d, lnext) = case prior of
-- | Determine if an action is a commit or not. -- | Determine if an action is a commit or not.
isCommitRef :: ThreadAction -> Bool isCommitRef :: ThreadAction -> Bool
isCommitRef (CommitCRef _ _) = True isCommitRef (CommitIORef _ _) = True
isCommitRef _ = False isCommitRef _ = False
-- | Get the maximum difference between two ints in a list. -- | Get the maximum difference between two ints in a list.

View File

@ -70,8 +70,8 @@ sct settings s0 sfun srun conc
sfun sfun
(srun (runSnap snap)) (srun (runSnap snap))
(runSnap snap) (runSnap snap)
(toId $ 1 + fst (_tids idsrc)) (toId $ 1 + fst (_tids idsrc))
(toId $ 1 + fst (_crids idsrc)) (toId $ 1 + fst (_iorids idsrc))
runFull sched s = runConcurrent sched (_memtype settings) s conc runFull sched s = runConcurrent sched (_memtype settings) s conc
runSnap snap sched s = runWithDCSnapshot sched (_memtype settings) s snap runSnap snap sched s = runWithDCSnapshot sched (_memtype settings) s snap
@ -93,8 +93,8 @@ sct' :: (MonadConc n, HasCallStack)
-- ^ Just run the computation -- ^ Just run the computation
-> ThreadId -> ThreadId
-- ^ The first available @ThreadId@ -- ^ The first available @ThreadId@
-> CRefId -> IORefId
-- ^ The first available @CRefId@ -- ^ The first available @IORefId@
-> n [(Either Failure a, Trace)] -> n [(Either Failure a, Trace)]
sct' settings s0 sfun srun run nTId nCRId = go Nothing [] s0 where sct' settings s0 sfun srun run nTId nCRId = go Nothing [] s0 where
go (Just res) _ _ | earlyExit res = pure [] go (Just res) _ _ | earlyExit res = pure []
@ -154,8 +154,8 @@ simplifyExecution :: (MonadConc n, HasCallStack)
-- ^ Just run the computation -- ^ Just run the computation
-> ThreadId -> ThreadId
-- ^ The first available @ThreadId@ -- ^ The first available @ThreadId@
-> CRefId -> IORefId
-- ^ The first available @CRefId@ -- ^ The first available @IORefId@
-> Either Failure a -> Either Failure a
-- ^ The expected result -- ^ The expected result
-> Trace -> Trace
@ -244,7 +244,7 @@ permuteBy safeIO memtype = go initialDepState where
dropCommits :: Bool -> MemType -> [(ThreadId, ThreadAction)] -> [(ThreadId, ThreadAction)] dropCommits :: Bool -> MemType -> [(ThreadId, ThreadAction)] -> [(ThreadId, ThreadAction)]
dropCommits _ SequentialConsistency = id dropCommits _ SequentialConsistency = id
dropCommits safeIO memtype = go initialDepState where dropCommits safeIO memtype = go initialDepState where
go ds (t1@(tid1, ta1@(CommitCRef _ _)):t2@(tid2, ta2):trc) go ds (t1@(tid1, ta1@(CommitIORef _ _)):t2@(tid2, ta2):trc)
| isBarrier (simplifyAction ta2) = go ds (t2:trc) | isBarrier (simplifyAction ta2) = go ds (t2:trc)
| independent safeIO ds tid1 ta1 tid2 ta2 = t2 : go (updateDepState memtype ds tid2 ta2) (t1:trc) | independent safeIO ds tid1 ta1 tid2 ta2 = t2 : go (updateDepState memtype ds tid2 ta2) (t1:trc)
go ds (t@(tid,ta):trc) = t : go (updateDepState memtype ds tid ta) trc go ds (t@(tid,ta):trc) = t : go (updateDepState memtype ds tid ta) trc
@ -302,11 +302,11 @@ pushForward safeIO memtype = go initialDepState where
| otherwise = Nothing | otherwise = Nothing
fgo _ _ = Nothing fgo _ _ = Nothing
-- | Re-number threads and CRefs. -- | Re-number threads and IORefs.
-- --
-- Permuting forks or newCRefs makes the existing numbering invalid, -- Permuting forks or newIORefs makes the existing numbering invalid,
-- which then causes problems for scheduling. Just re-numbering -- which then causes problems for scheduling. Just re-numbering
-- threads isn't enough, as CRef IDs are used to determine commit -- threads isn't enough, as IORef IDs are used to determine commit
-- thread IDs. -- thread IDs.
-- --
-- Renumbered things will not fix their names, so don't rely on those -- Renumbered things will not fix their names, so don't rely on those
@ -317,14 +317,14 @@ renumber
-> Int -> Int
-- ^ First free thread ID. -- ^ First free thread ID.
-> Int -> Int
-- ^ First free @CRef@ ID. -- ^ First free @IORef@ ID.
-> [(ThreadId, ThreadAction)] -> [(ThreadId, ThreadAction)]
-> [(ThreadId, ThreadAction)] -> [(ThreadId, ThreadAction)]
renumber memtype tid0 crid0 = snd . mapAccumL go (I.empty, tid0, I.empty, crid0) where renumber memtype tid0 crid0 = snd . mapAccumL go (I.empty, tid0, I.empty, crid0) where
go s@(tidmap, _, cridmap, _) (_, CommitCRef tid crid) = go s@(tidmap, _, cridmap, _) (_, CommitIORef tid crid) =
let tid' = renumbered tidmap tid let tid' = renumbered tidmap tid
crid' = renumbered cridmap crid crid' = renumbered cridmap crid
act' = CommitCRef tid' crid' act' = CommitIORef tid' crid'
in case memtype of in case memtype of
PartialStoreOrder -> (s, (commitThreadId tid' (Just crid'), act')) PartialStoreOrder -> (s, (commitThreadId tid' (Just crid'), act'))
_ -> (s, (commitThreadId tid' Nothing, act')) _ -> (s, (commitThreadId tid' Nothing, act'))
@ -351,22 +351,22 @@ renumber memtype tid0 crid0 = snd . mapAccumL go (I.empty, tid0, I.empty, crid0)
(s, TakeMVar mvid (map (renumbered tidmap) olds)) (s, TakeMVar mvid (map (renumbered tidmap) olds))
updateAction s@(tidmap, _, _, _) (TryTakeMVar mvid b olds) = updateAction s@(tidmap, _, _, _) (TryTakeMVar mvid b olds) =
(s, TryTakeMVar mvid b (map (renumbered tidmap) olds)) (s, TryTakeMVar mvid b (map (renumbered tidmap) olds))
updateAction (tidmap, nTId, cridmap, nCRId) (NewCRef old) = updateAction (tidmap, nTId, cridmap, nCRId) (NewIORef old) =
let cridmap' = I.insert (fromId old) nCRId cridmap let cridmap' = I.insert (fromId old) nCRId cridmap
nCRId' = nCRId + 1 nCRId' = nCRId + 1
in ((tidmap, nTId, cridmap', nCRId'), NewCRef (toId nCRId)) in ((tidmap, nTId, cridmap', nCRId'), NewIORef (toId nCRId))
updateAction s@(_, _, cridmap, _) (ReadCRef old) = updateAction s@(_, _, cridmap, _) (ReadIORef old) =
(s, ReadCRef (renumbered cridmap old)) (s, ReadIORef (renumbered cridmap old))
updateAction s@(_, _, cridmap, _) (ReadCRefCas old) = updateAction s@(_, _, cridmap, _) (ReadIORefCas old) =
(s, ReadCRefCas (renumbered cridmap old)) (s, ReadIORefCas (renumbered cridmap old))
updateAction s@(_, _, cridmap, _) (ModCRef old) = updateAction s@(_, _, cridmap, _) (ModIORef old) =
(s, ModCRef (renumbered cridmap old)) (s, ModIORef (renumbered cridmap old))
updateAction s@(_, _, cridmap, _) (ModCRefCas old) = updateAction s@(_, _, cridmap, _) (ModIORefCas old) =
(s, ModCRefCas (renumbered cridmap old)) (s, ModIORefCas (renumbered cridmap old))
updateAction s@(_, _, cridmap, _) (WriteCRef old) = updateAction s@(_, _, cridmap, _) (WriteIORef old) =
(s, WriteCRef (renumbered cridmap old)) (s, WriteIORef (renumbered cridmap old))
updateAction s@(_, _, cridmap, _) (CasCRef old b) = updateAction s@(_, _, cridmap, _) (CasIORef old b) =
(s, CasCRef (renumbered cridmap old) b) (s, CasIORef (renumbered cridmap old) b)
updateAction s@(tidmap, _, _, _) (STM tas olds) = updateAction s@(tidmap, _, _, _) (STM tas olds) =
(s, STM tas (map (renumbered tidmap) olds)) (s, STM tas (map (renumbered tidmap) olds))
updateAction s@(tidmap, _, _, _) (ThrowTo old b) = updateAction s@(tidmap, _, _, _) (ThrowTo old b) =

View File

@ -572,7 +572,7 @@ independent safeIO ds t1 a1 t2 a2
-- See #191 / #190 -- See #191 / #190
check _ (ThrowTo t _) tid _ | t == tid = True check _ (ThrowTo t _) tid _ | t == tid = True
check _ (BlockedThrowTo t) tid _ | t == tid = True check _ (BlockedThrowTo t) tid _ | t == tid = True
-- can't re-order an unsynchronised write with something which synchronises that CRef. -- can't re-order an unsynchronised write with something which synchronises that IORef.
check _ (simplifyAction -> UnsynchronisedWrite r) _ (simplifyAction -> a) | synchronises a r = True check _ (simplifyAction -> UnsynchronisedWrite r) _ (simplifyAction -> a) | synchronises a r = True
check _ _ _ _ = False check _ _ _ _ = False
@ -674,14 +674,14 @@ dependentActions ds a1 a2 = case (a1, a2) of
(SynchronisedWrite v1, SynchronisedRead v2) | v1 == v2 -> True (SynchronisedWrite v1, SynchronisedRead v2) | v1 == v2 -> True
(SynchronisedRead v1, SynchronisedWrite v2) | v1 == v2 -> True (SynchronisedRead v1, SynchronisedWrite v2) | v1 == v2 -> True
(_, _) -> maybe False (\r -> Just r == crefOf a2) (crefOf a1) (_, _) -> maybe False (\r -> Just r == iorefOf a2) (iorefOf a1)
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- ** Dependency function state -- ** Dependency function state
data DepState = DepState data DepState = DepState
{ depCRState :: Map CRefId Bool { depIOState :: Map IORefId Bool
-- ^ Keep track of which @CRef@s have buffered writes. -- ^ Keep track of which @IORef@s have buffered writes.
, depMVState :: Set MVarId , depMVState :: Set MVarId
-- ^ Keep track of which @MVar@s are full. -- ^ Keep track of which @MVar@s are full.
, depMaskState :: Map ThreadId MaskingState , depMaskState :: Map ThreadId MaskingState
@ -692,7 +692,7 @@ data DepState = DepState
} deriving (Eq, Show) } deriving (Eq, Show)
instance NFData DepState where instance NFData DepState where
rnf depstate = rnf ( depCRState depstate rnf depstate = rnf ( depIOState depstate
, depMVState depstate , depMVState depstate
, [(t, m `seq` ()) | (t, m) <- M.toList (depMaskState depstate)] , [(t, m `seq` ()) | (t, m) <- M.toList (depMaskState depstate)]
) )
@ -705,17 +705,17 @@ initialDepState = DepState M.empty S.empty M.empty
-- happened. -- happened.
updateDepState :: MemType -> DepState -> ThreadId -> ThreadAction -> DepState updateDepState :: MemType -> DepState -> ThreadId -> ThreadAction -> DepState
updateDepState memtype depstate tid act = DepState updateDepState memtype depstate tid act = DepState
{ depCRState = updateCRState memtype act $ depCRState depstate { depIOState = updateCRState memtype act $ depIOState depstate
, depMVState = updateMVState act $ depMVState depstate , depMVState = updateMVState act $ depMVState depstate
, depMaskState = updateMaskState tid act $ depMaskState depstate , depMaskState = updateMaskState tid act $ depMaskState depstate
} }
-- | Update the @CRef@ buffer state with the action that has just -- | Update the @IORef@ buffer state with the action that has just
-- happened. -- happened.
updateCRState :: MemType -> ThreadAction -> Map CRefId Bool -> Map CRefId Bool updateCRState :: MemType -> ThreadAction -> Map IORefId Bool -> Map IORefId Bool
updateCRState SequentialConsistency _ = const M.empty updateCRState SequentialConsistency _ = const M.empty
updateCRState _ (CommitCRef _ r) = M.delete r updateCRState _ (CommitIORef _ r) = M.delete r
updateCRState _ (WriteCRef r) = M.insert r True updateCRState _ (WriteIORef r) = M.insert r True
updateCRState _ ta updateCRState _ ta
| isBarrier $ simplifyAction ta = const M.empty | isBarrier $ simplifyAction ta = const M.empty
| otherwise = id | otherwise = id
@ -743,9 +743,9 @@ updateMaskState _ (ThrowTo tid True) = M.delete tid
updateMaskState tid Stop = M.delete tid updateMaskState tid Stop = M.delete tid
updateMaskState _ _ = id updateMaskState _ _ = id
-- | Check if a @CRef@ has a buffered write pending. -- | Check if a @IORef@ has a buffered write pending.
isBuffered :: DepState -> CRefId -> Bool isBuffered :: DepState -> IORefId -> Bool
isBuffered depstate r = M.findWithDefault False r (depCRState depstate) isBuffered depstate r = M.findWithDefault False r (depIOState depstate)
-- | Check if an @MVar@ is full. -- | Check if an @MVar@ is full.
isFull :: DepState -> MVarId -> Bool isFull :: DepState -> MVarId -> Bool

View File

@ -59,22 +59,22 @@ module Test.DejaFu.Settings
-- ** The @MemType@ -- ** The @MemType@
-- | When executed on a multi-core processor some @CRef@ / @IORef@ -- | When executed on a multi-core processor some @IORef@ / @IORef@
-- programs can exhibit \"relaxed memory\" behaviours, where the -- programs can exhibit \"relaxed memory\" behaviours, where the
-- apparent behaviour of the program is not a simple interleaving of -- apparent behaviour of the program is not a simple interleaving of
-- the actions of each thread. -- the actions of each thread.
-- --
-- __Example:__ This is a simple program which creates two @CRef@s -- __Example:__ This is a simple program which creates two @IORef@s
-- containing @False@, and forks two threads. Each thread writes -- containing @False@, and forks two threads. Each thread writes
-- @True@ to one of the @CRef@s and reads the other. The value that -- @True@ to one of the @IORef@s and reads the other. The value that
-- each thread reads is communicated back through an @MVar@: -- each thread reads is communicated back through an @MVar@:
-- --
-- > >>> :{ -- > >>> :{
-- > let relaxed = do -- > let relaxed = do
-- > r1 <- newCRef False -- > r1 <- newIORef False
-- > r2 <- newCRef False -- > r2 <- newIORef False
-- > x <- spawn $ writeCRef r1 True >> readCRef r2 -- > x <- spawn $ writeIORef r1 True >> readIORef r2
-- > y <- spawn $ writeCRef r2 True >> readCRef r1 -- > y <- spawn $ writeIORef r2 True >> readIORef r1
-- > (,) <$> readMVar x <*> readMVar y -- > (,) <$> readMVar x <*> readMVar y
-- > :} -- > :}
-- --
@ -94,12 +94,12 @@ module Test.DejaFu.Settings
-- > False -- > False
-- --
-- It's possible for both threads to read the value @False@, even -- It's possible for both threads to read the value @False@, even
-- though each writes @True@ to the other @CRef@ before reading. -- though each writes @True@ to the other @IORef@ before reading.
-- This is because processors are free to re-order reads and writes -- This is because processors are free to re-order reads and writes
-- to independent memory addresses in the name of performance. -- to independent memory addresses in the name of performance.
-- --
-- Execution traces for relaxed memory computations can include -- Execution traces for relaxed memory computations can include
-- \"C\" actions, as above, which show where @CRef@ writes were -- \"C\" actions, as above, which show where @IORef@ writes were
-- explicitly /committed/, and made visible to other threads. -- explicitly /committed/, and made visible to other threads.
-- --
-- However, modelling this behaviour can require more executions. -- However, modelling this behaviour can require more executions.

View File

@ -39,17 +39,14 @@ instance Show ThreadId where
-- | @since 1.3.1.0 -- | @since 1.3.1.0
deriving instance Generic ThreadId deriving instance Generic ThreadId
-- | Every @CRef@ has a unique identifier. -- | Every @IORef@ has a unique identifier.
-- --
-- @since 1.0.0.0 -- @since 1.11.0.0
newtype CRefId = CRefId Id newtype IORefId = IORefId Id
deriving (Eq, Ord, NFData) deriving (Eq, Ord, NFData, Generic)
instance Show CRefId where instance Show IORefId where
show (CRefId id_) = show id_ show (IORefId id_) = show id_
-- | @since 1.3.1.0
deriving instance Generic CRefId
-- | Every @MVar@ has a unique identifier. -- | Every @MVar@ has a unique identifier.
-- --
@ -75,7 +72,7 @@ instance Show TVarId where
-- | @since 1.3.1.0 -- | @since 1.3.1.0
deriving instance Generic TVarId deriving instance Generic TVarId
-- | An identifier for a thread, @MVar@, @CRef@, or @TVar@. -- | An identifier for a thread, @MVar@, @IORef@, or @TVar@.
-- --
-- The number is the important bit. The string is to make execution -- The number is the important bit. The string is to make execution
-- traces easier to read, but is meaningless. -- traces easier to read, but is meaningless.
@ -109,7 +106,7 @@ initialThread = ThreadId (Id (Just "main") 0)
-- | All the actions that a thread can perform. -- | All the actions that a thread can perform.
-- --
-- @since 1.9.0.0 -- @since 1.11.0.0
data ThreadAction = data ThreadAction =
Fork ThreadId Fork ThreadId
-- ^ Start a new thread. -- ^ Start a new thread.
@ -147,23 +144,23 @@ data ThreadAction =
-- ^ Get blocked on a take. -- ^ Get blocked on a take.
| TryTakeMVar MVarId Bool [ThreadId] | TryTakeMVar MVarId Bool [ThreadId]
-- ^ Try to take from a 'MVar', possibly waking up some threads. -- ^ Try to take from a 'MVar', possibly waking up some threads.
| NewCRef CRefId | NewIORef IORefId
-- ^ Create a new 'CRef'. -- ^ Create a new 'IORef'.
| ReadCRef CRefId | ReadIORef IORefId
-- ^ Read from a 'CRef'. -- ^ Read from a 'IORef'.
| ReadCRefCas CRefId | ReadIORefCas IORefId
-- ^ Read from a 'CRef' for a future compare-and-swap. -- ^ Read from a 'IORef' for a future compare-and-swap.
| ModCRef CRefId | ModIORef IORefId
-- ^ Modify a 'CRef'. -- ^ Modify a 'IORef'.
| ModCRefCas CRefId | ModIORefCas IORefId
-- ^ Modify a 'CRef' using a compare-and-swap. -- ^ Modify a 'IORef' using a compare-and-swap.
| WriteCRef CRefId | WriteIORef IORefId
-- ^ Write to a 'CRef' without synchronising. -- ^ Write to a 'IORef' without synchronising.
| CasCRef CRefId Bool | CasIORef IORefId Bool
-- ^ Attempt to to a 'CRef' using a compare-and-swap, synchronising -- ^ Attempt to to a 'IORef' using a compare-and-swap, synchronising
-- it. -- it.
| CommitCRef ThreadId CRefId | CommitIORef ThreadId IORefId
-- ^ Commit the last write to the given 'CRef' by the given thread, -- ^ Commit the last write to the given 'IORef' by the given thread,
-- so that all threads can see the updated value. -- so that all threads can see the updated value.
| STM [TAction] [ThreadId] | STM [TAction] [ThreadId]
-- ^ An STM transaction was executed, possibly waking up some -- ^ An STM transaction was executed, possibly waking up some
@ -203,10 +200,7 @@ data ThreadAction =
-- ^ Stop executing an action with @subconcurrency@. -- ^ Stop executing an action with @subconcurrency@.
| DontCheck Trace | DontCheck Trace
-- ^ Execute an action with @dontCheck@. -- ^ Execute an action with @dontCheck@.
deriving (Eq, Show) deriving (Eq, Generic, Show)
-- | @since 1.3.1.0
deriving instance Generic ThreadAction
-- this makes me sad -- this makes me sad
instance NFData ThreadAction where instance NFData ThreadAction where
@ -228,14 +222,14 @@ instance NFData ThreadAction where
rnf (TakeMVar m ts) = rnf (m, ts) rnf (TakeMVar m ts) = rnf (m, ts)
rnf (BlockedTakeMVar m) = rnf m rnf (BlockedTakeMVar m) = rnf m
rnf (TryTakeMVar m b ts) = rnf (m, b, ts) rnf (TryTakeMVar m b ts) = rnf (m, b, ts)
rnf (NewCRef c) = rnf c rnf (NewIORef c) = rnf c
rnf (ReadCRef c) = rnf c rnf (ReadIORef c) = rnf c
rnf (ReadCRefCas c) = rnf c rnf (ReadIORefCas c) = rnf c
rnf (ModCRef c) = rnf c rnf (ModIORef c) = rnf c
rnf (ModCRefCas c) = rnf c rnf (ModIORefCas c) = rnf c
rnf (WriteCRef c) = rnf c rnf (WriteIORef c) = rnf c
rnf (CasCRef c b) = rnf (c, b) rnf (CasIORef c b) = rnf (c, b)
rnf (CommitCRef t c) = rnf (t, c) rnf (CommitIORef t c) = rnf (t, c)
rnf (STM as ts) = rnf (as, ts) rnf (STM as ts) = rnf (as, ts)
rnf (BlockedSTM as) = rnf as rnf (BlockedSTM as) = rnf as
rnf Catching = () rnf Catching = ()
@ -254,7 +248,7 @@ instance NFData ThreadAction where
-- | A one-step look-ahead at what a thread will do next. -- | A one-step look-ahead at what a thread will do next.
-- --
-- @since 1.1.0.0 -- @since 1.11.0.0
data Lookahead = data Lookahead =
WillFork WillFork
-- ^ Will start a new thread. -- ^ Will start a new thread.
@ -288,23 +282,23 @@ data Lookahead =
-- ^ Will take from a 'MVar', possibly waking up some threads. -- ^ Will take from a 'MVar', possibly waking up some threads.
| WillTryTakeMVar MVarId | WillTryTakeMVar MVarId
-- ^ Will try to take from a 'MVar', possibly waking up some threads. -- ^ Will try to take from a 'MVar', possibly waking up some threads.
| WillNewCRef | WillNewIORef
-- ^ Will create a new 'CRef'. -- ^ Will create a new 'IORef'.
| WillReadCRef CRefId | WillReadIORef IORefId
-- ^ Will read from a 'CRef'. -- ^ Will read from a 'IORef'.
| WillReadCRefCas CRefId | WillReadIORefCas IORefId
-- ^ Will read from a 'CRef' for a future compare-and-swap. -- ^ Will read from a 'IORef' for a future compare-and-swap.
| WillModCRef CRefId | WillModIORef IORefId
-- ^ Will modify a 'CRef'. -- ^ Will modify a 'IORef'.
| WillModCRefCas CRefId | WillModIORefCas IORefId
-- ^ Will modify a 'CRef' using a compare-and-swap. -- ^ Will modify a 'IORef' using a compare-and-swap.
| WillWriteCRef CRefId | WillWriteIORef IORefId
-- ^ Will write to a 'CRef' without synchronising. -- ^ Will write to a 'IORef' without synchronising.
| WillCasCRef CRefId | WillCasIORef IORefId
-- ^ Will attempt to to a 'CRef' using a compare-and-swap, -- ^ Will attempt to to a 'IORef' using a compare-and-swap,
-- synchronising it. -- synchronising it.
| WillCommitCRef ThreadId CRefId | WillCommitIORef ThreadId IORefId
-- ^ Will commit the last write by the given thread to the 'CRef'. -- ^ Will commit the last write by the given thread to the 'IORef'.
| WillSTM | WillSTM
-- ^ Will execute an STM transaction, possibly waking up some -- ^ Will execute an STM transaction, possibly waking up some
-- threads. -- threads.
@ -337,10 +331,7 @@ data Lookahead =
-- ^ Will stop executing an extion with @subconcurrency@. -- ^ Will stop executing an extion with @subconcurrency@.
| WillDontCheck | WillDontCheck
-- ^ Will execute an action with @dontCheck@. -- ^ Will execute an action with @dontCheck@.
deriving (Eq, Show) deriving (Eq, Generic, Show)
-- | @since 1.3.1.0
deriving instance Generic Lookahead
-- this also makes me sad -- this also makes me sad
instance NFData Lookahead where instance NFData Lookahead where
@ -359,14 +350,14 @@ instance NFData Lookahead where
rnf (WillTryReadMVar m) = rnf m rnf (WillTryReadMVar m) = rnf m
rnf (WillTakeMVar m) = rnf m rnf (WillTakeMVar m) = rnf m
rnf (WillTryTakeMVar m) = rnf m rnf (WillTryTakeMVar m) = rnf m
rnf WillNewCRef = () rnf WillNewIORef = ()
rnf (WillReadCRef c) = rnf c rnf (WillReadIORef c) = rnf c
rnf (WillReadCRefCas c) = rnf c rnf (WillReadIORefCas c) = rnf c
rnf (WillModCRef c) = rnf c rnf (WillModIORef c) = rnf c
rnf (WillModCRefCas c) = rnf c rnf (WillModIORefCas c) = rnf c
rnf (WillWriteCRef c) = rnf c rnf (WillWriteIORef c) = rnf c
rnf (WillCasCRef c) = rnf c rnf (WillCasIORef c) = rnf c
rnf (WillCommitCRef t c) = rnf (t, c) rnf (WillCommitIORef t c) = rnf (t, c)
rnf WillSTM = () rnf WillSTM = ()
rnf WillCatching = () rnf WillCatching = ()
rnf WillPopCatching = () rnf WillPopCatching = ()
@ -715,13 +706,13 @@ strengthenDiscard d1 d2 =
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- * Memory Models -- * Memory Models
-- | The memory model to use for non-synchronised 'CRef' operations. -- | The memory model to use for non-synchronised 'IORef' operations.
-- --
-- @since 0.4.0.0 -- @since 0.4.0.0
data MemType = data MemType =
SequentialConsistency SequentialConsistency
-- ^ The most intuitive model: a program behaves as a simple -- ^ The most intuitive model: a program behaves as a simple
-- interleaving of the actions in different threads. When a 'CRef' -- interleaving of the actions in different threads. When a 'IORef'
-- is written to, that write is immediately visible to all threads. -- is written to, that write is immediately visible to all threads.
| TotalStoreOrder | TotalStoreOrder
-- ^ Each thread has a write buffer. A thread sees its writes -- ^ Each thread has a write buffer. A thread sees its writes
@ -729,9 +720,9 @@ data MemType =
-- committed, which may happen later. Writes are committed in the -- committed, which may happen later. Writes are committed in the
-- same order that they are created. -- same order that they are created.
| PartialStoreOrder | PartialStoreOrder
-- ^ Each 'CRef' has a write buffer. A thread sees its writes -- ^ Each 'IORef' has a write buffer. A thread sees its writes
-- immediately, but other threads will only see writes when they are -- immediately, but other threads will only see writes when they are
-- committed, which may happen later. Writes to different 'CRef's -- committed, which may happen later. Writes to different 'IORef's
-- are not necessarily committed in the same order that they are -- are not necessarily committed in the same order that they are
-- created. -- created.
deriving (Eq, Show, Read, Ord, Enum, Bounded) deriving (Eq, Show, Read, Ord, Enum, Bounded)

View File

@ -34,7 +34,7 @@ toTIdTrace =
showTrace :: Trace -> String showTrace :: Trace -> String
showTrace [] = "<trace discarded>" showTrace [] = "<trace discarded>"
showTrace trc = intercalate "\n" $ go False trc : strkey where showTrace trc = intercalate "\n" $ go False trc : strkey where
go _ ((_,_,CommitCRef _ _):rest) = "C-" ++ go False rest go _ ((_,_,CommitIORef _ _):rest) = "C-" ++ go False rest
go _ ((Start (ThreadId (Id _ i)),_,a):rest) = "S" ++ show i ++ "-" ++ go (didYield a) rest go _ ((Start (ThreadId (Id _ i)),_,a):rest) = "S" ++ show i ++ "-" ++ go (didYield a) rest
go y ((SwitchTo (ThreadId (Id _ i)),_,a):rest) = (if y then "p" else "P") ++ show i ++ "-" ++ go (didYield a) rest go y ((SwitchTo (ThreadId (Id _ i)),_,a):rest) = (if y then "p" else "P") ++ show i ++ "-" ++ go (didYield a) rest
go _ ((Continue,_,a):rest) = '-' : go (didYield a) rest go _ ((Continue,_,a):rest) = '-' : go (didYield a) rest
@ -63,7 +63,7 @@ simplestsBy f = map choose . collect where
choose = minimumBy . comparing $ \(_, trc) -> choose = minimumBy . comparing $ \(_, trc) ->
let switchTos = length . filter (\(d,_,_) -> case d of SwitchTo _ -> True; _ -> False) let switchTos = length . filter (\(d,_,_) -> case d of SwitchTo _ -> True; _ -> False)
starts = length . filter (\(d,_,_) -> case d of Start _ -> True; _ -> False) starts = length . filter (\(d,_,_) -> case d of Start _ -> True; _ -> False)
commits = length . filter (\(_,_,a) -> case a of CommitCRef _ _ -> True; _ -> False) commits = length . filter (\(_,_,a) -> case a of CommitIORef _ _ -> True; _ -> False)
in (switchTos trc, commits trc, length trc, starts trc) in (switchTos trc, commits trc, length trc, starts trc)
groupBy' res _ [] = res groupBy' res _ [] = res

View File

@ -2,7 +2,7 @@
-- documentation, see http://haskell.org/cabal/users-guide/ -- documentation, see http://haskell.org/cabal/users-guide/
name: dejafu name: dejafu
version: 1.10.1.0 version: 1.11.0.0
synopsis: A library for unit-testing concurrent programs. synopsis: A library for unit-testing concurrent programs.
description: description:
@ -33,7 +33,7 @@ source-repository head
source-repository this source-repository this
type: git type: git
location: https://github.com/barrucadu/dejafu.git location: https://github.com/barrucadu/dejafu.git
tag: dejafu-1.10.1.0 tag: dejafu-1.11.0.0
library library
exposed-modules: Test.DejaFu exposed-modules: Test.DejaFu
@ -58,7 +58,7 @@ library
-- other-modules: -- other-modules:
-- other-extensions: -- other-extensions:
build-depends: base >=4.9 && <5 build-depends: base >=4.9 && <5
, concurrency >=1.5 && <1.6 , concurrency >=1.6 && <1.7
, containers >=0.5 && <0.6 , containers >=0.5 && <0.6
, contravariant >=1.2 && <1.5 , contravariant >=1.2 && <1.5
, deepseq >=1.1 && <2 , deepseq >=1.1 && <2

View File

@ -76,23 +76,23 @@ These types live in ``Test.DejaFu.Types``:
-- ^ Get blocked on a take. -- ^ Get blocked on a take.
| TryTakeMVar MVarId Bool [ThreadId] | TryTakeMVar MVarId Bool [ThreadId]
-- ^ Try to take from a 'MVar', possibly waking up some threads. -- ^ Try to take from a 'MVar', possibly waking up some threads.
| NewCRef CRefId | NewIORef IORefId
-- ^ Create a new 'CRef'. -- ^ Create a new 'IORef'.
| ReadCRef CRefId | ReadIORef IORefId
-- ^ Read from a 'CRef'. -- ^ Read from a 'IORef'.
| ReadCRefCas CRefId | ReadIORefCas IORefId
-- ^ Read from a 'CRef' for a future compare-and-swap. -- ^ Read from a 'IORef' for a future compare-and-swap.
| ModCRef CRefId | ModIORef IORefId
-- ^ Modify a 'CRef'. -- ^ Modify a 'IORef'.
| ModCRefCas CRefId | ModIORefCas IORefId
-- ^ Modify a 'CRef' using a compare-and-swap. -- ^ Modify a 'IORef' using a compare-and-swap.
| WriteCRef CRefId | WriteIORef IORefId
-- ^ Write to a 'CRef' without synchronising. -- ^ Write to a 'IORef' without synchronising.
| CasCRef CRefId Bool | CasIORef IORefId Bool
-- ^ Attempt to to a 'CRef' using a compare-and-swap, synchronising -- ^ Attempt to to a 'IORef' using a compare-and-swap, synchronising
-- it. -- it.
| CommitCRef ThreadId CRefId | CommitIORef ThreadId IORefId
-- ^ Commit the last write to the given 'CRef' by the given thread, -- ^ Commit the last write to the given 'IORef' by the given thread,
-- so that all threads can see the updated value. -- so that all threads can see the updated value.
| STM TTrace [ThreadId] | STM TTrace [ThreadId]
-- ^ An STM transaction was executed, possibly waking up some -- ^ An STM transaction was executed, possibly waking up some
@ -210,13 +210,13 @@ continuation to call when it is done:
| forall a. ATakeMVar (MVar r a) (a -> Action n r) | forall a. ATakeMVar (MVar r a) (a -> Action n r)
| forall a. ATryTakeMVar (MVar r a) (Maybe a -> Action n r) | forall a. ATryTakeMVar (MVar r a) (Maybe a -> Action n r)
| forall a. ANewCRef String a (CRef r a -> Action n r) | forall a. ANewIORef String a (IORef r a -> Action n r)
| forall a. AReadCRef (CRef r a) (a -> Action n r) | forall a. AReadIORef (IORef r a) (a -> Action n r)
| forall a. AReadCRefCas (CRef r a) (Ticket a -> Action n r) | forall a. AReadIORefCas (IORef r a) (Ticket a -> Action n r)
| forall a b. AModCRef (CRef r a) (a -> (a, b)) (b -> Action n r) | forall a b. AModIORef (IORef r a) (a -> (a, b)) (b -> Action n r)
| forall a b. AModCRefCas (CRef r a) (a -> (a, b)) (b -> Action n r) | forall a b. AModIORefCas (IORef r a) (a -> (a, b)) (b -> Action n r)
| forall a. AWriteCRef (CRef r a) a (Action n r) | forall a. AWriteIORef (IORef r a) a (Action n r)
| forall a. ACasCRef (CRef r a) (Ticket a) a ((Bool, Ticket a) -> Action n r) | forall a. ACasIORef (IORef r a) (Ticket a) a ((Bool, Ticket a) -> Action n r)
| forall e. Exception e => AThrow e | forall e. Exception e => AThrow e
| forall e. Exception e => AThrowTo ThreadId e (Action n r) | forall e. Exception e => AThrowTo ThreadId e (Action n r)
@ -229,7 +229,7 @@ continuation to call when it is done:
| ALift (n (Action n r)) | ALift (n (Action n r))
| AYield (Action n r) | AYield (Action n r)
| AReturn (Action n r) | AReturn (Action n r)
| ACommit ThreadId CRefId | ACommit ThreadId IORefId
| AStop (n ()) | AStop (n ())
| forall a. ASub (M n r a) (Either Failure a -> Action n r) | forall a. ASub (M n r a) (Either Failure a -> Action n r)
@ -293,9 +293,9 @@ variable ID", this is a naming convention from the past which I
haven't updated yet. haven't updated yet.
The tricky bit here is ``synchronised``. It means that this action The tricky bit here is ``synchronised``. It means that this action
imposes a *memory barrier*: any uncommitted ``CRef`` writes get imposes a *memory barrier*: any uncommitted ``IORef`` writes get
flushed when this action is performed. Pretty much everything other flushed when this action is performed. Pretty much everything other
than a couple of ``CRef`` operations impose a memory barrier. than a couple of ``IORef`` operations impose a memory barrier.
Incidentally, this is what the ``SynchronisedWrite`` we mentioned Incidentally, this is what the ``SynchronisedWrite`` we mentioned
above refers to. above refers to.

View File

@ -24,7 +24,7 @@ The available settings are:
* **"Way"**, how to explore the behaviours of the program under test. * **"Way"**, how to explore the behaviours of the program under test.
* **Memory model**, which affects how non-synchronised operations, * **Memory model**, which affects how non-synchronised operations,
such as ``readCRef`` and ``writeCRef`` behave. such as ``readIORef`` and ``writeIORef`` behave.
* **Discarding**, which allows throwing away uninteresting results, * **Discarding**, which allows throwing away uninteresting results,
rather than keeping them around in memory. rather than keeping them around in memory.

View File

@ -27,10 +27,10 @@ There are a few different packages under the Déjà Fu umbrella:
.. csv-table:: .. csv-table::
:header: "Package", "Version", "Summary" :header: "Package", "Version", "Summary"
":hackage:`concurrency`", "1.5.0.0", "Typeclasses, functions, and data types for concurrency and STM" ":hackage:`concurrency`", "1.6.0.0", "Typeclasses, functions, and data types for concurrency and STM"
":hackage:`dejafu`", "1.10.1.0", "Systematic testing for Haskell concurrency" ":hackage:`dejafu`", "1.11.0.0", "Systematic testing for Haskell concurrency"
":hackage:`hunit-dejafu`", "1.2.0.5", "Déjà Fu support for the HUnit test framework" ":hackage:`hunit-dejafu`", "1.2.0.6", "Déjà Fu support for the HUnit test framework"
":hackage:`tasty-dejafu`", "1.2.0.6", "Déjà Fu support for the tasty test framework" ":hackage:`tasty-dejafu`", "1.2.0.7", "Déjà Fu support for the tasty test framework"
Installation Installation

View File

@ -103,7 +103,7 @@ functions. These functions are:
The signatures can have different state types, as long as the seed and The signatures can have different state types, as long as the seed and
observation types are the same. This lets you compare different observation types are the same. This lets you compare different
implementations of the same idea: for example, comparing a concurrent implementations of the same idea: for example, comparing a concurrent
stack implemented using ``MVar`` with one implemented using ``CRef``. stack implemented using ``MVar`` with one implemented using ``IORef``.
Properties can have parameters, given in the obvious way: Properties can have parameters, given in the obvious way:

View File

@ -32,22 +32,18 @@ process:
* ``TVar`` becomes ``TVar stm`` * ``TVar`` becomes ``TVar stm``
* ``MVar`` becomes ``MVar m`` * ``MVar`` becomes ``MVar m``
* ``IORef`` becomes ``CRef m`` [#]_ * ``IORef`` becomes ``IORef m``
5. Some functions are renamed: 5. Some functions are renamed:
* ``*IORef*`` becomes ``*CRef*``
* ``forkIO*`` becomes ``fork*`` * ``forkIO*`` becomes ``fork*``
* ``atomicModifyIORefCAS*`` becomes ``modifyCRefCAS*`` * ``atomicModifyIORefCAS*`` becomes ``modifyIORefCAS*``
6. Fix the type errors 6. Fix the type errors
If you're lucky enough to be starting a new concurrent Haskell If you're lucky enough to be starting a new concurrent Haskell
project, you can just program against the ``MonadConc`` interface. project, you can just program against the ``MonadConc`` interface.
.. [#] I felt that calling it ``IORef`` when there was no I/O involved
would be confusing, but this was perhaps a mistake.
What if I really need I/O? What if I really need I/O?
-------------------------- --------------------------

View File

@ -38,9 +38,9 @@ bugs. Here they are:
nondeterministic :: forall m. MonadConc m => m Int nondeterministic :: forall m. MonadConc m => m Int
nondeterministic = do nondeterministic = do
var <- newCRef 0 var <- newIORef 0
let settings = (defaultUpdateSettings :: UpdateSettings m ()) let settings = (defaultUpdateSettings :: UpdateSettings m ())
{ updateAction = atomicModifyCRef var (\x -> (x+1, x)) } { updateAction = atomicModifyIORef var (\x -> (x+1, x)) }
auto <- mkAutoUpdate settings auto <- mkAutoUpdate settings
auto auto
auto auto

View File

@ -7,6 +7,18 @@ standard Haskell versioning scheme.
.. _PVP: https://pvp.haskell.org/ .. _PVP: https://pvp.haskell.org/
1.2.0.6 (2018-07-01)
--------------------
* Git: :tag:`hunit-dejafu-1.2.0.6`
* Hackage: :hackage:`hunit-dejafu-1.2.0.6`
Miscellaneous
~~~~~~~~~~~~~
* The upper bound on :hackage:`dejafu` is <1.12.
1.2.0.5 (2018-06-17) 1.2.0.5 (2018-06-17)
-------------------- --------------------

View File

@ -115,7 +115,7 @@ testAutoWay :: (Eq a, Show a)
=> Way => Way
-- ^ How to execute the concurrent program. -- ^ How to execute the concurrent program.
-> MemType -> MemType
-- ^ The memory model to use for non-synchronised @CRef@ operations. -- ^ The memory model to use for non-synchronised @IORef@ operations.
-> Conc.ConcIO a -> Conc.ConcIO a
-- ^ The computation to test. -- ^ The computation to test.
-> Test -> Test
@ -157,7 +157,7 @@ testDejafuWay :: Show b
=> Way => Way
-- ^ How to execute the concurrent program. -- ^ How to execute the concurrent program.
-> MemType -> MemType
-- ^ The memory model to use for non-synchronised @CRef@ operations. -- ^ The memory model to use for non-synchronised @IORef@ operations.
-> String -> String
-- ^ The name of the test. -- ^ The name of the test.
-> ProPredicate a b -> ProPredicate a b
@ -191,7 +191,7 @@ testDejafuDiscard :: Show b
-> Way -> Way
-- ^ How to execute the concurrent program. -- ^ How to execute the concurrent program.
-> MemType -> MemType
-- ^ The memory model to use for non-synchronised @CRef@ operations. -- ^ The memory model to use for non-synchronised @IORef@ operations.
-> String -> String
-- ^ The name of the test. -- ^ The name of the test.
-> ProPredicate a b -> ProPredicate a b
@ -224,7 +224,7 @@ testDejafusWay :: Show b
=> Way => Way
-- ^ How to execute the concurrent program. -- ^ How to execute the concurrent program.
-> MemType -> MemType
-- ^ The memory model to use for non-synchronised @CRef@ operations. -- ^ The memory model to use for non-synchronised @IORef@ operations.
-> [(String, ProPredicate a b)] -> [(String, ProPredicate a b)]
-- ^ The list of predicates (with names) to check. -- ^ The list of predicates (with names) to check.
-> Conc.ConcIO a -> Conc.ConcIO a
@ -255,7 +255,7 @@ testDejafusDiscard :: Show b
-> Way -> Way
-- ^ How to execute the concurrent program. -- ^ How to execute the concurrent program.
-> MemType -> MemType
-- ^ The memory model to use for non-synchronised @CRef@ operations. -- ^ The memory model to use for non-synchronised @IORef@ operations.
-> [(String, ProPredicate a b)] -> [(String, ProPredicate a b)]
-- ^ The list of predicates (with names) to check. -- ^ The list of predicates (with names) to check.
-> Conc.ConcIO a -> Conc.ConcIO a

View File

@ -2,7 +2,7 @@
-- documentation, see http://haskell.org/cabal/users-guide/ -- documentation, see http://haskell.org/cabal/users-guide/
name: hunit-dejafu name: hunit-dejafu
version: 1.2.0.5 version: 1.2.0.6
synopsis: Deja Fu support for the HUnit test framework. synopsis: Deja Fu support for the HUnit test framework.
description: description:
@ -30,7 +30,7 @@ source-repository head
source-repository this source-repository this
type: git type: git
location: https://github.com/barrucadu/dejafu.git location: https://github.com/barrucadu/dejafu.git
tag: hunit-dejafu-1.2.0.5 tag: hunit-dejafu-1.2.0.6
library library
exposed-modules: Test.HUnit.DejaFu exposed-modules: Test.HUnit.DejaFu
@ -38,7 +38,7 @@ library
-- other-extensions: -- other-extensions:
build-depends: base >=4.9 && <5 build-depends: base >=4.9 && <5
, exceptions >=0.7 && <0.11 , exceptions >=0.7 && <0.11
, dejafu >=1.5 && <1.11 , dejafu >=1.5 && <1.12
, HUnit >=1.3.1 && <1.7 , HUnit >=1.3.1 && <1.7
-- hs-source-dirs: -- hs-source-dirs:
default-language: Haskell2010 default-language: Haskell2010

View File

@ -7,6 +7,18 @@ standard Haskell versioning scheme.
.. _PVP: https://pvp.haskell.org/ .. _PVP: https://pvp.haskell.org/
1.2.0.7 (2018-07-01)
--------------------
* Git: :tag:`tasty-dejafu-1.2.0.7`
* Hackage: :hackage:`tasty-dejafu-1.2.0.7`
Miscellaneous
~~~~~~~~~~~~~
* The upper bound on :hackage:`dejafu` is <1.12.
1.2.0.6 (2018-06-17) 1.2.0.6 (2018-06-17)
-------------------- --------------------

View File

@ -148,7 +148,7 @@ testAutoWay :: (Eq a, Show a)
=> Way => Way
-- ^ How to execute the concurrent program. -- ^ How to execute the concurrent program.
-> MemType -> MemType
-- ^ The memory model to use for non-synchronised @CRef@ operations. -- ^ The memory model to use for non-synchronised @IORef@ operations.
-> Conc.ConcIO a -> Conc.ConcIO a
-- ^ The computation to test. -- ^ The computation to test.
-> TestTree -> TestTree
@ -190,7 +190,7 @@ testDejafuWay :: Show b
=> Way => Way
-- ^ How to execute the concurrent program. -- ^ How to execute the concurrent program.
-> MemType -> MemType
-- ^ The memory model to use for non-synchronised @CRef@ operations. -- ^ The memory model to use for non-synchronised @IORef@ operations.
-> TestName -> TestName
-- ^ The name of the test. -- ^ The name of the test.
-> ProPredicate a b -> ProPredicate a b
@ -224,7 +224,7 @@ testDejafuDiscard :: Show b
-> Way -> Way
-- ^ How to execute the concurrent program. -- ^ How to execute the concurrent program.
-> MemType -> MemType
-- ^ The memory model to use for non-synchronised @CRef@ operations. -- ^ The memory model to use for non-synchronised @IORef@ operations.
-> String -> String
-- ^ The name of the test. -- ^ The name of the test.
-> ProPredicate a b -> ProPredicate a b
@ -257,7 +257,7 @@ testDejafusWay :: Show b
=> Way => Way
-- ^ How to execute the concurrent program. -- ^ How to execute the concurrent program.
-> MemType -> MemType
-- ^ The memory model to use for non-synchronised @CRef@ operations. -- ^ The memory model to use for non-synchronised @IORef@ operations.
-> [(TestName, ProPredicate a b)] -> [(TestName, ProPredicate a b)]
-- ^ The list of predicates (with names) to check. -- ^ The list of predicates (with names) to check.
-> Conc.ConcIO a -> Conc.ConcIO a
@ -288,7 +288,7 @@ testDejafusDiscard :: Show b
-> Way -> Way
-- ^ How to execute the concurrent program. -- ^ How to execute the concurrent program.
-> MemType -> MemType
-- ^ The memory model to use for non-synchronised @CRef@ operations. -- ^ The memory model to use for non-synchronised @IORef@ operations.
-> [(TestName, ProPredicate a b)] -> [(TestName, ProPredicate a b)]
-- ^ The list of predicates (with names) to check. -- ^ The list of predicates (with names) to check.
-> Conc.ConcIO a -> Conc.ConcIO a

View File

@ -2,7 +2,7 @@
-- documentation, see http://haskell.org/cabal/users-guide/ -- documentation, see http://haskell.org/cabal/users-guide/
name: tasty-dejafu name: tasty-dejafu
version: 1.2.0.6 version: 1.2.0.7
synopsis: Deja Fu support for the Tasty test framework. synopsis: Deja Fu support for the Tasty test framework.
description: description:
@ -30,14 +30,14 @@ source-repository head
source-repository this source-repository this
type: git type: git
location: https://github.com/barrucadu/dejafu.git location: https://github.com/barrucadu/dejafu.git
tag: tasty-dejafu-1.2.0.6 tag: tasty-dejafu-1.2.0.7
library library
exposed-modules: Test.Tasty.DejaFu exposed-modules: Test.Tasty.DejaFu
-- other-modules: -- other-modules:
-- other-extensions: -- other-extensions:
build-depends: base >=4.9 && <5 build-depends: base >=4.9 && <5
, dejafu >=1.5 && <1.11 , dejafu >=1.5 && <1.12
, random >=1.0 && <1.2 , random >=1.0 && <1.2
, tagged >=0.8 && <0.9 , tagged >=0.8 && <0.9
, tasty >=0.10 && <1.2 , tasty >=0.10 && <1.2