packages feed

dejafu 0.3.2.1 → 0.4.0.0

raw patch · 32 files changed

+2016/−4328 lines, 32 filesdep +concurrencydep +ref-fddep −arraydep −atomic-primopsdep −monad-controlPVP ok

version bump matches the API change (PVP)

Dependencies added: concurrency, ref-fd

Dependencies removed: array, atomic-primops, monad-control, stm, template-haskell

API changes (from Hackage documentation)

- Control.Concurrent.Classy.CRef: atomicModifyCRef :: MonadConc m => CRef m a -> (a -> (a, b)) -> m b
- Control.Concurrent.Classy.CRef: atomicModifyCRef' :: MonadConc m => CRef m a -> (a -> (a, b)) -> m b
- Control.Concurrent.Classy.CRef: atomicWriteCRef :: MonadConc m => CRef m a -> a -> m ()
- Control.Concurrent.Classy.CRef: modifyCRef :: MonadConc m => CRef m a -> (a -> a) -> m ()
- Control.Concurrent.Classy.CRef: modifyCRef' :: MonadConc m => CRef m a -> (a -> a) -> m ()
- Control.Concurrent.Classy.CRef: newCRef :: MonadConc m => a -> m (CRef m a)
- Control.Concurrent.Classy.CRef: readCRef :: MonadConc m => CRef m a -> m a
- Control.Concurrent.Classy.CRef: writeCRef :: MonadConc m => CRef m a -> a -> m ()
- Control.Concurrent.Classy.Chan: data Chan m a
- Control.Concurrent.Classy.Chan: dupChan :: MonadConc m => Chan m a -> m (Chan m a)
- Control.Concurrent.Classy.Chan: newChan :: MonadConc m => m (Chan m a)
- Control.Concurrent.Classy.Chan: readChan :: MonadConc m => Chan m a -> m a
- Control.Concurrent.Classy.Chan: writeChan :: MonadConc m => Chan m a -> a -> m ()
- Control.Concurrent.Classy.Chan: writeList2Chan :: MonadConc m => Chan m a -> [a] -> m ()
- Control.Concurrent.Classy.MVar: isEmptyMVar :: MonadConc m => MVar m a -> m Bool
- Control.Concurrent.Classy.MVar: modifyMVar :: MonadConc m => MVar m a -> (a -> m (a, b)) -> m b
- Control.Concurrent.Classy.MVar: modifyMVarMasked :: MonadConc m => MVar m a -> (a -> m (a, b)) -> m b
- Control.Concurrent.Classy.MVar: modifyMVarMasked_ :: MonadConc m => MVar m a -> (a -> m a) -> m ()
- Control.Concurrent.Classy.MVar: modifyMVar_ :: MonadConc m => MVar m a -> (a -> m a) -> m ()
- Control.Concurrent.Classy.MVar: newEmptyMVar :: MonadConc m => m (MVar m a)
- Control.Concurrent.Classy.MVar: newEmptyMVarN :: MonadConc m => String -> m (MVar m a)
- Control.Concurrent.Classy.MVar: newMVar :: MonadConc m => a -> m (MVar m a)
- Control.Concurrent.Classy.MVar: newMVarN :: MonadConc m => String -> a -> m (MVar m a)
- Control.Concurrent.Classy.MVar: putMVar :: MonadConc m => MVar m a -> a -> m ()
- Control.Concurrent.Classy.MVar: readMVar :: MonadConc m => MVar m a -> m a
- Control.Concurrent.Classy.MVar: swapMVar :: MonadConc m => MVar m a -> a -> m a
- Control.Concurrent.Classy.MVar: takeMVar :: MonadConc m => MVar m a -> m a
- Control.Concurrent.Classy.MVar: tryPutMVar :: MonadConc m => MVar m a -> a -> m Bool
- Control.Concurrent.Classy.MVar: tryTakeMVar :: MonadConc m => MVar m a -> m (Maybe a)
- Control.Concurrent.Classy.MVar: withMVar :: MonadConc m => MVar m a -> (a -> m b) -> m b
- Control.Concurrent.Classy.MVar: withMVarMasked :: MonadConc m => MVar m a -> (a -> m b) -> m b
- Control.Concurrent.Classy.QSem: data QSem m
- Control.Concurrent.Classy.QSem: newQSem :: MonadConc m => Int -> m (QSem m)
- Control.Concurrent.Classy.QSem: signalQSem :: MonadConc m => QSem m -> m ()
- Control.Concurrent.Classy.QSem: waitQSem :: MonadConc m => QSem m -> m ()
- Control.Concurrent.Classy.QSemN: data QSemN m
- Control.Concurrent.Classy.QSemN: newQSemN :: MonadConc m => Int -> m (QSemN m)
- Control.Concurrent.Classy.QSemN: signalQSemN :: MonadConc m => QSemN m -> Int -> m ()
- Control.Concurrent.Classy.QSemN: waitQSemN :: MonadConc m => QSemN m -> Int -> m ()
- Control.Concurrent.Classy.STM.TArray: data TArray stm i e
- Control.Concurrent.Classy.STM.TArray: instance Control.Monad.STM.Class.MonadSTM stm => Data.Array.Base.MArray (Control.Concurrent.Classy.STM.TArray.TArray stm) e stm
- Control.Concurrent.Classy.STM.TBQueue: data TBQueue stm a
- Control.Concurrent.Classy.STM.TBQueue: isEmptyTBQueue :: MonadSTM stm => TBQueue stm a -> stm Bool
- Control.Concurrent.Classy.STM.TBQueue: isFullTBQueue :: MonadSTM stm => TBQueue stm a -> stm Bool
- Control.Concurrent.Classy.STM.TBQueue: newTBQueue :: MonadSTM stm => Int -> stm (TBQueue stm a)
- Control.Concurrent.Classy.STM.TBQueue: peekTBQueue :: MonadSTM stm => TBQueue stm a -> stm a
- Control.Concurrent.Classy.STM.TBQueue: readTBQueue :: MonadSTM stm => TBQueue stm a -> stm a
- Control.Concurrent.Classy.STM.TBQueue: tryPeekTBQueue :: MonadSTM stm => TBQueue stm a -> stm (Maybe a)
- Control.Concurrent.Classy.STM.TBQueue: tryReadTBQueue :: MonadSTM stm => TBQueue stm a -> stm (Maybe a)
- Control.Concurrent.Classy.STM.TBQueue: unGetTBQueue :: MonadSTM stm => TBQueue stm a -> a -> stm ()
- Control.Concurrent.Classy.STM.TBQueue: writeTBQueue :: MonadSTM stm => TBQueue stm a -> a -> stm ()
- Control.Concurrent.Classy.STM.TChan: cloneTChan :: MonadSTM stm => TChan stm a -> stm (TChan stm a)
- Control.Concurrent.Classy.STM.TChan: data TChan stm a
- Control.Concurrent.Classy.STM.TChan: dupTChan :: MonadSTM stm => TChan stm a -> stm (TChan stm a)
- Control.Concurrent.Classy.STM.TChan: isEmptyTChan :: MonadSTM stm => TChan stm a -> stm Bool
- Control.Concurrent.Classy.STM.TChan: newBroadcastTChan :: MonadSTM stm => stm (TChan stm a)
- Control.Concurrent.Classy.STM.TChan: newTChan :: MonadSTM stm => stm (TChan stm a)
- Control.Concurrent.Classy.STM.TChan: peekTChan :: MonadSTM stm => TChan stm a -> stm a
- Control.Concurrent.Classy.STM.TChan: readTChan :: MonadSTM stm => TChan stm a -> stm a
- Control.Concurrent.Classy.STM.TChan: tryPeekTChan :: MonadSTM stm => TChan stm a -> stm (Maybe a)
- Control.Concurrent.Classy.STM.TChan: tryReadTChan :: MonadSTM stm => TChan stm a -> stm (Maybe a)
- Control.Concurrent.Classy.STM.TChan: unGetTChan :: MonadSTM stm => TChan stm a -> a -> stm ()
- Control.Concurrent.Classy.STM.TChan: writeTChan :: MonadSTM stm => TChan stm a -> a -> stm ()
- Control.Concurrent.Classy.STM.TMVar: data TMVar stm a
- Control.Concurrent.Classy.STM.TMVar: isEmptyTMVar :: MonadSTM stm => TMVar stm a -> stm Bool
- Control.Concurrent.Classy.STM.TMVar: newEmptyTMVar :: MonadSTM stm => stm (TMVar stm a)
- Control.Concurrent.Classy.STM.TMVar: newEmptyTMVarN :: MonadSTM stm => String -> stm (TMVar stm a)
- Control.Concurrent.Classy.STM.TMVar: newTMVar :: MonadSTM stm => a -> stm (TMVar stm a)
- Control.Concurrent.Classy.STM.TMVar: newTMVarN :: MonadSTM stm => String -> a -> stm (TMVar stm a)
- Control.Concurrent.Classy.STM.TMVar: putTMVar :: MonadSTM stm => TMVar stm a -> a -> stm ()
- Control.Concurrent.Classy.STM.TMVar: readTMVar :: MonadSTM stm => TMVar stm a -> stm a
- Control.Concurrent.Classy.STM.TMVar: swapTMVar :: MonadSTM stm => TMVar stm a -> a -> stm a
- Control.Concurrent.Classy.STM.TMVar: takeTMVar :: MonadSTM stm => TMVar stm a -> stm a
- Control.Concurrent.Classy.STM.TMVar: tryPutTMVar :: MonadSTM stm => TMVar stm a -> a -> stm Bool
- Control.Concurrent.Classy.STM.TMVar: tryReadTMVar :: MonadSTM stm => TMVar stm a -> stm (Maybe a)
- Control.Concurrent.Classy.STM.TMVar: tryTakeTMVar :: MonadSTM stm => TMVar stm a -> stm (Maybe a)
- Control.Concurrent.Classy.STM.TQueue: data TQueue stm a
- Control.Concurrent.Classy.STM.TQueue: isEmptyTQueue :: MonadSTM stm => TQueue stm a -> stm Bool
- Control.Concurrent.Classy.STM.TQueue: newTQueue :: MonadSTM stm => stm (TQueue stm a)
- Control.Concurrent.Classy.STM.TQueue: peekTQueue :: MonadSTM stm => TQueue stm a -> stm a
- Control.Concurrent.Classy.STM.TQueue: readTQueue :: MonadSTM stm => TQueue stm a -> stm a
- Control.Concurrent.Classy.STM.TQueue: tryPeekTQueue :: MonadSTM stm => TQueue stm a -> stm (Maybe a)
- Control.Concurrent.Classy.STM.TQueue: tryReadTQueue :: MonadSTM stm => TQueue stm a -> stm (Maybe a)
- Control.Concurrent.Classy.STM.TQueue: unGetTQueue :: MonadSTM stm => TQueue stm a -> a -> stm ()
- Control.Concurrent.Classy.STM.TQueue: writeTQueue :: MonadSTM stm => TQueue stm a -> a -> stm ()
- Control.Concurrent.Classy.STM.TVar: modifyTVar :: MonadSTM stm => TVar stm a -> (a -> a) -> stm ()
- Control.Concurrent.Classy.STM.TVar: modifyTVar' :: MonadSTM stm => TVar stm a -> (a -> a) -> stm ()
- Control.Concurrent.Classy.STM.TVar: newTVar :: MonadSTM stm => a -> stm (TVar stm a)
- Control.Concurrent.Classy.STM.TVar: newTVarN :: MonadSTM stm => String -> a -> stm (TVar stm a)
- Control.Concurrent.Classy.STM.TVar: readTVar :: MonadSTM stm => TVar stm a -> stm a
- Control.Concurrent.Classy.STM.TVar: readTVarConc :: MonadConc m => TVar (STM m) a -> m a
- Control.Concurrent.Classy.STM.TVar: registerDelay :: MonadConc m => Int -> m (TVar (STM m) Bool)
- Control.Concurrent.Classy.STM.TVar: swapTVar :: MonadSTM stm => TVar stm a -> a -> stm a
- Control.Concurrent.Classy.STM.TVar: writeTVar :: MonadSTM stm => TVar stm a -> a -> stm ()
- Control.Monad.Conc.Class: _concAllKnown :: MonadConc m => m ()
- Control.Monad.Conc.Class: _concForgets :: MonadConc m => Either (MVar m a) (TVar (STM m) a) -> m ()
- Control.Monad.Conc.Class: _concKnowsAbout :: MonadConc m => Either (MVar m a) (TVar (STM m) a) -> m ()
- Control.Monad.Conc.Class: _concMessage :: (MonadConc m, Typeable a) => a -> m ()
- Control.Monad.Conc.Class: atomicModifyCRef :: MonadConc m => CRef m a -> (a -> (a, b)) -> m b
- Control.Monad.Conc.Class: atomicWriteCRef :: MonadConc m => CRef m a -> a -> m ()
- Control.Monad.Conc.Class: atomically :: MonadConc m => STM m a -> m a
- Control.Monad.Conc.Class: cas :: MonadConc m => CRef m a -> a -> m (Bool, a)
- Control.Monad.Conc.Class: casCRef :: MonadConc m => CRef m a -> Ticket m a -> a -> m (Bool, Ticket m a)
- Control.Monad.Conc.Class: catch :: (MonadConc m, Exception e) => m a -> (e -> m a) -> m a
- Control.Monad.Conc.Class: class (Applicative m, Monad m, MonadCatch m, MonadThrow m, MonadMask m, MonadSTM (STM m), Ord (ThreadId m), Show (ThreadId m)) => MonadConc m where type STM m :: * -> * type MVar m :: * -> * type CRef m :: * -> * type Ticket m :: * -> * type ThreadId m :: * fork ma = forkWithUnmask (\ _ -> ma) forkWithUnmask = forkWithUnmaskN "" forkWithUnmaskN _ = forkWithUnmask forkOn c ma = forkOnWithUnmask c (\ _ -> ma) forkOnWithUnmask = forkOnWithUnmaskN "" forkOnWithUnmaskN _ = forkOnWithUnmask threadDelay _ = yield newEmptyMVar = newEmptyMVarN "" newEmptyMVarN _ = newEmptyMVar newCRef = newCRefN "" newCRefN _ = newCRef readCRef cref = readForCAS cref >>= peekTicket atomicWriteCRef r a = atomicModifyCRef r $ const (a, ()) modifyCRefCAS_ cref f = modifyCRefCAS cref (\ a -> (f a, ())) readTVarConc = atomically . readTVar _concKnowsAbout _ = pure () _concForgets _ = pure () _concAllKnown = pure () _concMessage _ = pure () where {
- Control.Monad.Conc.Class: fork :: MonadConc m => m () -> m (ThreadId m)
- Control.Monad.Conc.Class: forkFinally :: MonadConc m => m a -> (Either SomeException a -> m ()) -> m (ThreadId m)
- Control.Monad.Conc.Class: forkN :: MonadConc m => String -> m () -> m (ThreadId m)
- Control.Monad.Conc.Class: forkOn :: MonadConc m => Int -> m () -> m (ThreadId m)
- Control.Monad.Conc.Class: forkOnN :: MonadConc m => String -> Int -> m () -> m (ThreadId m)
- Control.Monad.Conc.Class: forkOnWithUnmask :: MonadConc m => Int -> ((forall a. m a -> m a) -> m ()) -> m (ThreadId m)
- Control.Monad.Conc.Class: forkOnWithUnmaskN :: MonadConc m => String -> Int -> ((forall a. m a -> m a) -> m ()) -> m (ThreadId m)
- Control.Monad.Conc.Class: forkWithUnmask :: MonadConc m => ((forall a. m a -> m a) -> m ()) -> m (ThreadId m)
- Control.Monad.Conc.Class: forkWithUnmaskN :: MonadConc m => String -> ((forall a. m a -> m a) -> m ()) -> m (ThreadId m)
- Control.Monad.Conc.Class: getNumCapabilities :: MonadConc m => m Int
- Control.Monad.Conc.Class: instance (Control.Monad.Conc.Class.MonadConc m, GHC.Base.Monoid w) => Control.Monad.Conc.Class.MonadConc (Control.Monad.Trans.RWS.Lazy.RWST r w s m)
- Control.Monad.Conc.Class: instance (Control.Monad.Conc.Class.MonadConc m, GHC.Base.Monoid w) => Control.Monad.Conc.Class.MonadConc (Control.Monad.Trans.RWS.Strict.RWST r w s m)
- Control.Monad.Conc.Class: instance (Control.Monad.Conc.Class.MonadConc m, GHC.Base.Monoid w) => Control.Monad.Conc.Class.MonadConc (Control.Monad.Trans.Writer.Lazy.WriterT w m)
- Control.Monad.Conc.Class: instance (Control.Monad.Conc.Class.MonadConc m, GHC.Base.Monoid w) => Control.Monad.Conc.Class.MonadConc (Control.Monad.Trans.Writer.Strict.WriterT w m)
- Control.Monad.Conc.Class: instance Control.Monad.Conc.Class.MonadConc GHC.Types.IO
- Control.Monad.Conc.Class: instance Control.Monad.Conc.Class.MonadConc m => Control.Monad.Conc.Class.MonadConc (Control.Monad.Trans.Identity.IdentityT m)
- Control.Monad.Conc.Class: instance Control.Monad.Conc.Class.MonadConc m => Control.Monad.Conc.Class.MonadConc (Control.Monad.Trans.Reader.ReaderT r m)
- Control.Monad.Conc.Class: instance Control.Monad.Conc.Class.MonadConc m => Control.Monad.Conc.Class.MonadConc (Control.Monad.Trans.State.Lazy.StateT s m)
- Control.Monad.Conc.Class: instance Control.Monad.Conc.Class.MonadConc m => Control.Monad.Conc.Class.MonadConc (Control.Monad.Trans.State.Strict.StateT s m)
- Control.Monad.Conc.Class: isCurrentThreadBound :: MonadConc m => m Bool
- Control.Monad.Conc.Class: killThread :: MonadConc m => ThreadId m -> m ()
- Control.Monad.Conc.Class: liftedF :: (MonadTransControl t, MonadConc m) => (forall x. StT t x -> x) -> (m a -> m b) -> t m a -> t m b
- Control.Monad.Conc.Class: liftedFork :: (MonadTransControl t, MonadConc m) => (forall x. StT t x -> x) -> (((forall x. m x -> m x) -> m a) -> m b) -> ((forall x. t m x -> t m x) -> t m a) -> t m b
- Control.Monad.Conc.Class: lineNum :: Q Exp
- Control.Monad.Conc.Class: makeTransConc :: Name -> DecsQ
- Control.Monad.Conc.Class: mask :: MonadConc m => ((forall a. m a -> m a) -> m b) -> m b
- Control.Monad.Conc.Class: modifyCRefCAS :: MonadConc m => CRef m a -> (a -> (a, b)) -> m b
- Control.Monad.Conc.Class: modifyCRefCAS_ :: MonadConc m => CRef m a -> (a -> a) -> m ()
- Control.Monad.Conc.Class: myThreadId :: MonadConc m => m (ThreadId m)
- Control.Monad.Conc.Class: newCRef :: MonadConc m => a -> m (CRef m a)
- Control.Monad.Conc.Class: newCRefN :: MonadConc m => String -> a -> m (CRef m a)
- Control.Monad.Conc.Class: newEmptyMVar :: MonadConc m => m (MVar m a)
- Control.Monad.Conc.Class: newEmptyMVarN :: MonadConc m => String -> m (MVar m a)
- Control.Monad.Conc.Class: newMVar :: MonadConc m => a -> m (MVar m a)
- Control.Monad.Conc.Class: newMVarN :: MonadConc m => String -> a -> m (MVar m a)
- Control.Monad.Conc.Class: peekTicket :: MonadConc m => Ticket m a -> m a
- Control.Monad.Conc.Class: putMVar :: MonadConc m => MVar m a -> a -> m ()
- Control.Monad.Conc.Class: readCRef :: MonadConc m => CRef m a -> m a
- Control.Monad.Conc.Class: readForCAS :: MonadConc m => CRef m a -> m (Ticket m a)
- Control.Monad.Conc.Class: readMVar :: MonadConc m => MVar m a -> m a
- Control.Monad.Conc.Class: readTVarConc :: MonadConc m => TVar (STM m) a -> m a
- Control.Monad.Conc.Class: rtsSupportsBoundThreads :: Bool
- Control.Monad.Conc.Class: setNumCapabilities :: MonadConc m => Int -> m ()
- Control.Monad.Conc.Class: spawn :: MonadConc m => m a -> m (MVar m a)
- Control.Monad.Conc.Class: takeMVar :: MonadConc m => MVar m a -> m a
- Control.Monad.Conc.Class: threadDelay :: MonadConc m => Int -> m ()
- Control.Monad.Conc.Class: throw :: (MonadConc m, Exception e) => e -> m a
- Control.Monad.Conc.Class: throwTo :: (MonadConc m, Exception e) => ThreadId m -> e -> m ()
- Control.Monad.Conc.Class: tryPutMVar :: MonadConc m => MVar m a -> a -> m Bool
- Control.Monad.Conc.Class: tryTakeMVar :: MonadConc m => MVar m a -> m (Maybe a)
- Control.Monad.Conc.Class: type family ThreadId m :: *;
- Control.Monad.Conc.Class: uninterruptibleMask :: MonadConc m => ((forall a. m a -> m a) -> m b) -> m b
- Control.Monad.Conc.Class: writeCRef :: MonadConc m => CRef m a -> a -> m ()
- Control.Monad.Conc.Class: yield :: MonadConc m => m ()
- Control.Monad.Conc.Class: }
- Control.Monad.STM.Class: catchSTM :: (MonadSTM stm, Exception e) => stm a -> (e -> stm a) -> stm a
- Control.Monad.STM.Class: check :: MonadSTM stm => Bool -> stm ()
- Control.Monad.STM.Class: class MonadCatch stm => MonadSTM stm where type TVar stm :: * -> * newTVar = newTVarN "" newTVarN _ = newTVar where {
- Control.Monad.STM.Class: instance (Control.Monad.STM.Class.MonadSTM stm, GHC.Base.Monoid w) => Control.Monad.STM.Class.MonadSTM (Control.Monad.Trans.RWS.Lazy.RWST r w s stm)
- Control.Monad.STM.Class: instance (Control.Monad.STM.Class.MonadSTM stm, GHC.Base.Monoid w) => Control.Monad.STM.Class.MonadSTM (Control.Monad.Trans.RWS.Strict.RWST r w s stm)
- Control.Monad.STM.Class: instance (Control.Monad.STM.Class.MonadSTM stm, GHC.Base.Monoid w) => Control.Monad.STM.Class.MonadSTM (Control.Monad.Trans.Writer.Lazy.WriterT w stm)
- Control.Monad.STM.Class: instance (Control.Monad.STM.Class.MonadSTM stm, GHC.Base.Monoid w) => Control.Monad.STM.Class.MonadSTM (Control.Monad.Trans.Writer.Strict.WriterT w stm)
- Control.Monad.STM.Class: instance Control.Monad.STM.Class.MonadSTM GHC.Conc.Sync.STM
- Control.Monad.STM.Class: instance Control.Monad.STM.Class.MonadSTM stm => Control.Monad.STM.Class.MonadSTM (Control.Monad.Trans.Identity.IdentityT stm)
- Control.Monad.STM.Class: instance Control.Monad.STM.Class.MonadSTM stm => Control.Monad.STM.Class.MonadSTM (Control.Monad.Trans.Reader.ReaderT r stm)
- Control.Monad.STM.Class: instance Control.Monad.STM.Class.MonadSTM stm => Control.Monad.STM.Class.MonadSTM (Control.Monad.Trans.State.Lazy.StateT s stm)
- Control.Monad.STM.Class: instance Control.Monad.STM.Class.MonadSTM stm => Control.Monad.STM.Class.MonadSTM (Control.Monad.Trans.State.Strict.StateT s stm)
- Control.Monad.STM.Class: liftedOrElse :: (MonadTransControl t, MonadSTM stm) => (forall x. StT t x -> x) -> t stm a -> t stm a -> t stm a
- Control.Monad.STM.Class: makeTransSTM :: Name -> DecsQ
- Control.Monad.STM.Class: newTVar :: MonadSTM stm => a -> stm (TVar stm a)
- Control.Monad.STM.Class: newTVarN :: MonadSTM stm => String -> a -> stm (TVar stm a)
- Control.Monad.STM.Class: orElse :: MonadSTM stm => stm a -> stm a -> stm a
- Control.Monad.STM.Class: readTVar :: MonadSTM stm => TVar stm a -> stm a
- Control.Monad.STM.Class: retry :: MonadSTM stm => stm a
- Control.Monad.STM.Class: throwSTM :: (MonadSTM stm, Exception e) => e -> stm a
- Control.Monad.STM.Class: type family TVar stm :: * -> *;
- Control.Monad.STM.Class: writeTVar :: MonadSTM stm => TVar stm a -> a -> stm ()
- Control.Monad.STM.Class: }
- Test.DejaFu: runTestIO :: Predicate a -> ConcIO a -> IO (Result a)
- Test.DejaFu: runTestIO' :: MemType -> Bounds -> Predicate a -> ConcIO a -> IO (Result a)
- Test.DejaFu.Deterministic: Abort :: Failure
- Test.DejaFu.Deterministic: AllKnown :: ThreadAction
- Test.DejaFu.Deterministic: BlockedPutVar :: MVarId -> ThreadAction
- Test.DejaFu.Deterministic: BlockedReadVar :: MVarId -> ThreadAction
- Test.DejaFu.Deterministic: BlockedSTM :: TTrace -> ThreadAction
- Test.DejaFu.Deterministic: BlockedTakeVar :: MVarId -> ThreadAction
- Test.DejaFu.Deterministic: BlockedThrowTo :: ThreadId -> ThreadAction
- Test.DejaFu.Deterministic: CasRef :: CRefId -> Bool -> ThreadAction
- Test.DejaFu.Deterministic: Catching :: ThreadAction
- Test.DejaFu.Deterministic: CommitRef :: ThreadId -> CRefId -> ThreadAction
- Test.DejaFu.Deterministic: Continue :: Decision tid
- Test.DejaFu.Deterministic: Deadlock :: Failure
- Test.DejaFu.Deterministic: Forgets :: ThreadAction
- Test.DejaFu.Deterministic: Fork :: ThreadId -> ThreadAction
- Test.DejaFu.Deterministic: GetNumCapabilities :: Int -> ThreadAction
- Test.DejaFu.Deterministic: InternalError :: Failure
- Test.DejaFu.Deterministic: Killed :: ThreadAction
- Test.DejaFu.Deterministic: KnowsAbout :: ThreadAction
- Test.DejaFu.Deterministic: Lift :: ThreadAction
- Test.DejaFu.Deterministic: MaskedInterruptible :: MaskingState
- Test.DejaFu.Deterministic: MaskedUninterruptible :: MaskingState
- Test.DejaFu.Deterministic: Message :: Dynamic -> ThreadAction
- Test.DejaFu.Deterministic: ModRef :: CRefId -> ThreadAction
- Test.DejaFu.Deterministic: ModRefCas :: CRefId -> ThreadAction
- Test.DejaFu.Deterministic: MyThreadId :: ThreadAction
- Test.DejaFu.Deterministic: NewRef :: CRefId -> ThreadAction
- Test.DejaFu.Deterministic: NewVar :: MVarId -> ThreadAction
- Test.DejaFu.Deterministic: PartialStoreOrder :: MemType
- Test.DejaFu.Deterministic: PeekTicket :: CRefId -> ThreadAction
- Test.DejaFu.Deterministic: PopCatching :: ThreadAction
- Test.DejaFu.Deterministic: PutVar :: MVarId -> [ThreadId] -> ThreadAction
- Test.DejaFu.Deterministic: ReadRef :: CRefId -> ThreadAction
- Test.DejaFu.Deterministic: ReadRefCas :: CRefId -> ThreadAction
- Test.DejaFu.Deterministic: ReadVar :: MVarId -> ThreadAction
- Test.DejaFu.Deterministic: ResetMasking :: Bool -> MaskingState -> ThreadAction
- Test.DejaFu.Deterministic: Return :: ThreadAction
- Test.DejaFu.Deterministic: STM :: TTrace -> [ThreadId] -> ThreadAction
- Test.DejaFu.Deterministic: STMDeadlock :: Failure
- Test.DejaFu.Deterministic: SequentialConsistency :: MemType
- Test.DejaFu.Deterministic: SetMasking :: Bool -> MaskingState -> ThreadAction
- Test.DejaFu.Deterministic: SetNumCapabilities :: Int -> ThreadAction
- Test.DejaFu.Deterministic: Start :: tid -> Decision tid
- Test.DejaFu.Deterministic: Stop :: ThreadAction
- Test.DejaFu.Deterministic: SwitchTo :: tid -> Decision tid
- Test.DejaFu.Deterministic: TakeVar :: MVarId -> [ThreadId] -> ThreadAction
- Test.DejaFu.Deterministic: ThreadId :: (Maybe String) -> Int -> ThreadId
- Test.DejaFu.Deterministic: Throw :: ThreadAction
- Test.DejaFu.Deterministic: ThrowTo :: ThreadId -> ThreadAction
- Test.DejaFu.Deterministic: TotalStoreOrder :: MemType
- Test.DejaFu.Deterministic: TryPutVar :: MVarId -> Bool -> [ThreadId] -> ThreadAction
- Test.DejaFu.Deterministic: TryTakeVar :: MVarId -> Bool -> [ThreadId] -> ThreadAction
- Test.DejaFu.Deterministic: UncaughtException :: Failure
- Test.DejaFu.Deterministic: Unmasked :: MaskingState
- Test.DejaFu.Deterministic: WillAllKnown :: Lookahead
- Test.DejaFu.Deterministic: WillCasRef :: CRefId -> Lookahead
- Test.DejaFu.Deterministic: WillCatching :: Lookahead
- Test.DejaFu.Deterministic: WillCommitRef :: ThreadId -> CRefId -> Lookahead
- Test.DejaFu.Deterministic: WillForgets :: Lookahead
- Test.DejaFu.Deterministic: WillFork :: Lookahead
- Test.DejaFu.Deterministic: WillGetNumCapabilities :: Lookahead
- Test.DejaFu.Deterministic: WillKnowsAbout :: Lookahead
- Test.DejaFu.Deterministic: WillLift :: Lookahead
- Test.DejaFu.Deterministic: WillMessage :: Dynamic -> Lookahead
- Test.DejaFu.Deterministic: WillModRef :: CRefId -> Lookahead
- Test.DejaFu.Deterministic: WillModRefCas :: CRefId -> Lookahead
- Test.DejaFu.Deterministic: WillMyThreadId :: Lookahead
- Test.DejaFu.Deterministic: WillNewRef :: Lookahead
- Test.DejaFu.Deterministic: WillNewVar :: Lookahead
- Test.DejaFu.Deterministic: WillPeekTicket :: CRefId -> Lookahead
- Test.DejaFu.Deterministic: WillPopCatching :: Lookahead
- Test.DejaFu.Deterministic: WillPutVar :: MVarId -> Lookahead
- Test.DejaFu.Deterministic: WillReadRef :: CRefId -> Lookahead
- Test.DejaFu.Deterministic: WillReadRefCas :: CRefId -> Lookahead
- Test.DejaFu.Deterministic: WillReadVar :: MVarId -> Lookahead
- Test.DejaFu.Deterministic: WillResetMasking :: Bool -> MaskingState -> Lookahead
- Test.DejaFu.Deterministic: WillReturn :: Lookahead
- Test.DejaFu.Deterministic: WillSTM :: Lookahead
- Test.DejaFu.Deterministic: WillSetMasking :: Bool -> MaskingState -> Lookahead
- Test.DejaFu.Deterministic: WillSetNumCapabilities :: Int -> Lookahead
- Test.DejaFu.Deterministic: WillStop :: Lookahead
- Test.DejaFu.Deterministic: WillTakeVar :: MVarId -> Lookahead
- Test.DejaFu.Deterministic: WillThrow :: Lookahead
- Test.DejaFu.Deterministic: WillThrowTo :: ThreadId -> Lookahead
- Test.DejaFu.Deterministic: WillTryPutVar :: MVarId -> Lookahead
- Test.DejaFu.Deterministic: WillTryTakeVar :: MVarId -> Lookahead
- Test.DejaFu.Deterministic: WillWriteRef :: CRefId -> Lookahead
- Test.DejaFu.Deterministic: WillYield :: Lookahead
- Test.DejaFu.Deterministic: WriteRef :: CRefId -> ThreadAction
- Test.DejaFu.Deterministic: Yield :: ThreadAction
- Test.DejaFu.Deterministic: data CRefId
- Test.DejaFu.Deterministic: data Conc n r s a
- Test.DejaFu.Deterministic: data Decision tid :: * -> *
- Test.DejaFu.Deterministic: data Failure
- Test.DejaFu.Deterministic: data Lookahead
- Test.DejaFu.Deterministic: data MVarId
- Test.DejaFu.Deterministic: data MaskingState :: *
- Test.DejaFu.Deterministic: data MemType
- Test.DejaFu.Deterministic: data ThreadAction
- Test.DejaFu.Deterministic: data ThreadId
- Test.DejaFu.Deterministic: instance Control.Monad.Base.MonadBase GHC.Types.IO Test.DejaFu.Deterministic.ConcIO
- Test.DejaFu.Deterministic: instance Control.Monad.Catch.MonadCatch (Test.DejaFu.Deterministic.Conc n r s)
- Test.DejaFu.Deterministic: instance Control.Monad.Catch.MonadMask (Test.DejaFu.Deterministic.Conc n r s)
- Test.DejaFu.Deterministic: instance Control.Monad.Catch.MonadThrow (Test.DejaFu.Deterministic.Conc n r s)
- Test.DejaFu.Deterministic: instance Control.Monad.IO.Class.MonadIO Test.DejaFu.Deterministic.ConcIO
- Test.DejaFu.Deterministic: instance GHC.Base.Applicative (Test.DejaFu.Deterministic.Conc n r s)
- Test.DejaFu.Deterministic: instance GHC.Base.Functor (Test.DejaFu.Deterministic.Conc n r s)
- Test.DejaFu.Deterministic: instance GHC.Base.Monad (Test.DejaFu.Deterministic.Conc n r s)
- Test.DejaFu.Deterministic: instance GHC.Base.Monad n => Control.Monad.Conc.Class.MonadConc (Test.DejaFu.Deterministic.Conc n r (Test.DejaFu.STM.STMLike n r))
- Test.DejaFu.Deterministic: runConcIO :: Scheduler ThreadId ThreadAction Lookahead s -> MemType -> s -> ConcIO a -> IO (Either Failure a, s, Trace ThreadId ThreadAction Lookahead)
- Test.DejaFu.Deterministic: runConcST :: Scheduler ThreadId ThreadAction Lookahead s -> MemType -> s -> (forall t. ConcST t a) -> (Either Failure a, s, Trace ThreadId ThreadAction Lookahead)
- Test.DejaFu.Deterministic: showFail :: Failure -> String
- Test.DejaFu.Deterministic: showTrace :: Trace ThreadId ThreadAction Lookahead -> String
- Test.DejaFu.Deterministic: type ConcIO = Conc IO IORef STMIO
- Test.DejaFu.Deterministic: type ConcST t = Conc (ST t) (STRef t) (STMST t)
- Test.DejaFu.Deterministic: type Trace tid action lookahead = [(Decision tid, [(tid, NonEmpty lookahead)], action)]
- Test.DejaFu.Deterministic.Internal: AAllKnown :: (Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal: AAtom :: (s a) -> (a -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal: ACasRef :: (CRef r a) -> (Ticket a) -> a -> ((Bool, Ticket a) -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal: ACatching :: (e -> M n r s a) -> (M n r s a) -> (a -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal: ACommit :: ThreadId -> CRefId -> Action n r s
- Test.DejaFu.Deterministic.Internal: AForgets :: (Either MVarId TVarId) -> (Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal: AFork :: String -> ((forall b. M n r s b -> M n r s b) -> Action n r s) -> (ThreadId -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal: AGetNumCapabilities :: (Int -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal: AKnowsAbout :: (Either MVarId TVarId) -> (Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal: ALift :: (n (Action n r s)) -> Action n r s
- Test.DejaFu.Deterministic.Internal: AMasking :: MaskingState -> ((forall b. M n r s b -> M n r s b) -> M n r s a) -> (a -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal: AMessage :: Dynamic -> (Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal: AModRef :: (CRef r a) -> (a -> (a, b)) -> (b -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal: AModRefCas :: (CRef r a) -> (a -> (a, b)) -> (b -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal: AMyTId :: (ThreadId -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal: ANewRef :: String -> a -> (CRef r a -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal: ANewVar :: String -> (MVar r a -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal: APeekTicket :: (Ticket a) -> (a -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal: APopCatching :: (Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal: APutVar :: (MVar r a) -> a -> (Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal: AReadRef :: (CRef r a) -> (a -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal: AReadRefCas :: (CRef r a) -> (Ticket a -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal: AReadVar :: (MVar r a) -> (a -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal: AResetMask :: Bool -> Bool -> MaskingState -> (Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal: AReturn :: (Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal: ASetNumCapabilities :: Int -> (Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal: AStop :: Action n r s
- Test.DejaFu.Deterministic.Internal: ATakeVar :: (MVar r a) -> (a -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal: AThrow :: e -> Action n r s
- Test.DejaFu.Deterministic.Internal: AThrowTo :: ThreadId -> e -> (Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal: ATryPutVar :: (MVar r a) -> a -> (Bool -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal: ATryTakeVar :: (MVar r a) -> (Maybe a -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal: AWriteRef :: (CRef r a) -> a -> (Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal: AYield :: (Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal: Abort :: Failure
- Test.DejaFu.Deterministic.Internal: AllKnown :: ThreadAction
- Test.DejaFu.Deterministic.Internal: BlockedPutVar :: MVarId -> ThreadAction
- Test.DejaFu.Deterministic.Internal: BlockedReadVar :: MVarId -> ThreadAction
- Test.DejaFu.Deterministic.Internal: BlockedSTM :: TTrace -> ThreadAction
- Test.DejaFu.Deterministic.Internal: BlockedTakeVar :: MVarId -> ThreadAction
- Test.DejaFu.Deterministic.Internal: BlockedThrowTo :: ThreadId -> ThreadAction
- Test.DejaFu.Deterministic.Internal: CRef :: CRefId -> r (Map ThreadId a, Integer, a) -> CRef r a
- Test.DejaFu.Deterministic.Internal: CRefId :: (Maybe String) -> Int -> CRefId
- Test.DejaFu.Deterministic.Internal: CasRef :: CRefId -> Bool -> ThreadAction
- Test.DejaFu.Deterministic.Internal: Catching :: ThreadAction
- Test.DejaFu.Deterministic.Internal: CommitRef :: ThreadId -> CRefId -> ThreadAction
- Test.DejaFu.Deterministic.Internal: Continue :: Decision tid
- Test.DejaFu.Deterministic.Internal: Deadlock :: Failure
- Test.DejaFu.Deterministic.Internal: Forgets :: ThreadAction
- Test.DejaFu.Deterministic.Internal: Fork :: ThreadId -> ThreadAction
- Test.DejaFu.Deterministic.Internal: GetNumCapabilities :: Int -> ThreadAction
- Test.DejaFu.Deterministic.Internal: InternalError :: Failure
- Test.DejaFu.Deterministic.Internal: Killed :: ThreadAction
- Test.DejaFu.Deterministic.Internal: KnowsAbout :: ThreadAction
- Test.DejaFu.Deterministic.Internal: Lift :: ThreadAction
- Test.DejaFu.Deterministic.Internal: M :: ((a -> Action n r s) -> Action n r s) -> M n r s a
- Test.DejaFu.Deterministic.Internal: MVar :: MVarId -> r (Maybe a) -> MVar r a
- Test.DejaFu.Deterministic.Internal: MVarId :: (Maybe String) -> Int -> MVarId
- Test.DejaFu.Deterministic.Internal: Message :: Dynamic -> ThreadAction
- Test.DejaFu.Deterministic.Internal: ModRef :: CRefId -> ThreadAction
- Test.DejaFu.Deterministic.Internal: ModRefCas :: CRefId -> ThreadAction
- Test.DejaFu.Deterministic.Internal: MyThreadId :: ThreadAction
- Test.DejaFu.Deterministic.Internal: NewRef :: CRefId -> ThreadAction
- Test.DejaFu.Deterministic.Internal: NewVar :: MVarId -> ThreadAction
- Test.DejaFu.Deterministic.Internal: PartialStoreOrder :: MemType
- Test.DejaFu.Deterministic.Internal: PartiallySynchronisedCommit :: CRefId -> ActionType
- Test.DejaFu.Deterministic.Internal: PartiallySynchronisedModify :: CRefId -> ActionType
- Test.DejaFu.Deterministic.Internal: PartiallySynchronisedWrite :: CRefId -> ActionType
- Test.DejaFu.Deterministic.Internal: PeekTicket :: CRefId -> ThreadAction
- Test.DejaFu.Deterministic.Internal: PopCatching :: ThreadAction
- Test.DejaFu.Deterministic.Internal: PutVar :: MVarId -> [ThreadId] -> ThreadAction
- Test.DejaFu.Deterministic.Internal: ReadRef :: CRefId -> ThreadAction
- Test.DejaFu.Deterministic.Internal: ReadRefCas :: CRefId -> ThreadAction
- Test.DejaFu.Deterministic.Internal: ReadVar :: MVarId -> ThreadAction
- Test.DejaFu.Deterministic.Internal: ResetMasking :: Bool -> MaskingState -> ThreadAction
- Test.DejaFu.Deterministic.Internal: Return :: ThreadAction
- Test.DejaFu.Deterministic.Internal: STM :: TTrace -> [ThreadId] -> ThreadAction
- Test.DejaFu.Deterministic.Internal: STMDeadlock :: Failure
- Test.DejaFu.Deterministic.Internal: SequentialConsistency :: MemType
- Test.DejaFu.Deterministic.Internal: SetMasking :: Bool -> MaskingState -> ThreadAction
- Test.DejaFu.Deterministic.Internal: SetNumCapabilities :: Int -> ThreadAction
- Test.DejaFu.Deterministic.Internal: Start :: tid -> Decision tid
- Test.DejaFu.Deterministic.Internal: Stop :: ThreadAction
- Test.DejaFu.Deterministic.Internal: SwitchTo :: tid -> Decision tid
- Test.DejaFu.Deterministic.Internal: SynchronisedModify :: CRefId -> ActionType
- Test.DejaFu.Deterministic.Internal: SynchronisedOther :: ActionType
- Test.DejaFu.Deterministic.Internal: SynchronisedRead :: MVarId -> ActionType
- Test.DejaFu.Deterministic.Internal: SynchronisedWrite :: MVarId -> ActionType
- Test.DejaFu.Deterministic.Internal: TakeVar :: MVarId -> [ThreadId] -> ThreadAction
- Test.DejaFu.Deterministic.Internal: ThreadId :: (Maybe String) -> Int -> ThreadId
- Test.DejaFu.Deterministic.Internal: Throw :: ThreadAction
- Test.DejaFu.Deterministic.Internal: ThrowTo :: ThreadId -> ThreadAction
- Test.DejaFu.Deterministic.Internal: Ticket :: CRefId -> Integer -> a -> Ticket a
- Test.DejaFu.Deterministic.Internal: TotalStoreOrder :: MemType
- Test.DejaFu.Deterministic.Internal: TryPutVar :: MVarId -> Bool -> [ThreadId] -> ThreadAction
- Test.DejaFu.Deterministic.Internal: TryTakeVar :: MVarId -> Bool -> [ThreadId] -> ThreadAction
- Test.DejaFu.Deterministic.Internal: UncaughtException :: Failure
- Test.DejaFu.Deterministic.Internal: UnsynchronisedOther :: ActionType
- Test.DejaFu.Deterministic.Internal: UnsynchronisedRead :: CRefId -> ActionType
- Test.DejaFu.Deterministic.Internal: UnsynchronisedWrite :: CRefId -> ActionType
- Test.DejaFu.Deterministic.Internal: WillAllKnown :: Lookahead
- Test.DejaFu.Deterministic.Internal: WillCasRef :: CRefId -> Lookahead
- Test.DejaFu.Deterministic.Internal: WillCatching :: Lookahead
- Test.DejaFu.Deterministic.Internal: WillCommitRef :: ThreadId -> CRefId -> Lookahead
- Test.DejaFu.Deterministic.Internal: WillForgets :: Lookahead
- Test.DejaFu.Deterministic.Internal: WillFork :: Lookahead
- Test.DejaFu.Deterministic.Internal: WillGetNumCapabilities :: Lookahead
- Test.DejaFu.Deterministic.Internal: WillKnowsAbout :: Lookahead
- Test.DejaFu.Deterministic.Internal: WillLift :: Lookahead
- Test.DejaFu.Deterministic.Internal: WillMessage :: Dynamic -> Lookahead
- Test.DejaFu.Deterministic.Internal: WillModRef :: CRefId -> Lookahead
- Test.DejaFu.Deterministic.Internal: WillModRefCas :: CRefId -> Lookahead
- Test.DejaFu.Deterministic.Internal: WillMyThreadId :: Lookahead
- Test.DejaFu.Deterministic.Internal: WillNewRef :: Lookahead
- Test.DejaFu.Deterministic.Internal: WillNewVar :: Lookahead
- Test.DejaFu.Deterministic.Internal: WillPeekTicket :: CRefId -> Lookahead
- Test.DejaFu.Deterministic.Internal: WillPopCatching :: Lookahead
- Test.DejaFu.Deterministic.Internal: WillPutVar :: MVarId -> Lookahead
- Test.DejaFu.Deterministic.Internal: WillReadRef :: CRefId -> Lookahead
- Test.DejaFu.Deterministic.Internal: WillReadRefCas :: CRefId -> Lookahead
- Test.DejaFu.Deterministic.Internal: WillReadVar :: MVarId -> Lookahead
- Test.DejaFu.Deterministic.Internal: WillResetMasking :: Bool -> MaskingState -> Lookahead
- Test.DejaFu.Deterministic.Internal: WillReturn :: Lookahead
- Test.DejaFu.Deterministic.Internal: WillSTM :: Lookahead
- Test.DejaFu.Deterministic.Internal: WillSetMasking :: Bool -> MaskingState -> Lookahead
- Test.DejaFu.Deterministic.Internal: WillSetNumCapabilities :: Int -> Lookahead
- Test.DejaFu.Deterministic.Internal: WillStop :: Lookahead
- Test.DejaFu.Deterministic.Internal: WillTakeVar :: MVarId -> Lookahead
- Test.DejaFu.Deterministic.Internal: WillThrow :: Lookahead
- Test.DejaFu.Deterministic.Internal: WillThrowTo :: ThreadId -> Lookahead
- Test.DejaFu.Deterministic.Internal: WillTryPutVar :: MVarId -> Lookahead
- Test.DejaFu.Deterministic.Internal: WillTryTakeVar :: MVarId -> Lookahead
- Test.DejaFu.Deterministic.Internal: WillWriteRef :: CRefId -> Lookahead
- Test.DejaFu.Deterministic.Internal: WillYield :: Lookahead
- Test.DejaFu.Deterministic.Internal: WriteRef :: CRefId -> ThreadAction
- Test.DejaFu.Deterministic.Internal: Yield :: ThreadAction
- Test.DejaFu.Deterministic.Internal: [_crefId] :: CRef r a -> CRefId
- Test.DejaFu.Deterministic.Internal: [_crefVal] :: CRef r a -> r (Map ThreadId a, Integer, a)
- Test.DejaFu.Deterministic.Internal: [_cvarId] :: MVar r a -> MVarId
- Test.DejaFu.Deterministic.Internal: [_cvarVal] :: MVar r a -> r (Maybe a)
- Test.DejaFu.Deterministic.Internal: [_ticketCRef] :: Ticket a -> CRefId
- Test.DejaFu.Deterministic.Internal: [_ticketVal] :: Ticket a -> a
- Test.DejaFu.Deterministic.Internal: [_ticketWrites] :: Ticket a -> Integer
- Test.DejaFu.Deterministic.Internal: [runM] :: M n r s a -> (a -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal: cont :: ((a -> Action n r s) -> Action n r s) -> M n r s a
- Test.DejaFu.Deterministic.Internal: crefOf :: ActionType -> Maybe CRefId
- Test.DejaFu.Deterministic.Internal: cvarOf :: ActionType -> Maybe MVarId
- Test.DejaFu.Deterministic.Internal: data Action n r s
- Test.DejaFu.Deterministic.Internal: data ActionType
- Test.DejaFu.Deterministic.Internal: data CRef r a
- Test.DejaFu.Deterministic.Internal: data CRefId
- Test.DejaFu.Deterministic.Internal: data Decision tid :: * -> *
- Test.DejaFu.Deterministic.Internal: data Failure
- Test.DejaFu.Deterministic.Internal: data Lookahead
- Test.DejaFu.Deterministic.Internal: data MVar r a
- Test.DejaFu.Deterministic.Internal: data MVarId
- Test.DejaFu.Deterministic.Internal: data MemType
- Test.DejaFu.Deterministic.Internal: data ThreadAction
- Test.DejaFu.Deterministic.Internal: data ThreadId
- Test.DejaFu.Deterministic.Internal: data Ticket a
- Test.DejaFu.Deterministic.Internal: initialThread :: ThreadId
- Test.DejaFu.Deterministic.Internal: isBarrier :: ActionType -> Bool
- Test.DejaFu.Deterministic.Internal: isBlock :: ThreadAction -> Bool
- Test.DejaFu.Deterministic.Internal: isCommit :: ActionType -> CRefId -> Bool
- Test.DejaFu.Deterministic.Internal: lookahead :: Action n r s -> NonEmpty Lookahead
- Test.DejaFu.Deterministic.Internal: newtype M n r s a
- Test.DejaFu.Deterministic.Internal: preEmpCount :: [(Decision ThreadId, ThreadAction)] -> (Decision ThreadId, Lookahead) -> Int
- Test.DejaFu.Deterministic.Internal: rewind :: ThreadAction -> Maybe Lookahead
- Test.DejaFu.Deterministic.Internal: runCont :: M n r s a -> (a -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal: runFixed :: (Functor n, Monad n) => Fixed n r s -> (forall x. s x -> IdSource -> n (Result x, IdSource, TTrace)) -> Scheduler ThreadId ThreadAction Lookahead g -> MemType -> g -> M n r s a -> n (Either Failure a, g, Trace ThreadId ThreadAction Lookahead)
- Test.DejaFu.Deterministic.Internal: runFixed' :: forall n r s g a. (Functor n, Monad n) => Fixed n r s -> (forall x. s x -> IdSource -> n (Result x, IdSource, TTrace)) -> Scheduler ThreadId ThreadAction Lookahead g -> MemType -> g -> IdSource -> M n r s a -> n (Either Failure a, g, IdSource, Trace ThreadId ThreadAction Lookahead)
- Test.DejaFu.Deterministic.Internal: showFail :: Failure -> String
- Test.DejaFu.Deterministic.Internal: showTrace :: Trace ThreadId ThreadAction Lookahead -> String
- Test.DejaFu.Deterministic.Internal: simplify :: ThreadAction -> ActionType
- Test.DejaFu.Deterministic.Internal: simplify' :: Lookahead -> ActionType
- Test.DejaFu.Deterministic.Internal: synchronises :: ActionType -> CRefId -> Bool
- Test.DejaFu.Deterministic.Internal: tvarsOf :: ThreadAction -> Set TVarId
- Test.DejaFu.Deterministic.Internal: type Fixed n r s = Ref n r (M n r s)
- Test.DejaFu.Deterministic.Internal: type Scheduler tid action lookahead s = [(Decision tid, action)] -> Maybe (tid, action) -> NonEmpty (tid, lookahead) -> s -> (Maybe tid, s)
- Test.DejaFu.Deterministic.Internal: type Trace tid action lookahead = [(Decision tid, [(tid, NonEmpty lookahead)], action)]
- Test.DejaFu.Deterministic.Internal: willRelease :: Lookahead -> Bool
- Test.DejaFu.Deterministic.Internal.Common: AAllKnown :: (Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: AAtom :: (s a) -> (a -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: ACasRef :: (CRef r a) -> (Ticket a) -> a -> ((Bool, Ticket a) -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: ACatching :: (e -> M n r s a) -> (M n r s a) -> (a -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: ACommit :: ThreadId -> CRefId -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: AForgets :: (Either MVarId TVarId) -> (Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: AFork :: String -> ((forall b. M n r s b -> M n r s b) -> Action n r s) -> (ThreadId -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: AGetNumCapabilities :: (Int -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: AKnowsAbout :: (Either MVarId TVarId) -> (Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: ALift :: (n (Action n r s)) -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: AMasking :: MaskingState -> ((forall b. M n r s b -> M n r s b) -> M n r s a) -> (a -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: AMessage :: Dynamic -> (Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: AModRef :: (CRef r a) -> (a -> (a, b)) -> (b -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: AModRefCas :: (CRef r a) -> (a -> (a, b)) -> (b -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: AMyTId :: (ThreadId -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: ANewRef :: String -> a -> (CRef r a -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: ANewVar :: String -> (MVar r a -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: APeekTicket :: (Ticket a) -> (a -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: APopCatching :: (Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: APutVar :: (MVar r a) -> a -> (Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: AReadRef :: (CRef r a) -> (a -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: AReadRefCas :: (CRef r a) -> (Ticket a -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: AReadVar :: (MVar r a) -> (a -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: AResetMask :: Bool -> Bool -> MaskingState -> (Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: AReturn :: (Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: ASetNumCapabilities :: Int -> (Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: AStop :: Action n r s
- Test.DejaFu.Deterministic.Internal.Common: ATakeVar :: (MVar r a) -> (a -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: AThrow :: e -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: AThrowTo :: ThreadId -> e -> (Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: ATryPutVar :: (MVar r a) -> a -> (Bool -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: ATryTakeVar :: (MVar r a) -> (Maybe a -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: AWriteRef :: (CRef r a) -> a -> (Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: AYield :: (Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: Abort :: Failure
- Test.DejaFu.Deterministic.Internal.Common: AllKnown :: ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: BlockedPutVar :: MVarId -> ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: BlockedReadVar :: MVarId -> ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: BlockedSTM :: TTrace -> ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: BlockedTakeVar :: MVarId -> ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: BlockedThrowTo :: ThreadId -> ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: CRef :: CRefId -> r (Map ThreadId a, Integer, a) -> CRef r a
- Test.DejaFu.Deterministic.Internal.Common: CRefId :: (Maybe String) -> Int -> CRefId
- Test.DejaFu.Deterministic.Internal.Common: CasRef :: CRefId -> Bool -> ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: Catching :: ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: CommitRef :: ThreadId -> CRefId -> ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: Deadlock :: Failure
- Test.DejaFu.Deterministic.Internal.Common: Forgets :: ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: Fork :: ThreadId -> ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: GetNumCapabilities :: Int -> ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: Id :: Int -> Int -> Int -> Int -> [String] -> [String] -> [String] -> [String] -> IdSource
- Test.DejaFu.Deterministic.Internal.Common: InternalError :: Failure
- Test.DejaFu.Deterministic.Internal.Common: Killed :: ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: KnowsAbout :: ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: Lift :: ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: M :: ((a -> Action n r s) -> Action n r s) -> M n r s a
- Test.DejaFu.Deterministic.Internal.Common: MVar :: MVarId -> r (Maybe a) -> MVar r a
- Test.DejaFu.Deterministic.Internal.Common: MVarId :: (Maybe String) -> Int -> MVarId
- Test.DejaFu.Deterministic.Internal.Common: Message :: Dynamic -> ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: ModRef :: CRefId -> ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: ModRefCas :: CRefId -> ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: MyThreadId :: ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: NewRef :: CRefId -> ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: NewVar :: MVarId -> ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: PartialStoreOrder :: MemType
- Test.DejaFu.Deterministic.Internal.Common: PartiallySynchronisedCommit :: CRefId -> ActionType
- Test.DejaFu.Deterministic.Internal.Common: PartiallySynchronisedModify :: CRefId -> ActionType
- Test.DejaFu.Deterministic.Internal.Common: PartiallySynchronisedWrite :: CRefId -> ActionType
- Test.DejaFu.Deterministic.Internal.Common: PeekTicket :: CRefId -> ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: PopCatching :: ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: PutVar :: MVarId -> [ThreadId] -> ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: ReadRef :: CRefId -> ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: ReadRefCas :: CRefId -> ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: ReadVar :: MVarId -> ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: ResetMasking :: Bool -> MaskingState -> ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: Return :: ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: STM :: TTrace -> [ThreadId] -> ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: STMDeadlock :: Failure
- Test.DejaFu.Deterministic.Internal.Common: SequentialConsistency :: MemType
- Test.DejaFu.Deterministic.Internal.Common: SetMasking :: Bool -> MaskingState -> ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: SetNumCapabilities :: Int -> ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: Stop :: ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: SynchronisedModify :: CRefId -> ActionType
- Test.DejaFu.Deterministic.Internal.Common: SynchronisedOther :: ActionType
- Test.DejaFu.Deterministic.Internal.Common: SynchronisedRead :: MVarId -> ActionType
- Test.DejaFu.Deterministic.Internal.Common: SynchronisedWrite :: MVarId -> ActionType
- Test.DejaFu.Deterministic.Internal.Common: TCatch :: TTrace -> (Maybe TTrace) -> TAction
- Test.DejaFu.Deterministic.Internal.Common: TLift :: TAction
- Test.DejaFu.Deterministic.Internal.Common: TNew :: TAction
- Test.DejaFu.Deterministic.Internal.Common: TOrElse :: TTrace -> (Maybe TTrace) -> TAction
- Test.DejaFu.Deterministic.Internal.Common: TRead :: TVarId -> TAction
- Test.DejaFu.Deterministic.Internal.Common: TRetry :: TAction
- Test.DejaFu.Deterministic.Internal.Common: TStop :: TAction
- Test.DejaFu.Deterministic.Internal.Common: TThrow :: TAction
- Test.DejaFu.Deterministic.Internal.Common: TVarId :: (Maybe String) -> Int -> TVarId
- Test.DejaFu.Deterministic.Internal.Common: TWrite :: TVarId -> TAction
- Test.DejaFu.Deterministic.Internal.Common: TakeVar :: MVarId -> [ThreadId] -> ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: ThreadId :: (Maybe String) -> Int -> ThreadId
- Test.DejaFu.Deterministic.Internal.Common: Throw :: ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: ThrowTo :: ThreadId -> ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: Ticket :: CRefId -> Integer -> a -> Ticket a
- Test.DejaFu.Deterministic.Internal.Common: TotalStoreOrder :: MemType
- Test.DejaFu.Deterministic.Internal.Common: TryPutVar :: MVarId -> Bool -> [ThreadId] -> ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: TryTakeVar :: MVarId -> Bool -> [ThreadId] -> ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: UncaughtException :: Failure
- Test.DejaFu.Deterministic.Internal.Common: UnsynchronisedOther :: ActionType
- Test.DejaFu.Deterministic.Internal.Common: UnsynchronisedRead :: CRefId -> ActionType
- Test.DejaFu.Deterministic.Internal.Common: UnsynchronisedWrite :: CRefId -> ActionType
- Test.DejaFu.Deterministic.Internal.Common: WillAllKnown :: Lookahead
- Test.DejaFu.Deterministic.Internal.Common: WillCasRef :: CRefId -> Lookahead
- Test.DejaFu.Deterministic.Internal.Common: WillCatching :: Lookahead
- Test.DejaFu.Deterministic.Internal.Common: WillCommitRef :: ThreadId -> CRefId -> Lookahead
- Test.DejaFu.Deterministic.Internal.Common: WillForgets :: Lookahead
- Test.DejaFu.Deterministic.Internal.Common: WillFork :: Lookahead
- Test.DejaFu.Deterministic.Internal.Common: WillGetNumCapabilities :: Lookahead
- Test.DejaFu.Deterministic.Internal.Common: WillKnowsAbout :: Lookahead
- Test.DejaFu.Deterministic.Internal.Common: WillLift :: Lookahead
- Test.DejaFu.Deterministic.Internal.Common: WillMessage :: Dynamic -> Lookahead
- Test.DejaFu.Deterministic.Internal.Common: WillModRef :: CRefId -> Lookahead
- Test.DejaFu.Deterministic.Internal.Common: WillModRefCas :: CRefId -> Lookahead
- Test.DejaFu.Deterministic.Internal.Common: WillMyThreadId :: Lookahead
- Test.DejaFu.Deterministic.Internal.Common: WillNewRef :: Lookahead
- Test.DejaFu.Deterministic.Internal.Common: WillNewVar :: Lookahead
- Test.DejaFu.Deterministic.Internal.Common: WillPeekTicket :: CRefId -> Lookahead
- Test.DejaFu.Deterministic.Internal.Common: WillPopCatching :: Lookahead
- Test.DejaFu.Deterministic.Internal.Common: WillPutVar :: MVarId -> Lookahead
- Test.DejaFu.Deterministic.Internal.Common: WillReadRef :: CRefId -> Lookahead
- Test.DejaFu.Deterministic.Internal.Common: WillReadRefCas :: CRefId -> Lookahead
- Test.DejaFu.Deterministic.Internal.Common: WillReadVar :: MVarId -> Lookahead
- Test.DejaFu.Deterministic.Internal.Common: WillResetMasking :: Bool -> MaskingState -> Lookahead
- Test.DejaFu.Deterministic.Internal.Common: WillReturn :: Lookahead
- Test.DejaFu.Deterministic.Internal.Common: WillSTM :: Lookahead
- Test.DejaFu.Deterministic.Internal.Common: WillSetMasking :: Bool -> MaskingState -> Lookahead
- Test.DejaFu.Deterministic.Internal.Common: WillSetNumCapabilities :: Int -> Lookahead
- Test.DejaFu.Deterministic.Internal.Common: WillStop :: Lookahead
- Test.DejaFu.Deterministic.Internal.Common: WillTakeVar :: MVarId -> Lookahead
- Test.DejaFu.Deterministic.Internal.Common: WillThrow :: Lookahead
- Test.DejaFu.Deterministic.Internal.Common: WillThrowTo :: ThreadId -> Lookahead
- Test.DejaFu.Deterministic.Internal.Common: WillTryPutVar :: MVarId -> Lookahead
- Test.DejaFu.Deterministic.Internal.Common: WillTryTakeVar :: MVarId -> Lookahead
- Test.DejaFu.Deterministic.Internal.Common: WillWriteRef :: CRefId -> Lookahead
- Test.DejaFu.Deterministic.Internal.Common: WillYield :: Lookahead
- Test.DejaFu.Deterministic.Internal.Common: WriteRef :: CRefId -> ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: Yield :: ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: [_crefId] :: CRef r a -> CRefId
- Test.DejaFu.Deterministic.Internal.Common: [_crefVal] :: CRef r a -> r (Map ThreadId a, Integer, a)
- Test.DejaFu.Deterministic.Internal.Common: [_cvarId] :: MVar r a -> MVarId
- Test.DejaFu.Deterministic.Internal.Common: [_cvarVal] :: MVar r a -> r (Maybe a)
- Test.DejaFu.Deterministic.Internal.Common: [_nextCRId] :: IdSource -> Int
- Test.DejaFu.Deterministic.Internal.Common: [_nextCVId] :: IdSource -> Int
- Test.DejaFu.Deterministic.Internal.Common: [_nextTId] :: IdSource -> Int
- Test.DejaFu.Deterministic.Internal.Common: [_nextTVId] :: IdSource -> Int
- Test.DejaFu.Deterministic.Internal.Common: [_ticketCRef] :: Ticket a -> CRefId
- Test.DejaFu.Deterministic.Internal.Common: [_ticketVal] :: Ticket a -> a
- Test.DejaFu.Deterministic.Internal.Common: [_ticketWrites] :: Ticket a -> Integer
- Test.DejaFu.Deterministic.Internal.Common: [_usedCRNames] :: IdSource -> [String]
- Test.DejaFu.Deterministic.Internal.Common: [_usedCVNames] :: IdSource -> [String]
- Test.DejaFu.Deterministic.Internal.Common: [_usedTNames] :: IdSource -> [String]
- Test.DejaFu.Deterministic.Internal.Common: [_usedTVNames] :: IdSource -> [String]
- Test.DejaFu.Deterministic.Internal.Common: [runM] :: M n r s a -> (a -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: cont :: ((a -> Action n r s) -> Action n r s) -> M n r s a
- Test.DejaFu.Deterministic.Internal.Common: crefOf :: ActionType -> Maybe CRefId
- Test.DejaFu.Deterministic.Internal.Common: cvarOf :: ActionType -> Maybe MVarId
- Test.DejaFu.Deterministic.Internal.Common: data Action n r s
- Test.DejaFu.Deterministic.Internal.Common: data ActionType
- Test.DejaFu.Deterministic.Internal.Common: data CRef r a
- Test.DejaFu.Deterministic.Internal.Common: data CRefId
- Test.DejaFu.Deterministic.Internal.Common: data Failure
- Test.DejaFu.Deterministic.Internal.Common: data IdSource
- Test.DejaFu.Deterministic.Internal.Common: data Lookahead
- Test.DejaFu.Deterministic.Internal.Common: data MVar r a
- Test.DejaFu.Deterministic.Internal.Common: data MVarId
- Test.DejaFu.Deterministic.Internal.Common: data MemType
- Test.DejaFu.Deterministic.Internal.Common: data TAction
- Test.DejaFu.Deterministic.Internal.Common: data TVarId
- Test.DejaFu.Deterministic.Internal.Common: data ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: data ThreadId
- Test.DejaFu.Deterministic.Internal.Common: data Ticket a
- Test.DejaFu.Deterministic.Internal.Common: initialIdSource :: IdSource
- Test.DejaFu.Deterministic.Internal.Common: initialThread :: ThreadId
- Test.DejaFu.Deterministic.Internal.Common: instance Control.DeepSeq.NFData Test.DejaFu.Deterministic.Internal.Common.ActionType
- Test.DejaFu.Deterministic.Internal.Common: instance Control.DeepSeq.NFData Test.DejaFu.Deterministic.Internal.Common.CRefId
- Test.DejaFu.Deterministic.Internal.Common: instance Control.DeepSeq.NFData Test.DejaFu.Deterministic.Internal.Common.Failure
- Test.DejaFu.Deterministic.Internal.Common: instance Control.DeepSeq.NFData Test.DejaFu.Deterministic.Internal.Common.Lookahead
- Test.DejaFu.Deterministic.Internal.Common: instance Control.DeepSeq.NFData Test.DejaFu.Deterministic.Internal.Common.MVarId
- Test.DejaFu.Deterministic.Internal.Common: instance Control.DeepSeq.NFData Test.DejaFu.Deterministic.Internal.Common.MemType
- Test.DejaFu.Deterministic.Internal.Common: instance Control.DeepSeq.NFData Test.DejaFu.Deterministic.Internal.Common.TAction
- Test.DejaFu.Deterministic.Internal.Common: instance Control.DeepSeq.NFData Test.DejaFu.Deterministic.Internal.Common.TVarId
- Test.DejaFu.Deterministic.Internal.Common: instance Control.DeepSeq.NFData Test.DejaFu.Deterministic.Internal.Common.ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: instance Control.DeepSeq.NFData Test.DejaFu.Deterministic.Internal.Common.ThreadId
- Test.DejaFu.Deterministic.Internal.Common: instance GHC.Base.Applicative (Test.DejaFu.Deterministic.Internal.Common.M n r s)
- Test.DejaFu.Deterministic.Internal.Common: instance GHC.Base.Functor (Test.DejaFu.Deterministic.Internal.Common.M n r s)
- Test.DejaFu.Deterministic.Internal.Common: instance GHC.Base.Monad (Test.DejaFu.Deterministic.Internal.Common.M n r s)
- Test.DejaFu.Deterministic.Internal.Common: instance GHC.Classes.Eq Test.DejaFu.Deterministic.Internal.Common.ActionType
- Test.DejaFu.Deterministic.Internal.Common: instance GHC.Classes.Eq Test.DejaFu.Deterministic.Internal.Common.CRefId
- Test.DejaFu.Deterministic.Internal.Common: instance GHC.Classes.Eq Test.DejaFu.Deterministic.Internal.Common.Failure
- Test.DejaFu.Deterministic.Internal.Common: instance GHC.Classes.Eq Test.DejaFu.Deterministic.Internal.Common.MVarId
- Test.DejaFu.Deterministic.Internal.Common: instance GHC.Classes.Eq Test.DejaFu.Deterministic.Internal.Common.MemType
- Test.DejaFu.Deterministic.Internal.Common: instance GHC.Classes.Eq Test.DejaFu.Deterministic.Internal.Common.TAction
- Test.DejaFu.Deterministic.Internal.Common: instance GHC.Classes.Eq Test.DejaFu.Deterministic.Internal.Common.TVarId
- Test.DejaFu.Deterministic.Internal.Common: instance GHC.Classes.Eq Test.DejaFu.Deterministic.Internal.Common.ThreadId
- Test.DejaFu.Deterministic.Internal.Common: instance GHC.Classes.Ord Test.DejaFu.Deterministic.Internal.Common.CRefId
- Test.DejaFu.Deterministic.Internal.Common: instance GHC.Classes.Ord Test.DejaFu.Deterministic.Internal.Common.Failure
- Test.DejaFu.Deterministic.Internal.Common: instance GHC.Classes.Ord Test.DejaFu.Deterministic.Internal.Common.MVarId
- Test.DejaFu.Deterministic.Internal.Common: instance GHC.Classes.Ord Test.DejaFu.Deterministic.Internal.Common.MemType
- Test.DejaFu.Deterministic.Internal.Common: instance GHC.Classes.Ord Test.DejaFu.Deterministic.Internal.Common.TVarId
- Test.DejaFu.Deterministic.Internal.Common: instance GHC.Classes.Ord Test.DejaFu.Deterministic.Internal.Common.ThreadId
- Test.DejaFu.Deterministic.Internal.Common: instance GHC.Enum.Bounded Test.DejaFu.Deterministic.Internal.Common.Failure
- Test.DejaFu.Deterministic.Internal.Common: instance GHC.Enum.Bounded Test.DejaFu.Deterministic.Internal.Common.MemType
- Test.DejaFu.Deterministic.Internal.Common: instance GHC.Enum.Enum Test.DejaFu.Deterministic.Internal.Common.Failure
- Test.DejaFu.Deterministic.Internal.Common: instance GHC.Enum.Enum Test.DejaFu.Deterministic.Internal.Common.MemType
- Test.DejaFu.Deterministic.Internal.Common: instance GHC.Read.Read Test.DejaFu.Deterministic.Internal.Common.Failure
- Test.DejaFu.Deterministic.Internal.Common: instance GHC.Read.Read Test.DejaFu.Deterministic.Internal.Common.MemType
- Test.DejaFu.Deterministic.Internal.Common: instance GHC.Show.Show Test.DejaFu.Deterministic.Internal.Common.ActionType
- Test.DejaFu.Deterministic.Internal.Common: instance GHC.Show.Show Test.DejaFu.Deterministic.Internal.Common.CRefId
- Test.DejaFu.Deterministic.Internal.Common: instance GHC.Show.Show Test.DejaFu.Deterministic.Internal.Common.Failure
- Test.DejaFu.Deterministic.Internal.Common: instance GHC.Show.Show Test.DejaFu.Deterministic.Internal.Common.Lookahead
- Test.DejaFu.Deterministic.Internal.Common: instance GHC.Show.Show Test.DejaFu.Deterministic.Internal.Common.MVarId
- Test.DejaFu.Deterministic.Internal.Common: instance GHC.Show.Show Test.DejaFu.Deterministic.Internal.Common.MemType
- Test.DejaFu.Deterministic.Internal.Common: instance GHC.Show.Show Test.DejaFu.Deterministic.Internal.Common.TAction
- Test.DejaFu.Deterministic.Internal.Common: instance GHC.Show.Show Test.DejaFu.Deterministic.Internal.Common.TVarId
- Test.DejaFu.Deterministic.Internal.Common: instance GHC.Show.Show Test.DejaFu.Deterministic.Internal.Common.ThreadAction
- Test.DejaFu.Deterministic.Internal.Common: instance GHC.Show.Show Test.DejaFu.Deterministic.Internal.Common.ThreadId
- Test.DejaFu.Deterministic.Internal.Common: isBarrier :: ActionType -> Bool
- Test.DejaFu.Deterministic.Internal.Common: isBlock :: ThreadAction -> Bool
- Test.DejaFu.Deterministic.Internal.Common: isCommit :: ActionType -> CRefId -> Bool
- Test.DejaFu.Deterministic.Internal.Common: lookahead :: Action n r s -> NonEmpty Lookahead
- Test.DejaFu.Deterministic.Internal.Common: newtype M n r s a
- Test.DejaFu.Deterministic.Internal.Common: nextCRId :: String -> IdSource -> (IdSource, CRefId)
- Test.DejaFu.Deterministic.Internal.Common: nextCVId :: String -> IdSource -> (IdSource, MVarId)
- Test.DejaFu.Deterministic.Internal.Common: nextTId :: String -> IdSource -> (IdSource, ThreadId)
- Test.DejaFu.Deterministic.Internal.Common: nextTVId :: String -> IdSource -> (IdSource, TVarId)
- Test.DejaFu.Deterministic.Internal.Common: preEmpCount :: [(Decision ThreadId, ThreadAction)] -> (Decision ThreadId, Lookahead) -> Int
- Test.DejaFu.Deterministic.Internal.Common: rewind :: ThreadAction -> Maybe Lookahead
- Test.DejaFu.Deterministic.Internal.Common: runCont :: M n r s a -> (a -> Action n r s) -> Action n r s
- Test.DejaFu.Deterministic.Internal.Common: showFail :: Failure -> String
- Test.DejaFu.Deterministic.Internal.Common: showTrace :: Trace ThreadId ThreadAction Lookahead -> String
- Test.DejaFu.Deterministic.Internal.Common: simplify :: ThreadAction -> ActionType
- Test.DejaFu.Deterministic.Internal.Common: simplify' :: Lookahead -> ActionType
- Test.DejaFu.Deterministic.Internal.Common: synchronises :: ActionType -> CRefId -> Bool
- Test.DejaFu.Deterministic.Internal.Common: tvarsOf :: ThreadAction -> Set TVarId
- Test.DejaFu.Deterministic.Internal.Common: type Fixed n r s = Ref n r (M n r s)
- Test.DejaFu.Deterministic.Internal.Common: type TTrace = [TAction]
- Test.DejaFu.Deterministic.Internal.Common: willRelease :: Lookahead -> Bool
- Test.DejaFu.Deterministic.Internal.Memory: WriteBuffer :: Map (ThreadId, Maybe CRefId) (Seq (BufferedWrite r)) -> WriteBuffer r
- Test.DejaFu.Deterministic.Internal.Memory: [BufferedWrite] :: ThreadId -> CRef r a -> a -> BufferedWrite r
- Test.DejaFu.Deterministic.Internal.Memory: [buffer] :: WriteBuffer r -> Map (ThreadId, Maybe CRefId) (Seq (BufferedWrite r))
- Test.DejaFu.Deterministic.Internal.Memory: addCommitThreads :: WriteBuffer r -> Threads n r s -> Threads n r s
- Test.DejaFu.Deterministic.Internal.Memory: bufferWrite :: Monad n => Fixed n r s -> WriteBuffer r -> (ThreadId, Maybe CRefId) -> CRef r a -> a -> n (WriteBuffer r)
- Test.DejaFu.Deterministic.Internal.Memory: casCRef :: Monad n => Fixed n r s -> CRef r a -> ThreadId -> Ticket a -> a -> n (Bool, Ticket a)
- Test.DejaFu.Deterministic.Internal.Memory: commitWrite :: Monad n => Fixed n r s -> WriteBuffer r -> (ThreadId, Maybe CRefId) -> n (WriteBuffer r)
- Test.DejaFu.Deterministic.Internal.Memory: data BufferedWrite r
- Test.DejaFu.Deterministic.Internal.Memory: delCommitThreads :: Threads n r s -> Threads n r s
- Test.DejaFu.Deterministic.Internal.Memory: emptyBuffer :: WriteBuffer r
- Test.DejaFu.Deterministic.Internal.Memory: mutMVar :: Monad n => Bool -> MVar r a -> a -> (Bool -> Action n r s) -> Fixed n r s -> ThreadId -> Threads n r s -> n (Bool, Threads n r s, [ThreadId])
- Test.DejaFu.Deterministic.Internal.Memory: newtype WriteBuffer r
- Test.DejaFu.Deterministic.Internal.Memory: putIntoMVar :: Monad n => MVar r a -> a -> Action n r s -> Fixed n r s -> ThreadId -> Threads n r s -> n (Bool, Threads n r s, [ThreadId])
- Test.DejaFu.Deterministic.Internal.Memory: readCRef :: Monad n => Fixed n r s -> CRef r a -> ThreadId -> n a
- Test.DejaFu.Deterministic.Internal.Memory: readCRefPrim :: Monad n => Fixed n r s -> CRef r a -> ThreadId -> n (a, Integer)
- Test.DejaFu.Deterministic.Internal.Memory: readForTicket :: Monad n => Fixed n r s -> CRef r a -> ThreadId -> n (Ticket a)
- Test.DejaFu.Deterministic.Internal.Memory: readFromMVar :: Monad n => MVar r a -> (a -> Action n r s) -> Fixed n r s -> ThreadId -> Threads n r s -> n (Bool, Threads n r s, [ThreadId])
- Test.DejaFu.Deterministic.Internal.Memory: seeMVar :: Monad n => Bool -> Bool -> MVar r a -> (Maybe a -> Action n r s) -> Fixed n r s -> ThreadId -> Threads n r s -> n (Bool, Threads n r s, [ThreadId])
- Test.DejaFu.Deterministic.Internal.Memory: takeFromMVar :: Monad n => MVar r a -> (a -> Action n r s) -> Fixed n r s -> ThreadId -> Threads n r s -> n (Bool, Threads n r s, [ThreadId])
- Test.DejaFu.Deterministic.Internal.Memory: tryPutIntoMVar :: Monad n => MVar r a -> a -> (Bool -> Action n r s) -> Fixed n r s -> ThreadId -> Threads n r s -> n (Bool, Threads n r s, [ThreadId])
- Test.DejaFu.Deterministic.Internal.Memory: tryTakeFromMVar :: Monad n => MVar r a -> (Maybe a -> Action n r s) -> Fixed n r s -> ThreadId -> Threads n r s -> n (Bool, Threads n r s, [ThreadId])
- Test.DejaFu.Deterministic.Internal.Memory: writeBarrier :: Monad n => Fixed n r s -> WriteBuffer r -> n ()
- Test.DejaFu.Deterministic.Internal.Memory: writeImmediate :: Monad n => Fixed n r s -> CRef r a -> a -> n ()
- Test.DejaFu.Deterministic.Internal.Threading: (~=) :: Thread n r s -> BlockedOn -> Bool
- Test.DejaFu.Deterministic.Internal.Threading: Handler :: (e -> Action n r s) -> Handler n r s
- Test.DejaFu.Deterministic.Internal.Threading: OnMVarEmpty :: MVarId -> BlockedOn
- Test.DejaFu.Deterministic.Internal.Threading: OnMVarFull :: MVarId -> BlockedOn
- Test.DejaFu.Deterministic.Internal.Threading: OnMask :: ThreadId -> BlockedOn
- Test.DejaFu.Deterministic.Internal.Threading: OnTVar :: [TVarId] -> BlockedOn
- Test.DejaFu.Deterministic.Internal.Threading: Thread :: Action n r s -> Maybe BlockedOn -> [Handler n r s] -> MaskingState -> [Either MVarId TVarId] -> Bool -> Thread n r s
- Test.DejaFu.Deterministic.Internal.Threading: [_blocking] :: Thread n r s -> Maybe BlockedOn
- Test.DejaFu.Deterministic.Internal.Threading: [_continuation] :: Thread n r s -> Action n r s
- Test.DejaFu.Deterministic.Internal.Threading: [_fullknown] :: Thread n r s -> Bool
- Test.DejaFu.Deterministic.Internal.Threading: [_handlers] :: Thread n r s -> [Handler n r s]
- Test.DejaFu.Deterministic.Internal.Threading: [_known] :: Thread n r s -> [Either MVarId TVarId]
- Test.DejaFu.Deterministic.Internal.Threading: [_masking] :: Thread n r s -> MaskingState
- Test.DejaFu.Deterministic.Internal.Threading: block :: BlockedOn -> ThreadId -> Threads n r s -> Threads n r s
- Test.DejaFu.Deterministic.Internal.Threading: catching :: Exception e => (e -> Action n r s) -> ThreadId -> Threads n r s -> Threads n r s
- Test.DejaFu.Deterministic.Internal.Threading: data BlockedOn
- Test.DejaFu.Deterministic.Internal.Threading: data Handler n r s
- Test.DejaFu.Deterministic.Internal.Threading: data Thread n r s
- Test.DejaFu.Deterministic.Internal.Threading: except :: Action n r s -> [Handler n r s] -> ThreadId -> Threads n r s -> Threads n r s
- Test.DejaFu.Deterministic.Internal.Threading: forgets :: [Either MVarId TVarId] -> ThreadId -> Threads n r s -> Threads n r s
- Test.DejaFu.Deterministic.Internal.Threading: fullknown :: ThreadId -> Threads n r s -> Threads n r s
- Test.DejaFu.Deterministic.Internal.Threading: goto :: Action n r s -> ThreadId -> Threads n r s -> Threads n r s
- Test.DejaFu.Deterministic.Internal.Threading: instance GHC.Classes.Eq Test.DejaFu.Deterministic.Internal.Threading.BlockedOn
- Test.DejaFu.Deterministic.Internal.Threading: interruptible :: Thread n r s -> Bool
- Test.DejaFu.Deterministic.Internal.Threading: isLocked :: ThreadId -> Threads n r a -> Bool
- Test.DejaFu.Deterministic.Internal.Threading: kill :: ThreadId -> Threads n r s -> Threads n r s
- Test.DejaFu.Deterministic.Internal.Threading: knows :: [Either MVarId TVarId] -> ThreadId -> Threads n r s -> Threads n r s
- Test.DejaFu.Deterministic.Internal.Threading: launch :: ThreadId -> ThreadId -> ((forall b. M n r s b -> M n r s b) -> Action n r s) -> Threads n r s -> Threads n r s
- Test.DejaFu.Deterministic.Internal.Threading: launch' :: MaskingState -> ThreadId -> ((forall b. M n r s b -> M n r s b) -> Action n r s) -> Threads n r s -> Threads n r s
- Test.DejaFu.Deterministic.Internal.Threading: mask :: MaskingState -> ThreadId -> Threads n r s -> Threads n r s
- Test.DejaFu.Deterministic.Internal.Threading: mkthread :: Action n r s -> Thread n r s
- Test.DejaFu.Deterministic.Internal.Threading: propagate :: SomeException -> ThreadId -> Threads n r s -> Maybe (Threads n r s)
- Test.DejaFu.Deterministic.Internal.Threading: type Threads n r s = Map ThreadId (Thread n r s)
- Test.DejaFu.Deterministic.Internal.Threading: uncatching :: ThreadId -> Threads n r s -> Threads n r s
- Test.DejaFu.Deterministic.Internal.Threading: wake :: BlockedOn -> Threads n r s -> (Threads n r s, [ThreadId])
- Test.DejaFu.Internal: Ref :: (forall a. a -> n (r a)) -> (forall a. r a -> n a) -> (forall a. r a -> a -> n ()) -> (forall a. n a -> m a) -> Ref n r m
- Test.DejaFu.Internal: [liftN] :: Ref n r m -> forall a. n a -> m a
- Test.DejaFu.Internal: [newRef] :: Ref n r m -> forall a. a -> n (r a)
- Test.DejaFu.Internal: [readRef] :: Ref n r m -> forall a. r a -> n a
- Test.DejaFu.Internal: [writeRef] :: Ref n r m -> forall a. r a -> a -> n ()
- Test.DejaFu.Internal: data Ref n r m
- Test.DejaFu.Internal: refIO :: (forall a. IO a -> m a) -> Ref IO IORef m
- Test.DejaFu.Internal: refST :: (forall a. ST t a -> m a) -> Ref (ST t) (STRef t) m
- Test.DejaFu.SCT: sctBoundIO :: MemType -> Bounds -> ConcIO a -> IO [(Either Failure a, Trace ThreadId ThreadAction Lookahead)]
- Test.DejaFu.SCT: sctBoundedIO :: MemType -> BoundFunc ThreadId ThreadAction Lookahead -> BacktrackFunc ThreadId ThreadAction Lookahead DepState -> ConcIO a -> IO [(Either Failure a, Trace ThreadId ThreadAction Lookahead)]
- Test.DejaFu.SCT: sctFairBoundIO :: MemType -> FairBound -> ConcIO a -> IO [(Either Failure a, Trace ThreadId ThreadAction Lookahead)]
- Test.DejaFu.SCT: sctLengthBoundIO :: MemType -> LengthBound -> ConcIO a -> IO [(Either Failure a, Trace ThreadId ThreadAction Lookahead)]
- Test.DejaFu.SCT: sctPreBoundIO :: MemType -> PreemptionBound -> ConcIO a -> IO [(Either Failure a, Trace ThreadId ThreadAction Lookahead)]
- Test.DejaFu.STM: TLift :: TAction
- Test.DejaFu.STM: runTransactionIO :: STMIO a -> IdSource -> IO (Result a, IdSource, TTrace)
- Test.DejaFu.STM: runTransactionST :: STMST t a -> IdSource -> ST t (Result a, IdSource, TTrace)
- Test.DejaFu.STM.Internal: SLift :: (n (STMAction n r)) -> STMAction n r
- Test.DejaFu.STM.Internal: type Fixed n r = Ref n r (Cont (STMAction n r))
+ Test.DejaFu: runTestM :: MonadRef r n => Predicate a -> Conc n r a -> n (Result a)
+ Test.DejaFu: runTestM' :: MonadRef r n => MemType -> Bounds -> Predicate a -> Conc n r a -> n (Result a)
+ Test.DejaFu.Common: Abort :: Failure
+ Test.DejaFu.Common: BlockedPutVar :: MVarId -> ThreadAction
+ Test.DejaFu.Common: BlockedReadVar :: MVarId -> ThreadAction
+ Test.DejaFu.Common: BlockedSTM :: TTrace -> ThreadAction
+ Test.DejaFu.Common: BlockedTakeVar :: MVarId -> ThreadAction
+ Test.DejaFu.Common: BlockedThrowTo :: ThreadId -> ThreadAction
+ Test.DejaFu.Common: CRefId :: (Maybe String) -> Int -> CRefId
+ Test.DejaFu.Common: CasRef :: CRefId -> Bool -> ThreadAction
+ Test.DejaFu.Common: Catching :: ThreadAction
+ Test.DejaFu.Common: CommitRef :: ThreadId -> CRefId -> ThreadAction
+ Test.DejaFu.Common: Continue :: Decision tid
+ Test.DejaFu.Common: Deadlock :: Failure
+ Test.DejaFu.Common: Fork :: ThreadId -> ThreadAction
+ Test.DejaFu.Common: GetNumCapabilities :: Int -> ThreadAction
+ Test.DejaFu.Common: Id :: Int -> Int -> Int -> Int -> [String] -> [String] -> [String] -> [String] -> IdSource
+ Test.DejaFu.Common: InternalError :: Failure
+ Test.DejaFu.Common: Killed :: ThreadAction
+ Test.DejaFu.Common: LiftIO :: ThreadAction
+ Test.DejaFu.Common: MVarId :: (Maybe String) -> Int -> MVarId
+ Test.DejaFu.Common: Message :: Dynamic -> ThreadAction
+ Test.DejaFu.Common: ModRef :: CRefId -> ThreadAction
+ Test.DejaFu.Common: ModRefCas :: CRefId -> ThreadAction
+ Test.DejaFu.Common: MyThreadId :: ThreadAction
+ Test.DejaFu.Common: NewRef :: CRefId -> ThreadAction
+ Test.DejaFu.Common: NewVar :: MVarId -> ThreadAction
+ Test.DejaFu.Common: PartialStoreOrder :: MemType
+ Test.DejaFu.Common: PartiallySynchronisedCommit :: CRefId -> ActionType
+ Test.DejaFu.Common: PartiallySynchronisedModify :: CRefId -> ActionType
+ Test.DejaFu.Common: PartiallySynchronisedWrite :: CRefId -> ActionType
+ Test.DejaFu.Common: PopCatching :: ThreadAction
+ Test.DejaFu.Common: PutVar :: MVarId -> [ThreadId] -> ThreadAction
+ Test.DejaFu.Common: ReadRef :: CRefId -> ThreadAction
+ Test.DejaFu.Common: ReadRefCas :: CRefId -> ThreadAction
+ Test.DejaFu.Common: ReadVar :: MVarId -> ThreadAction
+ Test.DejaFu.Common: ResetMasking :: Bool -> MaskingState -> ThreadAction
+ Test.DejaFu.Common: Return :: ThreadAction
+ Test.DejaFu.Common: STM :: TTrace -> [ThreadId] -> ThreadAction
+ Test.DejaFu.Common: STMDeadlock :: Failure
+ Test.DejaFu.Common: SequentialConsistency :: MemType
+ Test.DejaFu.Common: SetMasking :: Bool -> MaskingState -> ThreadAction
+ Test.DejaFu.Common: SetNumCapabilities :: Int -> ThreadAction
+ Test.DejaFu.Common: Start :: tid -> Decision tid
+ Test.DejaFu.Common: Stop :: ThreadAction
+ Test.DejaFu.Common: SwitchTo :: tid -> Decision tid
+ Test.DejaFu.Common: SynchronisedModify :: CRefId -> ActionType
+ Test.DejaFu.Common: SynchronisedOther :: ActionType
+ Test.DejaFu.Common: SynchronisedRead :: MVarId -> ActionType
+ Test.DejaFu.Common: SynchronisedWrite :: MVarId -> ActionType
+ Test.DejaFu.Common: TCatch :: TTrace -> (Maybe TTrace) -> TAction
+ Test.DejaFu.Common: TNew :: TAction
+ Test.DejaFu.Common: TOrElse :: TTrace -> (Maybe TTrace) -> TAction
+ Test.DejaFu.Common: TRead :: TVarId -> TAction
+ Test.DejaFu.Common: TRetry :: TAction
+ Test.DejaFu.Common: TStop :: TAction
+ Test.DejaFu.Common: TThrow :: TAction
+ Test.DejaFu.Common: TVarId :: (Maybe String) -> Int -> TVarId
+ Test.DejaFu.Common: TWrite :: TVarId -> TAction
+ Test.DejaFu.Common: TakeVar :: MVarId -> [ThreadId] -> ThreadAction
+ Test.DejaFu.Common: ThreadId :: (Maybe String) -> Int -> ThreadId
+ Test.DejaFu.Common: Throw :: ThreadAction
+ Test.DejaFu.Common: ThrowTo :: ThreadId -> ThreadAction
+ Test.DejaFu.Common: TotalStoreOrder :: MemType
+ Test.DejaFu.Common: TryPutVar :: MVarId -> Bool -> [ThreadId] -> ThreadAction
+ Test.DejaFu.Common: TryTakeVar :: MVarId -> Bool -> [ThreadId] -> ThreadAction
+ Test.DejaFu.Common: UncaughtException :: Failure
+ Test.DejaFu.Common: UnsynchronisedOther :: ActionType
+ Test.DejaFu.Common: UnsynchronisedRead :: CRefId -> ActionType
+ Test.DejaFu.Common: UnsynchronisedWrite :: CRefId -> ActionType
+ Test.DejaFu.Common: WillCasRef :: CRefId -> Lookahead
+ Test.DejaFu.Common: WillCatching :: Lookahead
+ Test.DejaFu.Common: WillCommitRef :: ThreadId -> CRefId -> Lookahead
+ Test.DejaFu.Common: WillFork :: Lookahead
+ Test.DejaFu.Common: WillGetNumCapabilities :: Lookahead
+ Test.DejaFu.Common: WillLiftIO :: Lookahead
+ Test.DejaFu.Common: WillMessage :: Dynamic -> Lookahead
+ Test.DejaFu.Common: WillModRef :: CRefId -> Lookahead
+ Test.DejaFu.Common: WillModRefCas :: CRefId -> Lookahead
+ Test.DejaFu.Common: WillMyThreadId :: Lookahead
+ Test.DejaFu.Common: WillNewRef :: Lookahead
+ Test.DejaFu.Common: WillNewVar :: Lookahead
+ Test.DejaFu.Common: WillPopCatching :: Lookahead
+ Test.DejaFu.Common: WillPutVar :: MVarId -> Lookahead
+ Test.DejaFu.Common: WillReadRef :: CRefId -> Lookahead
+ Test.DejaFu.Common: WillReadRefCas :: CRefId -> Lookahead
+ Test.DejaFu.Common: WillReadVar :: MVarId -> Lookahead
+ Test.DejaFu.Common: WillResetMasking :: Bool -> MaskingState -> Lookahead
+ Test.DejaFu.Common: WillReturn :: Lookahead
+ Test.DejaFu.Common: WillSTM :: Lookahead
+ Test.DejaFu.Common: WillSetMasking :: Bool -> MaskingState -> Lookahead
+ Test.DejaFu.Common: WillSetNumCapabilities :: Int -> Lookahead
+ Test.DejaFu.Common: WillStop :: Lookahead
+ Test.DejaFu.Common: WillTakeVar :: MVarId -> Lookahead
+ Test.DejaFu.Common: WillThrow :: Lookahead
+ Test.DejaFu.Common: WillThrowTo :: ThreadId -> Lookahead
+ Test.DejaFu.Common: WillTryPutVar :: MVarId -> Lookahead
+ Test.DejaFu.Common: WillTryTakeVar :: MVarId -> Lookahead
+ Test.DejaFu.Common: WillWriteRef :: CRefId -> Lookahead
+ Test.DejaFu.Common: WillYield :: Lookahead
+ Test.DejaFu.Common: WriteRef :: CRefId -> ThreadAction
+ Test.DejaFu.Common: Yield :: ThreadAction
+ Test.DejaFu.Common: [_nextCRId] :: IdSource -> Int
+ Test.DejaFu.Common: [_nextMVId] :: IdSource -> Int
+ Test.DejaFu.Common: [_nextTId] :: IdSource -> Int
+ Test.DejaFu.Common: [_nextTVId] :: IdSource -> Int
+ Test.DejaFu.Common: [_usedCRNames] :: IdSource -> [String]
+ Test.DejaFu.Common: [_usedMVNames] :: IdSource -> [String]
+ Test.DejaFu.Common: [_usedTNames] :: IdSource -> [String]
+ Test.DejaFu.Common: [_usedTVNames] :: IdSource -> [String]
+ Test.DejaFu.Common: crefOf :: ActionType -> Maybe CRefId
+ Test.DejaFu.Common: data ActionType
+ Test.DejaFu.Common: data CRefId
+ Test.DejaFu.Common: data Decision tid :: * -> *
+ Test.DejaFu.Common: data Failure
+ Test.DejaFu.Common: data IdSource
+ Test.DejaFu.Common: data Lookahead
+ Test.DejaFu.Common: data MVarId
+ Test.DejaFu.Common: data MemType
+ Test.DejaFu.Common: data TAction
+ Test.DejaFu.Common: data TVarId
+ Test.DejaFu.Common: data ThreadAction
+ Test.DejaFu.Common: data ThreadId
+ Test.DejaFu.Common: initialIdSource :: IdSource
+ Test.DejaFu.Common: initialThread :: ThreadId
+ Test.DejaFu.Common: instance Control.DeepSeq.NFData Test.DejaFu.Common.ActionType
+ Test.DejaFu.Common: instance Control.DeepSeq.NFData Test.DejaFu.Common.CRefId
+ Test.DejaFu.Common: instance Control.DeepSeq.NFData Test.DejaFu.Common.Failure
+ Test.DejaFu.Common: instance Control.DeepSeq.NFData Test.DejaFu.Common.Lookahead
+ Test.DejaFu.Common: instance Control.DeepSeq.NFData Test.DejaFu.Common.MVarId
+ Test.DejaFu.Common: instance Control.DeepSeq.NFData Test.DejaFu.Common.MemType
+ Test.DejaFu.Common: instance Control.DeepSeq.NFData Test.DejaFu.Common.TAction
+ Test.DejaFu.Common: instance Control.DeepSeq.NFData Test.DejaFu.Common.TVarId
+ Test.DejaFu.Common: instance Control.DeepSeq.NFData Test.DejaFu.Common.ThreadAction
+ Test.DejaFu.Common: instance Control.DeepSeq.NFData Test.DejaFu.Common.ThreadId
+ Test.DejaFu.Common: instance GHC.Classes.Eq Test.DejaFu.Common.ActionType
+ Test.DejaFu.Common: instance GHC.Classes.Eq Test.DejaFu.Common.CRefId
+ Test.DejaFu.Common: instance GHC.Classes.Eq Test.DejaFu.Common.Failure
+ Test.DejaFu.Common: instance GHC.Classes.Eq Test.DejaFu.Common.MVarId
+ Test.DejaFu.Common: instance GHC.Classes.Eq Test.DejaFu.Common.MemType
+ Test.DejaFu.Common: instance GHC.Classes.Eq Test.DejaFu.Common.TAction
+ Test.DejaFu.Common: instance GHC.Classes.Eq Test.DejaFu.Common.TVarId
+ Test.DejaFu.Common: instance GHC.Classes.Eq Test.DejaFu.Common.ThreadId
+ Test.DejaFu.Common: instance GHC.Classes.Ord Test.DejaFu.Common.CRefId
+ Test.DejaFu.Common: instance GHC.Classes.Ord Test.DejaFu.Common.Failure
+ Test.DejaFu.Common: instance GHC.Classes.Ord Test.DejaFu.Common.MVarId
+ Test.DejaFu.Common: instance GHC.Classes.Ord Test.DejaFu.Common.MemType
+ Test.DejaFu.Common: instance GHC.Classes.Ord Test.DejaFu.Common.TVarId
+ Test.DejaFu.Common: instance GHC.Classes.Ord Test.DejaFu.Common.ThreadId
+ Test.DejaFu.Common: instance GHC.Enum.Bounded Test.DejaFu.Common.Failure
+ Test.DejaFu.Common: instance GHC.Enum.Bounded Test.DejaFu.Common.MemType
+ Test.DejaFu.Common: instance GHC.Enum.Enum Test.DejaFu.Common.Failure
+ Test.DejaFu.Common: instance GHC.Enum.Enum Test.DejaFu.Common.MemType
+ Test.DejaFu.Common: instance GHC.Read.Read Test.DejaFu.Common.Failure
+ Test.DejaFu.Common: instance GHC.Read.Read Test.DejaFu.Common.MemType
+ Test.DejaFu.Common: instance GHC.Show.Show Test.DejaFu.Common.ActionType
+ Test.DejaFu.Common: instance GHC.Show.Show Test.DejaFu.Common.CRefId
+ Test.DejaFu.Common: instance GHC.Show.Show Test.DejaFu.Common.Failure
+ Test.DejaFu.Common: instance GHC.Show.Show Test.DejaFu.Common.Lookahead
+ Test.DejaFu.Common: instance GHC.Show.Show Test.DejaFu.Common.MVarId
+ Test.DejaFu.Common: instance GHC.Show.Show Test.DejaFu.Common.MemType
+ Test.DejaFu.Common: instance GHC.Show.Show Test.DejaFu.Common.TAction
+ Test.DejaFu.Common: instance GHC.Show.Show Test.DejaFu.Common.TVarId
+ Test.DejaFu.Common: instance GHC.Show.Show Test.DejaFu.Common.ThreadAction
+ Test.DejaFu.Common: instance GHC.Show.Show Test.DejaFu.Common.ThreadId
+ Test.DejaFu.Common: isBarrier :: ActionType -> Bool
+ Test.DejaFu.Common: isBlock :: ThreadAction -> Bool
+ Test.DejaFu.Common: isCommit :: ActionType -> CRefId -> Bool
+ Test.DejaFu.Common: mvarOf :: ActionType -> Maybe MVarId
+ Test.DejaFu.Common: nextCRId :: String -> IdSource -> (IdSource, CRefId)
+ Test.DejaFu.Common: nextMVId :: String -> IdSource -> (IdSource, MVarId)
+ Test.DejaFu.Common: nextTId :: String -> IdSource -> (IdSource, ThreadId)
+ Test.DejaFu.Common: nextTVId :: String -> IdSource -> (IdSource, TVarId)
+ Test.DejaFu.Common: preEmpCount :: [(Decision ThreadId, ThreadAction)] -> (Decision ThreadId, Lookahead) -> Int
+ Test.DejaFu.Common: rewind :: ThreadAction -> Maybe Lookahead
+ Test.DejaFu.Common: showFail :: Failure -> String
+ Test.DejaFu.Common: showTrace :: Trace ThreadId ThreadAction Lookahead -> String
+ Test.DejaFu.Common: simplifyAction :: ThreadAction -> ActionType
+ Test.DejaFu.Common: simplifyLookahead :: Lookahead -> ActionType
+ Test.DejaFu.Common: synchronises :: ActionType -> CRefId -> Bool
+ Test.DejaFu.Common: tvarsOf :: ThreadAction -> Set TVarId
+ Test.DejaFu.Common: type TTrace = [TAction]
+ Test.DejaFu.Common: type Trace tid action lookahead = [(Decision tid, [(tid, NonEmpty lookahead)], action)]
+ Test.DejaFu.Common: willRelease :: Lookahead -> Bool
+ Test.DejaFu.Conc: Abort :: Failure
+ Test.DejaFu.Conc: BlockedPutVar :: MVarId -> ThreadAction
+ Test.DejaFu.Conc: BlockedReadVar :: MVarId -> ThreadAction
+ Test.DejaFu.Conc: BlockedSTM :: TTrace -> ThreadAction
+ Test.DejaFu.Conc: BlockedTakeVar :: MVarId -> ThreadAction
+ Test.DejaFu.Conc: BlockedThrowTo :: ThreadId -> ThreadAction
+ Test.DejaFu.Conc: CasRef :: CRefId -> Bool -> ThreadAction
+ Test.DejaFu.Conc: Catching :: ThreadAction
+ Test.DejaFu.Conc: CommitRef :: ThreadId -> CRefId -> ThreadAction
+ Test.DejaFu.Conc: Continue :: Decision tid
+ Test.DejaFu.Conc: Deadlock :: Failure
+ Test.DejaFu.Conc: Fork :: ThreadId -> ThreadAction
+ Test.DejaFu.Conc: GetNumCapabilities :: Int -> ThreadAction
+ Test.DejaFu.Conc: InternalError :: Failure
+ Test.DejaFu.Conc: Killed :: ThreadAction
+ Test.DejaFu.Conc: LiftIO :: ThreadAction
+ Test.DejaFu.Conc: MaskedInterruptible :: MaskingState
+ Test.DejaFu.Conc: MaskedUninterruptible :: MaskingState
+ Test.DejaFu.Conc: Message :: Dynamic -> ThreadAction
+ Test.DejaFu.Conc: ModRef :: CRefId -> ThreadAction
+ Test.DejaFu.Conc: ModRefCas :: CRefId -> ThreadAction
+ Test.DejaFu.Conc: MyThreadId :: ThreadAction
+ Test.DejaFu.Conc: NewRef :: CRefId -> ThreadAction
+ Test.DejaFu.Conc: NewVar :: MVarId -> ThreadAction
+ Test.DejaFu.Conc: PartialStoreOrder :: MemType
+ Test.DejaFu.Conc: PopCatching :: ThreadAction
+ Test.DejaFu.Conc: PutVar :: MVarId -> [ThreadId] -> ThreadAction
+ Test.DejaFu.Conc: ReadRef :: CRefId -> ThreadAction
+ Test.DejaFu.Conc: ReadRefCas :: CRefId -> ThreadAction
+ Test.DejaFu.Conc: ReadVar :: MVarId -> ThreadAction
+ Test.DejaFu.Conc: ResetMasking :: Bool -> MaskingState -> ThreadAction
+ Test.DejaFu.Conc: Return :: ThreadAction
+ Test.DejaFu.Conc: STM :: TTrace -> [ThreadId] -> ThreadAction
+ Test.DejaFu.Conc: STMDeadlock :: Failure
+ Test.DejaFu.Conc: SequentialConsistency :: MemType
+ Test.DejaFu.Conc: SetMasking :: Bool -> MaskingState -> ThreadAction
+ Test.DejaFu.Conc: SetNumCapabilities :: Int -> ThreadAction
+ Test.DejaFu.Conc: Start :: tid -> Decision tid
+ Test.DejaFu.Conc: Stop :: ThreadAction
+ Test.DejaFu.Conc: SwitchTo :: tid -> Decision tid
+ Test.DejaFu.Conc: TakeVar :: MVarId -> [ThreadId] -> ThreadAction
+ Test.DejaFu.Conc: ThreadId :: (Maybe String) -> Int -> ThreadId
+ Test.DejaFu.Conc: Throw :: ThreadAction
+ Test.DejaFu.Conc: ThrowTo :: ThreadId -> ThreadAction
+ Test.DejaFu.Conc: TotalStoreOrder :: MemType
+ Test.DejaFu.Conc: TryPutVar :: MVarId -> Bool -> [ThreadId] -> ThreadAction
+ Test.DejaFu.Conc: TryTakeVar :: MVarId -> Bool -> [ThreadId] -> ThreadAction
+ Test.DejaFu.Conc: UncaughtException :: Failure
+ Test.DejaFu.Conc: Unmasked :: MaskingState
+ Test.DejaFu.Conc: WillCasRef :: CRefId -> Lookahead
+ Test.DejaFu.Conc: WillCatching :: Lookahead
+ Test.DejaFu.Conc: WillCommitRef :: ThreadId -> CRefId -> Lookahead
+ Test.DejaFu.Conc: WillFork :: Lookahead
+ Test.DejaFu.Conc: WillGetNumCapabilities :: Lookahead
+ Test.DejaFu.Conc: WillLiftIO :: Lookahead
+ Test.DejaFu.Conc: WillMessage :: Dynamic -> Lookahead
+ Test.DejaFu.Conc: WillModRef :: CRefId -> Lookahead
+ Test.DejaFu.Conc: WillModRefCas :: CRefId -> Lookahead
+ Test.DejaFu.Conc: WillMyThreadId :: Lookahead
+ Test.DejaFu.Conc: WillNewRef :: Lookahead
+ Test.DejaFu.Conc: WillNewVar :: Lookahead
+ Test.DejaFu.Conc: WillPopCatching :: Lookahead
+ Test.DejaFu.Conc: WillPutVar :: MVarId -> Lookahead
+ Test.DejaFu.Conc: WillReadRef :: CRefId -> Lookahead
+ Test.DejaFu.Conc: WillReadRefCas :: CRefId -> Lookahead
+ Test.DejaFu.Conc: WillReadVar :: MVarId -> Lookahead
+ Test.DejaFu.Conc: WillResetMasking :: Bool -> MaskingState -> Lookahead
+ Test.DejaFu.Conc: WillReturn :: Lookahead
+ Test.DejaFu.Conc: WillSTM :: Lookahead
+ Test.DejaFu.Conc: WillSetMasking :: Bool -> MaskingState -> Lookahead
+ Test.DejaFu.Conc: WillSetNumCapabilities :: Int -> Lookahead
+ Test.DejaFu.Conc: WillStop :: Lookahead
+ Test.DejaFu.Conc: WillTakeVar :: MVarId -> Lookahead
+ Test.DejaFu.Conc: WillThrow :: Lookahead
+ Test.DejaFu.Conc: WillThrowTo :: ThreadId -> Lookahead
+ Test.DejaFu.Conc: WillTryPutVar :: MVarId -> Lookahead
+ Test.DejaFu.Conc: WillTryTakeVar :: MVarId -> Lookahead
+ Test.DejaFu.Conc: WillWriteRef :: CRefId -> Lookahead
+ Test.DejaFu.Conc: WillYield :: Lookahead
+ Test.DejaFu.Conc: WriteRef :: CRefId -> ThreadAction
+ Test.DejaFu.Conc: Yield :: ThreadAction
+ Test.DejaFu.Conc: data CRefId
+ Test.DejaFu.Conc: data Conc n r a
+ Test.DejaFu.Conc: data Decision tid :: * -> *
+ Test.DejaFu.Conc: data Failure
+ Test.DejaFu.Conc: data Lookahead
+ Test.DejaFu.Conc: data MVarId
+ Test.DejaFu.Conc: data MaskingState :: *
+ Test.DejaFu.Conc: data MemType
+ Test.DejaFu.Conc: data ThreadAction
+ Test.DejaFu.Conc: data ThreadId
+ Test.DejaFu.Conc: instance Control.Monad.Base.MonadBase GHC.Types.IO Test.DejaFu.Conc.ConcIO
+ Test.DejaFu.Conc: instance Control.Monad.Catch.MonadCatch (Test.DejaFu.Conc.Conc n r)
+ Test.DejaFu.Conc: instance Control.Monad.Catch.MonadMask (Test.DejaFu.Conc.Conc n r)
+ Test.DejaFu.Conc: instance Control.Monad.Catch.MonadThrow (Test.DejaFu.Conc.Conc n r)
+ Test.DejaFu.Conc: instance Control.Monad.IO.Class.MonadIO Test.DejaFu.Conc.ConcIO
+ Test.DejaFu.Conc: instance GHC.Base.Applicative (Test.DejaFu.Conc.Conc n r)
+ Test.DejaFu.Conc: instance GHC.Base.Functor (Test.DejaFu.Conc.Conc n r)
+ Test.DejaFu.Conc: instance GHC.Base.Monad (Test.DejaFu.Conc.Conc n r)
+ Test.DejaFu.Conc: instance GHC.Base.Monad n => Control.Monad.Conc.Class.MonadConc (Test.DejaFu.Conc.Conc n r)
+ Test.DejaFu.Conc: runConcurrent :: MonadRef r n => Scheduler ThreadId ThreadAction Lookahead s -> MemType -> s -> Conc n r a -> n (Either Failure a, s, Trace ThreadId ThreadAction Lookahead)
+ Test.DejaFu.Conc: showFail :: Failure -> String
+ Test.DejaFu.Conc: showTrace :: Trace ThreadId ThreadAction Lookahead -> String
+ Test.DejaFu.Conc: type ConcIO = Conc IO IORef
+ Test.DejaFu.Conc: type ConcST t = Conc (ST t) (STRef t)
+ Test.DejaFu.Conc: type Trace tid action lookahead = [(Decision tid, [(tid, NonEmpty lookahead)], action)]
+ Test.DejaFu.Conc.Internal: runThreads :: MonadRef r n => (forall x. s x -> IdSource -> n (Result x, IdSource, TTrace)) -> Scheduler ThreadId ThreadAction Lookahead g -> MemType -> g -> Threads n r s -> IdSource -> r (Maybe (Either Failure a)) -> n (g, Trace ThreadId ThreadAction Lookahead)
+ Test.DejaFu.Conc.Internal: stepThread :: forall n r s. MonadRef r n => (forall x. s x -> IdSource -> n (Result x, IdSource, TTrace)) -> MemType -> Action n r s -> IdSource -> ThreadId -> Threads n r s -> WriteBuffer r -> Int -> n (Either Failure (Threads n r s, IdSource, ThreadAction, WriteBuffer r, Int))
+ Test.DejaFu.Conc.Internal.Common: AAtom :: (s a) -> (a -> Action n r s) -> Action n r s
+ Test.DejaFu.Conc.Internal.Common: ACasRef :: (CRef r a) -> (Ticket a) -> a -> ((Bool, Ticket a) -> Action n r s) -> Action n r s
+ Test.DejaFu.Conc.Internal.Common: ACatching :: (e -> M n r s a) -> (M n r s a) -> (a -> Action n r s) -> Action n r s
+ Test.DejaFu.Conc.Internal.Common: ACommit :: ThreadId -> CRefId -> Action n r s
+ Test.DejaFu.Conc.Internal.Common: AFork :: String -> ((forall b. M n r s b -> M n r s b) -> Action n r s) -> (ThreadId -> Action n r s) -> Action n r s
+ Test.DejaFu.Conc.Internal.Common: AGetNumCapabilities :: (Int -> Action n r s) -> Action n r s
+ Test.DejaFu.Conc.Internal.Common: ALift :: (n (Action n r s)) -> Action n r s
+ Test.DejaFu.Conc.Internal.Common: AMasking :: MaskingState -> ((forall b. M n r s b -> M n r s b) -> M n r s a) -> (a -> Action n r s) -> Action n r s
+ Test.DejaFu.Conc.Internal.Common: AMessage :: Dynamic -> (Action n r s) -> Action n r s
+ Test.DejaFu.Conc.Internal.Common: AModRef :: (CRef r a) -> (a -> (a, b)) -> (b -> Action n r s) -> Action n r s
+ Test.DejaFu.Conc.Internal.Common: AModRefCas :: (CRef r a) -> (a -> (a, b)) -> (b -> Action n r s) -> Action n r s
+ Test.DejaFu.Conc.Internal.Common: AMyTId :: (ThreadId -> Action n r s) -> Action n r s
+ Test.DejaFu.Conc.Internal.Common: ANewRef :: String -> a -> (CRef r a -> Action n r s) -> Action n r s
+ Test.DejaFu.Conc.Internal.Common: ANewVar :: String -> (MVar r a -> Action n r s) -> Action n r s
+ Test.DejaFu.Conc.Internal.Common: APopCatching :: (Action n r s) -> Action n r s
+ Test.DejaFu.Conc.Internal.Common: APutVar :: (MVar r a) -> a -> (Action n r s) -> Action n r s
+ Test.DejaFu.Conc.Internal.Common: AReadRef :: (CRef r a) -> (a -> Action n r s) -> Action n r s
+ Test.DejaFu.Conc.Internal.Common: AReadRefCas :: (CRef r a) -> (Ticket a -> Action n r s) -> Action n r s
+ Test.DejaFu.Conc.Internal.Common: AReadVar :: (MVar r a) -> (a -> Action n r s) -> Action n r s
+ Test.DejaFu.Conc.Internal.Common: AResetMask :: Bool -> Bool -> MaskingState -> (Action n r s) -> Action n r s
+ Test.DejaFu.Conc.Internal.Common: AReturn :: (Action n r s) -> Action n r s
+ Test.DejaFu.Conc.Internal.Common: ASetNumCapabilities :: Int -> (Action n r s) -> Action n r s
+ Test.DejaFu.Conc.Internal.Common: AStop :: (n ()) -> Action n r s
+ Test.DejaFu.Conc.Internal.Common: ATakeVar :: (MVar r a) -> (a -> Action n r s) -> Action n r s
+ Test.DejaFu.Conc.Internal.Common: AThrow :: e -> Action n r s
+ Test.DejaFu.Conc.Internal.Common: AThrowTo :: ThreadId -> e -> (Action n r s) -> Action n r s
+ Test.DejaFu.Conc.Internal.Common: ATryPutVar :: (MVar r a) -> a -> (Bool -> Action n r s) -> Action n r s
+ Test.DejaFu.Conc.Internal.Common: ATryTakeVar :: (MVar r a) -> (Maybe a -> Action n r s) -> Action n r s
+ Test.DejaFu.Conc.Internal.Common: AWriteRef :: (CRef r a) -> a -> (Action n r s) -> Action n r s
+ Test.DejaFu.Conc.Internal.Common: AYield :: (Action n r s) -> Action n r s
+ Test.DejaFu.Conc.Internal.Common: CRef :: CRefId -> r (Map ThreadId a, Integer, a) -> CRef r a
+ Test.DejaFu.Conc.Internal.Common: M :: ((a -> Action n r s) -> Action n r s) -> M n r s a
+ Test.DejaFu.Conc.Internal.Common: MVar :: MVarId -> r (Maybe a) -> MVar r a
+ Test.DejaFu.Conc.Internal.Common: Ticket :: CRefId -> Integer -> a -> Ticket a
+ Test.DejaFu.Conc.Internal.Common: [_crefId] :: CRef r a -> CRefId
+ Test.DejaFu.Conc.Internal.Common: [_crefVal] :: CRef r a -> r (Map ThreadId a, Integer, a)
+ Test.DejaFu.Conc.Internal.Common: [_cvarId] :: MVar r a -> MVarId
+ Test.DejaFu.Conc.Internal.Common: [_cvarVal] :: MVar r a -> r (Maybe a)
+ Test.DejaFu.Conc.Internal.Common: [_ticketCRef] :: Ticket a -> CRefId
+ Test.DejaFu.Conc.Internal.Common: [_ticketVal] :: Ticket a -> a
+ Test.DejaFu.Conc.Internal.Common: [_ticketWrites] :: Ticket a -> Integer
+ Test.DejaFu.Conc.Internal.Common: [runM] :: M n r s a -> (a -> Action n r s) -> Action n r s
+ Test.DejaFu.Conc.Internal.Common: cont :: ((a -> Action n r s) -> Action n r s) -> M n r s a
+ Test.DejaFu.Conc.Internal.Common: data Action n r s
+ Test.DejaFu.Conc.Internal.Common: data CRef r a
+ Test.DejaFu.Conc.Internal.Common: data MVar r a
+ Test.DejaFu.Conc.Internal.Common: data Ticket a
+ Test.DejaFu.Conc.Internal.Common: instance GHC.Base.Applicative (Test.DejaFu.Conc.Internal.Common.M n r s)
+ Test.DejaFu.Conc.Internal.Common: instance GHC.Base.Functor (Test.DejaFu.Conc.Internal.Common.M n r s)
+ Test.DejaFu.Conc.Internal.Common: instance GHC.Base.Monad (Test.DejaFu.Conc.Internal.Common.M n r s)
+ Test.DejaFu.Conc.Internal.Common: lookahead :: Action n r s -> NonEmpty Lookahead
+ Test.DejaFu.Conc.Internal.Common: newtype M n r s a
+ Test.DejaFu.Conc.Internal.Common: runCont :: M n r s a -> (a -> Action n r s) -> Action n r s
+ Test.DejaFu.Conc.Internal.Memory: WriteBuffer :: Map (ThreadId, Maybe CRefId) (Seq (BufferedWrite r)) -> WriteBuffer r
+ Test.DejaFu.Conc.Internal.Memory: [BufferedWrite] :: ThreadId -> CRef r a -> a -> BufferedWrite r
+ Test.DejaFu.Conc.Internal.Memory: [buffer] :: WriteBuffer r -> Map (ThreadId, Maybe CRefId) (Seq (BufferedWrite r))
+ Test.DejaFu.Conc.Internal.Memory: addCommitThreads :: WriteBuffer r -> Threads n r s -> Threads n r s
+ Test.DejaFu.Conc.Internal.Memory: bufferWrite :: MonadRef r n => WriteBuffer r -> (ThreadId, Maybe CRefId) -> CRef r a -> a -> n (WriteBuffer r)
+ Test.DejaFu.Conc.Internal.Memory: casCRef :: MonadRef r n => CRef r a -> ThreadId -> Ticket a -> a -> n (Bool, Ticket a)
+ Test.DejaFu.Conc.Internal.Memory: commitWrite :: MonadRef r n => WriteBuffer r -> (ThreadId, Maybe CRefId) -> n (WriteBuffer r)
+ Test.DejaFu.Conc.Internal.Memory: data BufferedWrite r
+ Test.DejaFu.Conc.Internal.Memory: delCommitThreads :: Threads n r s -> Threads n r s
+ Test.DejaFu.Conc.Internal.Memory: emptyBuffer :: WriteBuffer r
+ Test.DejaFu.Conc.Internal.Memory: mutMVar :: MonadRef r n => Bool -> MVar r a -> a -> (Bool -> Action n r s) -> ThreadId -> Threads n r s -> n (Bool, Threads n r s, [ThreadId])
+ Test.DejaFu.Conc.Internal.Memory: newtype WriteBuffer r
+ Test.DejaFu.Conc.Internal.Memory: putIntoMVar :: MonadRef r n => MVar r a -> a -> Action n r s -> ThreadId -> Threads n r s -> n (Bool, Threads n r s, [ThreadId])
+ Test.DejaFu.Conc.Internal.Memory: readCRef :: MonadRef r n => CRef r a -> ThreadId -> n a
+ Test.DejaFu.Conc.Internal.Memory: readCRefPrim :: MonadRef r n => CRef r a -> ThreadId -> n (a, Integer)
+ Test.DejaFu.Conc.Internal.Memory: readForTicket :: MonadRef r n => CRef r a -> ThreadId -> n (Ticket a)
+ Test.DejaFu.Conc.Internal.Memory: readFromMVar :: MonadRef r n => MVar r a -> (a -> Action n r s) -> ThreadId -> Threads n r s -> n (Bool, Threads n r s, [ThreadId])
+ Test.DejaFu.Conc.Internal.Memory: seeMVar :: MonadRef r n => Bool -> Bool -> MVar r a -> (Maybe a -> Action n r s) -> ThreadId -> Threads n r s -> n (Bool, Threads n r s, [ThreadId])
+ Test.DejaFu.Conc.Internal.Memory: takeFromMVar :: MonadRef r n => MVar r a -> (a -> Action n r s) -> ThreadId -> Threads n r s -> n (Bool, Threads n r s, [ThreadId])
+ Test.DejaFu.Conc.Internal.Memory: tryPutIntoMVar :: MonadRef r n => MVar r a -> a -> (Bool -> Action n r s) -> ThreadId -> Threads n r s -> n (Bool, Threads n r s, [ThreadId])
+ Test.DejaFu.Conc.Internal.Memory: tryTakeFromMVar :: MonadRef r n => MVar r a -> (Maybe a -> Action n r s) -> ThreadId -> Threads n r s -> n (Bool, Threads n r s, [ThreadId])
+ Test.DejaFu.Conc.Internal.Memory: writeBarrier :: MonadRef r n => WriteBuffer r -> n ()
+ Test.DejaFu.Conc.Internal.Memory: writeImmediate :: MonadRef r n => CRef r a -> a -> n ()
+ Test.DejaFu.Conc.Internal.Threading: (~=) :: Thread n r s -> BlockedOn -> Bool
+ Test.DejaFu.Conc.Internal.Threading: Handler :: (e -> Action n r s) -> Handler n r s
+ Test.DejaFu.Conc.Internal.Threading: OnMVarEmpty :: MVarId -> BlockedOn
+ Test.DejaFu.Conc.Internal.Threading: OnMVarFull :: MVarId -> BlockedOn
+ Test.DejaFu.Conc.Internal.Threading: OnMask :: ThreadId -> BlockedOn
+ Test.DejaFu.Conc.Internal.Threading: OnTVar :: [TVarId] -> BlockedOn
+ Test.DejaFu.Conc.Internal.Threading: Thread :: Action n r s -> Maybe BlockedOn -> [Handler n r s] -> MaskingState -> Thread n r s
+ Test.DejaFu.Conc.Internal.Threading: [_blocking] :: Thread n r s -> Maybe BlockedOn
+ Test.DejaFu.Conc.Internal.Threading: [_continuation] :: Thread n r s -> Action n r s
+ Test.DejaFu.Conc.Internal.Threading: [_handlers] :: Thread n r s -> [Handler n r s]
+ Test.DejaFu.Conc.Internal.Threading: [_masking] :: Thread n r s -> MaskingState
+ Test.DejaFu.Conc.Internal.Threading: block :: BlockedOn -> ThreadId -> Threads n r s -> Threads n r s
+ Test.DejaFu.Conc.Internal.Threading: catching :: Exception e => (e -> Action n r s) -> ThreadId -> Threads n r s -> Threads n r s
+ Test.DejaFu.Conc.Internal.Threading: data BlockedOn
+ Test.DejaFu.Conc.Internal.Threading: data Handler n r s
+ Test.DejaFu.Conc.Internal.Threading: data Thread n r s
+ Test.DejaFu.Conc.Internal.Threading: except :: Action n r s -> [Handler n r s] -> ThreadId -> Threads n r s -> Threads n r s
+ Test.DejaFu.Conc.Internal.Threading: goto :: Action n r s -> ThreadId -> Threads n r s -> Threads n r s
+ Test.DejaFu.Conc.Internal.Threading: instance GHC.Classes.Eq Test.DejaFu.Conc.Internal.Threading.BlockedOn
+ Test.DejaFu.Conc.Internal.Threading: interruptible :: Thread n r s -> Bool
+ Test.DejaFu.Conc.Internal.Threading: kill :: ThreadId -> Threads n r s -> Threads n r s
+ Test.DejaFu.Conc.Internal.Threading: launch :: ThreadId -> ThreadId -> ((forall b. M n r s b -> M n r s b) -> Action n r s) -> Threads n r s -> Threads n r s
+ Test.DejaFu.Conc.Internal.Threading: launch' :: MaskingState -> ThreadId -> ((forall b. M n r s b -> M n r s b) -> Action n r s) -> Threads n r s -> Threads n r s
+ Test.DejaFu.Conc.Internal.Threading: mask :: MaskingState -> ThreadId -> Threads n r s -> Threads n r s
+ Test.DejaFu.Conc.Internal.Threading: mkthread :: Action n r s -> Thread n r s
+ Test.DejaFu.Conc.Internal.Threading: propagate :: SomeException -> ThreadId -> Threads n r s -> Maybe (Threads n r s)
+ Test.DejaFu.Conc.Internal.Threading: type Threads n r s = Map ThreadId (Thread n r s)
+ Test.DejaFu.Conc.Internal.Threading: uncatching :: ThreadId -> Threads n r s -> Threads n r s
+ Test.DejaFu.Conc.Internal.Threading: wake :: BlockedOn -> Threads n r s -> (Threads n r s, [ThreadId])
+ Test.DejaFu.STM: runTransaction :: MonadRef r n => STMLike n r a -> IdSource -> n (Result a, IdSource, TTrace)
+ Test.DejaFu.STM.Internal: isSTMSuccess :: Result a -> Bool
- Test.DejaFu: autocheck' :: (Eq a, Show a) => MemType -> (forall t. ConcST t a) -> IO Bool
+ Test.DejaFu: autocheck' :: (Eq a, Show a) => MemType -> Bounds -> (forall t. ConcST t a) -> IO Bool
- Test.DejaFu: autocheckIO' :: (Eq a, Show a) => MemType -> ConcIO a -> IO Bool
+ Test.DejaFu: autocheckIO' :: (Eq a, Show a) => MemType -> Bounds -> ConcIO a -> IO Bool
- Test.DejaFu.SCT: sctBound :: MemType -> Bounds -> (forall t. ConcST t a) -> [(Either Failure a, Trace ThreadId ThreadAction Lookahead)]
+ Test.DejaFu.SCT: sctBound :: MonadRef r n => MemType -> Bounds -> Conc n r a -> n [(Either Failure a, Trace ThreadId ThreadAction Lookahead)]
- Test.DejaFu.SCT: sctBounded :: MemType -> BoundFunc ThreadId ThreadAction Lookahead -> BacktrackFunc ThreadId ThreadAction Lookahead DepState -> (forall t. ConcST t a) -> [(Either Failure a, Trace ThreadId ThreadAction Lookahead)]
+ Test.DejaFu.SCT: sctBounded :: MonadRef r n => MemType -> BoundFunc ThreadId ThreadAction Lookahead -> BacktrackFunc ThreadId ThreadAction Lookahead DepState -> Conc n r a -> n [(Either Failure a, Trace ThreadId ThreadAction Lookahead)]
- Test.DejaFu.SCT: sctFairBound :: MemType -> FairBound -> (forall t. ConcST t a) -> [(Either Failure a, Trace ThreadId ThreadAction Lookahead)]
+ Test.DejaFu.SCT: sctFairBound :: MonadRef r n => MemType -> FairBound -> Conc n r a -> n [(Either Failure a, Trace ThreadId ThreadAction Lookahead)]
- Test.DejaFu.SCT: sctLengthBound :: MemType -> LengthBound -> (forall t. ConcST t a) -> [(Either Failure a, Trace ThreadId ThreadAction Lookahead)]
+ Test.DejaFu.SCT: sctLengthBound :: MonadRef r n => MemType -> LengthBound -> Conc n r a -> n [(Either Failure a, Trace ThreadId ThreadAction Lookahead)]
- Test.DejaFu.SCT: sctPreBound :: MemType -> PreemptionBound -> (forall t. ConcST t a) -> [(Either Failure a, Trace ThreadId ThreadAction Lookahead)]
+ Test.DejaFu.SCT: sctPreBound :: MonadRef r n => MemType -> PreemptionBound -> Conc n r a -> n [(Either Failure a, Trace ThreadId ThreadAction Lookahead)]
- Test.DejaFu.STM.Internal: SStop :: STMAction n r
+ Test.DejaFu.STM.Internal: SStop :: (n ()) -> STMAction n r
- Test.DejaFu.STM.Internal: doTransaction :: Monad n => Fixed n r -> M n r a -> IdSource -> n (Result a, n (), IdSource, TTrace)
+ Test.DejaFu.STM.Internal: doTransaction :: MonadRef r n => M n r a -> IdSource -> n (Result a, n (), IdSource, TTrace)
- Test.DejaFu.STM.Internal: stepTrans :: Monad n => Fixed n r -> STMAction n r -> IdSource -> n (STMAction n r, n (), IdSource, [TVarId], [TVarId], TAction)
+ Test.DejaFu.STM.Internal: stepTrans :: MonadRef r n => STMAction n r -> IdSource -> n (STMAction n r, n (), IdSource, [TVarId], [TVarId], TAction)

Files

− Control/Concurrent/Classy.hs
@@ -1,40 +0,0 @@--- |--- Module      : Control.Concurrent.Classy--- Copyright   : (c) 2016 Michael Walker--- License     : MIT--- Maintainer  : Michael Walker <mike@barrucadu.co.uk>--- Stability   : experimental--- Portability : non-portable------ Classy concurrency.------ Concurrency is \"lightweight\", which means that both thread--- creation and context switching overheads are extremely--- low. Scheduling of Haskell threads is done internally in the--- Haskell runtime system, and doesn't make use of any operating--- system-supplied thread packages.------ Haskell threads can communicate via @MVar@s, a kind of synchronised--- mutable variable (see "Control.Concurrent.Classy.MVar"). Several--- common concurrency abstractions can be built from @MVar@s, and--- these are provided by the "Control.Concurrent.Classy"--- library. Threads may also communicate via exceptions.-module Control.Concurrent.Classy-  ( module Control.Monad.Conc.Class-  , module Control.Concurrent.Classy.Chan-  , module Control.Concurrent.Classy.CRef-  , module Control.Concurrent.Classy.MVar-  , module Control.Concurrent.Classy.STM-  , module Control.Concurrent.Classy.QSem-  , module Control.Concurrent.Classy.QSemN-  ) where--import Control.Monad.Conc.Class-import Control.Concurrent.Classy.Chan-import Control.Concurrent.Classy.CRef-import Control.Concurrent.Classy.MVar-import Control.Concurrent.Classy.STM-import Control.Concurrent.Classy.QSem-import Control.Concurrent.Classy.QSemN--{-# ANN module ("HLint: ignore Use import/export shortcut" :: String) #-}
− Control/Concurrent/Classy/CRef.hs
@@ -1,114 +0,0 @@--- |--- Module      : Control.Concurrent.Classy.CRef--- Copyright   : (c) 2016 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--- @CRef@ type. Furthermore, the @mkWeakIORef@ function is not--- provided.-module Control.Concurrent.Classy.CRef-  ( -- * CRefs-    newCRef-  , readCRef-  , writeCRef-  , modifyCRef-  , modifyCRef'-  , atomicModifyCRef-  , atomicModifyCRef'-  , atomicWriteCRef--  -- * Memory Model--  -- | In a concurrent program, @CRef@ 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:-  ---  -- > crefs :: MonadConc m => m (Bool, Bool)-  -- > crefs = do-  -- >   r1 <- newCRef False-  -- >   r2 <- newCRef False-  -- >-  -- >   x <- spawn $ writeCRef r1 True >> readCRef r2-  -- >   y <- spawn $ writeCRef r2 True >> readCRef r1-  -- >-  -- >   (,) <$> readCVar x <*> readCVar 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:-  ---  -- > > autocheck' SequentialConsistency crefs-  -- > [pass] Never Deadlocks (checked: 6)-  -- > [pass] No Exceptions (checked: 6)-  -- > [fail] Consistent Result (checked: 5)-  -- >         (False,True) S0-------S1-----S0--S2-----S0----  -- >         (True,False) S0-------S1-P2-----S1----S0-----  -- >         (True,True) S0-------S1--P2-----S1---S0-----  -- >         (False,True) S0-------S1---P2-----S1--S0-----  -- >         (True,False) S0-------S2-----S1-----S0-----  -- >         ...-  -- > False-  ---  -- > > autocheck' TotalStoreOrder crefs-  -- > [pass] Never Deadlocks (checked: 303)-  -- > [pass] No Exceptions (checked: 303)-  -- > [fail] Consistent Result (checked: 302)-  -- >         (False,True) S0-------S1-----C-S0--S2-----C-S0----  -- >         (True,False) S0-------S1-P2-----C-S1----S0-----  -- >         (True,True) S0-------S1-P2--C-S1----C-S0--S2---S0----  -- >         (False,True) S0-------S1-P2--P1--C-C-S1--S0--S2---S0----  -- >         (False,False) S0-------S1-P2--P1----S2---C-C-S0-----  -- >         ...-  -- > False-  ---  -- Traces for non-sequentially-consistent memory models show where-  -- writes to @CRef@s are /committed/, which makes a write visible to-  -- all threads rather than just the one which performed the-  -- write. Only 'writeCRef' is broken up into separate write and-  -- commit steps, 'atomicModifyCRef' is still atomic and imposes a-  -- memory barrier.-  ) where--import Control.Monad.Conc.Class---- | Mutate the contents of a @CRef@.------ Be warned that 'modifyCRef' does not apply the function strictly.--- This means if the program calls 'modifyCRef' 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 @CRef@ as--- 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.-modifyCRef :: MonadConc m => CRef m a -> (a -> a) -> m ()-modifyCRef ref f = readCRef ref >>= writeCRef ref . f---- | Strict version of 'modifyCRef'-modifyCRef' :: MonadConc m => CRef m a -> (a -> a) -> m ()-modifyCRef' ref f = do-  x <- readCRef ref-  writeCRef ref $! f x---- | Strict version of 'atomicModifyCRef'. This forces both the value--- stored in the @CRef@ as well as the value returned.-atomicModifyCRef' :: MonadConc m => CRef m a -> (a -> (a,b)) -> m b-atomicModifyCRef' ref f = do-  b <- atomicModifyCRef ref $ \a -> case f a of-    v@(a',_) -> a' `seq` v-  pure $! b
− Control/Concurrent/Classy/Chan.hs
@@ -1,79 +0,0 @@--- |--- Module      : Control.Concurrent.Classy.Chan--- Copyright   : (c) 2016 Michael Walker--- License     : MIT--- Maintainer  : Michael Walker <mike@barrucadu.co.uk>--- Stability   : stable--- Portability : portable------ Unbounded channels.------ __Deviations:__ @Chan@ as defined here does not have an @Eq@--- instance, this is because the @MonadConc@ @MVar@ type does not have--- an @Eq@ constraint. The deprecated @unGetChan@ and @isEmptyCHan@--- functions are not provided. Furthermore, the @getChanContents@--- function is not provided as it needs unsafe I/O.-module Control.Concurrent.Classy.Chan-  ( -- * The 'Chan' type-    Chan--  -- * Operations-  , newChan-  , writeChan-  , readChan-  , dupChan--  -- * Stream interface-  , writeList2Chan-  ) where--import Control.Concurrent.Classy.MVar-import Control.Monad.Catch (mask_)-import Control.Monad.Conc.Class (MonadConc)---- | 'Chan' is an abstract type representing an unbounded FIFO--- channel.-data Chan m a-  = Chan (MVar m (Stream m a))-         (MVar m (Stream m a)) -- Invariant: the Stream a is always an empty MVar--type Stream m a = MVar m (ChItem m a)--data ChItem m a = ChItem a (Stream m a)---- | Build and returns a new instance of 'Chan'.-newChan :: MonadConc m => m (Chan m a)-newChan = do-  hole  <- newEmptyMVar-  readVar  <- newMVar hole-  writeVar <- newMVar hole-  pure (Chan readVar writeVar)---- | Write a value to a 'Chan'.-writeChan :: MonadConc m => Chan m a -> a -> m ()-writeChan (Chan _ writeVar) val = do-  new_hole <- newEmptyMVar-  mask_ $ do-    old_hole <- takeMVar writeVar-    putMVar old_hole (ChItem val new_hole)-    putMVar writeVar new_hole---- | Read the next value from the 'Chan'.-readChan :: MonadConc m => Chan m a -> m a-readChan (Chan readVar _) =  modifyMVarMasked readVar $ \read_end -> do-  (ChItem val new_read_end) <- readMVar read_end-  pure (new_read_end, val)---- | Duplicate a 'Chan': the duplicate channel begins empty, but data--- written to either channel from then on will be available from both.--- Hence this creates a kind of broadcast channel, where data written--- by anyone is seen by everyone else.-dupChan :: MonadConc m => Chan m a -> m (Chan m a)-dupChan (Chan _ writeVar) = do-  hole       <- readMVar writeVar-  newReadVar <- newMVar hole-  pure (Chan newReadVar writeVar)---- | Write an entire list of items to a 'Chan'.-writeList2Chan :: MonadConc m => Chan m a -> [a] -> m ()-writeList2Chan = mapM_ . writeChan
− Control/Concurrent/Classy/MVar.hs
@@ -1,128 +0,0 @@--- |--- Module      : Control.Concurrent.Classy.MVar--- Copyright   : (c) 2016 Michael Walker--- License     : MIT--- Maintainer  : Michael Walker <mike@barrucadu.co.uk>--- Stability   : stable--- Portability : portable------ An @'MVar' t@ is mutable location that is either empty or contains--- a value of type @t@.  It has two fundamental operations: 'putMVar'--- which fills an 'MVar' if it is empty and blocks otherwise, and--- 'takeMVar' which empties an 'MVar' if it is full and blocks--- otherwise.  They can be used in multiple different ways:------   1. As synchronized mutable variables,------   2. As channels, with 'takeMVar' and 'putMVar' as receive and---      send, and------   3. As a binary semaphore @'MVar' ()@, with 'takeMVar' and---      'putMVar' as wait and signal.------ __Deviations:__ There is no @Eq@ instance for @MonadConc@ the--- @MVar@ type. Furthermore, the @mkWeakMVar@ and @addMVarFinalizer@--- functions are not provided. Finally, normal @MVar@s have a fairness--- guarantee, which dejafu does not currently make use of when--- generating schedules to test, so your program may be tested with--- /unfair/ schedules.-module Control.Concurrent.Classy.MVar- ( -- *@MVar@s-  MVar- , newEmptyMVar- , newEmptyMVarN- , newMVar- , newMVarN- , takeMVar- , putMVar- , readMVar- , swapMVar- , tryTakeMVar- , tryPutMVar- , isEmptyMVar- , withMVar- , withMVarMasked- , modifyMVar_- , modifyMVar- , modifyMVarMasked_- , modifyMVarMasked- ) where--import Control.Monad.Catch (mask_, onException)-import Control.Monad.Conc.Class---- | Swap the contents of a @MVar@, and return the value taken. This--- function is atomic only if there are no other producers fro this--- @MVar@.-swapMVar :: MonadConc m => MVar m a -> a -> m a-swapMVar cvar a = mask_ $ do-  old <- takeMVar cvar-  putMVar cvar a-  return old---- | Check if a @MVar@ is empty.-isEmptyMVar :: MonadConc m => MVar m a -> m Bool-isEmptyMVar cvar = do-  val <- tryTakeMVar cvar-  case val of-    Just val' -> putMVar cvar val' >> return True-    Nothing   -> return False---- | Operate on the contents of a @MVar@, replacing the contents after--- finishing. This operation is exception-safe: it will replace the--- original contents of the @MVar@ if an exception is raised. However,--- it is only atomic if there are no other producers for this @MVar@.-{-# INLINE withMVar #-}-withMVar :: MonadConc m => MVar m a -> (a -> m b) -> m b-withMVar cvar f = mask $ \restore -> do-  val <- takeMVar cvar-  out <- restore (f val) `onException` putMVar cvar val-  putMVar cvar val--  return out---- | Like 'withMVar', but the @IO@ action in the second argument is--- executed with asynchronous exceptions masked.-{-# INLINE withMVarMasked #-}-withMVarMasked :: MonadConc m => MVar m a -> (a -> m b) -> m b-withMVarMasked cvar f = mask_ $ do-  val <- takeMVar cvar-  out <- f val `onException` putMVar cvar val-  putMVar cvar val--  return out---- | An exception-safe wrapper for modifying the contents of a @MVar@.--- Like 'withMVar', 'modifyMVar' will replace the original contents of--- the @MVar@ if an exception is raised during the operation. This--- function is only atomic if there are no other producers for this--- @MVar@.-{-# INLINE modifyMVar_ #-}-modifyMVar_ :: MonadConc m => MVar m a -> (a -> m a) -> m ()-modifyMVar_ cvar f = modifyMVar cvar $ fmap (\a -> (a,())) . f---- | A slight variation on 'modifyMVar_' that allows a value to be--- returned (@b@) in addition to the modified value of the @MVar@.-{-# INLINE modifyMVar #-}-modifyMVar :: MonadConc m => MVar m a -> (a -> m (a, b)) -> m b-modifyMVar cvar f = mask $ \restore -> do-  val <- takeMVar cvar-  (val', out) <- restore (f val) `onException` putMVar cvar val-  putMVar cvar val'-  return out---- | Like 'modifyMVar_', but the @IO@ action in the second argument is--- executed with asynchronous exceptions masked.-{-# INLINE modifyMVarMasked_ #-}-modifyMVarMasked_ :: MonadConc m => MVar m a -> (a -> m a) -> m ()-modifyMVarMasked_ cvar f = modifyMVarMasked cvar $ fmap (\a -> (a,())) . f---- | Like 'modifyMVar', but the @IO@ action in the second argument is--- executed with asynchronous exceptions masked.-{-# INLINE modifyMVarMasked #-}-modifyMVarMasked :: MonadConc m => MVar m a -> (a -> m (a, b)) -> m b-modifyMVarMasked cvar f = mask_ $ do-  val <- takeMVar cvar-  (val', out) <- f val `onException` putMVar cvar val-  putMVar cvar val'-  return out
− Control/Concurrent/Classy/QSem.hs
@@ -1,45 +0,0 @@--- |--- Module      : Control.Concurrent.Classy.QSem--- Copyright   : (c) 2016 Michael Walker--- License     : MIT--- Maintainer  : Michael Walker <mike@barrucadu.co.uk>--- Stability   : stable--- Portability : portable------ Simple quantity semaphores.-module Control.Concurrent.Classy.QSem-  ( -- * Simple Quantity Semaphores-    QSem-  , newQSem-  , waitQSem-  , signalQSem-  ) where--import Control.Concurrent.Classy.QSemN-import Control.Monad.Conc.Class (MonadConc)---- | @QSem@ is a quantity semaphore in which the resource is acquired--- and released in units of one. It provides guaranteed FIFO ordering--- for satisfying blocked 'waitQSem' calls.------ The pattern------ > bracket_ qaitQSem signalSSem (...)------ is safe; it never loses a unit of the resource.-newtype QSem m = QSem (QSemN m)---- | Build a new 'QSem' with a supplied initial quantity. The initial--- quantity must be at least 0.-newQSem :: MonadConc m => Int -> m (QSem m)-newQSem initial-  | initial < 0 = fail "newQSem: Initial quantity mus tbe non-negative."-  | otherwise   = QSem <$> newQSemN initial---- | Wait for a unit to become available.-waitQSem :: MonadConc m => QSem m -> m ()-waitQSem (QSem qSemN) = waitQSemN qSemN 1---- | Signal that a unit of the 'QSem' is available.-signalQSem :: MonadConc m => QSem m -> m ()-signalQSem (QSem qSemN) = signalQSemN qSemN 1
− Control/Concurrent/Classy/QSemN.hs
@@ -1,97 +0,0 @@--- |--- Module      : Control.Concurrent.Classy.QSemN--- Copyright   : (c) 2016 Michael Walker--- License     : MIT--- Maintainer  : Michael Walker <mike@barrucadu.co.uk>--- Stability   : stable--- Portability : portable------ Quantity semaphores in which each thread may wait for an arbitrary--- \"amount\".-module Control.Concurrent.Classy.QSemN-  ( -- * General Quantity Semaphores-    QSemN-  , newQSemN-  , waitQSemN-  , signalQSemN-  ) where--import Control.Monad.Conc.Class (MonadConc)-import Control.Concurrent.Classy.MVar-import Control.Monad.Catch (mask_, onException, uninterruptibleMask_)-import Data.Maybe---- | 'QSemN' is a quantity semaphore in which the resource is aqcuired--- and released in units of one. It provides guaranteed FIFO ordering--- for satisfying blocked `waitQSemN` calls.------ The pattern------ > bracket_ (waitQSemN n) (signalQSemN n) (...)------ is safe; it never loses any of the resource.-newtype QSemN m = QSemN (MVar m (Int, [(Int, MVar m ())], [(Int, MVar m ())]))---- | Build a new 'QSemN' with a supplied initial quantity.---  The initial quantity must be at least 0.-newQSemN :: MonadConc m => Int -> m (QSemN m)-newQSemN initial-  | initial < 0 = fail "newQSemN: Initial quantity must be non-negative"-  | otherwise   = QSemN <$> newMVar (initial, [], [])---- | Wait for the specified quantity to become available-waitQSemN :: MonadConc m => QSemN m -> Int -> m ()-waitQSemN (QSemN m) sz = mask_ $ do-  (quantity, b1, b2) <- takeMVar m-  let remaining = quantity - sz-  if remaining < 0-  -- Enqueue and block the thread-  then do-    b <- newEmptyMVar-    putMVar m (quantity, b1, (sz,b):b2)-    wait b-  -- Claim the resource-  else-    putMVar m (remaining, b1, b2)--  where-    wait b = takeMVar b `onException` uninterruptibleMask_ (do-      (quantity, b1, b2) <- takeMVar m-      r  <- tryTakeMVar b-      r' <- if isJust r-           then signal sz (quantity, b1, b2)-           else putMVar b () >> pure (quantity, b1, b2)-      putMVar m r')---- | Signal that a given quantity is now available from the 'QSemN'.-signalQSemN :: MonadConc m => QSemN m -> Int -> m ()-signalQSemN (QSemN m) sz = uninterruptibleMask_ $ do-  r  <- takeMVar m-  r' <- signal sz r-  putMVar m r'---- | Fix the queue and signal as many threads as we can.-signal :: MonadConc m-  => Int-  -> (Int, [(Int,MVar m ())], [(Int,MVar m ())])-  -> m (Int, [(Int,MVar m ())], [(Int,MVar m ())])-signal sz0 (i,a1,a2) = loop (sz0 + i) a1 a2 where-  -- No more resource left, done.-  loop 0 bs b2 = pure (0,  bs, b2)--  -- Fix the queue-  loop sz [] [] = pure (sz, [], [])-  loop sz [] b2 = loop sz (reverse b2) []--  -- Signal as many threads as there is enough resource to satisfy,-  -- stopping as soon as one thread requires more resource than there-  -- is.-  loop sz ((j,b):bs) b2-    | j > sz = do-      r <- isEmptyMVar b-      if r then pure (sz, (j,b):bs, b2)-           else loop sz bs b2-    | otherwise = do-      r <- tryPutMVar b ()-      if r then loop (sz-j) bs b2-           else loop sz bs b2
− Control/Concurrent/Classy/STM.hs
@@ -1,28 +0,0 @@--- |--- Module      : Control.Concurrent.Classy.STM--- Copyright   : (c) 2016 Michael Walker--- License     : MIT--- Maintainer  : Michael Walker <mike@barrucadu.co.uk>--- Stability   : experimental--- Portability : non-portable------ Classy software transactional memory.-module Control.Concurrent.Classy.STM-  ( module Control.Monad.STM.Class-  , module Control.Concurrent.Classy.STM.TVar-  , module Control.Concurrent.Classy.STM.TMVar-  , module Control.Concurrent.Classy.STM.TChan-  , module Control.Concurrent.Classy.STM.TQueue-  , module Control.Concurrent.Classy.STM.TBQueue-  , module Control.Concurrent.Classy.STM.TArray-  ) where--import Control.Monad.STM.Class-import Control.Concurrent.Classy.STM.TVar-import Control.Concurrent.Classy.STM.TMVar-import Control.Concurrent.Classy.STM.TChan-import Control.Concurrent.Classy.STM.TQueue-import Control.Concurrent.Classy.STM.TBQueue-import Control.Concurrent.Classy.STM.TArray--{-# ANN module ("HLint: ignore Use import/export shortcut" :: String) #-}
− Control/Concurrent/Classy/STM/TArray.hs
@@ -1,56 +0,0 @@-{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}---- |--- Module      : Control.Concurrent.Classy.STM.--- Copyright   : (c) 2016 Michael Walker--- License     : MIT--- Maintainer  : Michael Walker <mike@barrucadu.co.uk>--- Stability   : stable--- Portability : FlexibleInstances, MultiParamTypeClasses------ TArrays: transactional arrays, for use in STM-like monads.------ __Deviations:__ @TArray@ as defined here does not have an @Eq@--- instance, this is because the @MonadSTM@ @TVar@ type does not have--- an @Eq@ constraint.-module Control.Concurrent.Classy.STM.TArray (TArray) where--import Data.Array (Array, bounds)-import Data.Array.Base (listArray, arrEleBottom, unsafeAt, MArray(..),-                        IArray(numElements))-import Data.Ix (rangeSize)--import Control.Monad.STM.Class---- | @TArray@ is a transactional array, supporting the usual 'MArray'--- interface for mutable arrays.------ It is currently implemented as @Array ix (TVar stm e)@, but it may--- be replaced by a more efficient implementation in the future (the--- interface will remain the same, however).-newtype TArray stm i e = TArray (Array i (TVar stm e))--instance MonadSTM stm => MArray (TArray stm) e stm where-  getBounds (TArray a) = pure (bounds a)--  newArray b e = do-    a <- rep (rangeSize b) (newTVar e)-    pure $ TArray (listArray b a)--  newArray_ b = newArray b arrEleBottom--  unsafeRead  (TArray a) = readTVar  . unsafeAt a-  unsafeWrite (TArray a) = writeTVar . unsafeAt a--  getNumElements (TArray a) = pure (numElements a)---- | Like 'replicateM' but uses an accumulator to prevent stack overflows.--- Unlike 'replicateM' the returned list is in reversed order.  This--- doesn't matter though since this function is only used to create--- arrays with identical elements.-rep :: Monad m => Int -> m a -> m [a]-rep n m = go n [] where-  go 0 xs = pure xs-  go i xs = do-    x <- m-    go (i-1) (x:xs)
− Control/Concurrent/Classy/STM/TBQueue.hs
@@ -1,146 +0,0 @@--- |--- Module      : Control.Concurrent.Classy.STM.TBQueue--- Copyright   : (c) 2016 Michael Walker--- License     : MIT--- Maintainer  : Michael Walker <mike@barrucadu.co.uk>--- Stability   : stable--- Portability : portable------ 'TBQueue' is a bounded version of 'TQueue'. The queue has a maximum--- capacity set when it is created.  If the queue already contains the--- maximum number of elements, then 'writeTBQueue' blocks until an--- element is removed from the queue.------ The implementation is based on the traditional purely-functional--- queue representation that uses two lists to obtain amortised /O(1)/--- enqueue and dequeue operations.------ __Deviations:__ @TBQueue@ as defined here does not have an @Eq@--- instance, this is because the @MonadSTM@ @TVar@ type does not have--- an @Eq@ constraint. Furthermore, the @newTBQueueIO@ function is not--- provided.-module Control.Concurrent.Classy.STM.TBQueue-  ( -- * TBQueue-    TBQueue-  , newTBQueue-  , readTBQueue-  , tryReadTBQueue-  , peekTBQueue-  , tryPeekTBQueue-  , writeTBQueue-  , unGetTBQueue-  , isEmptyTBQueue-  , isFullTBQueue-  ) where--import Control.Monad.STM.Class---- | 'TBQueue' is an abstract type representing a bounded FIFO--- channel.-data TBQueue stm a-   = TBQueue (TVar stm Int)-             (TVar stm [a])-             (TVar stm Int)-             (TVar stm [a])---- | Build and returns a new instance of 'TBQueue'-newTBQueue :: MonadSTM stm-  => Int   -- ^ maximum number of elements the queue can hold-  -> stm (TBQueue stm a)-newTBQueue size = do-  readT  <- newTVar []-  writeT <- newTVar []-  rsize <- newTVar 0-  wsize <- newTVar size-  pure (TBQueue rsize readT wsize writeT)---- | Write a value to a 'TBQueue'; retries if the queue is full.-writeTBQueue :: MonadSTM stm => TBQueue stm a -> a -> stm ()-writeTBQueue (TBQueue rsize _ wsize writeT) a = do-  w <- readTVar wsize-  if w /= 0-  then writeTVar wsize (w - 1)-  else do-    r <- readTVar rsize-    if r /= 0-    then do-      writeTVar rsize 0-      writeTVar wsize (r - 1)-    else retry-  listend <- readTVar writeT-  writeTVar writeT (a:listend)---- | Read the next value from the 'TBQueue'.-readTBQueue :: MonadSTM stm => TBQueue stm a -> stm a-readTBQueue (TBQueue rsize readT _ writeT) = do-  xs <- readTVar readT-  r  <- readTVar rsize-  writeTVar rsize (r + 1)-  case xs of-    (x:xs') -> do-      writeTVar readT xs'-      pure x-    [] -> do-      ys <- readTVar writeT-      case ys of-        [] -> retry-        _  -> do-          let (z:zs) = reverse ys-          writeTVar writeT []-          writeTVar readT zs-          pure z---- | A version of 'readTBQueue' which does not retry. Instead it--- returns @Nothing@ if no value is available.-tryReadTBQueue :: MonadSTM stm => TBQueue stm a -> stm (Maybe a)-tryReadTBQueue c = (Just <$> readTBQueue c) `orElse` pure Nothing---- | Get the next value from the @TBQueue@ without removing it,--- retrying if the channel is empty.-peekTBQueue :: MonadSTM stm => TBQueue stm a -> stm a-peekTBQueue c = do-  x <- readTBQueue c-  unGetTBQueue c x-  return x---- | A version of 'peekTBQueue' which does not retry. Instead it--- returns @Nothing@ if no value is available.-tryPeekTBQueue :: MonadSTM stm => TBQueue stm a -> stm (Maybe a)-tryPeekTBQueue c = do-  m <- tryReadTBQueue c-  case m of-    Nothing -> pure Nothing-    Just x  -> do-      unGetTBQueue c x-      pure m---- | Put a data item back onto a channel, where it will be the next item read.--- Retries if the queue is full.-unGetTBQueue :: MonadSTM stm => TBQueue stm a -> a -> stm ()-unGetTBQueue (TBQueue rsize readT wsize _) a = do-  r <- readTVar rsize-  if r > 0-  then writeTVar rsize (r - 1)-  else do-    w <- readTVar wsize-    if w > 0-    then writeTVar wsize (w - 1)-    else retry-  xs <- readTVar readT-  writeTVar readT (a:xs)---- | Returns 'True' if the supplied 'TBQueue' is empty.-isEmptyTBQueue :: MonadSTM stm => TBQueue stm a -> stm Bool-isEmptyTBQueue (TBQueue _ readT _ writeT) = do-  xs <- readTVar readT-  case xs of-    (_:_) -> pure False-    [] -> null <$> readTVar writeT---- | Returns 'True' if the supplied 'TBQueue' is full.-isFullTBQueue :: MonadSTM stm => TBQueue stm a -> stm Bool-isFullTBQueue (TBQueue rsize _ wsize _) = do-  w <- readTVar wsize-  if w > 0-  then pure False-  else (>0) <$> readTVar rsize
− Control/Concurrent/Classy/STM/TChan.hs
@@ -1,135 +0,0 @@--- |--- Module      : Control.Concurrent.Classy.STM.TChan--- Copyright   : (c) 2016 Michael Walker--- License     : MIT--- Maintainer  : Michael Walker <mike@barrucadu.co.uk>--- Stability   : stable--- Portability : portable------ Transactional channels------ __Deviations:__ @TChan@ as defined here does not have an @Eq@--- instance, this is because the @MonadSTM@ @TVar@ type does not have--- an @Eq@ constraint. Furthermore, the @newTChanIO@ and--- @newBroadcastTChanIO@ functions are not provided.-module Control.Concurrent.Classy.STM.TChan-  ( -- * TChans-    TChan--  -- * Construction-  , newTChan-  , newBroadcastTChan-  , dupTChan-  , cloneTChan--  -- * Reading and writing-  , readTChan-  , tryReadTChan-  , peekTChan-  , tryPeekTChan-  , writeTChan-  , unGetTChan-  , isEmptyTChan-  ) where--import Control.Monad.STM.Class---- | 'TChan' is an abstract type representing an unbounded FIFO--- channel.-data TChan stm a = TChan (TVar stm (TVarList stm a))-                         (TVar stm (TVarList stm a))--type TVarList stm a = TVar stm (TList stm a)-data TList stm a = TNil | TCons a (TVarList stm a)---- |Build and return a new instance of 'TChan'-newTChan :: MonadSTM stm => stm (TChan stm a)-newTChan = do-  hole   <- newTVar TNil-  readH  <- newTVar hole-  writeH <- newTVar hole-  pure (TChan readH writeH)---- | Create a write-only 'TChan'.  More precisely, 'readTChan' will 'retry'--- even after items have been written to the channel.  The only way to--- read a broadcast channel is to duplicate it with 'dupTChan'.-newBroadcastTChan :: MonadSTM stm => stm (TChan stm a)-newBroadcastTChan = do-    hole   <- newTVar TNil-    readT  <- newTVar (error "reading from a TChan created by newBroadcastTChan; use dupTChan first")-    writeT <- newTVar hole-    pure (TChan readT writeT)---- | Write a value to a 'TChan'.-writeTChan :: MonadSTM stm => TChan stm a -> a -> stm ()-writeTChan (TChan _ writeT) a = do-  listend  <- readTVar writeT-  listend' <- newTVar TNil-  writeTVar listend (TCons a listend')-  writeTVar writeT listend'---- | Read the next value from the 'TChan'.-readTChan :: MonadSTM stm => TChan stm a -> stm a-readTChan tchan = tryReadTChan tchan >>= maybe retry pure---- | A version of 'readTChan' which does not retry. Instead it--- returns @Nothing@ if no value is available.-tryReadTChan :: MonadSTM stm => TChan stm a -> stm (Maybe a)-tryReadTChan (TChan readT _) = do-  listhead <- readTVar readT-  hd <- readTVar listhead-  case hd of-    TNil       -> pure Nothing-    TCons a tl -> do-      writeTVar readT tl-      pure (Just a)---- | Get the next value from the 'TChan' without removing it,--- retrying if the channel is empty.-peekTChan :: MonadSTM stm => TChan stm a -> stm a-peekTChan tchan = tryPeekTChan tchan >>= maybe retry pure---- | A version of 'peekTChan' which does not retry. Instead it--- returns @Nothing@ if no value is available.-tryPeekTChan :: MonadSTM stm => TChan stm a -> stm (Maybe a)-tryPeekTChan (TChan readT _) = do-  listhead <- readTVar readT-  hd <- readTVar listhead-  pure $ case hd of-    TNil      -> Nothing-    TCons a _ -> Just a---- | Duplicate a 'TChan': the duplicate channel begins empty, but data written to--- either channel from then on will be available from both.  Hence--- this creates a kind of broadcast channel, where data written by--- anyone is seen by everyone else.-dupTChan :: MonadSTM stm => TChan stm a -> stm (TChan stm a)-dupTChan (TChan _ writeT) = do-  hole   <- readTVar writeT-  readT' <- newTVar hole-  return (TChan readT' writeT)---- | Put a data item back onto a channel, where it will be the next--- item read.-unGetTChan :: MonadSTM stm => TChan stm a -> a -> stm ()-unGetTChan (TChan readT _) a = do-   listhead <- readTVar readT-   head' <- newTVar (TCons a listhead)-   writeTVar readT head'---- | Returns 'True' if the supplied 'TChan' is empty.-isEmptyTChan :: MonadSTM stm => TChan stm a -> stm Bool-isEmptyTChan (TChan readT _) = do-  listhead <- readTVar readT-  hd <- readTVar listhead-  pure $ case hd of-    TNil -> True-    TCons _ _ -> False---- | Clone a 'TChan': similar to 'dupTChan', but the cloned channel starts with the--- same content available as the original channel.-cloneTChan :: MonadSTM stm => TChan stm a -> stm (TChan stm a)-cloneTChan (TChan readT writeT) = do-  readpos <- readTVar readT-  readT' <- newTVar readpos-  pure (TChan readT' writeT)
− Control/Concurrent/Classy/STM/TMVar.hs
@@ -1,118 +0,0 @@--- |--- Module      : Control.Concurrent.Classy.STM.TMVar--- Copyright   : (c) 2016 Michael Walker--- License     : MIT--- Maintainer  : Michael Walker <mike@barrucadu.co.uk>--- Stability   : stable--- Portability : portable------ Transactional @MVar@s, for use with 'MonadSTM'.------ __Deviations:__ @TMVar@ as defined here does not have an @Eq@--- instance, this is because the @MonadSTM@ @TVar@ type does not have--- an @Eq@ constraint. Furthermore, the @newTMVarIO@,--- @newEmptyTMVarIO@, and @mkWeakTMVar@ functions are not provided.-module Control.Concurrent.Classy.STM.TMVar-  ( -- * @TMVar@s-    TMVar-  , newTMVar-  , newTMVarN-  , newEmptyTMVar-  , newEmptyTMVarN-  , takeTMVar-  , putTMVar-  , readTMVar-  , tryTakeTMVar-  , tryPutTMVar-  , tryReadTMVar-  , isEmptyTMVar-  , swapTMVar-  ) where--import Control.Monad (liftM, when, unless)-import Control.Monad.STM.Class-import Data.Maybe (isJust, isNothing)---- | A @TMVar@ is like an @MVar@ or a @mVar@, but using transactional--- memory. As transactions are atomic, this makes dealing with--- multiple @TMVar@s easier than wrangling multiple @mVar@s.-newtype TMVar stm a = TMVar (TVar stm (Maybe a))---- | Create a 'TMVar' containing the given value.-newTMVar :: MonadSTM stm => a -> stm (TMVar stm a)-newTMVar = newTMVarN ""---- | Create a 'TMVar' containing the given value, with the given--- name.------ Name conflicts are handled as usual for 'TVar's. The name is--- prefixed with \"ctmvar-\".-newTMVarN :: MonadSTM stm => String -> a -> stm (TMVar stm a)-newTMVarN n a = do-  let n' = if null n then "ctmvar" else "ctmvar-" ++ n-  ctvar <- newTVarN n' $ Just a-  return $ TMVar ctvar---- | Create a new empty 'TMVar'.-newEmptyTMVar :: MonadSTM stm => stm (TMVar stm a)-newEmptyTMVar = newEmptyTMVarN ""---- | Create a new empty 'TMVar' with the given name.------ Name conflicts are handled as usual for 'TVar's. The name is--- prefixed with \"ctmvar-\".-newEmptyTMVarN :: MonadSTM stm => String -> stm (TMVar stm a)-newEmptyTMVarN n = do-  let n' = if null n then "ctmvar" else "ctmvar-" ++ n-  ctvar <- newTVarN n' Nothing-  return $ TMVar ctvar---- | Take the contents of a 'TMVar', or 'retry' if it is empty.-takeTMVar :: MonadSTM stm => TMVar stm a -> stm a-takeTMVar ctmvar = do-  taken <- tryTakeTMVar ctmvar-  maybe retry return taken---- | Write to a 'TMVar', or 'retry' if it is full.-putTMVar :: MonadSTM stm => TMVar stm a -> a -> stm ()-putTMVar ctmvar a = do-  putted <- tryPutTMVar ctmvar a-  unless putted retry---- | Read from a 'TMVar' without emptying, or 'retry' if it is empty.-readTMVar :: MonadSTM stm => TMVar stm a -> stm a-readTMVar ctmvar = do-  readed <- tryReadTMVar ctmvar-  maybe retry return readed---- | Try to take the contents of a 'TMVar', returning 'Nothing' if it--- is empty.-tryTakeTMVar :: MonadSTM stm => TMVar stm a -> stm (Maybe a)-tryTakeTMVar (TMVar ctvar) = do-  val <- readTVar ctvar-  when (isJust val) $ writeTVar ctvar Nothing-  return val---- | Try to write to a 'TMVar', returning 'False' if it is full.-tryPutTMVar :: MonadSTM stm => TMVar stm a -> a -> stm Bool-tryPutTMVar (TMVar ctvar) a = do-  val <- readTVar ctvar-  when (isNothing val) $ writeTVar ctvar (Just a)-  return $ isNothing val---- | Try to read from a 'TMVar' without emptying, returning 'Nothing'--- if it is empty.-tryReadTMVar :: MonadSTM stm => TMVar stm a -> stm (Maybe a)-tryReadTMVar (TMVar ctvar) = readTVar ctvar---- | Check if a 'TMVar' is empty or not.-isEmptyTMVar :: MonadSTM stm => TMVar stm a -> stm Bool-isEmptyTMVar ctmvar = isNothing `liftM` tryReadTMVar ctmvar---- | Swap the contents of a 'TMVar' returning the old contents, or--- 'retry' if it is empty.-swapTMVar :: MonadSTM stm => TMVar stm a -> a -> stm a-swapTMVar ctmvar a = do-  val <- takeTMVar ctmvar-  putTMVar ctmvar a-  return val
− Control/Concurrent/Classy/STM/TQueue.hs
@@ -1,113 +0,0 @@--- |--- Module      : Control.Concurrent.Classy.STM.TQueue--- Copyright   : (c) 2016 Michael Walker--- License     : MIT--- Maintainer  : Michael Walker <mike@barrucadu.co.uk>--- Stability   : stable--- Portability : portable------ A 'TQueue' is like a 'TChan', with two important differences:------  * it has faster throughput than both 'TChan' and 'Chan' (although---    the costs are amortised, so the cost of individual operations---    can vary a lot).------  * it does /not/ provide equivalents of the 'dupTChan' and---    'cloneTChan' operations.------ The implementation is based on the traditional purely-functional--- queue representation that uses two lists to obtain amortised /O(1)/--- enqueue and dequeue operations.------ __Deviations:__ @TQueue@ as defined here does not have an @Eq@--- instance, this is because the @MonadSTM@ @TVar@ type does not have--- an @Eq@ constraint. Furthermore, the @newTQueueIO@ function is not--- provided.-module Control.Concurrent.Classy.STM.TQueue-  ( -- * TQueue-    TQueue-  , newTQueue-  , readTQueue-  , tryReadTQueue-  , peekTQueue-  , tryPeekTQueue-  , writeTQueue-  , unGetTQueue-  , isEmptyTQueue-  ) where--import Control.Monad.STM.Class---- | 'TQueue' is an abstract type representing an unbounded FIFO channel.-data TQueue stm a = TQueue (TVar stm [a])-                           (TVar stm [a])---- | Build and returns a new instance of 'TQueue'-newTQueue :: MonadSTM stm => stm (TQueue stm a)-newTQueue = do-  readT  <- newTVar []-  writeT <- newTVar []-  pure (TQueue readT writeT)---- | Write a value to a 'TQueue'.-writeTQueue :: MonadSTM stm => TQueue stm a -> a -> stm ()-writeTQueue (TQueue _ writeT) a = do-  listend <- readTVar writeT-  writeTVar writeT (a:listend)---- | Read the next value from the 'TQueue'.-readTQueue :: MonadSTM stm => TQueue stm a -> stm a-readTQueue (TQueue readT writeT) = do-  xs <- readTVar readT-  case xs of-    (x:xs') -> do-      writeTVar readT xs'-      pure x-    [] -> do-      ys <- readTVar writeT-      case ys of-        [] -> retry-        _  -> case reverse ys of-               [] -> error "readTQueue"-               (z:zs) -> do-                 writeTVar writeT []-                 writeTVar readT zs-                 pure z---- | A version of 'readTQueue' which does not retry. Instead it--- returns @Nothing@ if no value is available.-tryReadTQueue :: MonadSTM stm => TQueue stm a -> stm (Maybe a)-tryReadTQueue c = (Just <$> readTQueue c) `orElse` pure Nothing---- | Get the next value from the @TQueue@ without removing it,--- retrying if the channel is empty.-peekTQueue :: MonadSTM stm => TQueue stm a -> stm a-peekTQueue c = do-  x <- readTQueue c-  unGetTQueue c x-  pure x---- | A version of 'peekTQueue' which does not retry. Instead it--- returns @Nothing@ if no value is available.-tryPeekTQueue :: MonadSTM stm => TQueue stm a -> stm (Maybe a)-tryPeekTQueue c = do-  m <- tryReadTQueue c-  case m of-    Nothing -> pure Nothing-    Just x  -> do-      unGetTQueue c x-      pure m---- |Put a data item back onto a channel, where it will be the next item read.-unGetTQueue :: MonadSTM stm => TQueue stm a -> a -> stm ()-unGetTQueue (TQueue readT _) a = do-  xs <- readTVar readT-  writeTVar readT (a:xs)---- |Returns 'True' if the supplied 'TQueue' is empty.-isEmptyTQueue :: MonadSTM stm => TQueue stm a -> stm Bool-isEmptyTQueue (TQueue readT writeT) = do-  xs <- readTVar readT-  case xs of-    (_:_) -> pure False-    [] -> null <$> readTVar writeT
− Control/Concurrent/Classy/STM/TVar.hs
@@ -1,62 +0,0 @@--- |--- Module      : Control.Concurrent.Classy.STM.TVar--- Copyright   : (c) 2016 Michael Walker--- License     : MIT--- Maintainer  : Michael Walker <mike@barrucadu.co.uk>--- Stability   : stable--- Portability : portable------ Transactional variables, for use with 'MonadSTM'.------ __Deviations:__ There is no @Eq@ instance for @MonadSTM@ the @TVar@--- type. Furthermore, the @newTVarIO@ and @mkWeakTVar@ functions are--- not provided.-module Control.Concurrent.Classy.STM.TVar-  ( -- * @TVar@s-    TVar-  , newTVar-  , newTVarN-  , readTVar-  , readTVarConc-  , writeTVar-  , modifyTVar-  , modifyTVar'-  , swapTVar-  , registerDelay-  ) where--import Control.Monad.STM.Class-import Control.Monad.Conc.Class-import Data.Functor (void)---- * @TVar@s---- | Mutate the contents of a 'TVar'. This is non-strict.-modifyTVar :: MonadSTM stm => TVar stm a -> (a -> a) -> stm ()-modifyTVar ctvar f = do-  a <- readTVar ctvar-  writeTVar ctvar $ f a---- | Mutate the contents of a 'TVar' strictly.-modifyTVar' :: MonadSTM stm => TVar stm a -> (a -> a) -> stm ()-modifyTVar' ctvar f = do-  a <- readTVar ctvar-  writeTVar ctvar $! f a---- | Swap the contents of a 'TVar', returning the old value.-swapTVar :: MonadSTM stm => TVar stm a -> a -> stm a-swapTVar ctvar a = do-  old <- readTVar ctvar-  writeTVar ctvar a-  return old---- | Set the value of returned 'TVar' to @True@ after a given number--- of microseconds. The caveats associated with 'threadDelay' also--- apply.-registerDelay :: MonadConc m => Int -> m (TVar (STM m) Bool)-registerDelay delay = do-  var <- atomically (newTVar False)-  void . fork $ do-    threadDelay delay-    atomically (writeTVar var True)-  pure var
− Control/Monad/Conc/Class.hs
@@ -1,736 +0,0 @@-{-# LANGUAGE CPP              #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE RankNTypes       #-}-{-# LANGUAGE TemplateHaskell  #-}-{-# LANGUAGE TypeFamilies     #-}---- |--- Module      : Control.Monad.Conc.Class--- Copyright   : (c) 2016 Michael Walker--- License     : MIT--- Maintainer  : Michael Walker <mike@barrucadu.co.uk>--- Stability   : experimental--- Portability : CPP, FlexibleContexts, RankNTypes, TemplateHaskell, TypeFamilies------ This module captures in a typeclass the interface of concurrency--- monads.------ __Deviations:__ An instance of @MonadCoonc@ is not required to be--- an instance of @MonadFix@, unlike @IO@. The @CRef@, @MVar@, and--- @Ticket@ types are not required to be instances of @Show@ or @Eq@,--- unlike their normal counterparts. The @threadCapability@,--- @threadWaitRead@, @threadWaitWrite@, @threadWaitReadSTM@,--- @threadWaitWriteSTM@, and @mkWeakThreadId@ functions are not--- provided. The @threadDelay@ function is not required to delay the--- thread, merely to yield it. Bound threads are not supported. The--- @BlockedIndefinitelyOnMVar@ (and similar) exceptions are /not/--- thrown during testing, so do not rely on them at all.-module Control.Monad.Conc.Class-  ( MonadConc(..)--  -- * Threads-  , spawn-  , forkFinally-  , killThread--  -- ** Named Threads-  , forkN-  , forkOnN-  , lineNum--  -- ** Bound Threads--  -- | @MonadConc@ does not support bound threads, if you need that-  -- sort of thing you will have to use regular @IO@.--  , rtsSupportsBoundThreads-  , isCurrentThreadBound--  -- * Exceptions-  , throw-  , catch-  , mask-  , uninterruptibleMask--  -- * Mutable State-  , newMVar-  , newMVarN-  , cas--  -- * Utilities for instance writers-  , makeTransConc-  , liftedF-  , liftedFork-  ) where---- for the class and utilities-import Control.Exception (Exception, AsyncException(ThreadKilled), SomeException)-import Control.Monad.Catch (MonadCatch, MonadThrow, MonadMask)-import qualified Control.Monad.Catch as Ca-import Control.Monad.STM.Class (MonadSTM, TVar, readTVar)-import Control.Monad.Trans.Control (MonadTransControl, StT, liftWith)-import Data.Typeable (Typeable)-import Language.Haskell.TH (Q, DecsQ, Exp, Loc(..), Info(VarI), Name, Type(..), reify, location, varE)---- for the 'IO' instance-import qualified Control.Concurrent as IO-import qualified Control.Concurrent.STM.TVar as IO-import qualified Control.Monad.STM as IO-import qualified Data.Atomics as IO-import qualified Data.IORef as IO---- for the transformer instances-import Control.Monad.Reader (ReaderT)-import Control.Monad.Trans (lift)-import Control.Monad.Trans.Identity (IdentityT)-import qualified Control.Monad.RWS.Lazy as RL-import qualified Control.Monad.RWS.Strict as RS-import qualified Control.Monad.State.Lazy as SL-import qualified Control.Monad.State.Strict as SS-import qualified Control.Monad.Writer.Lazy as WL-import qualified Control.Monad.Writer.Strict as WS--{-# ANN module ("HLint: ignore Use const" :: String) #-}---- | @MonadConc@ is an abstraction over GHC's typical concurrency--- abstraction. It captures the interface of concurrency monads in--- terms of how they can operate on shared state and in the presence--- of exceptions.------ Every @MonadConc@ has an associated 'MonadSTM', transactions of--- which can be run atomically.-class ( Applicative m, Monad m-      , MonadCatch m, MonadThrow m, MonadMask m-      , MonadSTM (STM m)-      , Ord (ThreadId m), Show (ThreadId m)) => MonadConc m  where--  {-# MINIMAL-        (forkWithUnmask | forkWithUnmaskN)-      , (forkOnWithUnmask | forkOnWithUnmaskN)-      , getNumCapabilities-      , setNumCapabilities-      , myThreadId-      , yield-      , (newEmptyMVar | newEmptyMVarN)-      , putMVar-      , tryPutMVar-      , readMVar-      , takeMVar-      , tryTakeMVar-      , (newCRef | newCRefN)-      , atomicModifyCRef-      , writeCRef-      , readForCAS-      , peekTicket-      , casCRef-      , modifyCRefCAS-      , atomically-      , throwTo-    #-}--  -- | The associated 'MonadSTM' for this class.-  type STM m :: * -> *--  -- | The mutable reference type, like 'MVar's. This may contain one-  -- value at a time, attempting to read or take from an \"empty\"-  -- @MVar@ will block until it is full, and attempting to put to a-  -- \"full\" @MVar@ will block until it is empty.-  type MVar m :: * -> *--  -- | The mutable non-blocking reference type. These may suffer from-  -- relaxed memory effects if functions outside the set @newCRef@,-  -- @readCRef@, @atomicModifyCRef@, and @atomicWriteCRef@ are used.-  type CRef m :: * -> *--  -- | When performing compare-and-swap operations on @CRef@s, a-  -- @Ticket@ is a proof that a thread observed a specific previous-  -- value.-  type Ticket m :: * -> *--  -- | An abstract handle to a thread.-  type ThreadId m :: *--  -- | Fork a computation to happen concurrently. Communication may-  -- happen over @MVar@s.-  ---  -- > fork ma = forkWithUnmask (\_ -> ma)-  fork :: m () -> m (ThreadId m)-  fork ma = forkWithUnmask (\_ -> ma)--  -- | Like 'fork', but the child thread is passed a function that can-  -- be used to unmask asynchronous exceptions. This function should-  -- not be used within a 'mask' or 'uninterruptibleMask'.-  ---  -- > forkWithUnmask = forkWithUnmaskN ""-  forkWithUnmask :: ((forall a. m a -> m a) -> m ()) -> m (ThreadId m)-  forkWithUnmask = forkWithUnmaskN ""--  -- | Like 'forkWithUnmask', but the thread is given a name which may-  -- be used to present more useful debugging information.-  ---  -- If an empty name is given, the @ThreadId@ is used. If names-  -- conflict, successive threads with the same name are given a-  -- numeric suffix, counting up from 1.-  ---  -- > forkWithUnmaskN _ = forkWithUnmask-  forkWithUnmaskN :: String -> ((forall a. m a -> m a) -> m ()) -> m (ThreadId m)-  forkWithUnmaskN _ = forkWithUnmask--  -- | Fork a computation to happen on a specific processor. The-  -- specified int is the /capability number/, typically capabilities-  -- correspond to physical processors or cores but this is-  -- implementation dependent. The int is interpreted modulo to the-  -- total number of capabilities as returned by 'getNumCapabilities'.-  ---  -- > forkOn c ma = forkOnWithUnmask c (\_ -> ma)-  forkOn :: Int -> m () -> m (ThreadId m)-  forkOn c ma = forkOnWithUnmask c (\_ -> ma)--  -- | Like 'forkWithUnmask', but the child thread is pinned to the-  -- given CPU, as with 'forkOn'.-  ---  -- > forkOnWithUnmask = forkOnWithUnmaskN ""-  forkOnWithUnmask :: Int -> ((forall a. m a -> m a) -> m ()) -> m (ThreadId m)-  forkOnWithUnmask = forkOnWithUnmaskN ""--  -- | Like 'forkWithUnmaskN', but the child thread is pinned to the-  -- given CPU, as with 'forkOn'.-  ---  -- > forkOnWithUnmaskN _ = forkOnWithUnmask-  forkOnWithUnmaskN :: String -> Int -> ((forall a. m a -> m a) -> m ()) -> m (ThreadId m)-  forkOnWithUnmaskN _ = forkOnWithUnmask--  -- | Get the number of Haskell threads that can run simultaneously.-  getNumCapabilities :: m Int--  -- | Set the number of Haskell threads that can run simultaneously.-  setNumCapabilities :: Int -> m ()--  -- | Get the @ThreadId@ of the current thread.-  myThreadId :: m (ThreadId m)--  -- | Allows a context-switch to any other currently runnable thread-  -- (if any).-  yield :: m ()--  -- | Yields the current thread, and optionally suspends the current-  -- thread for a given number of microseconds.-  ---  -- If suspended, there is no guarantee that the thread will be-  -- rescheduled promptly when the delay has expired, but the thread-  -- will never continue to run earlier than specified.-  ---  -- > threadDelay _ = yield-  threadDelay :: Int -> m ()-  threadDelay _ = yield--  -- | Create a new empty @MVar@.-  ---  -- > newEmptyMVar = newEmptyMVarN ""-  newEmptyMVar :: m (MVar m a)-  newEmptyMVar = newEmptyMVarN ""--  -- | Create a new empty @MVar@, but it is given a name which may be-  -- used to present more useful debugging information.-  ---  -- If an empty name is given, a counter starting from 0 is used. If-  -- names conflict, successive @MVar@s with the same name are given a-  -- numeric suffix, counting up from 1.-  ---  -- > newEmptyMVarN _ = newEmptyMVar-  newEmptyMVarN :: String -> m (MVar m a)-  newEmptyMVarN _ = newEmptyMVar--  -- | Put a value into a @MVar@. If there is already a value there,-  -- this will block until that value has been taken, at which point-  -- the value will be stored.-  putMVar :: MVar m a -> a -> m ()--  -- | Attempt to put a value in a @MVar@ non-blockingly, returning-  -- 'True' (and filling the @MVar@) if there was nothing there,-  -- otherwise returning 'False'.-  tryPutMVar :: MVar m a -> a -> m Bool--  -- | Block until a value is present in the @MVar@, and then return-  -- it. As with 'readMVar', this does not \"remove\" the value,-  -- multiple reads are possible.-  readMVar :: MVar m a -> m a--  -- | Take a value from a @MVar@. This \"empties\" the @MVar@,-  -- allowing a new value to be put in. This will block if there is no-  -- value in the @MVar@ already, until one has been put.-  takeMVar :: MVar m a -> m a--  -- | Attempt to take a value from a @MVar@ non-blockingly, returning-  -- a 'Just' (and emptying the @MVar@) if there was something there,-  -- otherwise returning 'Nothing'.-  tryTakeMVar :: MVar m a -> m (Maybe a)--  -- | Create a new reference.-  ---  -- > newCRef = newCRefN ""-  newCRef :: a -> m (CRef m a)-  newCRef = newCRefN ""--  -- | Create a new reference, but it is given a name which may be-  -- used to present more useful debugging information.-  ---  -- If an empty name is given, a counter starting from 0 is used. If-  -- names conflict, successive @CRef@s with the same name are given a-  -- numeric suffix, counting up from 1.-  ---  -- > newCRefN _ = newCRef-  newCRefN :: String -> a -> m (CRef m a)-  newCRefN _ = newCRef--  -- | Read the current value stored in a reference.-  ---  -- > readCRef cref = readForCAS cref >>= peekTicket-  readCRef :: CRef m a -> m a-  readCRef cref = readForCAS cref >>= peekTicket--  -- | Atomically modify the value stored in a reference. This imposes-  -- a full memory barrier.-  atomicModifyCRef :: CRef m a -> (a -> (a, b)) -> m b--  -- | Write a new value into an @CRef@, without imposing a memory-  -- barrier. This means that relaxed memory effects can be observed.-  writeCRef :: CRef m a -> a -> m ()--  -- | Replace the value stored in a reference, with the-  -- barrier-to-reordering property that 'atomicModifyCRef' has.-  ---  -- > atomicWriteCRef r a = atomicModifyCRef r $ const (a, ())-  atomicWriteCRef :: CRef m a -> a -> m ()-  atomicWriteCRef r a = atomicModifyCRef r $ const (a, ())--  -- | Read the current value stored in a reference, returning a-  -- @Ticket@, for use in future compare-and-swap operations.-  readForCAS :: CRef m a -> m (Ticket m a)--  -- | Extract the actual Haskell value from a @Ticket@.-  ---  -- This shouldn't need to do any monadic computation, the @m@-  -- appears in the result type because of the need for injectivity in-  -- the @Ticket@ type family, which can't be expressed currently.-  peekTicket :: Ticket m a -> m a--  -- | 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 :: CRef m a -> Ticket m a -> a -> m (Bool, Ticket m a)--  -- | A replacement for 'atomicModifyCRef' using a compare-and-swap.-  ---  -- This is strict in the \"new\" value argument.-  modifyCRefCAS :: CRef m a -> (a -> (a, b)) -> m b--  -- | A variant of 'modifyCRefCAS' which doesn't return a result.-  ---  -- > modifyCRefCAS_ cref f = modifyCRefCAS cref (\a -> (f a, ()))-  modifyCRefCAS_ :: CRef m a -> (a -> a) -> m ()-  modifyCRefCAS_ cref f = modifyCRefCAS cref (\a -> (f a, ()))--  -- | Perform an STM transaction atomically.-  atomically :: STM m a -> m a--  -- | Read the current value stored in a @TVar@. This may be-  -- implemented differently for speed.-  ---  -- > readTVarConc = atomically . readTVar-  readTVarConc :: TVar (STM m) a -> m a-  readTVarConc = atomically . readTVar--  -- | Throw an exception to the target thread. This blocks until the-  -- exception is delivered, and it is just as if the target thread-  -- had raised it with 'throw'. This can interrupt a blocked action.-  throwTo :: Exception e => ThreadId m -> e -> m ()--  -- | Does nothing.-  ---  -- This function is purely for testing purposes, and indicates that-  -- the thread has a reference to the provided @MVar@ or @TVar@. This-  -- function may be called multiple times, to add new knowledge to-  -- the system. It does not need to be called when @MVar@s or @TVar@s-  -- are created, these get recorded automatically.-  ---  -- Gathering this information allows detection of cases where the-  -- main thread is blocked on a variable no runnable thread has a-  -- reference to, which is a deadlock situation.-  ---  -- > _concKnowsAbout _ = pure ()-  _concKnowsAbout :: Either (MVar m a) (TVar (STM m) a) -> m ()-  _concKnowsAbout _ = pure ()--  -- | Does nothing.-  ---  -- The counterpart to '_concKnowsAbout'. Indicates that the-  -- referenced variable will never be touched again by the current-  -- thread.-  ---  -- Note that inappropriate use of @_concForgets@ can result in false-  -- positives! Be very sure that the current thread will /never/-  -- refer to the variable again, for instance when leaving its scope.-  ---  -- > _concForgets _ = pure ()-  _concForgets :: Either (MVar m a) (TVar (STM m) a) -> m ()-  _concForgets _ = pure ()--  -- | Does nothing.-  ---  -- Indicates to the test runner that all variables which have been-  -- passed in to this thread have been recorded by calls to-  -- '_concKnowsAbout'. If every thread has called '_concAllKnown',-  -- then detection of nonglobal deadlock is turned on.-  ---  -- If a thread receives references to @MVar@s or @TVar@s in the-  -- future (for instance, if one was sent over a channel), then-  -- '_concKnowsAbout' should be called immediately, otherwise there-  -- is a risk of identifying false positives.-  ---  -- > _concAllKnown = pure ()-  _concAllKnown :: m ()-  _concAllKnown = pure ()--  -- | Does nothing.-  ---  -- During testing, records a message which shows up in the trace.-  ---  -- > _concMessage _ = pure ()-  _concMessage :: Typeable a => a -> m ()-  _concMessage _ = pure ()------------------------------------------------------------------------------------ Utilities---- | Get the current line number as a String. Useful for automatically--- naming threads, @MVar@s, and @CRef@s.------ Example usage:------ > forkN $lineNum ...------ Unfortunately this can't be packaged up into a--- @forkL@/@forkOnL@/etc set of functions, because this imposes a--- 'Lift' constraint on the monad, which 'IO' does not have.-lineNum :: Q Exp-lineNum = do-  line <- show . fst . loc_start <$> location-  [| line |]---- Threads---- | Create a concurrent computation for the provided action, and--- return a @MVar@ which can be used to query the result.-spawn :: MonadConc m => m a -> m (MVar m a)-spawn ma = do-  cvar <- newEmptyMVar-  _ <- fork $ _concKnowsAbout (Left cvar) >> ma >>= putMVar cvar-  pure cvar---- | Fork a thread and call the supplied function when the thread is--- about to terminate, with an exception or a returned value. The--- function is called with asynchronous exceptions masked.------ This function is useful for informing the parent when a child--- terminates, for example.-forkFinally :: MonadConc m => m a -> (Either SomeException a -> m ()) -> m (ThreadId m)-forkFinally action and_then =-  mask $ \restore ->-    fork $ Ca.try (restore action) >>= and_then---- | Raise the 'ThreadKilled' exception in the target thread. Note--- that if the thread is prepared to catch this exception, it won't--- actually kill it.-killThread :: MonadConc m => ThreadId m -> m ()-killThread tid = throwTo tid ThreadKilled---- | Like 'fork', but the thread is given a name which may be used to--- present more useful debugging information.------ If no name is given, the @ThreadId@ is used. If names conflict,--- successive threads with the same name are given a numeric suffix,--- counting up from 1.-forkN :: MonadConc m => String -> m () -> m (ThreadId m)-forkN name ma = forkWithUnmaskN name (\_ -> ma)---- | Like 'forkOn', but the thread is given a name which may be used--- to present more useful debugging information.------ If no name is given, the @ThreadId@ is used. If names conflict,--- successive threads with the same name are given a numeric suffix,--- counting up from 1.-forkOnN :: MonadConc m => String -> Int -> m () -> m (ThreadId m)-forkOnN name i ma = forkOnWithUnmaskN name i (\_ -> ma)---- Bound Threads---- | Provided for compatibility, always returns 'False'.-rtsSupportsBoundThreads :: Bool-rtsSupportsBoundThreads = False---- | Provided for compatibility, always returns 'False'.-isCurrentThreadBound :: MonadConc m => m Bool-isCurrentThreadBound = pure False---- Exceptions---- | Throw an exception. This will \"bubble up\" looking for an--- exception handler capable of dealing with it and, if one is not--- found, the thread is killed.-throw :: (MonadConc m, Exception e) => e -> m a-throw = Ca.throwM---- | Catch an exception. This is only required to be able to catch--- exceptions raised by 'throw', unlike the more general--- Control.Exception.catch function. If you need to be able to catch--- /all/ errors, you will have to use 'IO'.-catch :: (MonadConc m, Exception e) => m a -> (e -> m a) -> m a-catch = Ca.catch---- | Executes a computation with asynchronous exceptions--- /masked/. That is, any thread which attempts to raise an exception--- in the current thread with 'throwTo' will be blocked until--- asynchronous exceptions are unmasked again.------ The argument passed to mask is a function that takes as its--- argument another function, which can be used to restore the--- prevailing masking state within the context of the masked--- computation. This function should not be used within an--- 'uninterruptibleMask'.-mask :: MonadConc m => ((forall a. m a -> m a) -> m b) -> m b-mask = Ca.mask---- | Like 'mask', but the masked computation is not--- interruptible. THIS SHOULD BE USED WITH GREAT CARE, because if a--- thread executing in 'uninterruptibleMask' blocks for any reason,--- then the thread (and possibly the program, if this is the main--- thread) will be unresponsive and unkillable. This function should--- only be necessary if you need to mask exceptions around an--- interruptible operation, and you can guarantee that the--- interruptible operation will only block for a short period of--- time. The supplied unmasking function should not be used within a--- 'mask'.-uninterruptibleMask :: MonadConc m => ((forall a. m a -> m a) -> m b) -> m b-uninterruptibleMask = Ca.uninterruptibleMask---- Mutable Variables---- | Create a new @MVar@ containing a value.-newMVar :: MonadConc m => a -> m (MVar m a)-newMVar a = do-  cvar <- newEmptyMVar-  putMVar cvar a-  pure cvar---- | Create a new @MVar@ containing a value, but it is given a name--- which may be used to present more useful debugging information.------ If no name is given, a counter starting from 0 is used. If names--- conflict, successive @MVar@s with the same name are given a numeric--- suffix, counting up from 1.-newMVarN :: MonadConc m => String -> a -> m (MVar m a)-newMVarN n a = do-  cvar <- newEmptyMVarN n-  putMVar cvar a-  pure cvar---- | Compare-and-swap a value in a @CRef@, returning an indication of--- success and the new value.-cas :: MonadConc m => CRef m a -> a -> m (Bool, a)-cas cref a = do-  tick         <- readForCAS cref-  (suc, tick') <- casCRef cref tick a-  a'           <- peekTicket tick'--  pure (suc, a')------------------------------------------------------------------------------------ Concrete instances--instance MonadConc IO where-  type STM      IO = IO.STM-  type MVar     IO = IO.MVar-  type CRef     IO = IO.IORef-  type Ticket   IO = IO.Ticket-  type ThreadId IO = IO.ThreadId--  fork   = IO.forkIO-  forkOn = IO.forkOn--  forkWithUnmask   = IO.forkIOWithUnmask-  forkOnWithUnmask = IO.forkOnWithUnmask--  getNumCapabilities = IO.getNumCapabilities-  setNumCapabilities = IO.setNumCapabilities-  readMVar           = IO.readMVar-  myThreadId         = IO.myThreadId-  yield              = IO.yield-  threadDelay        = IO.threadDelay-  throwTo            = IO.throwTo-  newEmptyMVar       = IO.newEmptyMVar-  putMVar            = IO.putMVar-  tryPutMVar         = IO.tryPutMVar-  takeMVar           = IO.takeMVar-  tryTakeMVar        = IO.tryTakeMVar-  newCRef            = IO.newIORef-  readCRef           = IO.readIORef-  atomicModifyCRef   = IO.atomicModifyIORef-  writeCRef          = IO.writeIORef-  atomicWriteCRef    = IO.atomicWriteIORef-  readForCAS         = IO.readForCAS-  peekTicket         = pure . IO.peekTicket-  casCRef            = IO.casIORef-  modifyCRefCAS      = IO.atomicModifyIORefCAS-  atomically         = IO.atomically-  readTVarConc       = IO.readTVarIO------------------------------------------------------------------------------------ Transformer instances--#define INSTANCE(T,C,F)                                          \-instance C => MonadConc (T m) where                             { \-  type STM      (T m) = STM m                                  ; \-  type MVar     (T m) = MVar m                                 ; \-  type CRef     (T m) = CRef m                                 ; \-  type Ticket   (T m) = Ticket m                               ; \-  type ThreadId (T m) = ThreadId m                             ; \-                                                                 \-  fork   = liftedF F fork                                      ; \-  forkOn = liftedF F . forkOn                                  ; \-                                                                 \-  forkWithUnmask        = liftedFork F forkWithUnmask          ; \-  forkWithUnmaskN   n   = liftedFork F (forkWithUnmaskN   n  ) ; \-  forkOnWithUnmask    i = liftedFork F (forkOnWithUnmask    i) ; \-  forkOnWithUnmaskN n i = liftedFork F (forkOnWithUnmaskN n i) ; \-                                                                 \-  getNumCapabilities = lift getNumCapabilities                 ; \-  setNumCapabilities = lift . setNumCapabilities               ; \-  myThreadId         = lift myThreadId                         ; \-  yield              = lift yield                              ; \-  threadDelay        = lift . threadDelay                      ; \-  throwTo t          = lift . throwTo t                        ; \-  newEmptyMVar       = lift newEmptyMVar                       ; \-  newEmptyMVarN      = lift . newEmptyMVarN                    ; \-  readMVar           = lift . readMVar                         ; \-  putMVar v          = lift . putMVar v                        ; \-  tryPutMVar v       = lift . tryPutMVar v                     ; \-  takeMVar           = lift . takeMVar                         ; \-  tryTakeMVar        = lift . tryTakeMVar                      ; \-  newCRef            = lift . newCRef                          ; \-  newCRefN n         = lift . newCRefN n                       ; \-  readCRef           = lift . readCRef                         ; \-  atomicModifyCRef r = lift . atomicModifyCRef r               ; \-  writeCRef r        = lift . writeCRef r                      ; \-  atomicWriteCRef r  = lift . atomicWriteCRef r                ; \-  readForCAS         = lift . readForCAS                       ; \-  peekTicket         = lift . peekTicket                       ; \-  casCRef r t        = lift . casCRef r t                      ; \-  modifyCRefCAS r    = lift . modifyCRefCAS r                  ; \-  atomically         = lift . atomically                       ; \-  readTVarConc       = lift . readTVarConc                     ; \-                                                                 \-  _concKnowsAbout = lift . _concKnowsAbout                     ; \-  _concForgets    = lift . _concForgets                        ; \-  _concAllKnown   = lift _concAllKnown                         ; \-  _concMessage    = lift . _concMessage                        }--INSTANCE(ReaderT r, MonadConc m, id)--INSTANCE(IdentityT, MonadConc m, id)--INSTANCE(WL.WriterT w, (MonadConc m, Monoid w), fst)-INSTANCE(WS.WriterT w, (MonadConc m, Monoid w), fst)--INSTANCE(SL.StateT s, MonadConc m, fst)-INSTANCE(SS.StateT s, MonadConc m, fst)--INSTANCE(RL.RWST r w s, (MonadConc m, Monoid w), (\(a,_,_) -> a))-INSTANCE(RS.RWST r w s, (MonadConc m, Monoid w), (\(a,_,_) -> a))--#undef INSTANCE------------------------------------------------------------------------------------- | Make an instance @MonadConc m => MonadConc (t m)@ for a given--- transformer, @t@. The parameter should be the name of a function--- @:: forall a. StT t a -> a@.-makeTransConc :: Name -> DecsQ-makeTransConc unstN = do-  unstI <- reify unstN-  case unstI of-#if MIN_VERSION_template_haskell(2,11,0)-    -- template-haskell-2.11.0.0 drops the 'Fixity' value from 'VarI'-    VarI _ (ForallT _ _ (AppT (AppT ArrowT (AppT (AppT (ConT _) t) _)) _)) _ ->-#else-    VarI _ (ForallT _ _ (AppT (AppT ArrowT (AppT (AppT (ConT _) t) _)) _)) _ _ ->-#endif-      [d|-        instance (MonadConc m) => MonadConc ($(pure t) m) where-          type STM      ($(pure t) m) = STM m-          type MVar     ($(pure t) m) = MVar m-          type CRef     ($(pure t) m) = CRef m-          type Ticket   ($(pure t) m) = Ticket m-          type ThreadId ($(pure t) m) = ThreadId m--          fork   = liftedF $(varE unstN) fork-          forkOn = liftedF $(varE unstN) . forkOn--          forkWithUnmask        = liftedFork $(varE unstN) forkWithUnmask-          forkWithUnmaskN   n   = liftedFork $(varE unstN) (forkWithUnmaskN   n  )-          forkOnWithUnmask    i = liftedFork $(varE unstN) (forkOnWithUnmask    i)-          forkOnWithUnmaskN n i = liftedFork $(varE unstN) (forkOnWithUnmaskN n i)--          getNumCapabilities = lift getNumCapabilities-          setNumCapabilities = lift . setNumCapabilities-          myThreadId         = lift myThreadId-          yield              = lift yield-          threadDelay        = lift . threadDelay-          throwTo tid        = lift . throwTo tid-          newEmptyMVar       = lift newEmptyMVar-          newEmptyMVarN      = lift . newEmptyMVarN-          readMVar           = lift . readMVar-          putMVar v          = lift . putMVar v-          tryPutMVar v       = lift . tryPutMVar v-          takeMVar           = lift . takeMVar-          tryTakeMVar        = lift . tryTakeMVar-          newCRef            = lift . newCRef-          newCRefN n         = lift . newCRefN n-          readCRef           = lift . readCRef-          atomicModifyCRef r = lift . atomicModifyCRef r-          writeCRef r        = lift . writeCRef r-          atomicWriteCRef r  = lift . atomicWriteCRef r-          readForCAS         = lift . readForCAS-          peekTicket         = lift . peekTicket-          casCRef r tick     = lift . casCRef r tick-          modifyCRefCAS r    = lift . modifyCRefCAS r-          atomically         = lift . atomically-          readTVarConc       = lift . readTVarConc--          _concKnowsAbout = lift . _concKnowsAbout-          _concForgets    = lift . _concForgets-          _concAllKnown   = lift _concAllKnown-          _concMessage    = lift . _concMessage-      |]-    _ -> fail "Expected a value of type (forall a -> StT t a -> a)"---- | Given a function to remove the transformer-specific state, lift--- a function invocation.-liftedF :: (MonadTransControl t, MonadConc m)-  => (forall x. StT t x -> x)-  -> (m a -> m b)-  -> t m a-  -> t m b-liftedF unst f ma = liftWith $ \run -> f (unst <$> run ma)---- | Given a function to remove the transformer-specific state, lift--- a @fork(on)WithUnmask@ invocation.-liftedFork :: (MonadTransControl t, MonadConc m)-  => (forall x. StT t x -> x)-  -> (((forall x. m x -> m x) -> m a) -> m b)-  -> ((forall x. t m x -> t m x) -> t m a)-  -> t m b-liftedFork unst f ma = liftWith $ \run ->-  f (\unmask -> unst <$> run (ma $ liftedF unst unmask))
− Control/Monad/STM/Class.hs
@@ -1,195 +0,0 @@-{-# LANGUAGE CPP             #-}-{-# LANGUAGE RankNTypes      #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeFamilies    #-}---- |--- Module      : Control.Monad.STM.Class--- Copyright   : (c) 2016 Michael Walker--- License     : MIT--- Maintainer  : Michael Walker <mike@barrucadu.co.uk>--- Stability   : experimental--- Portability : CPP, RankNTypes, TemplateHaskell, TypeFamilies------ This module provides an abstraction over 'STM', which can be used--- with 'MonadConc'.------ This module only defines the 'STM' class; you probably want to--- import "Control.Concurrent.Classy.STM" (which exports--- "Control.Monad.STM.Class").------ __Deviations:__ An instance of @MonadSTM@ is not required to be an--- @Alternative@, @MonadPlus@, and @MonadFix@, unlike @STM@. The--- @always@ and @alwaysSucceeds@ functions are not provided; if you--- need these file an issue and I'll look into it.-module Control.Monad.STM.Class-  ( MonadSTM(..)-  , check-  , throwSTM-  , catchSTM--  -- * Utilities for instance writers-  , makeTransSTM-  , liftedOrElse-  ) where--import Control.Exception (Exception)-import Control.Monad (unless)-import Control.Monad.Reader (ReaderT)-import Control.Monad.Trans (lift)-import Control.Monad.Trans.Control (MonadTransControl, StT, liftWith)-import Control.Monad.Trans.Identity (IdentityT)-import Language.Haskell.TH (DecsQ, Info(VarI), Name, Type(..), reify, varE)--import qualified Control.Concurrent.STM as STM-import qualified Control.Monad.Catch as Ca-import qualified Control.Monad.RWS.Lazy as RL-import qualified Control.Monad.RWS.Strict as RS-import qualified Control.Monad.State.Lazy as SL-import qualified Control.Monad.State.Strict as SS-import qualified Control.Monad.Writer.Lazy as WL-import qualified Control.Monad.Writer.Strict as WS---- | @MonadSTM@ is an abstraction over 'STM'.------ This class does not provide any way to run transactions, rather--- each 'MonadConc' has an associated @MonadSTM@ from which it can--- atomically run a transaction.-class Ca.MonadCatch stm => MonadSTM stm where-  {-# MINIMAL-        retry-      , orElse-      , (newTVar | newTVarN)-      , readTVar-      , writeTVar-    #-}--  -- | The mutable reference type. These behave like 'TVar's, in that-  -- they always contain a value and updates are non-blocking and-  -- synchronised.-  type TVar stm :: * -> *--  -- | Retry execution of this transaction because it has seen values-  -- in @TVar@s that it shouldn't have. This will result in the-  -- thread running the transaction being blocked until any @TVar@s-  -- referenced in it have been mutated.-  retry :: stm a--  -- | Run the first transaction and, if it @retry@s, run the second-  -- instead. If the monad is an instance of-  -- 'Alternative'/'MonadPlus', 'orElse' should be the '(<|>)'/'mplus'-  -- function.-  orElse :: stm a -> stm a -> stm a--  -- | Create a new @TVar@ containing the given value.-  ---  -- > newTVar = newTVarN ""-  newTVar :: a -> stm (TVar stm a)-  newTVar = newTVarN ""--  -- | Create a new @TVar@ containing the given value, but it is-  -- given a name which may be used to present more useful debugging-  -- information.-  ---  -- If an empty name is given, a counter starting from 0 is used. If-  -- names conflict, successive @TVar@s with the same name are given-  -- a numeric suffix, counting up from 1.-  ---  -- > newTVarN _ = newTVar-  newTVarN :: String -> a -> stm (TVar stm a)-  newTVarN _ = newTVar--  -- | Return the current value stored in a @TVar@.-  readTVar :: TVar stm a -> stm a--  -- | Write the supplied value into the @TVar@.-  writeTVar :: TVar stm a -> a -> stm ()---- | Check whether a condition is true and, if not, call @retry@.-check :: MonadSTM stm => Bool -> stm ()-check b = unless b retry---- | Throw an exception. This aborts the transaction and propagates--- the exception.-throwSTM :: (MonadSTM stm, Exception e) => e -> stm a-throwSTM = Ca.throwM---- | Handling exceptions from 'throwSTM'.-catchSTM :: (MonadSTM stm, Exception e) => stm a -> (e -> stm a) -> stm a-catchSTM = Ca.catch--instance MonadSTM STM.STM where-  type TVar STM.STM = STM.TVar--  retry     = STM.retry-  orElse    = STM.orElse-  newTVar   = STM.newTVar-  readTVar  = STM.readTVar-  writeTVar = STM.writeTVar------------------------------------------------------------------------------------ Transformer instances--#define INSTANCE(T,C,F)                                  \-instance C => MonadSTM (T stm) where { \-  type TVar (T stm) = TVar stm      ; \-                                      \-  retry       = lift retry          ; \-  orElse      = liftedOrElse F      ; \-  newTVar     = lift . newTVar      ; \-  newTVarN n  = lift . newTVarN n   ; \-  readTVar    = lift . readTVar     ; \-  writeTVar v = lift . writeTVar v  }--INSTANCE(ReaderT r, MonadSTM stm, id)--INSTANCE(IdentityT, MonadSTM stm, id)--INSTANCE(WL.WriterT w, (MonadSTM stm, Monoid w), fst)-INSTANCE(WS.WriterT w, (MonadSTM stm, Monoid w), fst)--INSTANCE(SL.StateT s, MonadSTM stm, fst)-INSTANCE(SS.StateT s, MonadSTM stm, fst)--INSTANCE(RL.RWST r w s, (MonadSTM stm, Monoid w), (\(a,_,_) -> a))-INSTANCE(RS.RWST r w s, (MonadSTM stm, Monoid w), (\(a,_,_) -> a))--#undef INSTANCE------------------------------------------------------------------------------------- | Make an instance @MonadSTM m => MonadSTM (t m)@ for a given--- transformer, @t@. The parameter should be the name of a function--- @:: forall a. StT t a -> a@.-makeTransSTM :: Name -> DecsQ-makeTransSTM unstN = do-  unstI <- reify unstN-  case unstI of-#if MIN_VERSION_template_haskell(2,11,0)-    -- template-haskell-2.11.0.0 drops the 'Fixity' value from 'VarI'-    VarI _ (ForallT _ _ (AppT (AppT ArrowT (AppT (AppT (ConT _) t) _)) _)) _ ->-#else-    VarI _ (ForallT _ _ (AppT (AppT ArrowT (AppT (AppT (ConT _) t) _)) _)) _ _ ->-#endif-      [d|-        instance (MonadSTM stm, MonadTransControl $(pure t)) => MonadSTM ($(pure t) stm) where-          type TVar ($(pure t) stm) = TVar stm--          retry       = lift retry-          orElse      = liftedOrElse $(varE unstN)-          newTVar     = lift . newTVar-          newTVarN n  = lift . newTVarN n-          readTVar    = lift . readTVar-          writeTVar v = lift . writeTVar v-      |]-    _ -> fail "Expected a value of type (forall a -> StT t a -> a)"---- | Given a function to remove the transformer-specific state, lift--- an @orElse@ invocation.-liftedOrElse :: (MonadTransControl t, MonadSTM stm)-  => (forall x. StT t x -> x)-  -> t stm a -> t stm a -> t stm a-liftedOrElse unst ma mb = liftWith $ \run ->-  let ma' = unst <$> run ma-      mb' = unst <$> run mb-  in ma' `orElse` mb'
Test/DejaFu.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RankNTypes #-}  -- |@@ -44,22 +45,25 @@ -- Here is what Deja Fu has to say about it: -- -- > > autocheck example1--- > [fail] Never Deadlocks (checked: 2)--- >         [deadlock] S0---------S1--P2---S1---- > [pass] No Exceptions (checked: 11)--- > [fail] Consistent Result (checked: 10)--- >         0 S0---------S1---------------S0--S2---------------S0------- >         [deadlock] S0---------S1--P2---S1-+-- > [fail] Never Deadlocks (checked: 5)+-- >         [deadlock] S0------------S1-P2--S1-+-- > [pass] No Exceptions (checked: 12)+-- > [fail] Consistent Result (checked: 11)+-- >         0 S0------------S2-----------------S1-----------------S0----+-- >+-- >         [deadlock] S0------------S1-P2--S1- -- > False -- -- It identifies the deadlock, and also the possible results the -- computation can produce, and displays a simplified trace leading to--- each failing outcome. It also returns @False@ as there are test--- failures. The automatic testing functionality is good enough if you--- only want to check your computation is deterministic, but if you--- have more specific requirements (or have some expected and--- tolerated level of nondeterminism), you can write tests yourself--- using the @dejafu*@ functions.+-- each failing outcome. The trace contains thread numbers, and the+-- names (which can be set by the programmer) are displayed beneath.+-- It also returns @False@ as there are test failures. The automatic+-- testing functionality is good enough if you only want to check your+-- computation is deterministic, but if you have more specific+-- requirements (or have some expected and tolerated level of+-- nondeterminism), you can write tests yourself using the @dejafu*@+-- functions. -- -- __Warning:__ If your computation under test does @IO@, the @IO@ -- will be executed lots of times! Be sure that it is deterministic@@ -199,8 +203,8 @@   , Failure(..)   , runTest   , runTest'-  , runTestIO-  , runTestIO'+  , runTestM+  , runTestM'    -- * Predicates @@ -238,12 +242,14 @@ import Control.Arrow (first) import Control.DeepSeq (NFData(..)) import Control.Monad (when, unless)+import Control.Monad.Ref (MonadRef)+import Control.Monad.ST (runST) import Data.Function (on) import Data.List (intercalate, intersperse, minimumBy)---import Data.List.NonEmpty import Data.Ord (comparing)-import Test.DejaFu.Deterministic-import Test.DejaFu.Deterministic.Internal (preEmpCount)++import Test.DejaFu.Common+import Test.DejaFu.Conc import Test.DejaFu.SCT  -- | The default memory model: @TotalStoreOrder@@@ -260,25 +266,38 @@   => (forall t. ConcST t a)   -- ^ The computation to test   -> IO Bool-autocheck = autocheck' defaultMemType+autocheck = autocheck' defaultMemType defaultBounds --- | Variant of 'autocheck' which tests a computation under a given--- memory model.+-- | Variant of 'autocheck' which takes a memor model and schedule+-- bounds.+--+-- Schedule bounding is used to filter the large number of possible+-- schedules, and can be iteratively increased for further coverage+-- guarantees. Empirical studies (/Concurrency Testing Using Schedule+-- Bounding: an Empirical Study/, P. Thompson, A. Donaldson, and+-- A. Betts) have found that many concurrency bugs can be exhibited+-- with as few as two threads and two pre-emptions, which is part of+-- what 'dejafus' uses.+--+-- __Warning:__ Using largers bounds will almost certainly+-- significantly increase the time taken to test! autocheck' :: (Eq a, Show a)   => MemType   -- ^ The memory model to use for non-synchronised @CRef@ operations.+  -> Bounds+  -- ^ The schedule bounds   -> (forall t. ConcST t a)   -- ^ The computation to test   -> IO Bool-autocheck' memtype conc = dejafus' memtype defaultBounds conc autocheckCases+autocheck' memtype cb conc = dejafus' memtype cb conc autocheckCases  -- | Variant of 'autocheck' for computations which do 'IO'. autocheckIO :: (Eq a, Show a) => ConcIO a -> IO Bool-autocheckIO = autocheckIO' defaultMemType+autocheckIO = autocheckIO' defaultMemType defaultBounds  -- | Variant of 'autocheck'' for computations which do 'IO'.-autocheckIO' :: (Eq a, Show a) => MemType -> ConcIO a -> IO Bool-autocheckIO' memtype concio = dejafusIO' memtype defaultBounds concio autocheckCases+autocheckIO' :: (Eq a, Show a) => MemType -> Bounds -> ConcIO a -> IO Bool+autocheckIO' memtype cb concio = dejafusIO' memtype cb concio autocheckCases  -- | Predicates for the various autocheck functions. autocheckCases :: (Eq a, Show a) => [(String, Predicate a)]@@ -300,17 +319,6 @@  -- | Variant of 'dejafu'' which takes a memory model and schedule -- bounds.------ Schedule bounding is used to filter the large number of possible--- schedules, and can be iteratively increased for further coverage--- guarantees. Empirical studies (/Concurrency Testing Using Schedule--- Bounding: an Empirical Study/, P. Thompson, A. Donaldson, and--- A. Betts) have found that many concurrency bugs can be exhibited--- with as few as two threads and two pre-emptions, which is part of--- what 'dejafus' uses.------ __Warning:__ Using largers bounds will almost certainly--- significantly increase the time taken to test! dejafu' :: Show a   => MemType   -- ^ The memory model to use for non-synchronised @CRef@ operations.@@ -346,7 +354,7 @@   -- ^ The list of predicates (with names) to check   -> IO Bool dejafus' memtype cb conc tests = do-  let traces = sctBound memtype cb conc+  let traces = runST (sctBound memtype cb conc)   results <- mapM (\(name, test) -> doTest name $ test traces) tests   return $ and results @@ -365,7 +373,7 @@ -- | Variant of 'dejafus'' for computations which do 'IO'. dejafusIO' :: Show a => MemType -> Bounds -> ConcIO a -> [(String, Predicate a)] -> IO Bool dejafusIO' memtype cb concio tests = do-  traces  <- sctBoundIO memtype cb concio+  traces  <- sctBound memtype cb concio   results <- mapM (\(name, test) -> doTest name $ test traces) tests   return $ and results @@ -409,7 +417,7 @@   -> (forall t. ConcST t a)   -- ^ The computation to test   -> Result a-runTest = runTest' defaultMemType defaultBounds+runTest test conc = runST (runTestM test conc)  -- | Variant of 'runTest' which takes a memory model and schedule -- bounds.@@ -423,15 +431,18 @@   -> (forall t. ConcST t a)   -- ^ The computation to test   -> Result a-runTest' memtype cb predicate conc = predicate $ sctBound memtype cb conc+runTest' memtype cb predicate conc =+  runST (runTestM' memtype cb predicate conc) --- | Variant of 'runTest' for computations which do 'IO'.-runTestIO :: Predicate a -> ConcIO a -> IO (Result a)-runTestIO = runTestIO' defaultMemType defaultBounds+-- | Monad-polymorphic variant of 'runTest'.+runTestM :: MonadRef r n+         => Predicate a -> Conc n r a -> n (Result a)+runTestM = runTestM' defaultMemType defaultBounds --- | Variant of 'runTest'' for computations which do 'IO'.-runTestIO' :: MemType -> Bounds -> Predicate a -> ConcIO a -> IO (Result a)-runTestIO' memtype cb predicate conc = predicate <$> sctBoundIO memtype cb conc+-- | Monad-polymorphic variant of 'runTest''.+runTestM' :: MonadRef r n+          => MemType -> Bounds -> Predicate a -> Conc n r a -> n (Result a)+runTestM' memtype cb predicate conc = predicate <$> sctBound memtype cb conc  -- * Predicates 
+ Test/DejaFu/Common.hs view
@@ -0,0 +1,746 @@+-- |+-- Module      : Test.DejaFu.Common+-- Copyright   : (c) 2016 Michael Walker+-- License     : MIT+-- Maintainer  : Michael Walker <mike@barrucadu.co.uk>+-- Stability   : experimental+-- Portability : portable+--+-- Common types and functions used throughout DejaFu. This module is+-- NOT considered to form part of the public interface of this+-- library.+module Test.DejaFu.Common+  ( -- * Identifiers+    ThreadId(..)+  , CRefId(..)+  , MVarId(..)+  , TVarId(..)+  , initialThread+  -- ** Identifier source+  , IdSource(..)+  , nextCRId+  , nextMVId+  , nextTVId+  , nextTId+  , initialIdSource++  -- * Actions+  -- ** Thread actions+  , ThreadAction(..)+  , isBlock+  , tvarsOf+  -- ** Lookahead+  , Lookahead(..)+  , rewind+  , willRelease+  -- ** Simplified actions+  , ActionType(..)+  , isBarrier+  , isCommit+  , synchronises+  , crefOf+  , mvarOf+  , simplifyAction+  , simplifyLookahead+  -- ** STM actions+  , TTrace+  , TAction(..)++  -- * Traces+  , Trace+  , Decision(..)+  , showTrace+  , preEmpCount++  -- * Failures+  , Failure(..)+  , showFail++  -- * Memory models+  , MemType(..)+  ) where++import Control.DeepSeq (NFData(..))+import Control.Exception (MaskingState(..))+import Data.Dynamic (Dynamic)+import Data.List (sort, nub, intercalate)+import Data.Maybe (fromMaybe, mapMaybe)+import Data.Set (Set)+import qualified Data.Set as S+import Test.DPOR (Decision(..), Trace)++-------------------------------------------------------------------------------+-- Identifiers++-- | Every live thread has a unique identitifer.+data ThreadId = ThreadId (Maybe String) Int+  deriving Eq++instance Ord ThreadId where+  compare (ThreadId _ i) (ThreadId _ j) = compare i j++instance Show ThreadId where+  show (ThreadId (Just n) _) = n+  show (ThreadId Nothing  i) = show i++instance NFData ThreadId where+  rnf (ThreadId n i) = rnf (n, i)++-- | Every @CRef@ has a unique identifier.+data CRefId = CRefId (Maybe String) Int+  deriving Eq++instance Ord CRefId where+  compare (CRefId _ i) (CRefId _ j) = compare i j++instance Show CRefId where+  show (CRefId (Just n) _) = n+  show (CRefId Nothing  i) = show i++instance NFData CRefId where+  rnf (CRefId n i) = rnf (n, i)++-- | Every @MVar@ has a unique identifier.+data MVarId = MVarId (Maybe String) Int+  deriving Eq++instance Ord MVarId where+  compare (MVarId _ i) (MVarId _ j) = compare i j++instance Show MVarId where+  show (MVarId (Just n) _) = n+  show (MVarId Nothing  i) = show i++instance NFData MVarId where+  rnf (MVarId n i) = rnf (n, i)++-- | Every @TVar@ has a unique identifier.+data TVarId = TVarId (Maybe String) Int+  deriving Eq++instance Ord TVarId where+  compare (TVarId _ i) (TVarId _ j) = compare i j++instance Show TVarId where+  show (TVarId (Just n) _) = n+  show (TVarId Nothing  i) = show i++instance NFData TVarId where+  rnf (TVarId n i) = rnf (n, i)++-- | The ID of the initial thread.+initialThread :: ThreadId+initialThread = ThreadId (Just "main") 0++---------------------------------------+-- Identifier source++-- | The number of ID parameters was getting a bit unwieldy, so this+-- hides them all away.+data IdSource = Id+  { _nextCRId  :: Int+  , _nextMVId  :: Int+  , _nextTVId  :: Int+  , _nextTId   :: Int+  , _usedCRNames :: [String]+  , _usedMVNames :: [String]+  , _usedTVNames :: [String]+  , _usedTNames  :: [String]+  }++-- | Get the next free 'CRefId'.+nextCRId :: String -> IdSource -> (IdSource, CRefId)+nextCRId name idsource = (newIdSource, newCRId) where+  newIdSource = idsource { _nextCRId = newId, _usedCRNames = newUsed }+  newCRId     = CRefId newName newId+  newId       = _nextCRId idsource + 1+  (newName, newUsed) = nextId name (_usedCRNames idsource)++-- | Get the next free 'MVarId'.+nextMVId :: String -> IdSource -> (IdSource, MVarId)+nextMVId name idsource = (newIdSource, newMVId) where+  newIdSource = idsource { _nextMVId = newId, _usedMVNames = newUsed }+  newMVId     = MVarId newName newId+  newId       = _nextMVId idsource + 1+  (newName, newUsed) = nextId name (_usedMVNames idsource)++-- | Get the next free 'TVarId'.+nextTVId :: String -> IdSource -> (IdSource, TVarId)+nextTVId name idsource = (newIdSource, newTVId) where+  newIdSource = idsource { _nextTVId = newId, _usedTVNames = newUsed }+  newTVId     = TVarId newName newId+  newId       = _nextTVId idsource + 1+  (newName, newUsed) = nextId name (_usedTVNames idsource)++-- | Get the next free 'ThreadId'.+nextTId :: String -> IdSource -> (IdSource, ThreadId)+nextTId name idsource = (newIdSource, newTId) where+  newIdSource = idsource { _nextTId = newId, _usedTNames = newUsed }+  newTId      = ThreadId newName newId+  newId       = _nextTId idsource + 1+  (newName, newUsed) = nextId name (_usedTNames idsource)++-- | The initial ID source.+initialIdSource :: IdSource+initialIdSource = Id 0 0 0 0 [] [] [] []++-------------------------------------------------------------------------------+-- Actions++---------------------------------------+-- Thread actions++-- | All the actions that a thread can perform.+data ThreadAction =+    Fork ThreadId+  -- ^ Start a new thread.+  | MyThreadId+  -- ^ Get the 'ThreadId' of the current thread.+  | GetNumCapabilities Int+  -- ^ Get the number of Haskell threads that can run simultaneously.+  | SetNumCapabilities Int+  -- ^ Set the number of Haskell threads that can run simultaneously.+  | Yield+  -- ^ Yield the current thread.+  | NewVar MVarId+  -- ^ Create a new 'MVar'.+  | PutVar MVarId [ThreadId]+  -- ^ Put into a 'MVar', possibly waking up some threads.+  | BlockedPutVar MVarId+  -- ^ Get blocked on a put.+  | TryPutVar MVarId Bool [ThreadId]+  -- ^ Try to put into a 'MVar', possibly waking up some threads.+  | ReadVar MVarId+  -- ^ Read from a 'MVar'.+  | BlockedReadVar MVarId+  -- ^ Get blocked on a read.+  | TakeVar MVarId [ThreadId]+  -- ^ Take from a 'MVar', possibly waking up some threads.+  | BlockedTakeVar MVarId+  -- ^ Get blocked on a take.+  | TryTakeVar MVarId Bool [ThreadId]+  -- ^ Try to take from a 'MVar', possibly waking up some threads.+  | NewRef CRefId+  -- ^ Create a new 'CRef'.+  | ReadRef CRefId+  -- ^ Read from a 'CRef'.+  | ReadRefCas CRefId+  -- ^ Read from a 'CRef' for a future compare-and-swap.+  | ModRef CRefId+  -- ^ Modify a 'CRef'.+  | ModRefCas CRefId+  -- ^ Modify a 'CRef' using a compare-and-swap.+  | WriteRef CRefId+  -- ^ Write to a 'CRef' without synchronising.+  | CasRef CRefId Bool+  -- ^ Attempt to to a 'CRef' using a compare-and-swap, synchronising+  -- it.+  | CommitRef ThreadId CRefId+  -- ^ Commit the last write to the given 'CRef' by the given thread,+  -- so that all threads can see the updated value.+  | STM TTrace [ThreadId]+  -- ^ An STM transaction was executed, possibly waking up some+  -- threads.+  | BlockedSTM TTrace+  -- ^ Got blocked in an STM transaction.+  | Catching+  -- ^ Register a new exception handler+  | PopCatching+  -- ^ Pop the innermost exception handler from the stack.+  | Throw+  -- ^ Throw an exception.+  | ThrowTo ThreadId+  -- ^ Throw an exception to a thread.+  | BlockedThrowTo ThreadId+  -- ^ Get blocked on a 'throwTo'.+  | Killed+  -- ^ Killed by an uncaught exception.+  | SetMasking Bool MaskingState+  -- ^ Set the masking state. If 'True', this is being used to set the+  -- masking state to the original state in the argument passed to a+  -- 'mask'ed function.+  | ResetMasking Bool MaskingState+  -- ^ Return to an earlier masking state.  If 'True', this is being+  -- used to return to the state of the masked block in the argument+  -- passed to a 'mask'ed function.+  | LiftIO+  -- ^ Lift an IO action. Note that this can only happen with+  -- 'ConcIO'.+  | Return+  -- ^ A 'return' or 'pure' action was executed.+  | Message Dynamic+  -- ^ A '_concMessage' annotation was processed.+  | Stop+  -- ^ Cease execution and terminate.+  deriving Show++instance NFData ThreadAction where+  rnf (Fork t) = rnf t+  rnf (GetNumCapabilities i) = rnf i+  rnf (SetNumCapabilities i) = rnf i+  rnf (NewVar c) = rnf c+  rnf (PutVar c ts) = rnf (c, ts)+  rnf (BlockedPutVar c) = rnf c+  rnf (TryPutVar c b ts) = rnf (c, b, ts)+  rnf (ReadVar c) = rnf c+  rnf (BlockedReadVar c) = rnf c+  rnf (TakeVar c ts) = rnf (c, ts)+  rnf (BlockedTakeVar c) = rnf c+  rnf (TryTakeVar c b ts) = rnf (c, b, ts)+  rnf (NewRef c) = rnf c+  rnf (ReadRef c) = rnf c+  rnf (ReadRefCas c) = rnf c+  rnf (ModRef c) = rnf c+  rnf (ModRefCas c) = rnf c+  rnf (WriteRef c) = rnf c+  rnf (CasRef c b) = rnf (c, b)+  rnf (CommitRef t c) = rnf (t, c)+  rnf (STM s ts) = rnf (s, ts)+  rnf (BlockedSTM s) = rnf s+  rnf (ThrowTo t) = rnf t+  rnf (BlockedThrowTo t) = rnf t+  rnf (SetMasking b m) = b `seq` m `seq` ()+  rnf (ResetMasking b m) = b `seq` m `seq` ()+  rnf (Message m) = m `seq` ()+  rnf a = a `seq` ()++-- | Check if a @ThreadAction@ immediately blocks.+isBlock :: ThreadAction -> Bool+isBlock (BlockedThrowTo  _) = True+isBlock (BlockedTakeVar _) = True+isBlock (BlockedReadVar _) = True+isBlock (BlockedPutVar  _) = True+isBlock (BlockedSTM _) = True+isBlock _ = False++-- | Get the @TVar@s affected by a @ThreadAction@.+tvarsOf :: ThreadAction -> Set TVarId+tvarsOf act = S.fromList $ case act of+  STM trc _ -> concatMap tvarsOf' trc+  BlockedSTM trc -> concatMap tvarsOf' trc+  _ -> []++  where+    tvarsOf' (TRead  tv) = [tv]+    tvarsOf' (TWrite tv) = [tv]+    tvarsOf' (TOrElse ta tb) = concatMap tvarsOf' (ta ++ fromMaybe [] tb)+    tvarsOf' (TCatch  ta tb) = concatMap tvarsOf' (ta ++ fromMaybe [] tb)+    tvarsOf' _ = []++---------------------------------------+-- Lookahead++-- | A one-step look-ahead at what a thread will do next.+data Lookahead =+    WillFork+  -- ^ Will start a new thread.+  | WillMyThreadId+  -- ^ Will get the 'ThreadId'.+  | WillGetNumCapabilities+  -- ^ Will get the number of Haskell threads that can run+  -- simultaneously.+  | WillSetNumCapabilities Int+  -- ^ Will set the number of Haskell threads that can run+  -- simultaneously.+  | WillYield+  -- ^ Will yield the current thread.+  | WillNewVar+  -- ^ Will create a new 'MVar'.+  | WillPutVar MVarId+  -- ^ Will put into a 'MVar', possibly waking up some threads.+  | WillTryPutVar MVarId+  -- ^ Will try to put into a 'MVar', possibly waking up some threads.+  | WillReadVar MVarId+  -- ^ Will read from a 'MVar'.+  | WillTakeVar MVarId+  -- ^ Will take from a 'MVar', possibly waking up some threads.+  | WillTryTakeVar MVarId+  -- ^ Will try to take from a 'MVar', possibly waking up some threads.+  | WillNewRef+  -- ^ Will create a new 'CRef'.+  | WillReadRef CRefId+  -- ^ Will read from a 'CRef'.+  | WillReadRefCas CRefId+  -- ^ Will read from a 'CRef' for a future compare-and-swap.+  | WillModRef CRefId+  -- ^ Will modify a 'CRef'.+  | WillModRefCas CRefId+  -- ^ Will nodify a 'CRef' using a compare-and-swap.+  | WillWriteRef CRefId+  -- ^ Will write to a 'CRef' without synchronising.+  | WillCasRef CRefId+  -- ^ Will attempt to to a 'CRef' using a compare-and-swap,+  -- synchronising it.+  | WillCommitRef ThreadId CRefId+  -- ^ Will commit the last write by the given thread to the 'CRef'.+  | WillSTM+  -- ^ Will execute an STM transaction, possibly waking up some+  -- threads.+  | WillCatching+  -- ^ Will register a new exception handler+  | WillPopCatching+  -- ^ Will pop the innermost exception handler from the stack.+  | WillThrow+  -- ^ Will throw an exception.+  | WillThrowTo ThreadId+  -- ^ Will throw an exception to a thread.+  | WillSetMasking Bool MaskingState+  -- ^ Will set the masking state. If 'True', this is being used to+  -- set the masking state to the original state in the argument+  -- passed to a 'mask'ed function.+  | WillResetMasking Bool MaskingState+  -- ^ Will return to an earlier masking state.  If 'True', this is+  -- being used to return to the state of the masked block in the+  -- argument passed to a 'mask'ed function.+  | WillLiftIO+  -- ^ Will lift an IO action. Note that this can only happen with+  -- 'ConcIO'.+  | WillReturn+  -- ^ Will execute a 'return' or 'pure' action.+  | WillMessage Dynamic+  -- ^ Will process a _concMessage' annotation.+  | WillStop+  -- ^ Will cease execution and terminate.+  deriving Show++instance NFData Lookahead where+  rnf (WillSetNumCapabilities i) = rnf i+  rnf (WillPutVar c) = rnf c+  rnf (WillTryPutVar c) = rnf c+  rnf (WillReadVar c) = rnf c+  rnf (WillTakeVar c) = rnf c+  rnf (WillTryTakeVar c) = rnf c+  rnf (WillReadRef c) = rnf c+  rnf (WillReadRefCas c) = rnf c+  rnf (WillModRef c) = rnf c+  rnf (WillModRefCas c) = rnf c+  rnf (WillWriteRef c) = rnf c+  rnf (WillCasRef c) = rnf c+  rnf (WillCommitRef t c) = rnf (t, c)+  rnf (WillThrowTo t) = rnf t+  rnf (WillSetMasking b m) = b `seq` m `seq` ()+  rnf (WillResetMasking b m) = b `seq` m `seq` ()+  rnf (WillMessage m) = m `seq` ()+  rnf l = l `seq` ()++-- | Convert a 'ThreadAction' into a 'Lookahead': \"rewind\" what has+-- happened. 'Killed' has no 'Lookahead' counterpart.+rewind :: ThreadAction -> Maybe Lookahead+rewind (Fork _) = Just WillFork+rewind MyThreadId = Just WillMyThreadId+rewind (GetNumCapabilities _) = Just WillGetNumCapabilities+rewind (SetNumCapabilities i) = Just (WillSetNumCapabilities i)+rewind Yield = Just WillYield+rewind (NewVar _) = Just WillNewVar+rewind (PutVar c _) = Just (WillPutVar c)+rewind (BlockedPutVar c) = Just (WillPutVar c)+rewind (TryPutVar c _ _) = Just (WillTryPutVar c)+rewind (ReadVar c) = Just (WillReadVar c)+rewind (BlockedReadVar c) = Just (WillReadVar c)+rewind (TakeVar c _) = Just (WillTakeVar c)+rewind (BlockedTakeVar c) = Just (WillTakeVar c)+rewind (TryTakeVar c _ _) = Just (WillTryTakeVar c)+rewind (NewRef _) = Just WillNewRef+rewind (ReadRef c) = Just (WillReadRef c)+rewind (ReadRefCas c) = Just (WillReadRefCas c)+rewind (ModRef c) = Just (WillModRef c)+rewind (ModRefCas c) = Just (WillModRefCas c)+rewind (WriteRef c) = Just (WillWriteRef c)+rewind (CasRef c _) = Just (WillCasRef c)+rewind (CommitRef t c) = Just (WillCommitRef t c)+rewind (STM _ _) = Just WillSTM+rewind (BlockedSTM _) = Just WillSTM+rewind Catching = Just WillCatching+rewind PopCatching = Just WillPopCatching+rewind Throw = Just WillThrow+rewind (ThrowTo t) = Just (WillThrowTo t)+rewind (BlockedThrowTo t) = Just (WillThrowTo t)+rewind Killed = Nothing+rewind (SetMasking b m) = Just (WillSetMasking b m)+rewind (ResetMasking b m) = Just (WillResetMasking b m)+rewind LiftIO = Just WillLiftIO+rewind Return = Just WillReturn+rewind (Message m) = Just (WillMessage m)+rewind Stop = Just WillStop++-- | Check if an operation could enable another thread.+willRelease :: Lookahead -> Bool+willRelease WillFork = True+willRelease WillYield = True+willRelease (WillPutVar _) = True+willRelease (WillTryPutVar _) = True+willRelease (WillReadVar _) = True+willRelease (WillTakeVar _) = True+willRelease (WillTryTakeVar _) = True+willRelease WillSTM = True+willRelease WillThrow = True+willRelease (WillSetMasking _ _) = True+willRelease (WillResetMasking _ _) = True+willRelease WillStop = True+willRelease _ = False++---------------------------------------+-- Simplified actions++-- | A simplified view of the possible actions a thread can perform.+data ActionType =+    UnsynchronisedRead  CRefId+  -- ^ A 'readCRef' or a 'readForCAS'.+  | UnsynchronisedWrite CRefId+  -- ^ A 'writeCRef'.+  | UnsynchronisedOther+  -- ^ Some other action which doesn't require cross-thread+  -- communication.+  | PartiallySynchronisedCommit CRefId+  -- ^ A commit.+  | PartiallySynchronisedWrite  CRefId+  -- ^ A 'casCRef'+  | PartiallySynchronisedModify CRefId+  -- ^ A 'modifyCRefCAS'+  | SynchronisedModify  CRefId+  -- ^ An 'atomicModifyCRef'.+  | SynchronisedRead    MVarId+  -- ^ A 'readMVar' or 'takeMVar' (or @try@/@blocked@ variants).+  | SynchronisedWrite   MVarId+  -- ^ A 'putMVar' (or @try@/@blocked@ variant).+  | SynchronisedOther+  -- ^ Some other action which does require cross-thread+  -- communication.+  deriving (Eq, Show)++instance NFData ActionType where+  rnf (UnsynchronisedRead  r) = rnf r+  rnf (UnsynchronisedWrite r) = rnf r+  rnf (PartiallySynchronisedCommit r) = rnf r+  rnf (PartiallySynchronisedWrite  r) = rnf r+  rnf (PartiallySynchronisedModify  r) = rnf r+  rnf (SynchronisedModify  r) = rnf r+  rnf (SynchronisedRead    c) = rnf c+  rnf (SynchronisedWrite   c) = rnf c+  rnf a = a `seq` ()++-- | Check if an action imposes a write barrier.+isBarrier :: ActionType -> Bool+isBarrier (SynchronisedModify _) = True+isBarrier (SynchronisedRead   _) = True+isBarrier (SynchronisedWrite  _) = True+isBarrier SynchronisedOther = True+isBarrier _ = False++-- | Check if an action commits a given 'CRef'.+isCommit :: ActionType -> CRefId -> Bool+isCommit (PartiallySynchronisedCommit c) r = c == r+isCommit (PartiallySynchronisedWrite  c) r = c == r+isCommit (PartiallySynchronisedModify c) r = c == r+isCommit _ _ = False++-- | Check if an action synchronises a given 'CRef'.+synchronises :: ActionType -> CRefId -> Bool+synchronises a r = isCommit a r || isBarrier a++-- | Get the 'CRef' affected.+crefOf :: ActionType -> Maybe CRefId+crefOf (UnsynchronisedRead  r) = Just r+crefOf (UnsynchronisedWrite r) = Just r+crefOf (SynchronisedModify  r) = Just r+crefOf (PartiallySynchronisedCommit r) = Just r+crefOf (PartiallySynchronisedWrite  r) = Just r+crefOf (PartiallySynchronisedModify r) = Just r+crefOf _ = Nothing++-- | Get the 'MVar' affected.+mvarOf :: ActionType -> Maybe MVarId+mvarOf (SynchronisedRead  c) = Just c+mvarOf (SynchronisedWrite c) = Just c+mvarOf _ = Nothing++-- | Throw away information from a 'ThreadAction' and give a+-- simplified view of what is happening.+--+-- This is used in the SCT code to help determine interesting+-- alternative scheduling decisions.+simplifyAction :: ThreadAction -> ActionType+simplifyAction = maybe UnsynchronisedOther simplifyLookahead . rewind++-- | Variant of 'simplifyAction' that takes a 'Lookahead'.+simplifyLookahead :: Lookahead -> ActionType+simplifyLookahead (WillPutVar c)     = SynchronisedWrite c+simplifyLookahead (WillTryPutVar c)  = SynchronisedWrite c+simplifyLookahead (WillReadVar c)    = SynchronisedRead c+simplifyLookahead (WillTakeVar c)    = SynchronisedRead c+simplifyLookahead (WillTryTakeVar c) = SynchronisedRead c+simplifyLookahead (WillReadRef r)     = UnsynchronisedRead r+simplifyLookahead (WillReadRefCas r)  = UnsynchronisedRead r+simplifyLookahead (WillModRef r)      = SynchronisedModify r+simplifyLookahead (WillModRefCas r)   = PartiallySynchronisedModify r+simplifyLookahead (WillWriteRef r)    = UnsynchronisedWrite r+simplifyLookahead (WillCasRef r)      = PartiallySynchronisedWrite r+simplifyLookahead (WillCommitRef _ r) = PartiallySynchronisedCommit r+simplifyLookahead WillSTM         = SynchronisedOther+simplifyLookahead (WillThrowTo _) = SynchronisedOther+simplifyLookahead _ = UnsynchronisedOther++---------------------------------------+-- STM actions++-- | A trace of an STM transaction is just a list of actions that+-- occurred, as there are no scheduling decisions to make.+type TTrace = [TAction]++-- | All the actions that an STM transaction can perform.+data TAction =+    TNew+  -- ^ Create a new @TVar@+  | TRead  TVarId+  -- ^ Read from a @TVar@.+  | TWrite TVarId+  -- ^ Write to a @TVar@.+  | TRetry+  -- ^ Abort and discard effects.+  | TOrElse TTrace (Maybe TTrace)+  -- ^ Execute a transaction until it succeeds (@STMStop@) or aborts+  -- (@STMRetry@) and, if it aborts, execute the other transaction.+  | TThrow+  -- ^ Throw an exception, abort, and discard effects.+  | TCatch TTrace (Maybe TTrace)+  -- ^ Execute a transaction until it succeeds (@STMStop@) or aborts+  -- (@STMThrow@). If the exception is of the appropriate type, it is+  -- handled and execution continues; otherwise aborts, propagating+  -- the exception upwards.+  | TStop+  -- ^ Terminate successfully and commit effects.+  deriving (Eq, Show)++instance NFData TAction where+  rnf (TRead  v) = rnf v+  rnf (TWrite v) = rnf v+  rnf (TCatch  s m) = rnf (s, m)+  rnf (TOrElse s m) = rnf (s, m)+  rnf a = a `seq` ()++-------------------------------------------------------------------------------+-- Traces++-- | Pretty-print a trace, including a key of the thread IDs (not+-- including thread 0). Each line of the key is indented by two+-- spaces.+showTrace :: Trace ThreadId ThreadAction Lookahead -> String+showTrace trc = intercalate "\n" $ concatMap go trc : strkey where+  go (_,_,CommitRef _ _) = "C-"+  go (Start    (ThreadId _ i),_,_) = "S" ++ show i ++ "-"+  go (SwitchTo (ThreadId _ i),_,_) = "P" ++ show i ++ "-"+  go (Continue,_,_) = "-"++  strkey = ["  " ++ show i ++ ": " ++ name | (i, name) <- key]++  key = sort . nub $ mapMaybe toKey trc where+    toKey (Start (ThreadId (Just name) i), _, _)+      | i > 0 = Just (i, name)+    toKey _ = Nothing++-- | Count the number of pre-emptions in a schedule prefix.+--+-- Commit threads complicate this a bit. Conceptually, commits are+-- happening truly in parallel, nondeterministically. The commit+-- thread implementation is just there to unify the two sources of+-- nondeterminism: commit timing and thread scheduling.+--+-- SO, we don't count a switch TO a commit thread as a+-- preemption. HOWEVER, the switch FROM a commit thread counts as a+-- preemption if it is not to the thread that the commit interrupted.+preEmpCount :: [(Decision ThreadId, ThreadAction)]+            -> (Decision ThreadId, Lookahead)+            -> Int+preEmpCount ts (d, _) = go initialThread Nothing ts where+  go _ (Just Yield) ((SwitchTo t, a):rest) = go t (Just a) rest+  go tid prior ((SwitchTo t, a):rest)+    | isCommitThread t = go tid prior (skip rest)+    | otherwise = 1 + go t (Just a) rest+  go _   _ ((Start t,  a):rest) = go t   (Just a) rest+  go tid _ ((Continue, a):rest) = go tid (Just a) rest+  go _ prior [] = case (prior, d) of+    (Just Yield, SwitchTo _) -> 0+    (_, SwitchTo _) -> 1+    _ -> 0++  -- Commit threads have negative thread IDs for easy identification.+  isCommitThread = (< initialThread)++  -- Skip until the next context switch.+  skip = dropWhile (not . isContextSwitch . fst)+  isContextSwitch Continue = False+  isContextSwitch _ = True++-------------------------------------------------------------------------------+-- Failures+++-- | An indication of how a concurrent computation failed.+data Failure =+    InternalError+  -- ^ Will be raised if the scheduler does something bad. This should+  -- never arise unless you write your own, faulty, scheduler! If it+  -- does, please file a bug report.+  | Abort+  -- ^ The scheduler chose to abort execution. This will be produced+  -- if, for example, all possible decisions exceed the specified+  -- bounds (there have been too many pre-emptions, the computation+  -- has executed for too long, or there have been too many yields).+  | Deadlock+  -- ^ The computation became blocked indefinitely on @MVar@s.+  | STMDeadlock+  -- ^ The computation became blocked indefinitely on @TVar@s.+  | UncaughtException+  -- ^ An uncaught exception bubbled to the top of the computation.+  deriving (Eq, Show, Read, Ord, Enum, Bounded)++instance NFData Failure where+  rnf f = f `seq` ()++-- | Pretty-print a failure+showFail :: Failure -> String+showFail Abort             = "[abort]"+showFail Deadlock          = "[deadlock]"+showFail STMDeadlock       = "[stm-deadlock]"+showFail InternalError     = "[internal-error]"+showFail UncaughtException = "[exception]"++-------------------------------------------------------------------------------+-- Memory Models++-- | The memory model to use for non-synchronised 'CRef' operations.+data MemType =+    SequentialConsistency+  -- ^ The most intuitive model: a program behaves as a simple+  -- interleaving of the actions in different threads. When a 'CRef'+  -- is written to, that write is immediately visible to all threads.+  | TotalStoreOrder+  -- ^ Each thread has a write buffer. A thread sees its writes+  -- immediately, but other threads will only see writes when they are+  -- committed, which may happen later. Writes are committed in the+  -- same order that they are created.+  | PartialStoreOrder+  -- ^ Each 'CRef' has a write buffer. A thread sees its writes+  -- immediately, but other threads will only see writes when they are+  -- committed, which may happen later. Writes to different 'CRef's+  -- are not necessarily committed in the same order that they are+  -- created.+  deriving (Eq, Show, Read, Ord, Enum, Bounded)++instance NFData MemType where+  rnf m = m `seq` ()++-------------------------------------------------------------------------------+-- Utilities++-- | Helper for @next*@+nextId :: String -> [String] -> (Maybe String, [String])+nextId name used = (newName, newUsed) where+  newName+    | null name = Nothing+    | occurrences > 0 = Just (name ++ "-" ++ show occurrences)+    | otherwise = Just name+  newUsed+    | null name = used+    | otherwise = name : used+  occurrences = length (filter (==name) used)
+ Test/DejaFu/Conc.hs view
@@ -0,0 +1,200 @@+{-# LANGUAGE FlexibleInstances          #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses      #-}+{-# LANGUAGE RankNTypes                 #-}+{-# LANGUAGE TypeFamilies               #-}+{-# LANGUAGE TypeSynonymInstances       #-}++-- |+-- Module      : Test.DejaFu.Conc+-- Copyright   : (c) 2016 Michael Walker+-- License     : MIT+-- Maintainer  : Michael Walker <mike@barrucadu.co.uk>+-- Stability   : experimental+-- Portability : FlexibleInstances, GeneralizedNewtypeDeriving, MultiParamTypeClasses, RankNTypes, TypeFamilies, TypeSynonymInstances+--+-- Deterministic traced execution of concurrent computations.+--+-- This works by executing the computation on a single thread, calling+-- out to the supplied scheduler after each step to determine which+-- thread runs next.+module Test.DejaFu.Conc+  ( -- * The @Conc@ Monad+    Conc+  , ConcST+  , ConcIO++  -- * Executing computations+  , Failure(..)+  , MemType(..)+  , runConcurrent++  -- * Execution traces+  , Trace+  , Decision(..)+  , ThreadId(..)+  , ThreadAction(..)+  , Lookahead(..)+  , MVarId+  , CRefId+  , MaskingState(..)+  , showTrace+  , showFail++  -- * Scheduling+  , module Test.DPOR.Schedule+  ) where++import Control.Exception (MaskingState(..))+import qualified Control.Monad.Base as Ba+import qualified Control.Monad.Catch as Ca+import qualified Control.Monad.IO.Class as IO+import Control.Monad.Ref (MonadRef, newRef, readRef, writeRef)+import Control.Monad.ST (ST)+import Data.Dynamic (toDyn)+import Data.IORef (IORef)+import qualified Data.Map.Strict as M+import Data.Maybe (fromJust)+import Data.STRef (STRef)+import Test.DPOR.Schedule++import qualified Control.Monad.Conc.Class as C+import Test.DejaFu.Common+import Test.DejaFu.Conc.Internal+import Test.DejaFu.Conc.Internal.Common+import Test.DejaFu.Conc.Internal.Threading+import Test.DejaFu.STM++{-# ANN module ("HLint: ignore Avoid lambda" :: String) #-}+{-# ANN module ("HLint: ignore Use const"    :: String) #-}++newtype Conc n r a = C { unC :: M n r (STMLike n r) a } deriving (Functor, Applicative, Monad)++-- | A 'MonadConc' implementation using @ST@, this should be preferred+-- if you do not need 'liftIO'.+type ConcST t = Conc (ST t) (STRef t)++-- | A 'MonadConc' implementation using @IO@.+type ConcIO = Conc IO IORef++toConc :: ((a -> Action n r (STMLike n r)) -> Action n r (STMLike n r)) -> Conc n r a+toConc = C . cont++wrap :: (M n r (STMLike n r) a -> M n r (STMLike n r) a) -> Conc n r a -> Conc n r a+wrap f = C . f . unC++instance IO.MonadIO ConcIO where+  liftIO ma = toConc (\c -> ALift (fmap c ma))++instance Ba.MonadBase IO ConcIO where+  liftBase = IO.liftIO++instance Ca.MonadCatch (Conc n r) where+  catch ma h = toConc (ACatching (unC . h) (unC ma))++instance Ca.MonadThrow (Conc n r) where+  throwM e = toConc (\_ -> AThrow e)++instance Ca.MonadMask (Conc n r) where+  mask                mb = toConc (AMasking MaskedInterruptible   (\f -> unC $ mb $ wrap f))+  uninterruptibleMask mb = toConc (AMasking MaskedUninterruptible (\f -> unC $ mb $ wrap f))++instance Monad n => C.MonadConc (Conc n r) where+  type MVar     (Conc n r) = MVar r+  type CRef     (Conc n r) = CRef r+  type Ticket   (Conc n r) = Ticket+  type STM      (Conc n r) = STMLike n r+  type ThreadId (Conc n r) = ThreadId++  -- ----------++  forkWithUnmaskN   n ma = toConc (AFork n (\umask -> runCont (unC $ ma $ wrap umask) (\_ -> AStop (pure ()))))+  forkOnWithUnmaskN n _  = C.forkWithUnmaskN n++  -- This implementation lies and returns 2 until a value is set. This+  -- will potentially avoid special-case behaviour for 1 capability,+  -- so it seems a sane choice.+  getNumCapabilities      = toConc AGetNumCapabilities+  setNumCapabilities caps = toConc (\c -> ASetNumCapabilities caps (c ()))++  myThreadId = toConc AMyTId++  yield = toConc (\c -> AYield (c ()))++  -- ----------++  newCRefN n a = toConc (\c -> ANewRef n a c)++  readCRef   ref = toConc (AReadRef    ref)+  readForCAS ref = toConc (AReadRefCas ref)++  peekTicket' _ = _ticketVal++  writeCRef ref      a = toConc (\c -> AWriteRef ref a (c ()))+  casCRef   ref tick a = toConc (ACasRef ref tick a)++  atomicModifyCRef ref f = toConc (AModRef    ref f)+  modifyCRefCAS    ref f = toConc (AModRefCas ref f)++  -- ----------++  newEmptyMVarN n = toConc (\c -> ANewVar n c)++  putMVar  var a = toConc (\c -> APutVar var a (c ()))+  readMVar var   = toConc (AReadVar var)+  takeMVar var   = toConc (ATakeVar var)++  tryPutMVar  var a = toConc (ATryPutVar  var a)+  tryTakeMVar var   = toConc (ATryTakeVar var)++  -- ----------++  throwTo tid e = toConc (\c -> AThrowTo tid e (c ()))++  -- ----------++  atomically = toConc . AAtom++  -- ----------++  _concMessage msg = toConc (\c -> AMessage (toDyn msg) (c ()))++-- | Run a concurrent computation with a given 'Scheduler' and initial+-- state, returning a failure reason on error. Also returned is the+-- final state of the scheduler, and an execution trace.+--+-- __Warning:__ Blocking on the action of another thread in 'liftIO'+-- cannot be detected! So if you perform some potentially blocking+-- action in a 'liftIO' the entire collection of threads may deadlock!+-- You should therefore keep @IO@ blocks small, and only perform+-- blocking operations with the supplied primitives, insofar as+-- possible.+--+-- __Note:__ In order to prevent computation from hanging, the runtime+-- will assume that a deadlock situation has arisen if the scheduler+-- attempts to (a) schedule a blocked thread, or (b) schedule a+-- nonexistent thread. In either of those cases, the computation will+-- be halted.+runConcurrent :: MonadRef r n+              => Scheduler ThreadId ThreadAction Lookahead s+              -> MemType+              -> s+              -> Conc n r a+              -> n (Either Failure a, s, Trace ThreadId ThreadAction Lookahead)+runConcurrent sched memtype s (C conc) = do+  ref <- newRef Nothing++  let c = runCont conc (AStop . writeRef ref . Just . Right)+  let threads = launch' Unmasked initialThread (const c) M.empty++  (s', trace) <- runThreads runTransaction+                           sched+                           memtype+                           s+                           threads+                           initialIdSource+                           ref++  out <- readRef ref++  pure (fromJust out, s', reverse trace)
+ Test/DejaFu/Conc/Internal.hs view
@@ -0,0 +1,385 @@+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE RankNTypes          #-}+{-# LANGUAGE ScopedTypeVariables #-}++-- |+-- Module      : Test.DejaFu.Conc.Internal+-- Copyright   : (c) 2016 Michael Walker+-- License     : MIT+-- Maintainer  : Michael Walker <mike@barrucadu.co.uk>+-- Stability   : experimental+-- Portability : RankNTypes, ScopedTypeVariables+--+-- Concurrent monads with a fixed scheduler: internal types and+-- functions. This module is NOT considered to form part of the public+-- interface of this library.+module Test.DejaFu.Conc.Internal where++import Control.Exception (MaskingState(..), toException)+import Control.Monad.Ref (MonadRef, newRef, writeRef)+import Data.Functor (void)+import Data.List (sort)+import Data.List.NonEmpty (NonEmpty(..), fromList)+import qualified Data.Map.Strict as M+import Data.Maybe (fromJust, isJust, isNothing, listToMaybe)+import Test.DPOR (Scheduler)++import Test.DejaFu.Common+import Test.DejaFu.Conc.Internal.Common+import Test.DejaFu.Conc.Internal.Memory+import Test.DejaFu.Conc.Internal.Threading+import Test.DejaFu.STM (Result(..))++{-# ANN module ("HLint: ignore Use record patterns" :: String) #-}+{-# ANN module ("HLint: ignore Use const"           :: String) #-}++--------------------------------------------------------------------------------+-- * Execution++-- | Run a collection of threads, until there are no threads left.+--+-- Note: this returns the trace in reverse order, because it's more+-- efficient to prepend to a list than append. As this function isn't+-- exposed to users of the library, this is just an internal gotcha to+-- watch out for.+runThreads :: MonadRef r n => (forall x. s x -> IdSource -> n (Result x, IdSource, TTrace))+           -> Scheduler ThreadId ThreadAction Lookahead g -> MemType -> g -> Threads n r s -> IdSource -> r (Maybe (Either Failure a)) -> n (g, Trace ThreadId ThreadAction Lookahead)+runThreads runstm sched memtype origg origthreads idsrc ref = go idsrc [] Nothing origg origthreads emptyBuffer 2 where+  go idSource sofar prior g threads wb caps+    | isTerminated  = stop g+    | isDeadlocked  = die g Deadlock+    | isSTMLocked   = die g STMDeadlock+    | isAborted     = die g' Abort+    | isNonexistant = die g' InternalError+    | isBlocked     = die g' InternalError+    | otherwise = do+      stepped <- stepThread runstm memtype (_continuation $ fromJust thread) idSource chosen threads wb caps+      case stepped of+        Right (threads', idSource', act, wb', caps') -> loop threads' idSource' act wb' caps'++        Left UncaughtException+          | chosen == initialThread -> die g' UncaughtException+          | otherwise -> loop (kill chosen threads) idSource Killed wb caps++        Left failure -> die g' failure++    where+      (choice, g')  = sched (map (\(d,_,a) -> (d,a)) $ reverse sofar) ((\p (_,_,a) -> (p,a)) <$> prior <*> listToMaybe sofar) (fromList $ map (\(t,l:|_) -> (t,l)) runnable') g+      chosen        = fromJust choice+      runnable'     = [(t, nextActions t) | t <- sort $ M.keys runnable]+      runnable      = M.filter (isNothing . _blocking) threadsc+      thread        = M.lookup chosen threadsc+      threadsc      = addCommitThreads wb threads+      isAborted     = isNothing choice+      isBlocked     = isJust . _blocking $ fromJust thread+      isNonexistant = isNothing thread+      isTerminated  = initialThread `notElem` M.keys threads+      isDeadlocked  = M.null (M.filter (isNothing . _blocking) threads) &&+        (((~=  OnMVarFull  undefined) <$> M.lookup initialThread threads) == Just True ||+         ((~=  OnMVarEmpty undefined) <$> M.lookup initialThread threads) == Just True ||+         ((~=  OnMask      undefined) <$> M.lookup initialThread threads) == Just True)+      isSTMLocked = M.null (M.filter (isNothing . _blocking) threads) &&+        ((~=  OnTVar []) <$> M.lookup initialThread threads) == Just True++      unblockWaitingOn tid = fmap unblock where+        unblock thrd = case _blocking thrd of+          Just (OnMask t) | t == tid -> thrd { _blocking = Nothing }+          _ -> thrd++      decision+        | Just chosen == prior = Continue+        | prior `notElem` map (Just . fst) runnable' = Start chosen+        | otherwise = SwitchTo chosen++      nextActions t = lookahead . _continuation . fromJust $ M.lookup t threadsc++      stop outg = pure (outg, sofar)+      die  outg reason = writeRef ref (Just $ Left reason) >> stop outg++      loop threads' idSource' act wb' =+        let sofar' = ((decision, runnable', act) : sofar)+            threads'' = if (interruptible <$> M.lookup chosen threads') /= Just False then unblockWaitingOn chosen threads' else threads'+        in go idSource' sofar' (Just chosen) g' (delCommitThreads threads'') wb'++--------------------------------------------------------------------------------+-- * Single-step execution++-- | Run a single thread one step, by dispatching on the type of+-- 'Action'.+stepThread :: forall n r s. MonadRef r n+  => (forall x. s x -> IdSource -> n (Result x, IdSource, TTrace))+  -- ^ Run a 'MonadSTM' transaction atomically.+  -> MemType+  -- ^ The memory model+  -> Action n r s+  -- ^ Action to step+  -> IdSource+  -- ^ Source of fresh IDs+  -> ThreadId+  -- ^ ID of the current thread+  -> Threads n r s+  -- ^ Current state of threads+  -> WriteBuffer r+  -- ^ @CRef@ write buffer+  -> Int+  -- ^ The number of capabilities+  -> n (Either Failure (Threads n r s, IdSource, ThreadAction, WriteBuffer r, Int))+stepThread runstm memtype action idSource tid threads wb caps = case action of+  AFork    n a b   -> stepFork        n a b+  AMyTId   c       -> stepMyTId       c+  AGetNumCapabilities   c -> stepGetNumCapabilities c+  ASetNumCapabilities i c -> stepSetNumCapabilities i c+  AYield   c       -> stepYield       c+  ANewVar  n c     -> stepNewVar      n c+  APutVar  var a c -> stepPutVar      var a c+  ATryPutVar var a c -> stepTryPutVar var a c+  AReadVar var c   -> stepReadVar     var c+  ATakeVar var c   -> stepTakeVar     var c+  ATryTakeVar var c -> stepTryTakeVar var c+  ANewRef  n a c   -> stepNewRef      n a c+  AReadRef ref c   -> stepReadRef     ref c+  AReadRefCas ref c -> stepReadRefCas ref c+  AModRef  ref f c -> stepModRef      ref f c+  AModRefCas ref f c -> stepModRefCas ref f c+  AWriteRef ref a c -> stepWriteRef   ref a c+  ACasRef ref tick a c -> stepCasRef ref tick a c+  ACommit  t c     -> stepCommit      t c+  AAtom    stm c   -> stepAtom        stm c+  ALift    na      -> stepLift        na+  AThrow   e       -> stepThrow       e+  AThrowTo t e c   -> stepThrowTo     t e c+  ACatching h ma c -> stepCatching    h ma c+  APopCatching a   -> stepPopCatching a+  AMasking m ma c  -> stepMasking     m ma c+  AResetMask b1 b2 m c -> stepResetMask b1 b2 m c+  AReturn     c    -> stepReturn c+  AMessage    m c  -> stepMessage m c+  AStop       na   -> stepStop na++  where+    -- | Start a new thread, assigning it the next 'ThreadId'+    --+    -- Explicit type signature needed for GHC 8. Looks like the+    -- impredicative polymorphism checks got stronger.+    stepFork :: String+             -> ((forall b. M n r s b -> M n r s b) -> Action n r s)+             -> (ThreadId -> Action n r s)+             -> n (Either Failure (Threads n r s, IdSource, ThreadAction, WriteBuffer r, Int))+    stepFork n a b = return $ Right (goto (b newtid) tid threads', idSource', Fork newtid, wb, caps) where+      threads' = launch tid newtid a threads+      (idSource', newtid) = nextTId n idSource++    -- | Get the 'ThreadId' of the current thread+    stepMyTId c = simple (goto (c tid) tid threads) MyThreadId++    -- | Get the number of capabilities+    stepGetNumCapabilities c = simple (goto (c caps) tid threads) $ GetNumCapabilities caps++    -- | Set the number of capabilities+    stepSetNumCapabilities i c = return $ Right (goto c tid threads, idSource, SetNumCapabilities i, wb, i)++    -- | Yield the current thread+    stepYield c = simple (goto c tid threads) Yield++    -- | Put a value into a @MVar@, blocking the thread until it's+    -- empty.+    stepPutVar cvar@(MVar cvid _) a c = synchronised $ do+      (success, threads', woken) <- putIntoMVar cvar a c tid threads+      simple threads' $ if success then PutVar cvid woken else BlockedPutVar cvid++    -- | Try to put a value into a @MVar@, without blocking.+    stepTryPutVar cvar@(MVar cvid _) a c = synchronised $ do+      (success, threads', woken) <- tryPutIntoMVar cvar a c tid threads+      simple threads' $ TryPutVar cvid success woken++    -- | Get the value from a @MVar@, without emptying, blocking the+    -- thread until it's full.+    stepReadVar cvar@(MVar cvid _) c = synchronised $ do+      (success, threads', _) <- readFromMVar cvar c tid threads+      simple threads' $ if success then ReadVar cvid else BlockedReadVar cvid++    -- | Take the value from a @MVar@, blocking the thread until it's+    -- full.+    stepTakeVar cvar@(MVar cvid _) c = synchronised $ do+      (success, threads', woken) <- takeFromMVar cvar c tid threads+      simple threads' $ if success then TakeVar cvid woken else BlockedTakeVar cvid++    -- | Try to take the value from a @MVar@, without blocking.+    stepTryTakeVar cvar@(MVar cvid _) c = synchronised $ do+      (success, threads', woken) <- tryTakeFromMVar cvar c tid threads+      simple threads' $ TryTakeVar cvid success woken++    -- | Read from a @CRef@.+    stepReadRef cref@(CRef crid _) c = do+      val <- readCRef cref tid+      simple (goto (c val) tid threads) $ ReadRef crid++    -- | Read from a @CRef@ for future compare-and-swap operations.+    stepReadRefCas cref@(CRef crid _) c = do+      tick <- readForTicket cref tid+      simple (goto (c tick) tid threads) $ ReadRefCas crid++    -- | Modify a @CRef@.+    stepModRef cref@(CRef crid _) f c = synchronised $ do+      (new, val) <- f <$> readCRef cref tid+      writeImmediate cref new+      simple (goto (c val) tid threads) $ ModRef crid++    -- | Modify a @CRef@ using a compare-and-swap.+    stepModRefCas cref@(CRef crid _) f c = synchronised $ do+      tick@(Ticket _ _ old) <- readForTicket cref tid+      let (new, val) = f old+      void $ casCRef cref tid tick new+      simple (goto (c val) tid threads) $ ModRefCas crid++    -- | Write to a @CRef@ without synchronising+    stepWriteRef cref@(CRef crid _) a c = case memtype of+      -- Write immediately.+      SequentialConsistency -> do+        writeImmediate cref a+        simple (goto c tid threads) $ WriteRef crid++      -- Add to buffer using thread id.+      TotalStoreOrder -> do+        wb' <- bufferWrite wb (tid, Nothing) cref a+        return $ Right (goto c tid threads, idSource, WriteRef crid, wb', caps)++      -- Add to buffer using both thread id and cref id+      PartialStoreOrder -> do+        wb' <- bufferWrite wb (tid, Just crid) cref a+        return $ Right (goto c tid threads, idSource, WriteRef crid, wb', caps)++    -- | Perform a compare-and-swap on a @CRef@.+    stepCasRef cref@(CRef crid _) tick a c = synchronised $ do+      (suc, tick') <- casCRef cref tid tick a+      simple (goto (c (suc, tick')) tid threads) $ CasRef crid suc++    -- | Commit a @CRef@ write+    stepCommit t c = do+      wb' <- case memtype of+        -- Shouldn't ever get here+        SequentialConsistency ->+          error "Attempting to commit under SequentialConsistency"++        -- Commit using the thread id.+        TotalStoreOrder -> commitWrite wb (t, Nothing)++        -- Commit using the cref id.+        PartialStoreOrder -> commitWrite wb (t, Just c)++      return $ Right (threads, idSource, CommitRef t c, wb', caps)++    -- | Run a STM transaction atomically.+    stepAtom stm c = synchronised $ do+      (res, idSource', trace) <- runstm stm idSource+      case res of+        Success _ written val ->+          let (threads', woken) = wake (OnTVar written) threads+          in return $ Right (goto (c val) tid threads', idSource', STM trace woken, wb, caps)+        Retry touched ->+          let threads' = block (OnTVar touched) tid threads+          in return $ Right (threads', idSource', BlockedSTM trace, wb, caps)+        Exception e -> do+          res' <- stepThrow e+          return $ case res' of+            Right (threads', _, _, _, _) -> Right (threads', idSource', Throw, wb, caps)+            Left err -> Left err++    -- | Run a subcomputation in an exception-catching context.+    stepCatching h ma c = simple threads' Catching where+      a     = runCont ma      (APopCatching . c)+      e exc = runCont (h exc) (APopCatching . c)++      threads' = goto a tid (catching e tid threads)++    -- | Pop the top exception handler from the thread's stack.+    stepPopCatching a = simple threads' PopCatching where+      threads' = goto a tid (uncatching tid threads)++    -- | Throw an exception, and propagate it to the appropriate+    -- handler.+    stepThrow e =+      case propagate (toException e) tid threads of+        Just threads' -> simple threads' Throw+        Nothing -> return $ Left UncaughtException++    -- | Throw an exception to the target thread, and propagate it to+    -- the appropriate handler.+    stepThrowTo t e c = synchronised $+      let threads' = goto c tid threads+          blocked  = block (OnMask t) tid threads+      in case M.lookup t threads of+           Just thread+             | interruptible thread -> case propagate (toException e) t threads' of+               Just threads'' -> simple threads'' $ ThrowTo t+               Nothing+                 | t == initialThread -> return $ Left UncaughtException+                 | otherwise -> simple (kill t threads') $ ThrowTo t+             | otherwise -> simple blocked $ BlockedThrowTo t+           Nothing -> simple threads' $ ThrowTo t++    -- | Execute a subcomputation with a new masking state, and give+    -- it a function to run a computation with the current masking+    -- state.+    --+    -- Explicit type sig necessary for checking in the prescence of+    -- 'umask', sadly.+    stepMasking :: MaskingState+                -> ((forall b. M n r s b -> M n r s b) -> M n r s a)+                -> (a -> Action n r s)+                -> n (Either Failure (Threads n r s, IdSource, ThreadAction, WriteBuffer r, Int))+    stepMasking m ma c = simple threads' $ SetMasking False m where+      a = runCont (ma umask) (AResetMask False False m' . c)++      m' = _masking . fromJust $ M.lookup tid threads+      umask mb = resetMask True m' >> mb >>= \b -> resetMask False m >> return b+      resetMask typ ms = cont $ \k -> AResetMask typ True ms $ k ()++      threads' = goto a tid (mask m tid threads)++    -- | Reset the masking thread of the state.+    stepResetMask b1 b2 m c = simple threads' act where+      act      = (if b1 then SetMasking else ResetMasking) b2 m+      threads' = goto c tid (mask m tid threads)++    -- | Create a new @MVar@, using the next 'MVarId'.+    stepNewVar n c = do+      let (idSource', newmvid) = nextMVId n idSource+      ref <- newRef Nothing+      let mvar = MVar newmvid ref+      return $ Right (goto (c mvar) tid threads, idSource', NewVar newmvid, wb, caps)++    -- | Create a new @CRef@, using the next 'CRefId'.+    stepNewRef n a c = do+      let (idSource', newcrid) = nextCRId n idSource+      ref <- newRef (M.empty, 0, a)+      let cref = CRef newcrid ref+      return $ Right (goto (c cref) tid threads, idSource', NewRef newcrid, wb, caps)++    -- | Lift an action from the underlying monad into the @Conc@+    -- computation.+    stepLift na = do+      a <- na+      simple (goto a tid threads) LiftIO++    -- | Execute a 'return' or 'pure'.+    stepReturn c = simple (goto c tid threads) Return++    -- | Add a message to the trace.+    stepMessage m c = simple (goto c tid threads) (Message m)++    -- | Kill the current thread.+    stepStop na = na >> simple (kill tid threads) Stop++    -- | Helper for actions which don't touch the 'IdSource' or+    -- 'WriteBuffer'+    simple threads' act = return $ Right (threads', idSource, act, wb, caps)++    -- | Helper for actions impose a write barrier.+    synchronised ma = do+      writeBarrier wb+      res <- ma++      return $ case res of+        Right (threads', idSource', act', _, caps') -> Right (threads', idSource', act', emptyBuffer, caps')+        _ -> res
+ Test/DejaFu/Conc/Internal/Common.hs view
@@ -0,0 +1,172 @@+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE RankNTypes                #-}++-- |+-- Module      : Test.DejaFu.Conc.Internal.Common+-- Copyright   : (c) 2016 Michael Walker+-- License     : MIT+-- Maintainer  : Michael Walker <mike@barrucadu.co.uk>+-- Stability   : experimental+-- Portability : ExistentialQuantification, RankNTypes+--+-- Common types and utility functions for deterministic execution of+-- 'MonadConc' implementations. This module is NOT considered to form+module Test.DejaFu.Conc.Internal.Common where++import Control.Exception (Exception, MaskingState(..))+import Data.Dynamic (Dynamic)+import Data.Map.Strict (Map)+import Data.List.NonEmpty (NonEmpty, fromList)+import Test.DejaFu.Common++{-# ANN module ("HLint: ignore Use record patterns" :: String) #-}++--------------------------------------------------------------------------------+-- * The @Conc@ Monad++-- | The underlying monad is based on continuations over 'Action's.+--+-- One might wonder why the return type isn't reflected in 'Action',+-- and a free monad formulation used. This would remove the need for a+-- @AStop@ actions having their parameter. However, this makes the+-- current expression of threads and exception handlers very difficult+-- (perhaps even not possible without significant reworking), so I+-- abandoned the attempt.+newtype M n r s a = M { runM :: (a -> Action n r s) -> Action n r s }++instance Functor (M n r s) where+    fmap f m = M $ \ c -> runM m (c . f)++instance Applicative (M n r s) where+    pure x  = M $ \c -> AReturn $ c x+    f <*> v = M $ \c -> runM f (\g -> runM v (c . g))++instance Monad (M n r s) where+    return  = pure+    m >>= k = M $ \c -> runM m (\x -> runM (k x) c)++-- | The concurrent variable type used with the 'Conc' monad. One+-- notable difference between these and 'MVar's is that 'MVar's are+-- single-wakeup, and wake up in a FIFO order. Writing to a @MVar@+-- wakes up all threads blocked on reading it, and it is up to the+-- scheduler which one runs next. Taking from a @MVar@ behaves+-- analogously.+data MVar r a = MVar+  { _cvarId   :: MVarId+  , _cvarVal  :: r (Maybe a)+  }++-- | The mutable non-blocking reference type. These are like 'IORef's.+--+-- @CRef@s are represented as a unique numeric identifier and a+-- reference containing (a) any thread-local non-synchronised writes+-- (so each thread sees its latest write), (b) a commit count (used in+-- compare-and-swaps), and (c) the current value visible to all+-- threads.+data CRef r a = CRef+  { _crefId   :: CRefId+  , _crefVal  :: r (Map ThreadId a, Integer, a)+  }++-- | The compare-and-swap proof type.+--+-- @Ticket@s are represented as just a wrapper around the identifier+-- of the 'CRef' it came from, the commit count at the time it was+-- produced, and an @a@ value. This doesn't work in the source package+-- (atomic-primops) because of the need to use pointer equality. Here+-- we can just pack extra information into 'CRef' to avoid that need.+data Ticket a = Ticket+  { _ticketCRef   :: CRefId+  , _ticketWrites :: Integer+  , _ticketVal    :: a+  }++-- | Construct a continuation-passing operation from a function.+cont :: ((a -> Action n r s) -> Action n r s) -> M n r s a+cont = M++-- | Run a CPS computation with the given final computation.+runCont :: M n r s a -> (a -> Action n r s) -> Action n r s+runCont = runM++--------------------------------------------------------------------------------+-- * Primitive Actions++-- | Scheduling is done in terms of a trace of 'Action's. Blocking can+-- only occur as a result of an action, and they cover (most of) the+-- primitives of the concurrency. 'spawn' is absent as it is+-- implemented in terms of 'newEmptyMVar', 'fork', and 'putMVar'.+data Action n r s =+    AFork  String ((forall b. M n r s b -> M n r s b) -> Action n r s) (ThreadId -> Action n r s)+  | AMyTId (ThreadId -> Action n r s)++  | AGetNumCapabilities (Int -> Action n r s)+  | ASetNumCapabilities Int (Action n r s)++  | forall a. ANewVar String (MVar r a -> Action n r s)+  | forall a. APutVar     (MVar r a) a (Action n r s)+  | forall a. ATryPutVar  (MVar r a) a (Bool -> Action n r s)+  | forall a. AReadVar    (MVar r a) (a -> Action n r s)+  | forall a. ATakeVar    (MVar r a) (a -> Action n r s)+  | forall a. ATryTakeVar (MVar r a) (Maybe a -> Action n r s)++  | forall a.   ANewRef String a (CRef r a -> Action n r s)+  | forall a.   AReadRef    (CRef r a) (a -> Action n r s)+  | forall a.   AReadRefCas (CRef r a) (Ticket a -> Action n r s)+  | forall a b. AModRef     (CRef r a) (a -> (a, b)) (b -> Action n r s)+  | forall a b. AModRefCas  (CRef r a) (a -> (a, b)) (b -> Action n r s)+  | forall a.   AWriteRef   (CRef r a) a (Action n r s)+  | forall a.   ACasRef     (CRef r a) (Ticket a) a ((Bool, Ticket a) -> Action n r s)++  | forall e.   Exception e => AThrow e+  | forall e.   Exception e => AThrowTo ThreadId e (Action n r s)+  | forall a e. Exception e => ACatching (e -> M n r s a) (M n r s a) (a -> Action n r s)+  | APopCatching (Action n r s)+  | forall a. AMasking MaskingState ((forall b. M n r s b -> M n r s b) -> M n r s a) (a -> Action n r s)+  | AResetMask Bool Bool MaskingState (Action n r s)++  | AMessage    Dynamic (Action n r s)++  | forall a. AAtom (s a) (a -> Action n r s)+  | ALift (n (Action n r s))+  | AYield  (Action n r s)+  | AReturn (Action n r s)+  | ACommit ThreadId CRefId+  | AStop (n ())++--------------------------------------------------------------------------------+-- * Scheduling & Traces++-- | Look as far ahead in the given continuation as possible.+lookahead :: Action n r s -> NonEmpty Lookahead+lookahead = fromList . lookahead' where+  lookahead' (AFork _ _ _)           = [WillFork]+  lookahead' (AMyTId _)              = [WillMyThreadId]+  lookahead' (AGetNumCapabilities _) = [WillGetNumCapabilities]+  lookahead' (ASetNumCapabilities i k) = WillSetNumCapabilities i : lookahead' k+  lookahead' (ANewVar _ _)           = [WillNewVar]+  lookahead' (APutVar (MVar c _) _ k)    = WillPutVar c : lookahead' k+  lookahead' (ATryPutVar (MVar c _) _ _) = [WillTryPutVar c]+  lookahead' (AReadVar (MVar c _) _)     = [WillReadVar c]+  lookahead' (ATakeVar (MVar c _) _)     = [WillTakeVar c]+  lookahead' (ATryTakeVar (MVar c _) _)  = [WillTryTakeVar c]+  lookahead' (ANewRef _ _ _)         = [WillNewRef]+  lookahead' (AReadRef (CRef r _) _)     = [WillReadRef r]+  lookahead' (AReadRefCas (CRef r _) _)  = [WillReadRefCas r]+  lookahead' (AModRef (CRef r _) _ _)    = [WillModRef r]+  lookahead' (AModRefCas (CRef r _) _ _) = [WillModRefCas r]+  lookahead' (AWriteRef (CRef r _) _ k) = WillWriteRef r : lookahead' k+  lookahead' (ACasRef (CRef r _) _ _ _) = [WillCasRef r]+  lookahead' (ACommit t c)           = [WillCommitRef t c]+  lookahead' (AAtom _ _)             = [WillSTM]+  lookahead' (AThrow _)              = [WillThrow]+  lookahead' (AThrowTo tid _ k)      = WillThrowTo tid : lookahead' k+  lookahead' (ACatching _ _ _)       = [WillCatching]+  lookahead' (APopCatching k)        = WillPopCatching : lookahead' k+  lookahead' (AMasking ms _ _)       = [WillSetMasking False ms]+  lookahead' (AResetMask b1 b2 ms k) = (if b1 then WillSetMasking else WillResetMasking) b2 ms : lookahead' k+  lookahead' (ALift _)               = [WillLiftIO]+  lookahead' (AMessage m k)          = WillMessage m : lookahead' k+  lookahead' (AYield k)              = WillYield : lookahead' k+  lookahead' (AReturn k)             = WillReturn : lookahead' k+  lookahead' (AStop _)               = [WillStop]
+ Test/DejaFu/Conc/Internal/Memory.hs view
@@ -0,0 +1,211 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE GADTs        #-}+{-# LANGUAGE MultiParamTypeClasses #-}++-- |+-- Module      : Test.DejaFu.Conc.Internal.Memory+-- Copyright   : (c) 2016 Michael Walker+-- License     : MIT+-- Maintainer  : Michael Walker <mike@barrucadu.co.uk>+-- Stability   : experimental+-- Portability : BangPatterns, GADTs+--+-- Operations over @CRef@s and @MVar@s. This module is NOT considered+-- to form part of the public interface of this library.+--+-- Relaxed memory operations over @CRef@s are implemented with an+-- explicit write buffer: one per thread for TSO, and one per+-- thread/variable combination for PSO. Unsynchronised writes append+-- to this buffer, and periodically separate threads commit from these+-- buffers to the \"actual\" @CRef@.+--+-- This model comes from /Dynamic Partial Order Reduction for Relaxed+-- Memory Models/, N. Zhang, M. Kusano, and C. Wang (2015).+module Test.DejaFu.Conc.Internal.Memory where++import Control.Monad (when)+import Control.Monad.Ref (MonadRef, readRef, writeRef)+import Data.Map.Strict (Map)+import Data.Maybe (isJust, fromJust)+import Data.Monoid ((<>))+import Data.Sequence (Seq, ViewL(..), (><), singleton, viewl)++import Test.DejaFu.Common+import Test.DejaFu.Conc.Internal.Common+import Test.DejaFu.Conc.Internal.Threading++import qualified Data.Map.Strict as M++--------------------------------------------------------------------------------+-- * Manipulating @CRef@s++-- | In non-sequentially-consistent memory models, non-synchronised+-- writes get buffered.+--+-- The @CRefId@ parameter is only used under PSO. Under TSO each+-- thread has a single buffer.+newtype WriteBuffer r = WriteBuffer+  { buffer :: Map (ThreadId, Maybe CRefId) (Seq (BufferedWrite r)) }++-- | A buffered write is a reference to the variable, and the value to+-- 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.+data BufferedWrite r where+  BufferedWrite :: ThreadId -> CRef r a -> a -> BufferedWrite r++-- | An empty write buffer.+emptyBuffer :: WriteBuffer r+emptyBuffer = WriteBuffer M.empty++-- | Add a new write to the end of a buffer.+bufferWrite :: MonadRef r n => WriteBuffer r -> (ThreadId, Maybe CRefId) -> CRef r a -> a -> n (WriteBuffer r)+bufferWrite (WriteBuffer wb) k@(tid, _) cref@(CRef _ ref) new = do+  -- Construct the new write buffer+  let write = singleton $ BufferedWrite tid cref new+  let buffer' = M.insertWith (flip (><)) k write wb++  -- Write the thread-local value to the @CRef@'s update map.+  (locals, count, def) <- readRef ref+  writeRef ref (M.insert tid new locals, count, def)++  return $ WriteBuffer buffer'++-- | Commit the write at the head of a buffer.+commitWrite :: MonadRef r n => WriteBuffer r -> (ThreadId, Maybe CRefId) -> n (WriteBuffer r)+commitWrite w@(WriteBuffer wb) k = case maybe EmptyL viewl $ M.lookup k wb of+  BufferedWrite _ cref a :< rest -> do+    writeImmediate cref a+    return . WriteBuffer $ M.insert k rest wb++  EmptyL -> return w++-- | Read from a @CRef@, returning a newer thread-local non-committed+-- write if there is one.+readCRef :: MonadRef r n => CRef r a -> ThreadId -> n a+readCRef cref tid = do+  (val, _) <- readCRefPrim cref tid+  return val++-- | Read from a @CRef@, returning a @Ticket@ representing the current+-- view of the thread.+readForTicket :: MonadRef r n => CRef r a -> ThreadId -> n (Ticket a)+readForTicket cref@(CRef crid _) tid = do+  (val, count) <- readCRefPrim cref tid+  return $ Ticket crid count val++-- | Perform a compare-and-swap on a @CRef@ if the ticket is still+-- valid. This is strict in the \"new\" value argument.+casCRef :: MonadRef r n => CRef r a -> ThreadId -> Ticket a -> a -> n (Bool, Ticket a)+casCRef cref tid (Ticket _ cc _) !new = do+  tick'@(Ticket _ cc' _) <- readForTicket cref tid++  if cc == cc'+  then do+    writeImmediate cref new+    tick'' <- readForTicket cref tid+    return (True, tick'')+  else return (False, tick')++-- | Read the local state of a @CRef@.+readCRefPrim :: MonadRef r n => CRef r a -> ThreadId -> n (a, Integer)+readCRefPrim (CRef _ ref) tid = do+  (vals, count, def) <- readRef ref++  return (M.findWithDefault def tid vals, count)++-- | Write and commit to a @CRef@ immediately, clearing the update map+-- and incrementing the write count.+writeImmediate :: MonadRef r n => CRef r a -> a -> n ()+writeImmediate (CRef _ ref) a = do+  (_, count, _) <- readRef ref+  writeRef ref (M.empty, count + 1, a)++-- | Flush all writes in the buffer.+writeBarrier :: MonadRef r n => WriteBuffer r -> n ()+writeBarrier (WriteBuffer wb) = mapM_ flush $ M.elems wb where+  flush = mapM_ $ \(BufferedWrite _ cref a) -> writeImmediate cref a++-- | Add phantom threads to the thread list to commit pending writes.+addCommitThreads :: WriteBuffer r -> Threads n r s -> Threads n r s+addCommitThreads (WriteBuffer wb) ts = ts <> M.fromList phantoms where+  phantoms = [ (ThreadId Nothing $ negate tid, mkthread $ fromJust c)+             | ((k, b), tid) <- zip (M.toList wb) [1..]+             , let c = go $ viewl b+             , isJust c]+  go (BufferedWrite tid (CRef crid _) _ :< _) = Just $ ACommit tid crid+  go EmptyL = Nothing++-- | Remove phantom threads.+delCommitThreads :: Threads n r s -> Threads n r s+delCommitThreads = M.filterWithKey $ \k _ -> k >= initialThread++--------------------------------------------------------------------------------+-- * Manipulating @MVar@s++-- | Put into a @MVar@, blocking if full.+putIntoMVar :: MonadRef r n => MVar r a -> a -> Action n r s+            -> ThreadId -> Threads n r s -> n (Bool, Threads n r s, [ThreadId])+putIntoMVar cvar a c = mutMVar True cvar a (const c)++-- | Try to put into a @MVar@, not blocking if full.+tryPutIntoMVar :: MonadRef r n => MVar r a -> a -> (Bool -> Action n r s)+               -> ThreadId -> Threads n r s -> n (Bool, Threads n r s, [ThreadId])+tryPutIntoMVar = mutMVar False++-- | Read from a @MVar@, blocking if empty.+readFromMVar :: MonadRef r n => MVar r a -> (a -> Action n r s)+            -> ThreadId -> Threads n r s -> n (Bool, Threads n r s, [ThreadId])+readFromMVar cvar c = seeMVar False True cvar (c . fromJust)++-- | Take from a @MVar@, blocking if empty.+takeFromMVar :: MonadRef r n => MVar r a -> (a -> Action n r s)+             -> ThreadId -> Threads n r s -> n (Bool, Threads n r s, [ThreadId])+takeFromMVar cvar c = seeMVar True True cvar (c . fromJust)++-- | Try to take from a @MVar@, not blocking if empty.+tryTakeFromMVar :: MonadRef r n => MVar r a -> (Maybe a -> Action n r s)+                -> ThreadId -> Threads n r s -> n (Bool, Threads n r s, [ThreadId])+tryTakeFromMVar = seeMVar True False++-- | Mutate a @MVar@, in either a blocking or nonblocking way.+mutMVar :: MonadRef r n+        => Bool -> MVar r a -> a -> (Bool -> Action n r s)+        -> ThreadId -> Threads n r s -> n (Bool, Threads n r s, [ThreadId])+mutMVar blocking (MVar cvid ref) a c threadid threads = do+  val <- readRef ref++  case val of+    Just _+      | blocking ->+        let threads' = block (OnMVarEmpty cvid) threadid threads+        in return (False, threads', [])++      | otherwise ->+        return (False, goto (c False) threadid threads, [])++    Nothing -> do+      writeRef ref $ Just a+      let (threads', woken) = wake (OnMVarFull cvid) threads+      return (True, goto (c True) threadid threads', woken)++-- | Read a @MVar@, in either a blocking or nonblocking+-- way.+seeMVar :: MonadRef r n+        => Bool -> Bool -> MVar r a -> (Maybe a -> Action n r s)+        -> ThreadId -> Threads n r s -> n (Bool, Threads n r s, [ThreadId])+seeMVar emptying blocking (MVar cvid ref) c threadid threads = do+  val <- readRef ref++  case val of+    Just _ -> do+      when emptying $ writeRef ref Nothing+      let (threads', woken) = wake (OnMVarEmpty cvid) threads+      return (True, goto (c val) threadid threads', woken)++    Nothing+      | blocking ->+        let threads' = block (OnMVarFull cvid) threadid threads+        in return (False, threads', [])++      | otherwise ->+        return (False, goto (c Nothing) threadid threads, [])
+ Test/DejaFu/Conc/Internal/Threading.hs view
@@ -0,0 +1,143 @@+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE RankNTypes                #-}++-- |+-- Module      : Test.DejaFu.Conc.Internal.Threading+-- Copyright   : (c) 2016 Michael Walker+-- License     : MIT+-- Maintainer  : Michael Walker <mike@barrucadu.co.uk>+-- Stability   : experimental+-- Portability : ExistentialQuantification, RankNTypes+--+-- Operations and types for threads. This module is NOT considered to+-- form part of the public interface of this library.+module Test.DejaFu.Conc.Internal.Threading where++import Control.Exception (Exception, MaskingState(..), SomeException, fromException)+import Data.List (intersect)+import Data.Map.Strict (Map)+import Data.Maybe (fromMaybe, isJust)++import Test.DejaFu.Common+import Test.DejaFu.Conc.Internal.Common++import qualified Data.Map.Strict as M++--------------------------------------------------------------------------------+-- * Threads++-- | Threads are stored in a map index by 'ThreadId'.+type Threads n r s = Map ThreadId (Thread n r s)++-- | All the state of a thread.+data Thread n r s = Thread+  { _continuation :: Action n r s+  -- ^ The next action to execute.+  , _blocking     :: Maybe BlockedOn+  -- ^ The state of any blocks.+  , _handlers     :: [Handler n r s]+  -- ^ Stack of exception handlers+  , _masking      :: MaskingState+  -- ^ The exception masking state.+  }++-- | Construct a thread with just one action+mkthread :: Action n r s -> Thread n r s+mkthread c = Thread c Nothing [] Unmasked++--------------------------------------------------------------------------------+-- * Blocking++-- | A @BlockedOn@ is used to determine what sort of variable a thread+-- is blocked on.+data BlockedOn = OnMVarFull MVarId | OnMVarEmpty MVarId | OnTVar [TVarId] | OnMask ThreadId deriving Eq++-- | Determine if a thread is blocked in a certain way.+(~=) :: Thread n r s -> BlockedOn -> Bool+thread ~= theblock = case (_blocking thread, theblock) of+  (Just (OnMVarFull  _), OnMVarFull  _) -> True+  (Just (OnMVarEmpty _), OnMVarEmpty _) -> True+  (Just (OnTVar      _), OnTVar      _) -> True+  (Just (OnMask      _), OnMask      _) -> True+  _ -> False++--------------------------------------------------------------------------------+-- * Exceptions++-- | An exception handler.+data Handler n r s = forall e. Exception e => Handler (e -> Action n r s)++-- | Propagate an exception upwards, finding the closest handler+-- which can deal with it.+propagate :: SomeException -> ThreadId -> Threads n r s -> Maybe (Threads n r s)+propagate e tid threads = case M.lookup tid threads >>= go . _handlers of+  Just (act, hs) -> Just $ except act hs tid threads+  Nothing -> Nothing++  where+    go [] = Nothing+    go (Handler h:hs) = maybe (go hs) (\act -> Just (act, hs)) $ h <$> fromException e++-- | Check if a thread can be interrupted by an exception.+interruptible :: Thread n r s -> Bool+interruptible thread = _masking thread == Unmasked || (_masking thread == MaskedInterruptible && isJust (_blocking thread))++-- | Register a new exception handler.+catching :: Exception e => (e -> Action n r s) -> ThreadId -> Threads n r s -> Threads n r s+catching h = M.alter $ \(Just thread) -> Just $ thread { _handlers = Handler h : _handlers thread }++-- | Remove the most recent exception handler.+uncatching :: ThreadId -> Threads n r s -> Threads n r s+uncatching = M.alter $ \(Just thread) -> Just $ thread { _handlers = tail $ _handlers thread }++-- | Raise an exception in a thread.+except :: Action n r s -> [Handler n r s] -> ThreadId -> Threads n r s -> Threads n r s+except act hs = M.alter $ \(Just thread) -> Just $ thread { _continuation = act, _handlers = hs, _blocking = Nothing }++-- | Set the masking state of a thread.+mask :: MaskingState -> ThreadId -> Threads n r s -> Threads n r s+mask ms = M.alter $ \(Just thread) -> Just $ thread { _masking = ms }++--------------------------------------------------------------------------------+-- * Manipulating threads++-- | Replace the @Action@ of a thread.+goto :: Action n r s -> ThreadId -> Threads n r s -> Threads n r s+goto a = M.alter $ \(Just thread) -> Just (thread { _continuation = a })++-- | Start a thread with the given ID, inheriting the masking state+-- from the parent thread. This ID must not already be in use!+launch :: ThreadId -> ThreadId -> ((forall b. M n r s b -> M n r s b) -> Action n r s) -> Threads n r s -> Threads n r s+launch parent tid a threads = launch' ms tid a threads where+  ms = fromMaybe Unmasked $ _masking <$> M.lookup parent threads++-- | Start a thread with the given ID and masking state. This must not already be in use!+launch' :: MaskingState -> ThreadId -> ((forall b. M n r s b -> M n r s b) -> Action n r s) -> Threads n r s -> Threads n r s+launch' ms tid a = M.insert tid thread where+  thread = Thread { _continuation = a umask, _blocking = Nothing, _handlers = [], _masking = ms }++  umask mb = resetMask True Unmasked >> mb >>= \b -> resetMask False ms >> return b+  resetMask typ m = cont $ \k -> AResetMask typ True m $ k ()++-- | Kill a thread.+kill :: ThreadId -> Threads n r s -> Threads n r s+kill = M.delete++-- | Block a thread.+block :: BlockedOn -> ThreadId -> Threads n r s -> Threads n r s+block blockedOn = M.alter doBlock where+  doBlock (Just thread) = Just $ thread { _blocking = Just blockedOn }+  doBlock _ = error "Invariant failure in 'block': thread does NOT exist!"++-- | Unblock all threads waiting on the appropriate block. For 'TVar'+-- blocks, this will wake all threads waiting on at least one of the+-- given 'TVar's.+wake :: BlockedOn -> Threads n r s -> (Threads n r s, [ThreadId])+wake blockedOn threads = (unblock <$> threads, M.keys $ M.filter isBlocked threads) where+  unblock thread+    | isBlocked thread = thread { _blocking = Nothing }+    | otherwise = thread++  isBlocked thread = case (_blocking thread, blockedOn) of+    (Just (OnTVar tvids), OnTVar blockedOn') -> tvids `intersect` blockedOn' /= []+    (theblock, _) -> theblock == Just blockedOn
− Test/DejaFu/Deterministic.hs
@@ -1,209 +0,0 @@-{-# LANGUAGE FlexibleInstances          #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE MultiParamTypeClasses      #-}-{-# LANGUAGE RankNTypes                 #-}-{-# LANGUAGE TypeFamilies               #-}-{-# LANGUAGE TypeSynonymInstances       #-}---- |--- Module      : Test.DejaFu.Deterministic--- Copyright   : (c) 2016 Michael Walker--- License     : MIT--- Maintainer  : Michael Walker <mike@barrucadu.co.uk>--- Stability   : experimental--- Portability : FlexibleInstances, GeneralizedNewtypeDeriving, MultiParamTypeClasses, RankNTypes, TypeFamilies, TypeSynonymInstances------ Deterministic traced execution of concurrent computations.------ This works by executing the computation on a single thread, calling--- out to the supplied scheduler after each step to determine which--- thread runs next.-module Test.DejaFu.Deterministic-  ( -- * The @Conc@ Monad-    Conc-  , ConcST-  , ConcIO--  -- * Executing computations-  , Failure(..)-  , MemType(..)-  , runConcST-  , runConcIO--  -- * Execution traces-  , Trace-  , Decision(..)-  , ThreadId(..)-  , ThreadAction(..)-  , Lookahead(..)-  , MVarId-  , CRefId-  , MaskingState(..)-  , showTrace-  , showFail--  -- * Scheduling-  , module Test.DPOR.Schedule-  ) where--import Control.Exception (MaskingState(..))-import Control.Monad.ST (ST, runST)-import Data.Dynamic (toDyn)-import Data.IORef (IORef)-import Data.STRef (STRef)-import Test.DejaFu.Deterministic.Internal-import Test.DejaFu.Internal (refST, refIO)-import Test.DejaFu.STM (STMLike, STMIO, STMST, runTransactionIO, runTransactionST)-import Test.DejaFu.STM.Internal (TVar(..))-import Test.DPOR.Schedule--import qualified Control.Monad.Base as Ba-import qualified Control.Monad.Catch as Ca-import qualified Control.Monad.Conc.Class as C-import qualified Control.Monad.IO.Class as IO--{-# ANN module ("HLint: ignore Avoid lambda" :: String) #-}-{-# ANN module ("HLint: ignore Use const"    :: String) #-}--newtype Conc n r s a = C { unC :: M n r s a } deriving (Functor, Applicative, Monad)---- | A 'MonadConc' implementation using @ST@, this should be preferred--- if you do not need 'liftIO'.-type ConcST t = Conc (ST t) (STRef t) (STMST t)---- | A 'MonadConc' implementation using @IO@.-type ConcIO = Conc IO IORef STMIO--toConc :: ((a -> Action n r s) -> Action n r s) -> Conc n r s a-toConc = C . cont--wrap :: (M n r s a -> M n r s a) -> Conc n r s a -> Conc n r s a-wrap f = C . f . unC--instance IO.MonadIO ConcIO where-  liftIO ma = toConc (\c -> ALift (fmap c ma))--instance Ba.MonadBase IO ConcIO where-  liftBase = IO.liftIO--instance Ca.MonadCatch (Conc n r s) where-  catch ma h = toConc (ACatching (unC . h) (unC ma))--instance Ca.MonadThrow (Conc n r s) where-  throwM e = toConc (\_ -> AThrow e)--instance Ca.MonadMask (Conc n r s) where-  mask                mb = toConc (AMasking MaskedInterruptible   (\f -> unC $ mb $ wrap f))-  uninterruptibleMask mb = toConc (AMasking MaskedUninterruptible (\f -> unC $ mb $ wrap f))--instance Monad n => C.MonadConc (Conc n r (STMLike n r)) where-  type MVar     (Conc n r (STMLike n r)) = MVar r-  type CRef     (Conc n r (STMLike n r)) = CRef r-  type Ticket   (Conc n r (STMLike n r)) = Ticket-  type STM      (Conc n r (STMLike n r)) = STMLike n r-  type ThreadId (Conc n r (STMLike n r)) = ThreadId--  -- ------------  forkWithUnmaskN   n ma = toConc (AFork n (\umask -> runCont (unC $ ma $ wrap umask) (\_ -> AStop)))-  forkOnWithUnmaskN n _  = C.forkWithUnmaskN n--  -- This implementation lies and returns 2 until a value is set. This-  -- will potentially avoid special-case behaviour for 1 capability,-  -- so it seems a sane choice.-  getNumCapabilities      = toConc AGetNumCapabilities-  setNumCapabilities caps = toConc (\c -> ASetNumCapabilities caps (c ()))--  myThreadId = toConc AMyTId--  yield = toConc (\c -> AYield (c ()))--  -- ------------  newCRefN n a = toConc (\c -> ANewRef n a c)--  readCRef   ref = toConc (AReadRef    ref)-  readForCAS ref = toConc (AReadRefCas ref)--  peekTicket tick = toConc (APeekTicket tick)--  writeCRef ref      a = toConc (\c -> AWriteRef ref a (c ()))-  casCRef   ref tick a = toConc (ACasRef ref tick a)--  atomicModifyCRef ref f = toConc (AModRef    ref f)-  modifyCRefCAS    ref f = toConc (AModRefCas ref f)--  -- ------------  newEmptyMVarN n = toConc (\c -> ANewVar n c)--  putMVar  var a = toConc (\c -> APutVar var a (c ()))-  readMVar var   = toConc (AReadVar var)-  takeMVar var   = toConc (ATakeVar var)--  tryPutMVar  var a = toConc (ATryPutVar  var a)-  tryTakeMVar var   = toConc (ATryTakeVar var)--  -- ------------  throwTo tid e = toConc (\c -> AThrowTo tid e (c ()))--  -- ------------  atomically = toConc . AAtom--  -- ------------  _concKnowsAbout (Left  (MVar cvarid  _)) = toConc (\c -> AKnowsAbout (Left  cvarid)  (c ()))-  _concKnowsAbout (Right (TVar (ctvarid, _))) = toConc (\c -> AKnowsAbout (Right ctvarid) (c ()))--  _concForgets (Left  (MVar cvarid  _)) = toConc (\c -> AForgets (Left  cvarid)  (c ()))-  _concForgets (Right (TVar (ctvarid, _))) = toConc (\c -> AForgets (Right ctvarid) (c ()))--  _concAllKnown = toConc (\c -> AAllKnown (c ()))--  _concMessage msg = toConc (\c -> AMessage (toDyn msg) (c ()))---- | Run a concurrent computation with a given 'Scheduler' and initial--- state, returning a failure reason on error. Also returned is the--- final state of the scheduler, and an execution trace.------ Note how the @t@ in 'Conc' is universally quantified, what this--- means in practice is that you can't do something like this:------ > runConc roundRobinSched SequentialConsistency () newEmptyMVar------ So mutable references cannot leak out of the 'Conc' computation. If--- this is making your head hurt, check out the \"How @runST@ works\"--- section of--- <https://ocharles.org.uk/blog/guest-posts/2014-12-18-rank-n-types.html>------ __Note:__ In order to prevent computation from hanging, the runtime--- will assume that a deadlock situation has arisen if the scheduler--- attempts to (a) schedule a blocked thread, or (b) schedule a--- nonexistent thread. In either of those cases, the computation will--- be halted.-runConcST :: Scheduler ThreadId ThreadAction Lookahead s -> MemType -> s -> (forall t. ConcST t a) -> (Either Failure a, s, Trace ThreadId ThreadAction Lookahead)-runConcST sched memtype s ma = runST $ runFixed fixed runTransactionST sched memtype s $ unC ma where-  fixed = refST $ \mb -> cont (\c -> ALift $ c <$> mb)---- | Run a concurrent computation in the @IO@ monad with a given--- 'Scheduler' and initial state, returning a failure reason on--- error. Also returned is the final state of the scheduler, and an--- execution trace.------ __Warning:__ Blocking on the action of another thread in 'liftIO'--- cannot be detected! So if you perform some potentially blocking--- action in a 'liftIO' the entire collection of threads may deadlock!--- You should therefore keep @IO@ blocks small, and only perform--- blocking operations with the supplied primitives, insofar as--- possible.------ __Note:__ In order to prevent computation from hanging, the runtime--- will assume that a deadlock situation has arisen if the scheduler--- attempts to (a) schedule a blocked thread, or (b) schedule a--- nonexistent thread. In either of those cases, the computation will--- be halted.-runConcIO :: Scheduler ThreadId ThreadAction Lookahead s -> MemType -> s -> ConcIO a -> IO (Either Failure a, s, Trace ThreadId ThreadAction Lookahead)-runConcIO sched memtype s ma = runFixed fixed runTransactionIO sched memtype s $ unC ma where-  fixed = refIO $ \mb -> cont (\c -> ALift $ c <$> mb)
− Test/DejaFu/Deterministic/Internal.hs
@@ -1,475 +0,0 @@-{-# LANGUAGE RankNTypes          #-}-{-# LANGUAGE ScopedTypeVariables #-}---- |--- Module      : Test.DejaFu.Deterministic.Internal--- Copyright   : (c) 2016 Michael Walker--- License     : MIT--- Maintainer  : Michael Walker <mike@barrucadu.co.uk>--- Stability   : experimental--- Portability : RankNTypes, ScopedTypeVariables------ Concurrent monads with a fixed scheduler: internal types and--- functions. This module is NOT considered to form part of the public--- interface of this library.-module Test.DejaFu.Deterministic.Internal- ( -- * Execution-   runFixed- , runFixed'-- -- * The @Conc@ Monad- , M(..)- , MVar(..)- , CRef(..)- , Ticket(..)- , Fixed- , cont- , runCont-- -- * Primitive Actions- , Action(..)-- -- * Identifiers- , ThreadId(..)- , MVarId(..)- , CRefId(..)- , initialThread-- -- * Memory Models- , MemType(..)-- -- * Scheduling & Traces- , Scheduler- , Trace- , Decision(..)- , ThreadAction(..)- , Lookahead(..)- , isBlock- , lookahead- , rewind- , willRelease- , preEmpCount- , showTrace- , showFail- , tvarsOf-- -- * Synchronised and Unsynchronised Actions- , ActionType(..)- , isBarrier- , isCommit- , synchronises- , crefOf- , cvarOf- , simplify- , simplify'-- -- * Failures- , Failure(..)- ) where--import Control.Exception (MaskingState(..), toException)-import Data.Functor (void)-import Data.List (sort)-import Data.List.NonEmpty (NonEmpty(..), fromList)-import Data.Maybe (fromJust, isJust, isNothing, listToMaybe)-import Test.DejaFu.STM (Result(..))-import Test.DejaFu.Internal-import Test.DejaFu.Deterministic.Internal.Common-import Test.DejaFu.Deterministic.Internal.Memory-import Test.DejaFu.Deterministic.Internal.Threading-import Test.DPOR (Decision(..), Scheduler, Trace)--import qualified Data.Map.Strict as M--{-# ANN module ("HLint: ignore Use record patterns" :: String) #-}-{-# ANN module ("HLint: ignore Use const"           :: String) #-}------------------------------------------------------------------------------------- * Execution---- | Run a concurrent computation with a given 'Scheduler' and initial--- state, returning a 'Just' if it terminates, and 'Nothing' if a--- deadlock is detected. Also returned is the final state of the--- scheduler, and an execution trace.-runFixed :: (Functor n, Monad n) => Fixed n r s -> (forall x. s x -> IdSource -> n (Result x, IdSource, TTrace))-         -> Scheduler ThreadId ThreadAction Lookahead g -> MemType -> g -> M n r s a -> n (Either Failure a, g, Trace ThreadId ThreadAction Lookahead)-runFixed fixed runstm sched memtype s ma = (\(e,g,_,t) -> (e,g,t)) <$> runFixed' fixed runstm sched memtype s initialIdSource ma---- | Same as 'runFixed', be parametrised by an 'IdSource'.-runFixed' :: forall n r s g a. (Functor n, Monad n)-  => Fixed n r s -> (forall x. s x -> IdSource -> n (Result x, IdSource, TTrace))-  -> Scheduler ThreadId ThreadAction Lookahead g -> MemType -> g -> IdSource -> M n r s a -> n (Either Failure a, g, IdSource, Trace ThreadId ThreadAction Lookahead)-runFixed' fixed runstm sched memtype s idSource ma = do-  ref <- newRef fixed Nothing--  let c       = ma >>= liftN fixed . writeRef fixed ref . Just . Right-  let threads = launch' Unmasked initialThread ((\a _ -> a) $ runCont c $ const AStop) M.empty--  (s', idSource', trace) <- runThreads fixed runstm sched memtype s threads idSource ref-  out <- readRef fixed ref--  return (fromJust out, s', idSource', reverse trace)---- | Run a collection of threads, until there are no threads left.------ Note: this returns the trace in reverse order, because it's more--- efficient to prepend to a list than append. As this function isn't--- exposed to users of the library, this is just an internal gotcha to--- watch out for.-runThreads :: (Functor n, Monad n) => Fixed n r s -> (forall x. s x -> IdSource -> n (Result x, IdSource, TTrace))-           -> Scheduler ThreadId ThreadAction Lookahead g -> MemType -> g -> Threads n r s -> IdSource -> r (Maybe (Either Failure a)) -> n (g, IdSource, Trace ThreadId ThreadAction Lookahead)-runThreads fixed runstm sched memtype origg origthreads idsrc ref = go idsrc [] Nothing origg origthreads emptyBuffer 2 where-  go idSource sofar prior g threads wb caps-    | isTerminated  = stop g-    | isDeadlocked  = die g Deadlock-    | isSTMLocked   = die g STMDeadlock-    | isAborted     = die g' Abort-    | isNonexistant = die g' InternalError-    | isBlocked     = die g' InternalError-    | otherwise = do-      stepped <- stepThread fixed runstm memtype (_continuation $ fromJust thread) idSource chosen threads wb caps-      case stepped of-        Right (threads', idSource', act, wb', caps') -> loop threads' idSource' act wb' caps'--        Left UncaughtException-          | chosen == initialThread -> die g' UncaughtException-          | otherwise -> loop (kill chosen threads) idSource Killed wb caps--        Left failure -> die g' failure--    where-      (choice, g')  = sched (map (\(d,_,a) -> (d,a)) $ reverse sofar) ((\p (_,_,a) -> (p,a)) <$> prior <*> listToMaybe sofar) (fromList $ map (\(t,l:|_) -> (t,l)) runnable') g-      chosen        = fromJust choice-      runnable'     = [(t, nextActions t) | t <- sort $ M.keys runnable]-      runnable      = M.filter (isNothing . _blocking) threadsc-      thread        = M.lookup chosen threadsc-      threadsc      = addCommitThreads wb threads-      isAborted     = isNothing choice-      isBlocked     = isJust . _blocking $ fromJust thread-      isNonexistant = isNothing thread-      isTerminated  = initialThread `notElem` M.keys threads-      isDeadlocked  = isLocked initialThread threads &&-        (((~=  OnMVarFull  undefined) <$> M.lookup initialThread threads) == Just True ||-         ((~=  OnMVarEmpty undefined) <$> M.lookup initialThread threads) == Just True ||-         ((~=  OnMask      undefined) <$> M.lookup initialThread threads) == Just True)-      isSTMLocked = isLocked initialThread threads &&-        ((~=  OnTVar []) <$> M.lookup initialThread threads) == Just True--      unblockWaitingOn tid = fmap unblock where-        unblock thrd = case _blocking thrd of-          Just (OnMask t) | t == tid -> thrd { _blocking = Nothing }-          _ -> thrd--      decision-        | Just chosen == prior = Continue-        | prior `notElem` map (Just . fst) runnable' = Start chosen-        | otherwise = SwitchTo chosen--      nextActions t = lookahead . _continuation . fromJust $ M.lookup t threadsc--      stop outg = return (outg, idSource, sofar)-      die  outg reason = writeRef fixed ref (Just $ Left reason) >> stop outg--      loop threads' idSource' act wb' =-        let sofar' = ((decision, runnable', act) : sofar)-            threads'' = if (interruptible <$> M.lookup chosen threads') /= Just False then unblockWaitingOn chosen threads' else threads'-        in go idSource' sofar' (Just chosen) g' (delCommitThreads threads'') wb'------------------------------------------------------------------------------------- * Single-step execution---- | Run a single thread one step, by dispatching on the type of--- 'Action'.-stepThread :: forall n r s. (Functor n, Monad n) => Fixed n r s-  -> (forall x. s x -> IdSource -> n (Result x, IdSource, TTrace))-  -- ^ Run a 'MonadSTM' transaction atomically.-  -> MemType-  -- ^ The memory model-  -> Action n r s-  -- ^ Action to step-  -> IdSource-  -- ^ Source of fresh IDs-  -> ThreadId-  -- ^ ID of the current thread-  -> Threads n r s-  -- ^ Current state of threads-  -> WriteBuffer r-  -- ^ @CRef@ write buffer-  -> Int-  -- ^ The number of capabilities-  -> n (Either Failure (Threads n r s, IdSource, ThreadAction, WriteBuffer r, Int))-stepThread fixed runstm memtype action idSource tid threads wb caps = case action of-  AFork    n a b   -> stepFork        n a b-  AMyTId   c       -> stepMyTId       c-  AGetNumCapabilities   c -> stepGetNumCapabilities c-  ASetNumCapabilities i c -> stepSetNumCapabilities i c-  AYield   c       -> stepYield       c-  ANewVar  n c     -> stepNewVar      n c-  APutVar  var a c -> stepPutVar      var a c-  ATryPutVar var a c -> stepTryPutVar var a c-  AReadVar var c   -> stepReadVar     var c-  ATakeVar var c   -> stepTakeVar     var c-  ATryTakeVar var c -> stepTryTakeVar var c-  ANewRef  n a c   -> stepNewRef      n a c-  AReadRef ref c   -> stepReadRef     ref c-  AReadRefCas ref c -> stepReadRefCas ref c-  APeekTicket tick c -> stepPeekTicket tick c-  AModRef  ref f c -> stepModRef      ref f c-  AModRefCas ref f c -> stepModRefCas ref f c-  AWriteRef ref a c -> stepWriteRef   ref a c-  ACasRef ref tick a c -> stepCasRef ref tick a c-  ACommit  t c     -> stepCommit      t c-  AAtom    stm c   -> stepAtom        stm c-  ALift    na      -> stepLift        na-  AThrow   e       -> stepThrow       e-  AThrowTo t e c   -> stepThrowTo     t e c-  ACatching h ma c -> stepCatching    h ma c-  APopCatching a   -> stepPopCatching a-  AMasking m ma c  -> stepMasking     m ma c-  AResetMask b1 b2 m c -> stepResetMask b1 b2 m c-  AReturn     c    -> stepReturn c-  AKnowsAbout v c  -> stepKnowsAbout  v c-  AForgets    v c  -> stepForgets v c-  AAllKnown   c    -> stepAllKnown c-  AMessage    m c  -> stepMessage m c-  AStop            -> stepStop--  where-    -- | Start a new thread, assigning it the next 'ThreadId'-    ---    -- Explicit type signature needed for GHC 8. Looks like the-    -- impredicative polymorphism checks got stronger.-    stepFork :: String-             -> ((forall b. M n r s b -> M n r s b) -> Action n r s)-             -> (ThreadId -> Action n r s)-             -> n (Either Failure (Threads n r s, IdSource, ThreadAction, WriteBuffer r, Int))-    stepFork n a b = return $ Right (goto (b newtid) tid threads', idSource', Fork newtid, wb, caps) where-      threads' = launch tid newtid a threads-      (idSource', newtid) = nextTId n idSource--    -- | Get the 'ThreadId' of the current thread-    stepMyTId c = simple (goto (c tid) tid threads) MyThreadId--    -- | Get the number of capabilities-    stepGetNumCapabilities c = simple (goto (c caps) tid threads) $ GetNumCapabilities caps--    -- | Set the number of capabilities-    stepSetNumCapabilities i c = return $ Right (goto c tid threads, idSource, SetNumCapabilities i, wb, i)--    -- | Yield the current thread-    stepYield c = simple (goto c tid threads) Yield--    -- | Put a value into a @MVar@, blocking the thread until it's-    -- empty.-    stepPutVar cvar@(MVar cvid _) a c = synchronised $ do-      (success, threads', woken) <- putIntoMVar cvar a c fixed tid threads-      simple threads' $ if success then PutVar cvid woken else BlockedPutVar cvid--    -- | Try to put a value into a @MVar@, without blocking.-    stepTryPutVar cvar@(MVar cvid _) a c = synchronised $ do-      (success, threads', woken) <- tryPutIntoMVar cvar a c fixed tid threads-      simple threads' $ TryPutVar cvid success woken--    -- | Get the value from a @MVar@, without emptying, blocking the-    -- thread until it's full.-    stepReadVar cvar@(MVar cvid _) c = synchronised $ do-      (success, threads', _) <- readFromMVar cvar c fixed tid threads-      simple threads' $ if success then ReadVar cvid else BlockedReadVar cvid--    -- | Take the value from a @MVar@, blocking the thread until it's-    -- full.-    stepTakeVar cvar@(MVar cvid _) c = synchronised $ do-      (success, threads', woken) <- takeFromMVar cvar c fixed tid threads-      simple threads' $ if success then TakeVar cvid woken else BlockedTakeVar cvid--    -- | Try to take the value from a @MVar@, without blocking.-    stepTryTakeVar cvar@(MVar cvid _) c = synchronised $ do-      (success, threads', woken) <- tryTakeFromMVar cvar c fixed tid threads-      simple threads' $ TryTakeVar cvid success woken--    -- | Read from a @CRef@.-    stepReadRef cref@(CRef crid _) c = do-      val <- readCRef fixed cref tid-      simple (goto (c val) tid threads) $ ReadRef crid--    -- | Read from a @CRef@ for future compare-and-swap operations.-    stepReadRefCas cref@(CRef crid _) c = do-      tick <- readForTicket fixed cref tid-      simple (goto (c tick) tid threads) $ ReadRefCas crid--    -- | Extract the value from a @Ticket@.-    stepPeekTicket (Ticket crid _ a) c = simple (goto (c a) tid threads) $ PeekTicket crid--    -- | Modify a @CRef@.-    stepModRef cref@(CRef crid _) f c = synchronised $ do-      (new, val) <- f <$> readCRef fixed cref tid-      writeImmediate fixed cref new-      simple (goto (c val) tid threads) $ ModRef crid--    -- | Modify a @CRef@ using a compare-and-swap.-    stepModRefCas cref@(CRef crid _) f c = synchronised $ do-      tick@(Ticket _ _ old) <- readForTicket fixed cref tid-      let (new, val) = f old-      void $ casCRef fixed cref tid tick new-      simple (goto (c val) tid threads) $ ModRefCas crid--    -- | Write to a @CRef@ without synchronising-    stepWriteRef cref@(CRef crid _) a c = case memtype of-      -- Write immediately.-      SequentialConsistency -> do-        writeImmediate fixed cref a-        simple (goto c tid threads) $ WriteRef crid--      -- Add to buffer using thread id.-      TotalStoreOrder -> do-        wb' <- bufferWrite fixed wb (tid, Nothing) cref a-        return $ Right (goto c tid threads, idSource, WriteRef crid, wb', caps)--      -- Add to buffer using both thread id and cref id-      PartialStoreOrder -> do-        wb' <- bufferWrite fixed wb (tid, Just crid) cref a-        return $ Right (goto c tid threads, idSource, WriteRef crid, wb', caps)--    -- | Perform a compare-and-swap on a @CRef@.-    stepCasRef cref@(CRef crid _) tick a c = synchronised $ do-      (suc, tick') <- casCRef fixed cref tid tick a-      simple (goto (c (suc, tick')) tid threads) $ CasRef crid suc--    -- | Commit a @CRef@ write-    stepCommit t c = do-      wb' <- case memtype of-        -- Shouldn't ever get here-        SequentialConsistency ->-          error "Attempting to commit under SequentialConsistency"--        -- Commit using the thread id.-        TotalStoreOrder -> commitWrite fixed wb (t, Nothing)--        -- Commit using the cref id.-        PartialStoreOrder -> commitWrite fixed wb (t, Just c)--      return $ Right (threads, idSource, CommitRef t c, wb', caps)--    -- | Run a STM transaction atomically.-    stepAtom stm c = synchronised $ do-      (res, idSource', trace) <- runstm stm idSource-      case res of-        Success _ written val ->-          let (threads', woken) = wake (OnTVar written) threads-          in return $ Right (knows (map Right written) tid $ goto (c val) tid threads', idSource', STM trace woken, wb, caps)-        Retry touched ->-          let threads' = block (OnTVar touched) tid threads-          in return $ Right (threads', idSource', BlockedSTM trace, wb, caps)-        Exception e -> do-          res' <- stepThrow e-          return $ case res' of-            Right (threads', _, _, _, _) -> Right (threads', idSource', Throw, wb, caps)-            Left err -> Left err--    -- | Run a subcomputation in an exception-catching context.-    stepCatching h ma c = simple threads' Catching where-      a     = runCont ma      (APopCatching . c)-      e exc = runCont (h exc) (APopCatching . c)--      threads' = goto a tid (catching e tid threads)--    -- | Pop the top exception handler from the thread's stack.-    stepPopCatching a = simple threads' PopCatching where-      threads' = goto a tid (uncatching tid threads)--    -- | Throw an exception, and propagate it to the appropriate-    -- handler.-    stepThrow e =-      case propagate (toException e) tid threads of-        Just threads' -> simple threads' Throw-        Nothing -> return $ Left UncaughtException--    -- | Throw an exception to the target thread, and propagate it to-    -- the appropriate handler.-    stepThrowTo t e c = synchronised $-      let threads' = goto c tid threads-          blocked  = block (OnMask t) tid threads-      in case M.lookup t threads of-           Just thread-             | interruptible thread -> case propagate (toException e) t threads' of-               Just threads'' -> simple threads'' $ ThrowTo t-               Nothing-                 | t == initialThread -> return $ Left UncaughtException-                 | otherwise -> simple (kill t threads') $ ThrowTo t-             | otherwise -> simple blocked $ BlockedThrowTo t-           Nothing -> simple threads' $ ThrowTo t--    -- | Execute a subcomputation with a new masking state, and give-    -- it a function to run a computation with the current masking-    -- state.-    ---    -- Explicit type sig necessary for checking in the prescence of-    -- 'umask', sadly.-    stepMasking :: MaskingState-                -> ((forall b. M n r s b -> M n r s b) -> M n r s a)-                -> (a -> Action n r s)-                -> n (Either Failure (Threads n r s, IdSource, ThreadAction, WriteBuffer r, Int))-    stepMasking m ma c = simple threads' $ SetMasking False m where-      a = runCont (ma umask) (AResetMask False False m' . c)--      m' = _masking . fromJust $ M.lookup tid threads-      umask mb = resetMask True m' >> mb >>= \b -> resetMask False m >> return b-      resetMask typ ms = cont $ \k -> AResetMask typ True ms $ k ()--      threads' = goto a tid (mask m tid threads)--    -- | Reset the masking thread of the state.-    stepResetMask b1 b2 m c = simple threads' act where-      act      = (if b1 then SetMasking else ResetMasking) b2 m-      threads' = goto c tid (mask m tid threads)--    -- | Create a new @MVar@, using the next 'MVarId'.-    stepNewVar n c = do-      let (idSource', newcvid) = nextCVId n idSource-      ref <- newRef fixed Nothing-      let cvar = MVar newcvid ref-      return $ Right (knows [Left newcvid] tid $ goto (c cvar) tid threads, idSource', NewVar newcvid, wb, caps)--    -- | Create a new @CRef@, using the next 'CRefId'.-    stepNewRef n a c = do-      let (idSource', newcrid) = nextCRId n idSource-      ref <- newRef fixed (M.empty, 0, a)-      let cref = CRef newcrid ref-      return $ Right (goto (c cref) tid threads, idSource', NewRef newcrid, wb, caps)--    -- | Lift an action from the underlying monad into the @Conc@-    -- computation.-    stepLift na = do-      a <- na-      simple (goto a tid threads) Lift--    -- | Execute a 'return' or 'pure'.-    stepReturn c = simple (goto c tid threads) Return--    -- | Record that a variable is known about.-    stepKnowsAbout v c = simple (knows [v] tid $ goto c tid threads) KnowsAbout--    -- | Record that a variable will never be touched again.-    stepForgets v c = simple (forgets [v] tid $ goto c tid threads) Forgets--    -- | Record that all shared variables are known.-    stepAllKnown c = simple (fullknown tid $ goto c tid threads) AllKnown--    -- | Add a message to the trace.-    stepMessage m c = simple (goto c tid threads) (Message m)--    -- | Kill the current thread.-    stepStop = simple (kill tid threads) Stop--    -- | Helper for actions which don't touch the 'IdSource' or-    -- 'WriteBuffer'-    simple threads' act = return $ Right (threads', idSource, act, wb, caps)--    -- | Helper for actions impose a write barrier.-    synchronised ma = do-      writeBarrier fixed wb-      res <- ma--      return $ case res of-        Right (threads', idSource', act', _, caps') -> Right (threads', idSource', act', emptyBuffer, caps')-        _ -> res
− Test/DejaFu/Deterministic/Internal/Common.hs
@@ -1,873 +0,0 @@-{-# LANGUAGE ExistentialQuantification #-}-{-# LANGUAGE RankNTypes                #-}---- |--- Module      : Test.DejaFu.Deterministic.Internal.Common--- Copyright   : (c) 2016 Michael Walker--- License     : MIT--- Maintainer  : Michael Walker <mike@barrucadu.co.uk>--- Stability   : experimental--- Portability : ExistentialQuantification, RankNTypes------ Common types and utility functions for deterministic execution of--- 'MonadConc' implementations. This module is NOT considered to form--- part of the public interface of this library.-module Test.DejaFu.Deterministic.Internal.Common where--import Control.DeepSeq (NFData(..))-import Control.Exception (Exception, MaskingState(..))-import Data.Dynamic (Dynamic)-import Data.Map.Strict (Map)-import Data.Maybe (fromMaybe, mapMaybe)-import Data.List (sort, nub, intercalate)-import Data.List.NonEmpty (NonEmpty, fromList)-import Data.Set (Set)-import qualified Data.Set as S-import Test.DejaFu.Internal-import Test.DPOR (Decision(..), Trace)--{-# ANN module ("HLint: ignore Use record patterns" :: String) #-}------------------------------------------------------------------------------------- * The @Conc@ Monad---- | The underlying monad is based on continuations over 'Action's.------ One might wonder why the return type isn't reflected in 'Action',--- and a free monad formulation used. This would remove the need for a--- @Lift@ action as the penultimate action of thread 0 used to--- communicate back the result, and be more pleasing in a--- sense. However, this makes the current expression of threads and--- exception handlers very difficult (perhaps even not possible--- without significant reworking), so I abandoned the attempt.-newtype M n r s a = M { runM :: (a -> Action n r s) -> Action n r s }--instance Functor (M n r s) where-    fmap f m = M $ \ c -> runM m (c . f)--instance Applicative (M n r s) where-    pure x  = M $ \c -> AReturn $ c x-    f <*> v = M $ \c -> runM f (\g -> runM v (c . g))--instance Monad (M n r s) where-    return  = pure-    m >>= k = M $ \c -> runM m (\x -> runM (k x) c)---- | The concurrent variable type used with the 'Conc' monad. One--- notable difference between these and 'MVar's is that 'MVar's are--- single-wakeup, and wake up in a FIFO order. Writing to a @MVar@--- wakes up all threads blocked on reading it, and it is up to the--- scheduler which one runs next. Taking from a @MVar@ behaves--- analogously.-data MVar r a = MVar-  { _cvarId   :: MVarId-  , _cvarVal  :: r (Maybe a)-  }---- | The mutable non-blocking reference type. These are like 'IORef's.------ @CRef@s are represented as a unique numeric identifier and a--- reference containing (a) any thread-local non-synchronised writes--- (so each thread sees its latest write), (b) a commit count (used in--- compare-and-swaps), and (c) the current value visible to all--- threads.-data CRef r a = CRef-  { _crefId   :: CRefId-  , _crefVal  :: r (Map ThreadId a, Integer, a)-  }---- | The compare-and-swap proof type.------ @Ticket@s are represented as just a wrapper around the identifier--- of the 'CRef' it came from, the commit count at the time it was--- produced, and an @a@ value. This doesn't work in the source package--- (atomic-primops) because of the need to use pointer equality. Here--- we can just pack extra information into 'CRef' to avoid that need.-data Ticket a = Ticket-  { _ticketCRef   :: CRefId-  , _ticketWrites :: Integer-  , _ticketVal    :: a-  }---- | Dict of methods for implementations to override.-type Fixed n r s = Ref n r (M n r s)---- | Construct a continuation-passing operation from a function.-cont :: ((a -> Action n r s) -> Action n r s) -> M n r s a-cont = M---- | Run a CPS computation with the given final computation.-runCont :: M n r s a -> (a -> Action n r s) -> Action n r s-runCont = runM------------------------------------------------------------------------------------- * Primitive Actions---- | Scheduling is done in terms of a trace of 'Action's. Blocking can--- only occur as a result of an action, and they cover (most of) the--- primitives of the concurrency. 'spawn' is absent as it is--- implemented in terms of 'newEmptyMVar', 'fork', and 'putMVar'.-data Action n r s =-    AFork  String ((forall b. M n r s b -> M n r s b) -> Action n r s) (ThreadId -> Action n r s)-  | AMyTId (ThreadId -> Action n r s)--  | AGetNumCapabilities (Int -> Action n r s)-  | ASetNumCapabilities Int (Action n r s)--  | forall a. ANewVar String (MVar r a -> Action n r s)-  | forall a. APutVar     (MVar r a) a (Action n r s)-  | forall a. ATryPutVar  (MVar r a) a (Bool -> Action n r s)-  | forall a. AReadVar    (MVar r a) (a -> Action n r s)-  | forall a. ATakeVar    (MVar r a) (a -> Action n r s)-  | forall a. ATryTakeVar (MVar r a) (Maybe a -> Action n r s)--  | forall a.   ANewRef String a (CRef r a -> Action n r s)-  | forall a.   AReadRef    (CRef r a) (a -> Action n r s)-  | forall a.   AReadRefCas (CRef r a) (Ticket a -> Action n r s)-  | forall a.   APeekTicket (Ticket a) (a -> Action n r s)-  | forall a b. AModRef     (CRef r a) (a -> (a, b)) (b -> Action n r s)-  | forall a b. AModRefCas  (CRef r a) (a -> (a, b)) (b -> Action n r s)-  | forall a.   AWriteRef   (CRef r a) a (Action n r s)-  | forall a.   ACasRef     (CRef r a) (Ticket a) a ((Bool, Ticket a) -> Action n r s)--  | forall e.   Exception e => AThrow e-  | forall e.   Exception e => AThrowTo ThreadId e (Action n r s)-  | forall a e. Exception e => ACatching (e -> M n r s a) (M n r s a) (a -> Action n r s)-  | APopCatching (Action n r s)-  | forall a. AMasking MaskingState ((forall b. M n r s b -> M n r s b) -> M n r s a) (a -> Action n r s)-  | AResetMask Bool Bool MaskingState (Action n r s)--  | AKnowsAbout (Either MVarId TVarId) (Action n r s)-  | AForgets    (Either MVarId TVarId) (Action n r s)-  | AAllKnown   (Action n r s)-  | AMessage    Dynamic (Action n r s)--  | forall a. AAtom (s a) (a -> Action n r s)-  | ALift (n (Action n r s))-  | AYield  (Action n r s)-  | AReturn (Action n r s)-  | ACommit ThreadId CRefId-  | AStop------------------------------------------------------------------------------------- * Identifiers---- | Every live thread has a unique identitifer.-data ThreadId = ThreadId (Maybe String) Int-  deriving Eq--instance Ord ThreadId where-  compare (ThreadId _ i) (ThreadId _ j) = compare i j--instance Show ThreadId where-  show (ThreadId (Just n) _) = n-  show (ThreadId Nothing  i) = show i--instance NFData ThreadId where-  rnf (ThreadId n i) = rnf (n, i)---- | The ID of the initial thread.-initialThread :: ThreadId-initialThread = ThreadId (Just "main") 0---- | Every @MVar@ has a unique identifier.-data MVarId = MVarId (Maybe String) Int-  deriving Eq--instance Ord MVarId where-  compare (MVarId _ i) (MVarId _ j) = compare i j--instance Show MVarId where-  show (MVarId (Just n) _) = n-  show (MVarId Nothing  i) = show i--instance NFData MVarId where-  rnf (MVarId n i) = rnf (n, i)---- | Every @CRef@ has a unique identifier.-data CRefId = CRefId (Maybe String) Int-  deriving Eq--instance Ord CRefId where-  compare (CRefId _ i) (CRefId _ j) = compare i j--instance Show CRefId where-  show (CRefId (Just n) _) = n-  show (CRefId Nothing  i) = show i--instance NFData CRefId where-  rnf (CRefId n i) = rnf (n, i)---- | Every @TVar@ has a unique identifier.-data TVarId = TVarId (Maybe String) Int-  deriving Eq--instance Ord TVarId where-  compare (TVarId _ i) (TVarId _ j) = compare i j--instance Show TVarId where-  show (TVarId (Just n) _) = n-  show (TVarId Nothing  i) = show i--instance NFData TVarId where-  rnf (TVarId n i) = rnf (n, i)---- | The number of ID parameters was getting a bit unwieldy, so this--- hides them all away.-data IdSource = Id-  { _nextCRId  :: Int-  , _nextCVId  :: Int-  , _nextTVId  :: Int-  , _nextTId   :: Int-  , _usedCRNames :: [String]-  , _usedCVNames :: [String]-  , _usedTVNames :: [String]-  , _usedTNames  :: [String] }---- | Get the next free 'CRefId'.-nextCRId :: String -> IdSource -> (IdSource, CRefId)-nextCRId name idsource = (idsource { _nextCRId = newid, _usedCRNames = newlst }, CRefId newname newid) where-  newid  = _nextCRId idsource + 1-  newlst-    | null name = _usedCRNames idsource-    | otherwise = name : _usedCRNames idsource-  newname-    | null name       = Nothing-    | occurrences > 0 = Just (name ++ "-" ++ show occurrences)-    | otherwise       = Just name-  occurrences = length . filter (==name) $ _usedCRNames idsource---- | Get the next free 'MVarId'.-nextCVId :: String -> IdSource -> (IdSource, MVarId)-nextCVId name idsource = (idsource { _nextCVId = newid, _usedCVNames = newlst }, MVarId newname newid) where-  newid  = _nextCVId idsource + 1-  newlst-    | null name = _usedCVNames idsource-    | otherwise = name : _usedCVNames idsource-  newname-    | null name       = Nothing-    | occurrences > 0 = Just (name ++ "-" ++ show occurrences)-    | otherwise       = Just name-  occurrences = length . filter (==name) $ _usedCVNames idsource---- | Get the next free 'TVarId'.-nextTVId :: String -> IdSource -> (IdSource, TVarId)-nextTVId name idsource = (idsource { _nextTVId = newid, _usedTVNames = newlst }, TVarId newname newid) where-  newid  = _nextTVId idsource + 1-  newlst-    | null name = _usedTVNames idsource-    | otherwise = name : _usedTVNames idsource-  newname-    | null name       = Nothing-    | occurrences > 0 = Just (name ++ "-" ++ show occurrences)-    | otherwise       = Just name-  occurrences = length . filter (==name) $ _usedTVNames idsource---- | Get the next free 'ThreadId'.-nextTId :: String -> IdSource -> (IdSource, ThreadId)-nextTId name idsource = (idsource { _nextTId = newid, _usedTNames = newlst }, ThreadId newname newid) where-  newid  = _nextTId idsource + 1-  newlst-    | null name = _usedTNames idsource-    | otherwise = name : _usedTNames idsource-  newname-    | null name       = Nothing-    | occurrences > 0 = Just (name ++ "-" ++ show occurrences)-    | otherwise       = Just name-  occurrences = length . filter (==name) $ _usedTNames idsource---- | The initial ID source.-initialIdSource :: IdSource-initialIdSource = Id 0 0 0 0 [] [] [] []------------------------------------------------------------------------------------- * Scheduling & Traces---- | Pretty-print a trace, including a key of the thread IDs. Each--- line of the key is indented by two spaces.-showTrace :: Trace ThreadId ThreadAction Lookahead -> String-showTrace trc = intercalate "\n" $ trace "" 0 trc : (map ("  "++) . sort . nub $ mapMaybe toKey trc) where-  trace prefix num ((_,_,CommitRef _ _):ds) = thread prefix num ++ trace "C" 1 ds-  trace prefix num ((Start    (ThreadId _ i),_,_):ds) = thread prefix num ++ trace ("S" ++ show i) 1 ds-  trace prefix num ((SwitchTo (ThreadId _ i),_,_):ds) = thread prefix num ++ trace ("P" ++ show i) 1 ds-  trace prefix num ((Continue,_,_):ds) = trace prefix (num + 1) ds-  trace prefix num [] = thread prefix num--  thread prefix num = prefix ++ replicate num '-'--  toKey (Start (ThreadId (Just name) i), _, _) = Just $ show i ++ ": " ++ name-  toKey _ = Nothing---- | All the actions that a thread can perform.-data ThreadAction =-    Fork ThreadId-  -- ^ Start a new thread.-  | MyThreadId-  -- ^ Get the 'ThreadId' of the current thread.-  | GetNumCapabilities Int-  -- ^ Get the number of Haskell threads that can run simultaneously.-  | SetNumCapabilities Int-  -- ^ Set the number of Haskell threads that can run simultaneously.-  | Yield-  -- ^ Yield the current thread.-  | NewVar MVarId-  -- ^ Create a new 'MVar'.-  | PutVar MVarId [ThreadId]-  -- ^ Put into a 'MVar', possibly waking up some threads.-  | BlockedPutVar MVarId-  -- ^ Get blocked on a put.-  | TryPutVar MVarId Bool [ThreadId]-  -- ^ Try to put into a 'MVar', possibly waking up some threads.-  | ReadVar MVarId-  -- ^ Read from a 'MVar'.-  | BlockedReadVar MVarId-  -- ^ Get blocked on a read.-  | TakeVar MVarId [ThreadId]-  -- ^ Take from a 'MVar', possibly waking up some threads.-  | BlockedTakeVar MVarId-  -- ^ Get blocked on a take.-  | TryTakeVar MVarId Bool [ThreadId]-  -- ^ Try to take from a 'MVar', possibly waking up some threads.-  | NewRef CRefId-  -- ^ Create a new 'CRef'.-  | ReadRef CRefId-  -- ^ Read from a 'CRef'.-  | ReadRefCas CRefId-  -- ^ Read from a 'CRef' for a future compare-and-swap.-  | PeekTicket CRefId-  -- ^ Extract the value from a 'Ticket'.-  | ModRef CRefId-  -- ^ Modify a 'CRef'.-  | ModRefCas CRefId-  -- ^ Modify a 'CRef' using a compare-and-swap.-  | WriteRef CRefId-  -- ^ Write to a 'CRef' without synchronising.-  | CasRef CRefId Bool-  -- ^ Attempt to to a 'CRef' using a compare-and-swap, synchronising-  -- it.-  | CommitRef ThreadId CRefId-  -- ^ Commit the last write to the given 'CRef' by the given thread,-  -- so that all threads can see the updated value.-  | STM TTrace [ThreadId]-  -- ^ An STM transaction was executed, possibly waking up some-  -- threads.-  | BlockedSTM TTrace-  -- ^ Got blocked in an STM transaction.-  | Catching-  -- ^ Register a new exception handler-  | PopCatching-  -- ^ Pop the innermost exception handler from the stack.-  | Throw-  -- ^ Throw an exception.-  | ThrowTo ThreadId-  -- ^ Throw an exception to a thread.-  | BlockedThrowTo ThreadId-  -- ^ Get blocked on a 'throwTo'.-  | Killed-  -- ^ Killed by an uncaught exception.-  | SetMasking Bool MaskingState-  -- ^ Set the masking state. If 'True', this is being used to set the-  -- masking state to the original state in the argument passed to a-  -- 'mask'ed function.-  | ResetMasking Bool MaskingState-  -- ^ Return to an earlier masking state.  If 'True', this is being-  -- used to return to the state of the masked block in the argument-  -- passed to a 'mask'ed function.-  | Lift-  -- ^ Lift an action from the underlying monad. Note that the-  -- penultimate action in a trace will always be a @Lift@, this is an-  -- artefact of how the runner works.-  | Return-  -- ^ A 'return' or 'pure' action was executed.-  | KnowsAbout-  -- ^ A '_concKnowsAbout' annotation was processed.-  | Forgets-  -- ^ A '_concForgets' annotation was processed.-  | AllKnown-  -- ^ A '_concALlKnown' annotation was processed.-  | Message Dynamic-  -- ^ A '_concMessage' annotation was processed.-  | Stop-  -- ^ Cease execution and terminate.-  deriving Show--instance NFData ThreadAction where-  rnf (Fork t) = rnf t-  rnf (GetNumCapabilities i) = rnf i-  rnf (SetNumCapabilities i) = rnf i-  rnf (NewVar c) = rnf c-  rnf (PutVar c ts) = rnf (c, ts)-  rnf (BlockedPutVar c) = rnf c-  rnf (TryPutVar c b ts) = rnf (c, b, ts)-  rnf (ReadVar c) = rnf c-  rnf (BlockedReadVar c) = rnf c-  rnf (TakeVar c ts) = rnf (c, ts)-  rnf (BlockedTakeVar c) = rnf c-  rnf (TryTakeVar c b ts) = rnf (c, b, ts)-  rnf (NewRef c) = rnf c-  rnf (ReadRef c) = rnf c-  rnf (ReadRefCas c) = rnf c-  rnf (PeekTicket c) = rnf c-  rnf (ModRef c) = rnf c-  rnf (ModRefCas c) = rnf c-  rnf (WriteRef c) = rnf c-  rnf (CasRef c b) = rnf (c, b)-  rnf (CommitRef t c) = rnf (t, c)-  rnf (STM s ts) = rnf (s, ts)-  rnf (BlockedSTM s) = rnf s-  rnf (ThrowTo t) = rnf t-  rnf (BlockedThrowTo t) = rnf t-  rnf (SetMasking b m) = b `seq` m `seq` ()-  rnf (ResetMasking b m) = b `seq` m `seq` ()-  rnf (Message m) = m `seq` ()-  rnf a = a `seq` ()---- | Check if a @ThreadAction@ immediately blocks.-isBlock :: ThreadAction -> Bool-isBlock (BlockedThrowTo  _) = True-isBlock (BlockedTakeVar _) = True-isBlock (BlockedReadVar _) = True-isBlock (BlockedPutVar  _) = True-isBlock (BlockedSTM _) = True-isBlock _ = False---- | A trace of an STM transaction is just a list of actions that--- occurred, as there are no scheduling decisions to make.-type TTrace = [TAction]---- | All the actions that an STM transaction can perform.-data TAction =-    TNew-  -- ^ Create a new @TVar@-  | TRead  TVarId-  -- ^ Read from a @TVar@.-  | TWrite TVarId-  -- ^ Write to a @TVar@.-  | TRetry-  -- ^ Abort and discard effects.-  | TOrElse TTrace (Maybe TTrace)-  -- ^ Execute a transaction until it succeeds (@STMStop@) or aborts-  -- (@STMRetry@) and, if it aborts, execute the other transaction.-  | TThrow-  -- ^ Throw an exception, abort, and discard effects.-  | TCatch TTrace (Maybe TTrace)-  -- ^ Execute a transaction until it succeeds (@STMStop@) or aborts-  -- (@STMThrow@). If the exception is of the appropriate type, it is-  -- handled and execution continues; otherwise aborts, propagating-  -- the exception upwards.-  | TStop-  -- ^ Terminate successfully and commit effects.-  | TLift-  -- ^ Lifts an action from the underlying monad. Note that the-  -- penultimate action in a trace will always be a @Lift@, this is an-  -- artefact of how the runner works.-  deriving (Eq, Show)--instance NFData TAction where-  rnf (TRead  v) = rnf v-  rnf (TWrite v) = rnf v-  rnf (TCatch  s m) = rnf (s, m)-  rnf (TOrElse s m) = rnf (s, m)-  rnf a = a `seq` ()---- | A one-step look-ahead at what a thread will do next.-data Lookahead =-    WillFork-  -- ^ Will start a new thread.-  | WillMyThreadId-  -- ^ Will get the 'ThreadId'.-  | WillGetNumCapabilities-  -- ^ Will get the number of Haskell threads that can run-  -- simultaneously.-  | WillSetNumCapabilities Int-  -- ^ Will set the number of Haskell threads that can run-  -- simultaneously.-  | WillYield-  -- ^ Will yield the current thread.-  | WillNewVar-  -- ^ Will create a new 'MVar'.-  | WillPutVar MVarId-  -- ^ Will put into a 'MVar', possibly waking up some threads.-  | WillTryPutVar MVarId-  -- ^ Will try to put into a 'MVar', possibly waking up some threads.-  | WillReadVar MVarId-  -- ^ Will read from a 'MVar'.-  | WillTakeVar MVarId-  -- ^ Will take from a 'MVar', possibly waking up some threads.-  | WillTryTakeVar MVarId-  -- ^ Will try to take from a 'MVar', possibly waking up some threads.-  | WillNewRef-  -- ^ Will create a new 'CRef'.-  | WillReadRef CRefId-  -- ^ Will read from a 'CRef'.-  | WillPeekTicket CRefId-  -- ^ Will extract the value from a 'Ticket'.-  | WillReadRefCas CRefId-  -- ^ Will read from a 'CRef' for a future compare-and-swap.-  | WillModRef CRefId-  -- ^ Will modify a 'CRef'.-  | WillModRefCas CRefId-  -- ^ Will nodify a 'CRef' using a compare-and-swap.-  | WillWriteRef CRefId-  -- ^ Will write to a 'CRef' without synchronising.-  | WillCasRef CRefId-  -- ^ Will attempt to to a 'CRef' using a compare-and-swap,-  -- synchronising it.-  | WillCommitRef ThreadId CRefId-  -- ^ Will commit the last write by the given thread to the 'CRef'.-  | WillSTM-  -- ^ Will execute an STM transaction, possibly waking up some-  -- threads.-  | WillCatching-  -- ^ Will register a new exception handler-  | WillPopCatching-  -- ^ Will pop the innermost exception handler from the stack.-  | WillThrow-  -- ^ Will throw an exception.-  | WillThrowTo ThreadId-  -- ^ Will throw an exception to a thread.-  | WillSetMasking Bool MaskingState-  -- ^ Will set the masking state. If 'True', this is being used to-  -- set the masking state to the original state in the argument-  -- passed to a 'mask'ed function.-  | WillResetMasking Bool MaskingState-  -- ^ Will return to an earlier masking state.  If 'True', this is-  -- being used to return to the state of the masked block in the-  -- argument passed to a 'mask'ed function.-  | WillLift-  -- ^ Will lift an action from the underlying monad. Note that the-  -- penultimate action in a trace will always be a @Lift@, this is an-  -- artefact of how the runner works.-  | WillReturn-  -- ^ Will execute a 'return' or 'pure' action.-  | WillKnowsAbout-  -- ^ Will process a '_concKnowsAbout' annotation.-  | WillForgets-  -- ^ Will process a '_concForgets' annotation.-  | WillAllKnown-  -- ^ Will process a '_concALlKnown' annotation.-  | WillMessage Dynamic-  -- ^ Will process a _concMessage' annotation.-  | WillStop-  -- ^ Will cease execution and terminate.-  deriving Show--instance NFData Lookahead where-  rnf (WillSetNumCapabilities i) = rnf i-  rnf (WillPutVar c) = rnf c-  rnf (WillTryPutVar c) = rnf c-  rnf (WillReadVar c) = rnf c-  rnf (WillTakeVar c) = rnf c-  rnf (WillTryTakeVar c) = rnf c-  rnf (WillReadRef c) = rnf c-  rnf (WillReadRefCas c) = rnf c-  rnf (WillPeekTicket c) = rnf c-  rnf (WillModRef c) = rnf c-  rnf (WillModRefCas c) = rnf c-  rnf (WillWriteRef c) = rnf c-  rnf (WillCasRef c) = rnf c-  rnf (WillCommitRef t c) = rnf (t, c)-  rnf (WillThrowTo t) = rnf t-  rnf (WillSetMasking b m) = b `seq` m `seq` ()-  rnf (WillResetMasking b m) = b `seq` m `seq` ()-  rnf (WillMessage m) = m `seq` ()-  rnf l = l `seq` ()---- | Convert a 'ThreadAction' into a 'Lookahead': \"rewind\" what has--- happened. 'Killed' has no 'Lookahead' counterpart.-rewind :: ThreadAction -> Maybe Lookahead-rewind (Fork _) = Just WillFork-rewind MyThreadId = Just WillMyThreadId-rewind (GetNumCapabilities _) = Just WillGetNumCapabilities-rewind (SetNumCapabilities i) = Just (WillSetNumCapabilities i)-rewind Yield = Just WillYield-rewind (NewVar _) = Just WillNewVar-rewind (PutVar c _) = Just (WillPutVar c)-rewind (BlockedPutVar c) = Just (WillPutVar c)-rewind (TryPutVar c _ _) = Just (WillTryPutVar c)-rewind (ReadVar c) = Just (WillReadVar c)-rewind (BlockedReadVar c) = Just (WillReadVar c)-rewind (TakeVar c _) = Just (WillTakeVar c)-rewind (BlockedTakeVar c) = Just (WillTakeVar c)-rewind (TryTakeVar c _ _) = Just (WillTryTakeVar c)-rewind (NewRef _) = Just WillNewRef-rewind (ReadRef c) = Just (WillReadRef c)-rewind (ReadRefCas c) = Just (WillReadRefCas c)-rewind (PeekTicket c) = Just (WillPeekTicket c)-rewind (ModRef c) = Just (WillModRef c)-rewind (ModRefCas c) = Just (WillModRefCas c)-rewind (WriteRef c) = Just (WillWriteRef c)-rewind (CasRef c _) = Just (WillCasRef c)-rewind (CommitRef t c) = Just (WillCommitRef t c)-rewind (STM _ _) = Just WillSTM-rewind (BlockedSTM _) = Just WillSTM-rewind Catching = Just WillCatching-rewind PopCatching = Just WillPopCatching-rewind Throw = Just WillThrow-rewind (ThrowTo t) = Just (WillThrowTo t)-rewind (BlockedThrowTo t) = Just (WillThrowTo t)-rewind Killed = Nothing-rewind (SetMasking b m) = Just (WillSetMasking b m)-rewind (ResetMasking b m) = Just (WillResetMasking b m)-rewind Lift = Just WillLift-rewind Return = Just WillReturn-rewind KnowsAbout = Just WillKnowsAbout-rewind Forgets = Just WillForgets-rewind AllKnown = Just WillAllKnown-rewind (Message m) = Just (WillMessage m)-rewind Stop = Just WillStop---- | Look as far ahead in the given continuation as possible.-lookahead :: Action n r s -> NonEmpty Lookahead-lookahead = fromList . lookahead' where-  lookahead' (AFork _ _ _)           = [WillFork]-  lookahead' (AMyTId _)              = [WillMyThreadId]-  lookahead' (AGetNumCapabilities _) = [WillGetNumCapabilities]-  lookahead' (ASetNumCapabilities i k) = WillSetNumCapabilities i : lookahead' k-  lookahead' (ANewVar _ _)           = [WillNewVar]-  lookahead' (APutVar (MVar c _) _ k)    = WillPutVar c : lookahead' k-  lookahead' (ATryPutVar (MVar c _) _ _) = [WillTryPutVar c]-  lookahead' (AReadVar (MVar c _) _)     = [WillReadVar c]-  lookahead' (ATakeVar (MVar c _) _)     = [WillTakeVar c]-  lookahead' (ATryTakeVar (MVar c _) _)  = [WillTryTakeVar c]-  lookahead' (ANewRef _ _ _)         = [WillNewRef]-  lookahead' (AReadRef (CRef r _) _)     = [WillReadRef r]-  lookahead' (AReadRefCas (CRef r _) _)  = [WillReadRefCas r]-  lookahead' (APeekTicket (Ticket r _ _) _) = [WillPeekTicket r]-  lookahead' (AModRef (CRef r _) _ _)    = [WillModRef r]-  lookahead' (AModRefCas (CRef r _) _ _) = [WillModRefCas r]-  lookahead' (AWriteRef (CRef r _) _ k) = WillWriteRef r : lookahead' k-  lookahead' (ACasRef (CRef r _) _ _ _) = [WillCasRef r]-  lookahead' (ACommit t c)           = [WillCommitRef t c]-  lookahead' (AAtom _ _)             = [WillSTM]-  lookahead' (AThrow _)              = [WillThrow]-  lookahead' (AThrowTo tid _ k)      = WillThrowTo tid : lookahead' k-  lookahead' (ACatching _ _ _)       = [WillCatching]-  lookahead' (APopCatching k)        = WillPopCatching : lookahead' k-  lookahead' (AMasking ms _ _)       = [WillSetMasking False ms]-  lookahead' (AResetMask b1 b2 ms k) = (if b1 then WillSetMasking else WillResetMasking) b2 ms : lookahead' k-  lookahead' (ALift _)               = [WillLift]-  lookahead' (AKnowsAbout _ k)       = WillKnowsAbout : lookahead' k-  lookahead' (AForgets _ k)          = WillForgets : lookahead' k-  lookahead' (AAllKnown k)           = WillAllKnown : lookahead' k-  lookahead' (AMessage m k)          = WillMessage m : lookahead' k-  lookahead' (AYield k)              = WillYield : lookahead' k-  lookahead' (AReturn k)             = WillReturn : lookahead' k-  lookahead' AStop                   = [WillStop]---- | Check if an operation could enable another thread.-willRelease :: Lookahead -> Bool-willRelease WillFork = True-willRelease WillYield = True-willRelease (WillPutVar _) = True-willRelease (WillTryPutVar _) = True-willRelease (WillReadVar _) = True-willRelease (WillTakeVar _) = True-willRelease (WillTryTakeVar _) = True-willRelease WillSTM = True-willRelease WillThrow = True-willRelease (WillSetMasking _ _) = True-willRelease (WillResetMasking _ _) = True-willRelease WillStop = True-willRelease _ = False---- Count the number of pre-emptions in a schedule prefix.------ Commit threads complicate this a bit. Conceptually, commits are--- happening truly in parallel, nondeterministically. The commit--- thread implementation is just there to unify the two sources of--- nondeterminism: commit timing and thread scheduling.------ SO, we don't count a switch TO a commit thread as a--- preemption. HOWEVER, the switch FROM a commit thread counts as a--- preemption if it is not to the thread that the commit interrupted.-preEmpCount :: [(Decision ThreadId, ThreadAction)] -> (Decision ThreadId, Lookahead) -> Int-preEmpCount ts (d, _) = go initialThread Nothing ts where-  go _ (Just Yield) ((SwitchTo t, a):rest) = go t (Just a) rest-  go tid prior ((SwitchTo t, a):rest)-    | isCommitThread t = go tid prior (skip rest)-    | otherwise = 1 + go t (Just a) rest-  go _   _ ((Start t,  a):rest) = go t   (Just a) rest-  go tid _ ((Continue, a):rest) = go tid (Just a) rest-  go _ prior [] = case (prior, d) of-    (Just Yield, SwitchTo _) -> 0-    (_, SwitchTo _) -> 1-    _ -> 0--  -- Commit threads have negative thread IDs for easy identification.-  isCommitThread = (< initialThread)--  -- Skip until the next context switch.-  skip = dropWhile (not . isContextSwitch . fst)-  isContextSwitch Continue = False-  isContextSwitch _ = True---- | A simplified view of the possible actions a thread can perform.-data ActionType =-    UnsynchronisedRead  CRefId-  -- ^ A 'readCRef' or a 'readForCAS'.-  | UnsynchronisedWrite CRefId-  -- ^ A 'writeCRef'.-  | UnsynchronisedOther-  -- ^ Some other action which doesn't require cross-thread-  -- communication.-  | PartiallySynchronisedCommit CRefId-  -- ^ A commit.-  | PartiallySynchronisedWrite  CRefId-  -- ^ A 'casCRef'-  | PartiallySynchronisedModify CRefId-  -- ^ A 'modifyCRefCAS'-  | SynchronisedModify  CRefId-  -- ^ An 'atomicModifyCRef'.-  | SynchronisedRead    MVarId-  -- ^ A 'readMVar' or 'takeMVar' (or @try@/@blocked@ variants).-  | SynchronisedWrite   MVarId-  -- ^ A 'putMVar' (or @try@/@blocked@ variant).-  | SynchronisedOther-  -- ^ Some other action which does require cross-thread-  -- communication.-  deriving (Eq, Show)--instance NFData ActionType where-  rnf (UnsynchronisedRead  r) = rnf r-  rnf (UnsynchronisedWrite r) = rnf r-  rnf (PartiallySynchronisedCommit r) = rnf r-  rnf (PartiallySynchronisedWrite  r) = rnf r-  rnf (PartiallySynchronisedModify  r) = rnf r-  rnf (SynchronisedModify  r) = rnf r-  rnf (SynchronisedRead    c) = rnf c-  rnf (SynchronisedWrite   c) = rnf c-  rnf a = a `seq` ()---- | Check if an action imposes a write barrier.-isBarrier :: ActionType -> Bool-isBarrier (SynchronisedModify _) = True-isBarrier (SynchronisedRead   _) = True-isBarrier (SynchronisedWrite  _) = True-isBarrier SynchronisedOther = True-isBarrier _ = False---- | Check if an action commits a given 'CRef'.-isCommit :: ActionType -> CRefId -> Bool-isCommit (PartiallySynchronisedCommit c) r = c == r-isCommit (PartiallySynchronisedWrite  c) r = c == r-isCommit (PartiallySynchronisedModify c) r = c == r-isCommit _ _ = False---- | Check if an action synchronises a given 'CRef'.-synchronises :: ActionType -> CRefId -> Bool-synchronises a r = isCommit a r || isBarrier a---- | Get the 'CRef' affected.-crefOf :: ActionType -> Maybe CRefId-crefOf (UnsynchronisedRead  r) = Just r-crefOf (UnsynchronisedWrite r) = Just r-crefOf (SynchronisedModify  r) = Just r-crefOf (PartiallySynchronisedCommit r) = Just r-crefOf (PartiallySynchronisedWrite  r) = Just r-crefOf (PartiallySynchronisedModify r) = Just r-crefOf _ = Nothing---- | Get the 'MVar' affected.-cvarOf :: ActionType -> Maybe MVarId-cvarOf (SynchronisedRead  c) = Just c-cvarOf (SynchronisedWrite c) = Just c-cvarOf _ = Nothing---- | Get the 'TVar's affected.-tvarsOf :: ThreadAction -> Set TVarId-tvarsOf act = S.fromList $ case act of-  STM trc _ -> concatMap tvarsOf' trc-  BlockedSTM trc -> concatMap tvarsOf' trc-  _ -> []--  where-    tvarsOf' (TRead  tv) = [tv]-    tvarsOf' (TWrite tv) = [tv]-    tvarsOf' (TOrElse ta tb) = concatMap tvarsOf' (ta ++ fromMaybe [] tb)-    tvarsOf' (TCatch  ta tb) = concatMap tvarsOf' (ta ++ fromMaybe [] tb)-    tvarsOf' _ = []---- | Throw away information from a 'ThreadAction' and give a--- simplified view of what is happening.------ This is used in the SCT code to help determine interesting--- alternative scheduling decisions.-simplify :: ThreadAction -> ActionType-simplify = maybe UnsynchronisedOther simplify' . rewind---- | Variant of 'simplify' that takes a 'Lookahead'.-simplify' :: Lookahead -> ActionType-simplify' (WillPutVar c)     = SynchronisedWrite c-simplify' (WillTryPutVar c)  = SynchronisedWrite c-simplify' (WillReadVar c)    = SynchronisedRead c-simplify' (WillTakeVar c)    = SynchronisedRead c-simplify' (WillTryTakeVar c) = SynchronisedRead c-simplify' (WillReadRef r)     = UnsynchronisedRead r-simplify' (WillReadRefCas r)  = UnsynchronisedRead r-simplify' (WillModRef r)      = SynchronisedModify r-simplify' (WillModRefCas r)   = PartiallySynchronisedModify r-simplify' (WillWriteRef r)    = UnsynchronisedWrite r-simplify' (WillCasRef r)      = PartiallySynchronisedWrite r-simplify' (WillCommitRef _ r) = PartiallySynchronisedCommit r-simplify' WillSTM         = SynchronisedOther-simplify' (WillThrowTo _) = SynchronisedOther-simplify' _ = UnsynchronisedOther------------------------------------------------------------------------------------- * Failures---- | An indication of how a concurrent computation failed.-data Failure =-    InternalError-  -- ^ Will be raised if the scheduler does something bad. This should-  -- never arise unless you write your own, faulty, scheduler! If it-  -- does, please file a bug report.-  | Abort-  -- ^ The scheduler chose to abort execution. This will be produced-  -- if, for example, all possible decisions exceed the specified-  -- bounds (there have been too many pre-emptions, the computation-  -- has executed for too long, or there have been too many yields).-  | Deadlock-  -- ^ The computation became blocked indefinitely on @MVar@s.-  | STMDeadlock-  -- ^ The computation became blocked indefinitely on @TVar@s.-  | UncaughtException-  -- ^ An uncaught exception bubbled to the top of the computation.-  deriving (Eq, Show, Read, Ord, Enum, Bounded)--instance NFData Failure where-  rnf f = f `seq` () -- WHNF == NF---- | Pretty-print a failure-showFail :: Failure -> String-showFail Abort = "[abort]"-showFail Deadlock = "[deadlock]"-showFail STMDeadlock = "[stm-deadlock]"-showFail InternalError = "[internal-error]"-showFail UncaughtException = "[exception]"------------------------------------------------------------------------------------- * Memory Models---- | The memory model to use for non-synchronised 'CRef' operations.-data MemType =-    SequentialConsistency-  -- ^ The most intuitive model: a program behaves as a simple-  -- interleaving of the actions in different threads. When a 'CRef'-  -- is written to, that write is immediately visible to all threads.-  | TotalStoreOrder-  -- ^ Each thread has a write buffer. A thread sees its writes-  -- immediately, but other threads will only see writes when they are-  -- committed, which may happen later. Writes are committed in the-  -- same order that they are created.-  | PartialStoreOrder-  -- ^ Each 'CRef' has a write buffer. A thread sees its writes-  -- immediately, but other threads will only see writes when they are-  -- committed, which may happen later. Writes to different 'CRef's-  -- are not necessarily committed in the same order that they are-  -- created.-  deriving (Eq, Show, Read, Ord, Enum, Bounded)--instance NFData MemType where-  rnf m = m `seq` () -- WHNF == NF
− Test/DejaFu/Deterministic/Internal/Memory.hs
@@ -1,208 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE GADTs        #-}---- |--- Module      : Test.DejaFu.Deterministic.Internal.Memory--- Copyright   : (c) 2016 Michael Walker--- License     : MIT--- Maintainer  : Michael Walker <mike@barrucadu.co.uk>--- Stability   : experimental--- Portability : BangPatterns, GADTs------ Operations over @CRef@s and @MVar@s. This module is NOT considered--- to form part of the public interface of this library.------ Relaxed memory operations over @CRef@s are implemented with an--- explicit write buffer: one per thread for TSO, and one per--- thread/variable combination for PSO. Unsynchronised writes append--- to this buffer, and periodically separate threads commit from these--- buffers to the \"actual\" @CRef@.------ This model comes from /Dynamic Partial Order Reduction for Relaxed--- Memory Models/, N. Zhang, M. Kusano, and C. Wang (2015).-module Test.DejaFu.Deterministic.Internal.Memory where--import Control.Monad (when)-import Data.Map.Strict (Map)-import Data.Maybe (isJust, fromJust)-import Data.Monoid ((<>))-import Data.Sequence (Seq, ViewL(..), (><), singleton, viewl)-import Test.DejaFu.Deterministic.Internal.Common-import Test.DejaFu.Deterministic.Internal.Threading-import Test.DejaFu.Internal--import qualified Data.Map.Strict as M------------------------------------------------------------------------------------- * Manipulating @CRef@s---- | In non-sequentially-consistent memory models, non-synchronised--- writes get buffered.------ The @CRefId@ parameter is only used under PSO. Under TSO each--- thread has a single buffer.-newtype WriteBuffer r = WriteBuffer-  { buffer :: Map (ThreadId, Maybe CRefId) (Seq (BufferedWrite r)) }---- | A buffered write is a reference to the variable, and the value to--- 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.-data BufferedWrite r where-  BufferedWrite :: ThreadId -> CRef r a -> a -> BufferedWrite r---- | An empty write buffer.-emptyBuffer :: WriteBuffer r-emptyBuffer = WriteBuffer M.empty---- | Add a new write to the end of a buffer.-bufferWrite :: Monad n => Fixed n r s -> WriteBuffer r -> (ThreadId, Maybe CRefId) -> CRef r a -> a -> n (WriteBuffer r)-bufferWrite fixed (WriteBuffer wb) k@(tid, _) cref@(CRef _ ref) new = do-  -- Construct the new write buffer-  let write = singleton $ BufferedWrite tid cref new-  let buffer' = M.insertWith (flip (><)) k write wb--  -- Write the thread-local value to the @CRef@'s update map.-  (locals, count, def) <- readRef fixed ref-  writeRef fixed ref (M.insert tid new locals, count, def)--  return $ WriteBuffer buffer'---- | Commit the write at the head of a buffer.-commitWrite :: Monad n => Fixed n r s -> WriteBuffer r -> (ThreadId, Maybe CRefId) -> n (WriteBuffer r)-commitWrite fixed w@(WriteBuffer wb) k = case maybe EmptyL viewl $ M.lookup k wb of-  BufferedWrite _ cref a :< rest -> do-    writeImmediate fixed cref a-    return . WriteBuffer $ M.insert k rest wb--  EmptyL -> return w---- | Read from a @CRef@, returning a newer thread-local non-committed--- write if there is one.-readCRef :: Monad n => Fixed n r s -> CRef r a -> ThreadId -> n a-readCRef fixed cref tid = do-  (val, _) <- readCRefPrim fixed cref tid-  return val---- | Read from a @CRef@, returning a @Ticket@ representing the current--- view of the thread.-readForTicket :: Monad n => Fixed n r s -> CRef r a -> ThreadId -> n (Ticket a)-readForTicket fixed cref@(CRef crid _) tid = do-  (val, count) <- readCRefPrim fixed cref tid-  return $ Ticket crid count val---- | Perform a compare-and-swap on a @CRef@ if the ticket is still--- valid. This is strict in the \"new\" value argument.-casCRef :: Monad n => Fixed n r s -> CRef r a -> ThreadId -> Ticket a -> a -> n (Bool, Ticket a)-casCRef fixed cref tid (Ticket _ cc _) !new = do-  tick'@(Ticket _ cc' _) <- readForTicket fixed cref tid--  if cc == cc'-  then do-    writeImmediate fixed cref new-    tick'' <- readForTicket fixed cref tid-    return (True, tick'')-  else return (False, tick')---- | Read the local state of a @CRef@.-readCRefPrim :: Monad n => Fixed n r s -> CRef r a -> ThreadId -> n (a, Integer)-readCRefPrim fixed (CRef _ ref) tid = do-  (vals, count, def) <- readRef fixed ref--  return (M.findWithDefault def tid vals, count)---- | Write and commit to a @CRef@ immediately, clearing the update map--- and incrementing the write count.-writeImmediate :: Monad n => Fixed n r s -> CRef r a -> a -> n ()-writeImmediate fixed (CRef _ ref) a = do-  (_, count, _) <- readRef fixed ref-  writeRef fixed ref (M.empty, count + 1, a)---- | Flush all writes in the buffer.-writeBarrier :: Monad n => Fixed n r s -> WriteBuffer r -> n ()-writeBarrier fixed (WriteBuffer wb) = mapM_ flush $ M.elems wb where-  flush = mapM_ $ \(BufferedWrite _ cref a) -> writeImmediate fixed cref a---- | Add phantom threads to the thread list to commit pending writes.-addCommitThreads :: WriteBuffer r -> Threads n r s -> Threads n r s-addCommitThreads (WriteBuffer wb) ts = ts <> M.fromList phantoms where-  phantoms = [ (ThreadId Nothing $ negate tid, mkthread $ fromJust c)-             | ((k, b), tid) <- zip (M.toList wb) [1..]-             , let c = go $ viewl b-             , isJust c]-  go (BufferedWrite tid (CRef crid _) _ :< _) = Just $ ACommit tid crid-  go EmptyL = Nothing---- | Remove phantom threads.-delCommitThreads :: Threads n r s -> Threads n r s-delCommitThreads = M.filterWithKey $ \k _ -> k >= initialThread------------------------------------------------------------------------------------- * Manipulating @MVar@s---- | Put into a @MVar@, blocking if full.-putIntoMVar :: Monad n => MVar r a -> a -> Action n r s-             -> Fixed n r s -> ThreadId -> Threads n r s -> n (Bool, Threads n r s, [ThreadId])-putIntoMVar cvar a c = mutMVar True cvar a (const c)---- | Try to put into a @MVar@, not blocking if full.-tryPutIntoMVar :: Monad n => MVar r a -> a -> (Bool -> Action n r s)-                 -> Fixed n r s -> ThreadId -> Threads n r s -> n (Bool, Threads n r s, [ThreadId])-tryPutIntoMVar = mutMVar False---- | Read from a @MVar@, blocking if empty.-readFromMVar :: Monad n => MVar r a -> (a -> Action n r s)-              -> Fixed n r s -> ThreadId -> Threads n r s -> n (Bool, Threads n r s, [ThreadId])-readFromMVar cvar c = seeMVar False True cvar (c . fromJust)---- | Take from a @MVar@, blocking if empty.-takeFromMVar :: Monad n => MVar r a -> (a -> Action n r s)-              -> Fixed n r s -> ThreadId -> Threads n r s -> n (Bool, Threads n r s, [ThreadId])-takeFromMVar cvar c = seeMVar True True cvar (c . fromJust)---- | Try to take from a @MVar@, not blocking if empty.-tryTakeFromMVar :: Monad n => MVar r a -> (Maybe a -> Action n r s)-                  -> Fixed n r s -> ThreadId -> Threads n r s -> n (Bool, Threads n r s, [ThreadId])-tryTakeFromMVar = seeMVar True False---- | Mutate a @MVar@, in either a blocking or nonblocking way.-mutMVar :: Monad n-         => Bool -> MVar r a -> a -> (Bool -> Action n r s)-         -> Fixed n r s -> ThreadId -> Threads n r s -> n (Bool, Threads n r s, [ThreadId])-mutMVar blocking (MVar cvid ref) a c fixed threadid threads = do-  val <- readRef fixed ref--  case val of-    Just _-      | blocking ->-        let threads' = block (OnMVarEmpty cvid) threadid threads-        in return (False, threads', [])--      | otherwise ->-        return (False, goto (c False) threadid threads, [])--    Nothing -> do-      writeRef fixed ref $ Just a-      let (threads', woken) = wake (OnMVarFull cvid) threads-      return (True, goto (c True) threadid threads', woken)---- | Read a @MVar@, in either a blocking or nonblocking--- way.-seeMVar :: Monad n-         => Bool -> Bool -> MVar r a -> (Maybe a -> Action n r s)-         -> Fixed n r s -> ThreadId -> Threads n r s -> n (Bool, Threads n r s, [ThreadId])-seeMVar emptying blocking (MVar cvid ref) c fixed threadid threads = do-  val <- readRef fixed ref--  case val of-    Just _ -> do-      when emptying $ writeRef fixed ref Nothing-      let (threads', woken) = wake (OnMVarEmpty cvid) threads-      return (True, goto (c val) threadid threads', woken)--    Nothing-      | blocking ->-        let threads' = block (OnMVarFull cvid) threadid threads-        in return (False, threads', [])--      | otherwise ->-        return (False, goto (c Nothing) threadid threads, [])
− Test/DejaFu/Deterministic/Internal/Threading.hs
@@ -1,200 +0,0 @@-{-# LANGUAGE ExistentialQuantification #-}-{-# LANGUAGE RankNTypes                #-}---- |--- Module      : Test.DejaFu.Deterministic.Internal.Threading--- Copyright   : (c) 2016 Michael Walker--- License     : MIT--- Maintainer  : Michael Walker <mike@barrucadu.co.uk>--- Stability   : experimental--- Portability : ExistentialQuantification, RankNTypes------ Operations and types for threads. This module is NOT considered to--- form part of the public interface of this library.-module Test.DejaFu.Deterministic.Internal.Threading where--import Control.Exception (Exception, MaskingState(..), SomeException, fromException)-import Data.List (intersect, nub)-import Data.Map.Strict (Map)-import Data.Maybe (fromMaybe, isJust, isNothing)-import Test.DejaFu.Deterministic.Internal.Common--import qualified Data.Map.Strict as M------------------------------------------------------------------------------------- * Threads---- | Threads are stored in a map index by 'ThreadId'.-type Threads n r s = Map ThreadId (Thread n r s)---- | All the state of a thread.-data Thread n r s = Thread-  { _continuation :: Action n r s-  -- ^ The next action to execute.-  , _blocking     :: Maybe BlockedOn-  -- ^ The state of any blocks.-  , _handlers     :: [Handler n r s]-  -- ^ Stack of exception handlers-  , _masking      :: MaskingState-  -- ^ The exception masking state.-  , _known        :: [Either MVarId TVarId]-  -- ^ Shared variables the thread knows about.-  , _fullknown    :: Bool-  -- ^ Whether the referenced variables of the thread are completely-  -- known. If every thread has _fullknown == True, then turn on-  -- detection of nonglobal deadlock.-  }---- | Construct a thread with just one action-mkthread :: Action n r s -> Thread n r s-mkthread c = Thread c Nothing [] Unmasked [] False------------------------------------------------------------------------------------- * Blocking---- | A @BlockedOn@ is used to determine what sort of variable a thread--- is blocked on.-data BlockedOn = OnMVarFull MVarId | OnMVarEmpty MVarId | OnTVar [TVarId] | OnMask ThreadId deriving Eq---- | Determine if a thread is blocked in a certain way.-(~=) :: Thread n r s -> BlockedOn -> Bool-thread ~= theblock = case (_blocking thread, theblock) of-  (Just (OnMVarFull  _), OnMVarFull  _) -> True-  (Just (OnMVarEmpty _), OnMVarEmpty _) -> True-  (Just (OnTVar      _), OnTVar      _) -> True-  (Just (OnMask      _), OnMask      _) -> True-  _ -> False---- | Determine if a thread is deadlocked. If at least one thread is--- not in a fully-known state, this will only check for global--- deadlock.-isLocked :: ThreadId -> Threads n r a -> Bool-isLocked tid ts-  | allKnown = case M.lookup tid ts of-    Just thread -> noRefs $ _blocking thread-    Nothing -> False-  | otherwise = M.null $ M.filter (isNothing . _blocking) ts--  where-    -- | Check if all threads are in a fully-known state.-    allKnown = all _fullknown $ M.elems ts--    -- | Check if no other runnable thread has a reference to anything-    -- the block references.-    noRefs (Just (OnMVarFull  cvarid)) = null $ findMVar  cvarid-    noRefs (Just (OnMVarEmpty cvarid)) = null $ findMVar  cvarid-    noRefs (Just (OnTVar      tvids))  = null $ findTVars tvids-    noRefs _ = True--    -- | Get IDs of all threads (other than the one under-    -- consideration) which reference a 'MVar'.-    findMVar cvarid = M.keys $ M.filterWithKey (check [Left cvarid]) ts--    -- | Get IDs of all runnable threads (other than the one under-    -- consideration) which reference some 'TVar's.-    findTVars tvids = M.keys $ M.filterWithKey (check (map Right tvids)) ts--    -- | Check if a thread references a variable, and if it's not the-    -- thread under consideration.-    check lookingfor thetid thethread-      | thetid == tid = False-      | otherwise     = (not . null $ lookingfor `intersect` _known thethread) && isNothing (_blocking thethread)------------------------------------------------------------------------------------- * Exceptions---- | An exception handler.-data Handler n r s = forall e. Exception e => Handler (e -> Action n r s)---- | Propagate an exception upwards, finding the closest handler--- which can deal with it.-propagate :: SomeException -> ThreadId -> Threads n r s -> Maybe (Threads n r s)-propagate e tid threads = case M.lookup tid threads >>= go . _handlers of-  Just (act, hs) -> Just $ except act hs tid threads-  Nothing -> Nothing--  where-    go [] = Nothing-    go (Handler h:hs) = maybe (go hs) (\act -> Just (act, hs)) $ h <$> fromException e---- | Check if a thread can be interrupted by an exception.-interruptible :: Thread n r s -> Bool-interruptible thread = _masking thread == Unmasked || (_masking thread == MaskedInterruptible && isJust (_blocking thread))---- | Register a new exception handler.-catching :: Exception e => (e -> Action n r s) -> ThreadId -> Threads n r s -> Threads n r s-catching h = M.alter $ \(Just thread) -> Just $ thread { _handlers = Handler h : _handlers thread }---- | Remove the most recent exception handler.-uncatching :: ThreadId -> Threads n r s -> Threads n r s-uncatching = M.alter $ \(Just thread) -> Just $ thread { _handlers = tail $ _handlers thread }---- | Raise an exception in a thread.-except :: Action n r s -> [Handler n r s] -> ThreadId -> Threads n r s -> Threads n r s-except act hs = M.alter $ \(Just thread) -> Just $ thread { _continuation = act, _handlers = hs, _blocking = Nothing }---- | Set the masking state of a thread.-mask :: MaskingState -> ThreadId -> Threads n r s -> Threads n r s-mask ms = M.alter $ \(Just thread) -> Just $ thread { _masking = ms }------------------------------------------------------------------------------------- * Manipulating threads---- | Replace the @Action@ of a thread.-goto :: Action n r s -> ThreadId -> Threads n r s -> Threads n r s-goto a = M.alter $ \(Just thread) -> Just (thread { _continuation = a })---- | Start a thread with the given ID, inheriting the masking state--- from the parent thread. This ID must not already be in use!-launch :: ThreadId -> ThreadId -> ((forall b. M n r s b -> M n r s b) -> Action n r s) -> Threads n r s -> Threads n r s-launch parent tid a threads = launch' ms tid a threads where-  ms = fromMaybe Unmasked $ _masking <$> M.lookup parent threads---- | Start a thread with the given ID and masking state. This must not already be in use!-launch' :: MaskingState -> ThreadId -> ((forall b. M n r s b -> M n r s b) -> Action n r s) -> Threads n r s -> Threads n r s-launch' ms tid a = M.insert tid thread where-  thread = Thread { _continuation = a umask, _blocking = Nothing, _handlers = [], _masking = ms, _known = [], _fullknown = False }--  umask mb = resetMask True Unmasked >> mb >>= \b -> resetMask False ms >> return b-  resetMask typ m = cont $ \k -> AResetMask typ True m $ k ()---- | Kill a thread.-kill :: ThreadId -> Threads n r s -> Threads n r s-kill = M.delete---- | Block a thread.-block :: BlockedOn -> ThreadId -> Threads n r s -> Threads n r s-block blockedOn = M.alter doBlock where-  doBlock (Just thread) = Just $ thread { _blocking = Just blockedOn }-  doBlock _ = error "Invariant failure in 'block': thread does NOT exist!"---- | Unblock all threads waiting on the appropriate block. For 'TVar'--- blocks, this will wake all threads waiting on at least one of the--- given 'TVar's.-wake :: BlockedOn -> Threads n r s -> (Threads n r s, [ThreadId])-wake blockedOn threads = (unblock <$> threads, M.keys $ M.filter isBlocked threads) where-  unblock thread-    | isBlocked thread = thread { _blocking = Nothing }-    | otherwise = thread--  isBlocked thread = case (_blocking thread, blockedOn) of-    (Just (OnTVar tvids), OnTVar blockedOn') -> tvids `intersect` blockedOn' /= []-    (theblock, _) -> theblock == Just blockedOn---- | Record that a thread knows about a shared variable.-knows :: [Either MVarId TVarId] -> ThreadId -> Threads n r s -> Threads n r s-knows theids = M.alter go where-  go (Just thread) = Just $ thread { _known = nub $ theids ++ _known thread }-  go _ = error "Invariant failure in 'knows': thread does NOT exist!"---- | Forget about a shared variable.-forgets :: [Either MVarId TVarId] -> ThreadId -> Threads n r s -> Threads n r s-forgets theids = M.alter go where-  go (Just thread) = Just $ thread { _known = filter (`notElem` theids) $ _known thread }-  go _ = error "Invariant failure in 'forgets': thread does NOT exist!"---- | Record that a thread's shared variable state is fully known.-fullknown :: ThreadId -> Threads n r s -> Threads n r s-fullknown = M.alter go where-  go (Just thread) = Just $ thread { _fullknown = True }-  go _ = error "Invariant failure in 'fullknown': thread does NOT exist!"
− Test/DejaFu/Internal.hs
@@ -1,43 +0,0 @@-{-# LANGUAGE RankNTypes #-}---- |--- Module      : Test.DejaFu.Internal--- Copyright   : (c) 2016 Michael Walker--- License     : MIT--- Maintainer  : Michael Walker <mike@barrucadu.co.uk>--- Stability   : experimental--- Portability : RankNTypes------ Dealing with mutable state. This module is NOT considered to form--- part of the public interface of this library.-module Test.DejaFu.Internal where--import Control.Monad.ST (ST)-import Data.IORef (IORef, newIORef, readIORef, writeIORef)-import Data.STRef (STRef, newSTRef, readSTRef, writeSTRef)---- | Mutable references.-data Ref n r m = Ref-  { newRef   :: forall a. a -> n (r a)-  , readRef  :: forall a. r a -> n a-  , writeRef :: forall a. r a -> a -> n ()-  , liftN    :: forall a. n a -> m a-  }---- | Method dict for 'ST'.-refST :: (forall a. ST t a -> m a) -> Ref (ST t) (STRef t) m-refST lftN = Ref-  { newRef   = newSTRef-  , readRef  = readSTRef-  , writeRef = writeSTRef-  , liftN    = lftN-  }---- | Method dict for 'IO'.-refIO :: (forall a. IO a -> m a) -> Ref IO IORef m-refIO lftN = Ref-  { newRef   = newIORef-  , readRef  = readIORef-  , writeRef = writeIORef-  , liftN    = lftN-  }
Test/DejaFu/SCT.hs view
@@ -1,5 +1,4 @@ {-# LANGUAGE CPP #-}-{-# LANGUAGE RankNTypes #-}  -- | -- Module      : Test.DejaFu.SCT@@ -7,7 +6,7 @@ -- License     : MIT -- Maintainer  : Michael Walker <mike@barrucadu.co.uk> -- Stability   : experimental--- Portability : CPP, RankNTypes+-- Portability : CPP -- -- Systematic testing for concurrent computations. module Test.DejaFu.SCT@@ -32,7 +31,6 @@   -- K. McKinley for more details.      sctBounded-  , sctBoundedIO    -- * Combination Bounds @@ -51,7 +49,6 @@   , noBounds    , sctBound-  , sctBoundIO    -- * Individual Bounds @@ -67,7 +64,6 @@   , PreemptionBound(..)   , defaultPreemptionBound   , sctPreBound-  , sctPreBoundIO   , pBacktrack   , pBound @@ -82,7 +78,6 @@   , FairBound(..)   , defaultFairBound   , sctFairBound-  , sctFairBoundIO   , fBacktrack   , fBound @@ -94,7 +89,6 @@   , LengthBound(..)   , defaultLengthBound   , sctLengthBound-  , sctLengthBoundIO    -- * Backtracking @@ -103,8 +97,7 @@   ) where  import Control.DeepSeq (NFData(..))-import Control.Exception (MaskingState(..))-import Data.Functor.Identity (Identity(..), runIdentity)+import Control.Monad.Ref (MonadRef) import Data.Map.Strict (Map) import qualified Data.Map.Strict as M import Data.Maybe (isJust, fromJust)@@ -117,8 +110,8 @@                  , LengthBound(..), defaultLengthBound, lenBound, lenBacktrack                  ) -import Test.DejaFu.Deterministic (ConcIO, ConcST, runConcIO, runConcST)-import Test.DejaFu.Deterministic.Internal+import Test.DejaFu.Common+import Test.DejaFu.Conc  ------------------------------------------------------------------------------- -- Combined Bounds@@ -148,22 +141,16 @@   }  -- | An SCT runner using a bounded scheduler-sctBound :: MemType+sctBound :: MonadRef r n+  => MemType   -- ^ The memory model to use for non-synchronised @CRef@ operations.   -> Bounds   -- ^ The combined bounds.-  -> (forall t. ConcST t a)+  -> Conc n r a   -- ^ The computation to run many times-  -> [(Either Failure a, Trace ThreadId ThreadAction Lookahead)]+  -> n [(Either Failure a, Trace ThreadId ThreadAction Lookahead)] sctBound memtype cb = sctBounded memtype (cBound cb) (cBacktrack cb) --- | Variant of 'sctBound' for computations which do 'IO'.-sctBoundIO :: MemType-  -> Bounds-  -> ConcIO a-  -> IO [(Either Failure a, Trace ThreadId ThreadAction Lookahead)]-sctBoundIO memtype cb = sctBoundedIO memtype (cBound cb) (cBacktrack cb)- -- | Combination bound function cBound :: Bounds -> BoundFunc ThreadId ThreadAction Lookahead cBound (Bounds pb fb lb) = maybe trueBound pBound pb &+& maybe trueBound fBound fb &+& maybe trueBound lenBound lb@@ -183,23 +170,17 @@ -- Pre-emption bounding  -- | An SCT runner using a pre-emption bounding scheduler.-sctPreBound :: MemType+sctPreBound :: MonadRef r n+  => MemType   -- ^ The memory model to use for non-synchronised @CRef@ operations.   -> PreemptionBound   -- ^ The maximum number of pre-emptions to allow in a single   -- execution-  -> (forall t. ConcST t a)+  -> Conc n r a   -- ^ The computation to run many times-  -> [(Either Failure a, Trace ThreadId ThreadAction Lookahead)]+  -> n [(Either Failure a, Trace ThreadId ThreadAction Lookahead)] sctPreBound memtype pb = sctBounded memtype (pBound pb) pBacktrack --- | Variant of 'sctPreBound' for computations which do 'IO'.-sctPreBoundIO :: MemType-  -> PreemptionBound-  -> ConcIO a-  -> IO [(Either Failure a, Trace ThreadId ThreadAction Lookahead)]-sctPreBoundIO memtype pb = sctBoundedIO memtype (pBound pb) pBacktrack- -- | Add a backtrack point, and also conservatively add one prior to -- the most recent transition before that point. This may result in -- the same state being reached multiple times, but is needed because@@ -217,23 +198,17 @@ -- Fair bounding  -- | An SCT runner using a fair bounding scheduler.-sctFairBound :: MemType+sctFairBound :: MonadRef r n+  => MemType   -- ^ The memory model to use for non-synchronised @CRef@ operations.   -> FairBound   -- ^ The maximum difference between the number of yield operations   -- performed by different threads.-  -> (forall t. ConcST t a)+  -> Conc n r a   -- ^ The computation to run many times-  -> [(Either Failure a, Trace ThreadId ThreadAction Lookahead)]+  -> n [(Either Failure a, Trace ThreadId ThreadAction Lookahead)] sctFairBound memtype fb = sctBounded memtype (fBound fb) fBacktrack --- | Variant of 'sctFairBound' for computations which do 'IO'.-sctFairBoundIO :: MemType-  -> FairBound-  -> ConcIO a-  -> IO [(Either Failure a, Trace ThreadId ThreadAction Lookahead)]-sctFairBoundIO memtype fb = sctBoundedIO memtype (fBound fb) fBacktrack- -- | Fair bound function fBound :: FairBound -> BoundFunc ThreadId ThreadAction Lookahead fBound = fairBound didYield willYield (\act -> case act of Fork t -> [t]; _ -> [])@@ -247,23 +222,17 @@ -- Length bounding  -- | An SCT runner using a length bounding scheduler.-sctLengthBound :: MemType+sctLengthBound :: MonadRef r n+  => MemType   -- ^ The memory model to use for non-synchronised @CRef@ operations.   -> LengthBound   -- ^ The maximum length of a schedule, in terms of primitive   -- actions.-  -> (forall t. ConcST t a)+  -> Conc n r a   -- ^ The computation to run many times-  -> [(Either Failure a, Trace ThreadId ThreadAction Lookahead)]+  -> n [(Either Failure a, Trace ThreadId ThreadAction Lookahead)] sctLengthBound memtype lb = sctBounded memtype (lenBound lb) lenBacktrack --- | Variant of 'sctFairBound' for computations which do 'IO'.-sctLengthBoundIO :: MemType-  -> LengthBound-  -> ConcIO a-  -> IO [(Either Failure a, Trace ThreadId ThreadAction Lookahead)]-sctLengthBoundIO memtype lb = sctBoundedIO memtype (lenBound lb) lenBacktrack- ------------------------------------------------------------------------------- -- DPOR @@ -279,7 +248,8 @@ -- Note that unlike with non-bounded partial-order reduction, this may -- do some redundant work as the introduction of a bound can make -- previously non-interfering events interfere with each other.-sctBounded :: MemType+sctBounded :: MonadRef r n+  => MemType   -- ^ The memory model to use for non-synchronised @CRef@ operations.   -> BoundFunc ThreadId ThreadAction Lookahead   -- ^ Check if a prefix trace is within the bound@@ -288,27 +258,9 @@   -- execution so far, the index to insert the backtracking point, and   -- the thread to backtrack to. This may insert more than one   -- backtracking point.-  -> (forall t. ConcST t a) -> [(Either Failure a, Trace ThreadId ThreadAction Lookahead)]-sctBounded memtype bf backtrack c = runIdentity $ sctBoundedM memtype bf backtrack run where-  run memty sched s = Identity $ runConcST sched memty s c---- | Variant of 'sctBounded' for computations which do 'IO'.-sctBoundedIO :: MemType-  -> BoundFunc ThreadId ThreadAction Lookahead-  -> BacktrackFunc ThreadId ThreadAction Lookahead DepState-  -> ConcIO a -> IO [(Either Failure a, Trace ThreadId ThreadAction Lookahead)]-sctBoundedIO memtype bf backtrack c = sctBoundedM memtype bf backtrack run where-  run memty sched s = runConcIO sched memty s c---- | Generic SCT runner.-sctBoundedM :: Monad m-  => MemType-  -> ([(Decision ThreadId, ThreadAction)] -> (Decision ThreadId, Lookahead) -> Bool)-  -> BacktrackFunc ThreadId ThreadAction Lookahead DepState-  -> (forall s. MemType -> Scheduler ThreadId ThreadAction Lookahead s -> s -> m (Either Failure a, s, Trace ThreadId ThreadAction Lookahead))-  -- ^ Monadic runner, with computation fixed.-  -> m [(Either Failure a, Trace ThreadId ThreadAction Lookahead)]-sctBoundedM memtype bf backtrack run =+  -> Conc n r a+  -> n [(Either Failure a, Trace ThreadId ThreadAction Lookahead)]+sctBounded memtype bf backtrack conc =   dpor didYield        willYield        initialDepState@@ -324,7 +276,7 @@        bf        backtrack        pruneCommits-       (run memtype)+       (\sched s -> runConcurrent sched memtype s conc)  ------------------------------------------------------------------------------- -- Post-processing@@ -345,7 +297,7 @@     onlycommits = all (<initialThread) . M.keys $ dporTodo bpor     alldonesync = all barrier . M.elems $ dporDone bpor -    barrier = isBarrier . simplify . fromJust . dporAction+    barrier = isBarrier . simplifyAction . fromJust . dporAction  ------------------------------------------------------------------------------- -- Dependency function@@ -381,9 +333,9 @@   Just l2     | isSTM a1 && isSTM a2       -> not . S.null $ tvarsOf a1 `S.intersection` tvarsOf a2-    | not (isBlock a1 && isBarrier (simplify' l2)) ->+    | not (isBlock a1 && isBarrier (simplifyLookahead l2)) ->       dependent' memtype ds (t1, a1) (t2, l2)-  _ -> dependentActions memtype ds (simplify a1) (simplify a2)+  _ -> dependentActions memtype ds (simplifyAction a1) (simplifyAction a2)    where     isSTM (STM _ _) = True@@ -403,7 +355,7 @@ #endif    -- Worst-case assumption: all IO is dependent.-  (Lift, WillLift) -> True+  (LiftIO, WillLiftIO) -> True    -- Throwing an exception is only dependent with actions in that   -- thread and if the actions can be interrupted. We can also@@ -429,8 +381,8 @@   -- anyway so there's no point pre-empting the action UNLESS the   -- pre-emption would possibly allow for a different relaxed memory   -- stage.-  _ | isBlock a1 && isBarrier (simplify' l2) -> False-    | otherwise -> dependentActions memtype ds (simplify a1) (simplify' l2)+  _ | isBlock a1 && isBarrier (simplifyLookahead l2) -> False+    | otherwise -> dependentActions memtype ds (simplifyAction a1) (simplifyLookahead l2)  -- | Check if two 'ActionType's are dependent. Note that this is not -- sufficient to know if two 'ThreadAction's are dependent, without@@ -460,7 +412,7 @@     -- Two actions on the same CRef where at least one is synchronised     | same crefOf && (synchronises a1 (fromJust $ crefOf a1) || synchronises a2 (fromJust $ crefOf a2)) -> True     -- Two actions on the same MVar-    | same cvarOf -> True+    | same mvarOf -> True    _ -> False @@ -508,7 +460,7 @@ updateCRState (CommitRef _ r) = M.delete r updateCRState (WriteRef    r) = M.insert r True updateCRState ta-  | isBarrier $ simplify ta = const M.empty+  | isBarrier $ simplifyAction ta = const M.empty   | otherwise = id  -- | Update the thread masking state with the action that has just
Test/DejaFu/STM.hs view
@@ -23,23 +23,20 @@   , TTrace   , TAction(..)   , TVarId-  , runTransactionST-  , runTransactionIO+  , runTransaction   ) where -import Control.Monad (liftM)+import Control.Monad (unless) import Control.Monad.Catch (MonadCatch(..), MonadThrow(..)) import Control.Monad.Cont (cont)+import Control.Monad.Ref (MonadRef) import Control.Monad.ST (ST) import Data.IORef (IORef) import Data.STRef (STRef)-import Test.DejaFu.Deterministic.Internal.Common (TVarId, IdSource, TAction(..), TTrace)-import Test.DejaFu.Internal-import Test.DejaFu.STM.Internal  import qualified Control.Monad.STM.Class as C--{-# ANN module ("HLint: ignore Use record patterns" :: String) #-}+import Test.DejaFu.Common+import Test.DejaFu.STM.Internal  newtype STMLike n r a = S { runSTM :: M n r a } deriving (Functor, Applicative, Monad) @@ -82,26 +79,14 @@    writeTVar tvar a = toSTM (\c -> SWrite tvar a (c ())) --- | Run a transaction in the 'ST' monad, returning the result and new--- initial 'TVarId'. If the transaction ended by calling 'retry', any--- 'TVar' modifications are undone.-runTransactionST :: STMST t a -> IdSource -> ST t (Result a, IdSource, TTrace)-runTransactionST = runTransactionM fixedST where-  fixedST = refST $ \mb -> cont (\c -> SLift $ c `liftM` mb)---- | Run a transaction in the 'IO' monad, returning the result and new--- initial 'TVarId'. If the transaction ended by calling 'retry', any--- 'TVar' modifications are undone.-runTransactionIO :: STMIO a -> IdSource -> IO (Result a, IdSource, TTrace)-runTransactionIO = runTransactionM fixedIO where-  fixedIO = refIO $ \mb -> cont (\c -> SLift $ c `liftM` mb)+-- | Run a transaction, returning the result and new initial+-- 'TVarId'. If the transaction ended by calling 'retry', any 'TVar'+-- modifications are undone.+runTransaction :: MonadRef r n+               => STMLike n r a -> IdSource -> n (Result a, IdSource, TTrace)+runTransaction ma tvid = do+  (res, undo, tvid', trace) <- doTransaction (runSTM ma) tvid --- | Run a transaction in an arbitrary monad.-runTransactionM :: Monad n-  => Fixed n r -> STMLike n r a -> IdSource -> n (Result a, IdSource, TTrace)-runTransactionM ref ma tvid = do-  (res, undo, tvid', trace) <- doTransaction ref (runSTM ma) tvid+  unless (isSTMSuccess res) undo -  case res of-    Success _ _ _ -> return (res, tvid', trace)-    _ -> undo >> return (res, tvid, trace)+  pure (res, tvid', trace)
Test/DejaFu/STM/Internal.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE ExistentialQuantification #-}-{-# LANGUAGE RankNTypes                #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE RankNTypes #-}  -- | -- Module      : Test.DejaFu.STM.Internal@@ -16,10 +17,13 @@  import Control.Exception (Exception, SomeException, fromException, toException) import Control.Monad.Cont (Cont, runCont)+import Control.Monad.Ref (MonadRef, newRef, readRef, writeRef) import Data.List (nub)-import Test.DejaFu.Deterministic.Internal.Common (TVarId, IdSource, TAction(..), TTrace, nextTVId)-import Test.DejaFu.Internal +import Test.DejaFu.Common++{-# ANN module ("HLint: ignore Use record patterns" :: String) #-}+ -------------------------------------------------------------------------------- -- The @STMLike@ monad @@ -27,9 +31,6 @@ -- actions. type M n r a = Cont (STMAction n r) a --- | Dict of methods for implementations to override.-type Fixed n r = Ref n r (Cont (STMAction n r))- -------------------------------------------------------------------------------- -- * Primitive actions @@ -41,10 +42,9 @@   | forall a. SWrite (TVar r a) a (STMAction n r)   | forall a. SOrElse (M n r a) (M n r a) (a -> STMAction n r)   | forall a. SNew String a (TVar r a -> STMAction n r)-  | SLift (n (STMAction n r))   | forall e. Exception e => SThrow e   | SRetry-  | SStop+  | SStop (n ())  -------------------------------------------------------------------------------- -- * @TVar@s@@ -71,6 +71,11 @@   -- ^ The transaction aborted by throwing an exception.   deriving Show +-- | Check if a 'Result' is a @Success@.+isSTMSuccess :: Result a -> Bool+isSTMSuccess (Success _ _ _) = True+isSTMSuccess _ = False+ instance Functor Result where   fmap f (Success rs ws a) = Success rs ws $ f a   fmap _ (Retry rs)    = Retry rs@@ -84,15 +89,15 @@ -- * Execution  -- | Run a STM transaction, returning an action to undo its effects.-doTransaction :: Monad n => Fixed n r -> M n r a -> IdSource -> n (Result a, n (), IdSource, TTrace)-doTransaction fixed ma idsource = do-  ref <- newRef fixed Nothing+doTransaction :: MonadRef r n => M n r a -> IdSource -> n (Result a, n (), IdSource, TTrace)+doTransaction ma idsource = do+  ref <- newRef Nothing -  let c = runCont (ma >>= liftN fixed . writeRef fixed ref . Just . Right) $ const SStop+  let c = runCont ma (SStop . writeRef ref . Just . Right)    (idsource', undo, readen, written, trace) <- go ref c (return ()) idsource [] [] [] -  res <- readRef fixed ref+  res <- readRef ref    case res of     Just (Right val) -> return (Success (nub readen) (nub written) val, undo, idsource', reverse trace)@@ -102,7 +107,7 @@    where     go ref act undo nidsrc readen written sofar = do-      (act', undo', nidsrc', readen', written', tact) <- stepTrans fixed act nidsrc+      (act', undo', nidsrc', readen', written', tact) <- stepTrans act nidsrc        let newIDSource = nidsrc'           newAct = act'@@ -113,25 +118,24 @@        case tact of         TStop  -> return (newIDSource, newUndo, newReaden, newWritten, TStop:newSofar)-        TRetry -> writeRef fixed ref Nothing+        TRetry -> writeRef ref Nothing           >> return (newIDSource, newUndo, newReaden, newWritten, TRetry:newSofar)-        TThrow -> writeRef fixed ref (Just . Left $ case act of SThrow e -> toException e; _ -> undefined)+        TThrow -> writeRef ref (Just . Left $ case act of SThrow e -> toException e; _ -> undefined)           >> return (newIDSource, newUndo, newReaden, newWritten, TThrow:newSofar)         _ -> go ref newAct newUndo newIDSource newReaden newWritten newSofar  -- | Run a transaction for one step.-stepTrans :: Monad n => Fixed n r -> STMAction n r -> IdSource -> n (STMAction n r, n (), IdSource, [TVarId], [TVarId], TAction)-stepTrans fixed act idsource = case act of+stepTrans :: MonadRef r n => STMAction n r -> IdSource -> n (STMAction n r, n (), IdSource, [TVarId], [TVarId], TAction)+stepTrans act idsource = case act of   SCatch  h stm c -> stepCatch h stm c   SRead   ref c   -> stepRead ref c   SWrite  ref a c -> stepWrite ref a c   SNew    n a c   -> stepNew n a c   SOrElse a b c   -> stepOrElse a b c-  SLift   na      -> stepLift na+  SStop   na      -> stepStop na    SThrow e -> return (SThrow e, nothing, idsource, [], [], TThrow)   SRetry   -> return (SRetry,   nothing, idsource, [], [], TRetry)-  SStop    -> return (SStop,    nothing, idsource, [], [], TStop)    where     nothing = return ()@@ -143,17 +147,17 @@         Nothing   -> return (SThrow exc, nothing, idsource, [], [], TCatch trace Nothing))      stepRead (TVar (tvid, ref)) c = do-      val <- readRef fixed ref+      val <- readRef ref       return (c val, nothing, idsource, [tvid], [], TRead tvid)      stepWrite (TVar (tvid, ref)) a c = do-      old <- readRef fixed ref-      writeRef fixed ref a-      return (c, writeRef fixed ref old, idsource, [], [tvid], TWrite tvid)+      old <- readRef ref+      writeRef ref a+      return (c, writeRef ref old, idsource, [], [tvid], TWrite tvid)      stepNew n a c = do       let (idsource', tvid) = nextTVId n idsource-      ref <- newRef fixed a+      ref <- newRef a       let tvar = TVar (tvid, ref)       return (c tvar, nothing, idsource', [], [tvid], TNew) @@ -161,12 +165,12 @@       (\trace   -> transaction (TOrElse trace . Just) b c)       (\trace exc -> return (SThrow exc, nothing, idsource, [], [], TOrElse trace Nothing)) -    stepLift na = do-      a <- na-      return (a, nothing, idsource, [], [], TLift)+    stepStop na = do+      na+      return (SStop na, nothing, idsource, [], [], TStop)      cases tact stm onSuccess onRetry onException = do-      (res, undo, idsource', trace) <- doTransaction fixed stm idsource+      (res, undo, idsource', trace) <- doTransaction stm idsource       case res of         Success readen written val -> return (onSuccess val, undo, idsource', readen, written, tact trace Nothing)         Retry readen -> do
dejafu.cabal view
@@ -2,8 +2,8 @@ -- documentation, see http://haskell.org/cabal/users-guide/  name:                dejafu-version:             0.3.2.1-synopsis:            Overloadable primitives for testable, potentially non-deterministic, concurrency.+version:             0.4.0.0+synopsis:            Systematic testing for Haskell concurrency.  description:   /[Déjà Fu is] A martial art in which the user's limbs move in time as well as space, […] It is best described as "the feeling that you have been kicked in the head this way before"/ -- Terry Pratchett, Thief of Time@@ -14,18 +14,17 @@   provides deterministic parallelism, but sometimes we can tolerate a   bit of nondeterminism.   .-  This package provides a class of monads for potentially-  nondeterministic concurrency, with an interface in the spirit of-  GHC's normal concurrency abstraction.+  This package builds on the+  <https://hackage.haskell.org/package/concurrency concurrency>+  package by enabling you to systematically and deterministically test+  your concurrent programs.   .-  == @MonadConc@ with 'IO':+  == Déjà Fu with 'IO':   .-  The intention of the @MonadConc@ class is to provide concurrency-  where any apparent nondeterminism arises purely from the scheduling-  behaviour. To put it another way, a given computation, parametrised-  with a fixed set of scheduling decisions, is deterministic. This-  assumption is used by the testing functionality provided by-  Test.DejaFu.+  The core assumption underlying Déjà Fu is that any apparent+  nondeterminism arises purely from the scheduling behaviour. To put+  it another way, a given computation, parametrised with a fixed set+  of scheduling decisions, is deterministic.   .   Whilst this assumption may not hold in general when 'IO' is   involved, you should strive to produce test cases where it does.@@ -75,53 +74,33 @@ source-repository this   type:     git   location: https://github.com/barrucadu/dejafu.git-  tag:      dejafu-0.3.2.1+  tag:      dejafu-0.4.0.0  library-  exposed-modules:     Control.Monad.Conc.Class-                     , Control.Monad.STM.Class--                     , Control.Concurrent.Classy-                     , Control.Concurrent.Classy.Chan-                     , Control.Concurrent.Classy.CRef-                     , Control.Concurrent.Classy.MVar-                     , Control.Concurrent.Classy.QSem-                     , Control.Concurrent.Classy.QSemN-                     , Control.Concurrent.Classy.STM-                     , Control.Concurrent.Classy.STM.TVar-                     , Control.Concurrent.Classy.STM.TMVar-                     , Control.Concurrent.Classy.STM.TChan-                     , Control.Concurrent.Classy.STM.TQueue-                     , Control.Concurrent.Classy.STM.TBQueue-                     , Control.Concurrent.Classy.STM.TArray--                     , Test.DejaFu-                     , Test.DejaFu.Deterministic+  exposed-modules:     Test.DejaFu+                     , Test.DejaFu.Conc+                     , Test.DejaFu.Common                      , Test.DejaFu.SCT                      , Test.DejaFu.STM -                     , Test.DejaFu.Deterministic.Internal-                     , Test.DejaFu.Deterministic.Internal.Common-                     , Test.DejaFu.Deterministic.Internal.Memory-                     , Test.DejaFu.Deterministic.Internal.Threading-                     , Test.DejaFu.Internal+                     , Test.DejaFu.Conc.Internal+                     , Test.DejaFu.Conc.Internal.Common+                     , Test.DejaFu.Conc.Internal.Memory+                     , Test.DejaFu.Conc.Internal.Threading                      , Test.DejaFu.STM.Internal    -- other-modules:          -- other-extensions:       build-depends:       base              >=4.8  && <5-                     , array             >=0.5  && <0.6-                     , atomic-primops    >=0.8  && <0.9+                     , concurrency       >=1.0  && <1.1                      , containers        >=0.5  && <0.6-                     , dpor              >=0.1  && <0.3                      , deepseq           >=1.3  && <1.5+                     , dpor              >=0.1  && <0.3                      , exceptions        >=0.7  && <0.9-                     , monad-control     >=1.0  && <1.1                      , monad-loops       >=0.4  && <0.5                      , mtl               >=2.2  && <2.3+                     , ref-fd            >=0.4  && <0.5                      , semigroups        >=0.16 && <0.19-                     , stm               >=2.4  && <2.5-                     , template-haskell  >=2.10 && <2.12                      , transformers      >=0.4  && <0.6                      , transformers-base >=0.4  && <0.5   -- hs-source-dirs: