-- Hoogle documentation, generated by Haddock
-- See Hoogle, http://www.haskell.org/hoogle/
-- | A safe approach to CAS and other atomic ops in Haskell.
--
@package atomic-primops
@version 0.6.1
-- | This reference version is implemented with atomicModifyIORef and can
-- be a useful fallback if one of the other implementations needs to be
-- debugged for a given architecture.
module Data.Atomics.Counter.Reference
data AtomicCounter
type CTicket = Int
-- | Create a new counter initialized to the given value.
newCounter :: Int -> IO AtomicCounter
-- | Just like the Data.Atomics CAS interface, this routine returns
-- an opaque ticket that can be used in CAS operations.
readCounterForCAS :: AtomicCounter -> IO CTicket
-- | Equivalent to readCounterForCAS followed by peekCTicket.
readCounter :: AtomicCounter -> IO Int
-- | Opaque tickets cannot be constructed, but they can be destructed into
-- values.
peekCTicket :: CTicket -> Int
-- | Make a non-atomic write to the counter. No memory-barrier.
writeCounter :: AtomicCounter -> Int -> IO ()
-- | Compare and swap for the counter ADT. Similar behavior to
-- casIORef.
casCounter :: AtomicCounter -> CTicket -> Int -> IO (Bool, CTicket)
-- | Try repeatedly until we successfully increment the counter by a given
-- amount. Returns the original value of the counter (pre-increment).
incrCounter :: Int -> AtomicCounter -> IO Int
incrCounter_ :: Int -> AtomicCounter -> IO ()
-- | This module provides only the raw primops (and necessary types) for
-- atomic operations.
module Data.Atomics.Internal
-- | Machine-level atomic compare and swap on a word within a ByteArray.
casIntArray# :: MutableByteArray# d -> Int# -> Int# -> Int# -> State# d -> (# State# d, Int# #)
-- | Machine-level word-sized fetch-and-add within a ByteArray.
fetchAddIntArray# :: MutableByteArray# d -> Int# -> Int# -> State# d -> (# State# d, Int# #)
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 #)
-- | Unsafe, machine-level atomic compare and swap on an element within an
-- Array.
casArrayTicketed# :: MutableArray# RealWorld a -> Int# -> 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.
--
-- Design note: Tickets exist to hide objects from the GHC
-- compiler, which can normally perform many optimizations that change
-- pointer equality. A Ticket, on the other hand, is a first-class object
-- that can be handled by the user, but will not have its pointer
-- identity changed by compiler optimizations (but will of course, change
-- addresses during garbage collection).
data Ticket a
ptrEq :: a -> a -> Bool
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.
--
-- Design note: Tickets exist to hide objects from the GHC
-- compiler, which can normally perform many optimizations that change
-- pointer equality. A Ticket, on the other hand, is a first-class object
-- that can be handled by the user, but will not have its pointer
-- identity changed by compiler optimizations (but will of course, change
-- addresses during garbage collection).
data Ticket a
-- | A ticket contains or can get the usable Haskell value. This function
-- does just that.
peekTicket :: Ticket a -> a
-- | Ordinary processor load instruction (non-atomic, not implying any
-- memory barriers).
--
-- The difference between this function and readIORef, is that it
-- returns a ticket, for use in future compare-and-swap
-- operations.
readForCAS :: IORef a -> IO (Ticket a)
-- | Performs a machine-level compare and swap (CAS) operation on an
-- IORef. Returns a tuple containing a Bool which is
-- True when a swap is performed, along with the most
-- current value from the IORef. Note that this differs
-- from the more common CAS behavior, which is to return the old
-- value before the CAS occured.
--
-- The reason for the difference is the ticket API. This function always
-- returns the ticket that you should use in your next CAS attempt. In
-- case of success, this ticket corresponds to the new value
-- which you yourself installed in the IORef, whereas in the case
-- of failure it represents the preexisting value currently in the IORef.
--
-- Note "compare" here means pointer equality in the sense of
-- reallyUnsafePtrEquality#. However, the ticket API absolves the
-- user of this module from needing to worry about the pointer equality
-- of their values, which in general requires reasoning about the details
-- of the Haskell implementation (GHC).
--
-- By convention this function is strict in the "new" value argument.
-- This isn't absolutely necesary, but we think it's a bad habit to use
-- unevaluated thunks in this context.
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)
-- | A drop-in replacement for atomicModifyIORefCAS that
-- optimistically attempts to compute the new value and CAS it into place
-- without introducing new thunks or locking anything. Note that this is
-- more STRICT than its standard counterpart and will only place
-- evaluated (WHNF) values in the IORef.
--
-- The upside is that sometimes we see a performance benefit. The
-- downside is that this version is speculative -- when it retries, it
-- must reexecute the compution.
atomicModifyIORefCAS :: IORef a -> (a -> (a, b)) -> IO b
-- | A simpler version that modifies the state but does not return
-- anything.
atomicModifyIORefCAS_ :: IORef t -> (t -> t) -> IO ()
-- | Compare-and-swap. Follows the same rules as casIORef, returning
-- the ticket for then next operation.
--
-- By convention this is WHNF strict in the "new" value provided.
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)
-- | Ordinary processor load instruction (non-atomic, not implying any
-- memory barriers).
readArrayElem :: MutableArray RealWorld a -> Int -> IO (Ticket a)
-- | Compare and swap on word-sized chunks of a byte-array. For indexing
-- purposes the bytearray is treated as an array of words (Ints).
-- Note that UNLIKE casIORef and casArrayTicketed, this
-- does not need to operate on tickets.
--
-- Further, this version always returns the old value, that was
-- read from the array during the CAS operation. That is, it follows the
-- normal protocol for CAS operations (and matches the underlying
-- instruction on most architectures).
casByteArrayInt :: MutableByteArray RealWorld -> Int -> Int -> Int -> IO Int
-- | Atomically add to a word of memory within a MutableByteArray.
--
-- This function returns the NEW value of the location after the
-- increment. Thus, it is a bit misnamed, and in other contexts might be
-- called "add-and-fetch", such as in GCC's
-- __sync_add_and_fetch.
fetchAddByteArrayInt :: MutableByteArray RealWorld -> Int -> Int -> IO Int
-- | Like readForCAS, but for MutVar#.
readMutVarForCAS :: MutVar# RealWorld a -> IO (Ticket a)
-- | MutVar counterpart of casIORef.
--
-- By convention this is WHNF strict in the "new" value provided.
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 (see SMP.h).
storeLoadBarrier :: IO ()
-- | Memory barrier implemented by the GHC rts (see SMP.h).
loadLoadBarrier :: IO ()
-- | Memory barrier implemented by the GHC rts (see SMP.h).
writeBarrier :: IO ()
-- | This should be the most efficient implementation of atomic counters.
-- You probably don't need the others! (Except for testing/debugging.)
module Data.Atomics.Counter.Unboxed
-- | The type of mutable atomic counters.
data AtomicCounter
-- | You should not depend on this type. It varies between different
-- implementations of atomic counters.
type CTicket = Int
-- | Create a new counter initialized to the given value.
newCounter :: Int -> IO AtomicCounter
-- | Just like the Data.Atomics CAS interface, this routine returns
-- an opaque ticket that can be used in CAS operations. Except for the
-- difference in return type, the semantics of this are the same as
-- readCounter.
readCounterForCAS :: AtomicCounter -> IO CTicket
-- | Equivalent to readCounterForCAS followed by peekCTicket.
readCounter :: AtomicCounter -> IO Int
-- | Opaque tickets cannot be constructed, but they can be destructed into
-- values.
peekCTicket :: CTicket -> Int
-- | Make a non-atomic write to the counter. No memory-barrier.
writeCounter :: AtomicCounter -> Int -> IO ()
-- | Compare and swap for the counter ADT. Similar behavior to
-- casIORef, in particular, in both success and failure cases it
-- returns a ticket that you should use for the next attempt. (That is,
-- in the success case, it actually returns the new value that you
-- provided as input, but in ticket form.)
casCounter :: AtomicCounter -> CTicket -> Int -> IO (Bool, CTicket)
-- | Increment the counter by a given amount. Returns the value AFTER the
-- increment (in contrast with the behavior of the underlying instruction
-- on architectures like x86.)
--
-- Note that UNLIKE with boxed implementations of counters, where
-- increment is based on CAS, this increment is O(1).
-- Fetch-and-add does not require a retry loop like CAS.
incrCounter :: Int -> AtomicCounter -> IO Int
-- | An alternate version for when you don't care about the old value.
incrCounter_ :: Int -> AtomicCounter -> IO ()
-- | Integer counters providing thread-safe, lock-free mutation functions.
--
-- While this package provides multiple implementations, this module will
-- always expose the default (best) implementation. Atomic counters are
-- represented by a single memory location, such that built-in processor
-- instructions are sufficient to perform fetch-and-add or
-- compare-and-swap.
--
-- Remember, contention on such counters should still be minimized!
module Data.Atomics.Counter
-- | The type of mutable atomic counters.
data AtomicCounter
-- | Create a new counter initialized to the given value.
newCounter :: Int -> IO AtomicCounter
-- | You should not depend on this type. It varies between different
-- implementations of atomic counters.
type CTicket = Int
-- | Opaque tickets cannot be constructed, but they can be destructed into
-- values.
peekCTicket :: CTicket -> Int
-- | Compare and swap for the counter ADT. Similar behavior to
-- casIORef, in particular, in both success and failure cases it
-- returns a ticket that you should use for the next attempt. (That is,
-- in the success case, it actually returns the new value that you
-- provided as input, but in ticket form.)
casCounter :: AtomicCounter -> CTicket -> Int -> IO (Bool, CTicket)
-- | Increment the counter by a given amount. Returns the value AFTER the
-- increment (in contrast with the behavior of the underlying instruction
-- on architectures like x86.)
--
-- Note that UNLIKE with boxed implementations of counters, where
-- increment is based on CAS, this increment is O(1).
-- Fetch-and-add does not require a retry loop like CAS.
incrCounter :: Int -> AtomicCounter -> IO Int
-- | An alternate version for when you don't care about the old value.
incrCounter_ :: Int -> AtomicCounter -> IO ()
-- | Equivalent to readCounterForCAS followed by peekCTicket.
readCounter :: AtomicCounter -> IO Int
-- | Just like the Data.Atomics CAS interface, this routine returns
-- an opaque ticket that can be used in CAS operations. Except for the
-- difference in return type, the semantics of this are the same as
-- readCounter.
readCounterForCAS :: AtomicCounter -> IO CTicket
-- | Make a non-atomic write to the counter. No memory-barrier.
writeCounter :: AtomicCounter -> Int -> IO ()
-- | This version uses a boxed IORef representation, but it can be somewhat
-- cheaper than the Refence version because it uses raw CAS rather than
-- full atomicModifyIORef.
module Data.Atomics.Counter.IORef
data AtomicCounter
type CTicket = Ticket Int
-- | Create a new counter initialized to the given value.
newCounter :: Int -> IO AtomicCounter
-- | Just like the Data.Atomics CAS interface, this routine returns
-- an opaque ticket that can be used in CAS operations.
readCounterForCAS :: AtomicCounter -> IO CTicket
-- | Equivalent to readCounterForCAS followed by peekCTicket.
readCounter :: AtomicCounter -> IO Int
-- | Opaque tickets cannot be constructed, but they can be destructed into
-- values.
peekCTicket :: CTicket -> Int
-- | Make a non-atomic write to the counter. No memory-barrier.
writeCounter :: AtomicCounter -> Int -> IO ()
-- | Compare and swap for the counter ADT. Similar behavior to
-- casIORef.
casCounter :: AtomicCounter -> CTicket -> Int -> IO (Bool, CTicket)
-- | Try repeatedly until we successfully increment the counter by a given
-- amount. Returns the original value of the counter (pre-increment).
incrCounter :: Int -> AtomicCounter -> IO Int
incrCounter_ :: Int -> AtomicCounter -> IO ()