-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | A safe approach to CAS and other atomic ops in Haskell. -- -- After GHC 7.4 a new `casMutVar#` primop became available, but it's -- difficult to use safely, because pointer equality is a highly unstable -- property in Haskell. This library provides a safer method based on the -- concept of Tickets. -- -- Also, this library uses the foreign primop capability of GHC to -- add access to other variants that may be of interest, specifically, -- compare and swap inside an array. @package atomic-primops @version 0.2.2 -- | This implementation stores an unboxed counter and uses FFI operations -- to modify its contents. module Data.Atomics.Counter.Foreign type AtomicCounter = ForeignPtr Int type CTicket = Int -- | Create a new counter initialized to zero. newCounter :: IO AtomicCounter -- | Try repeatedly until we successfully increment the counter. Returns -- the original value before the increment. incrCounter :: AtomicCounter -> IO Int readCounterForCAS :: AtomicCounter -> IO CTicket peekCTicket :: CTicket -> Int readCounter :: AtomicCounter -> IO Int -- | Make a non-atomic write to the counter. No memory-barrier. writeCounter :: AtomicCounter -> Int -> IO () casCounter :: AtomicCounter -> CTicket -> Int -> IO (Bool, CTicket) -- | This reference version is implemented with atomicModifyIORef and can -- be a useful fallback if one of the other implementations needs to be -- debugged. module Data.Atomics.Counter.Reference newtype AtomicCounter AtomicCounter :: (IORef Int) -> AtomicCounter type CTicket = Int -- | Create a new counter initialized to zero. newCounter :: IO AtomicCounter -- | Try repeatedly until we successfully increment the counter. -- incrCounter = readCounterForCAS :: AtomicCounter -> IO CTicket peekCTicket :: CTicket -> Int readCounter :: AtomicCounter -> IO Int -- | Make a non-atomic write to the counter. No memory-barrier. writeCounter :: AtomicCounter -> Int -> IO () casCounter :: AtomicCounter -> CTicket -> Int -> IO (Bool, CTicket) -- | This module provides only the raw primops (and necessary types) for -- atomic operations. module Data.Atomics.Internal -- | Unsafe, machine-level atomic compare and swap on an element within an -- Array. casArray# :: MutableArray# RealWorld a -> Int# -> Ticket a -> Ticket a -> State# RealWorld -> (# State# RealWorld, Int#, Ticket a #) readForCAS# :: MutVar# RealWorld a -> State# RealWorld -> (# State# RealWorld, Ticket a #) casMutVarTicketed# :: MutVar# RealWorld a -> Ticket a -> Ticket a -> State# RealWorld -> (# State# RealWorld, Int#, Ticket a #) -- | When performing compare-and-swaps, the ticket encapsulates -- proof that a thread observed a specific previous value of a mutable -- variable. It is provided in lieu of the old value to -- compare-and-swap. type Ticket a = Any a stg_storeLoadBarrier# :: State# RealWorld -> (# State# RealWorld, Int# #) stg_loadLoadBarrier# :: State# RealWorld -> (# State# RealWorld, Int# #) stg_writeBarrier# :: State# RealWorld -> (# State# RealWorld, Int# #) instance Eq (Ticket a) instance Show (Ticket a) -- | Provides atomic memory operations on IORefs and Mutable Arrays. -- -- Pointer equality need not be maintained by a Haskell compiler. For -- example, Int values will frequently be boxed and unboxed, changing the -- pointer identity of the thunk. To deal with this, the compare-and-swap -- (CAS) approach used in this module is uses a sealed -- representation of pointers into the Haskell heap (Tickets). -- Currently, the user cannot coin new tickets, rather a Ticket -- provides evidence of a past observation, and grants permission to make -- a future change. module Data.Atomics -- | When performing compare-and-swaps, the ticket encapsulates -- proof that a thread observed a specific previous value of a mutable -- variable. It is provided in lieu of the old value to -- compare-and-swap. type Ticket a = Any a -- | A ticket contains or can get the usable Haskell value. peekTicket :: Ticket a -> a -- | Compare-and-swap casArrayElem :: MutableArray RealWorld a -> Int -> Ticket a -> a -> IO (Bool, Ticket a) -- | This variant takes two tickets: the new value is a ticket -- rather than an arbitrary, lifted, Haskell value. casArrayElem2 :: MutableArray RealWorld a -> Int -> Ticket a -> Ticket a -> IO (Bool, Ticket a) readArrayElem :: MutableArray RealWorld a -> Int -> IO (Ticket a) readForCAS :: IORef a -> IO (Ticket a) -- | Performs a machine-level compare and swap operation on an -- IORef. Returns a tuple containing a Bool which is -- True when a swap is performed, along with the current -- value from the IORef. -- -- Note "compare" here means pointer equality in the sense of -- reallyUnsafePtrEquality#. casIORef :: IORef a -> Ticket a -> a -> IO (Bool, Ticket a) -- | This variant takes two tickets, i.e. the new value is a -- ticket rather than an arbitrary, lifted, Haskell value. casIORef2 :: IORef a -> Ticket a -> Ticket a -> IO (Bool, Ticket a) readMutVarForCAS :: MutVar# RealWorld a -> IO (Ticket a) -- | MutVar counterpart of casIORef. casMutVar :: MutVar# RealWorld a -> Ticket a -> a -> IO (Bool, Ticket a) -- | This variant takes two tickets, i.e. the new value is a -- ticket rather than an arbitrary, lifted, Haskell value. casMutVar2 :: MutVar# RealWorld a -> Ticket a -> Ticket a -> IO (Bool, Ticket a) -- | Memory barrier implemented by the GHC rts (SMP.h). storeLoadBarrier :: IO () -- | Memory barrier implemented by the GHC rts (SMP.h). loadLoadBarrier :: IO () -- | Memory barrier implemented by the GHC rts (SMP.h). writeBarrier :: IO () -- | This version uses a boxed IORef representation, but it can be somewhat -- cheaper because it uses raw CAS rather than full atomicModifyIORef. module Data.Atomics.Counter.IORef newtype AtomicCounter AtomicCounter :: (IORef Int) -> AtomicCounter type CTicket = Ticket Int -- | Create a new counter initialized to zero. newCounter :: IO AtomicCounter -- | Try repeatedly until we successfully increment the counter. -- incrCounter = readCounterForCAS :: AtomicCounter -> IO CTicket peekCTicket :: CTicket -> Int readCounter :: AtomicCounter -> IO Int -- | Make a non-atomic write to the counter. No memory-barrier. writeCounter :: AtomicCounter -> Int -> IO () casCounter :: AtomicCounter -> CTicket -> Int -> IO (Bool, CTicket) module Data.Atomics.Counter