-- 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.
--
-- Note that as of GHC 7.8, the relevant primops have been included in
-- GHC itself. This library is engineered to work pre- and post-GHC-7.8,
-- while exposing the same interface.
--
-- Changes in 0.3:
--
--
-- - Major internal change. Duplicate the barrier code from the GHC RTS
-- and thus enable support for executables that are NOT built with
-- '-threaded'.
--
--
-- Changes in 0.4:
--
--
--
-- Changes in 0.5:
--
--
-- - Remove dependency on bits-atomic unless a flag is turned on.
--
--
-- Changes in 0.5.0.2:
--
--
-- - IMPORTANT BUGFIXES - don't use earlier versions. They have been
-- marked deprecated.
--
--
-- Changes in 0.6.1
--
--
-- - This is a good version to use for GHC 7.8.3. It includes
-- portability and bug fixes and adds atomicModifyIORefCAS.
--
--
-- Changes in 0.7:
--
--
-- - This release adds support for GHC 7.10
--
@package atomic-primops
@version 0.7
-- | 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.
-- | Deprecated: Replaced by fetchAddIntArray which returns the OLD
-- value
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 ()
-- | Integer counters providing thread-safe, lock-free mutation functions.
--
-- 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 ()