-- 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: -- -- -- -- Changes in 0.4: -- -- -- -- Changes in 0.5: -- -- -- -- Changes in 0.5.0.2: -- -- -- -- Changes in 0.6.1 -- -- -- -- Changes in 0.7: -- -- @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 ()