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