atomic.3   [plain text]

.Dd May 26, 2004
.Os Darwin
.Nm OSAtomicAdd32 ,
.Nm OSAtomicAdd32Barrier ,
.Nm OSAtomicIncrement32 ,
.Nm OSAtomicIncrement32Barrier ,
.Nm OSAtomicDecrement32 ,
.Nm OSAtomicDecrement32Barrier ,
.Nm OSAtomicOr32 ,
.Nm OSAtomicOr32Barrier ,
.Nm OSAtomicAnd32 ,
.Nm OSAtomicAnd32Barrier ,
.Nm OSAtomicXor32 ,
.Nm OSAtomicXor32Barrier ,
.Nm OSAtomicAdd64 ,
.Nm OSAtomicAdd64Barrier ,
.Nm OSAtomicIncrement64 ,
.Nm OSAtomicIncrement64Barrier ,
.Nm OSAtomicDecrement64 ,
.Nm OSAtomicDecrement64Barrier ,
.Nm OSAtomicCompareAndSwap32 ,
.Nm OSAtomicCompareAndSwap32Barrier ,
.Nm OSAtomicCompareAndSwap64 ,
.Nm OSAtomicCompareAndSwap64Barrier ,
.Nm OSAtomicTestAndSet ,
.Nm OSAtomicTestAndSetBarrier ,
.Nm OSAtomicTestAndClear ,
.Nm OSAtomicTestAndClearBarrier
.Nd atomic add, increment, decrement, or, and, xor, compare and swap, test and set, and test and clear
.Lb libc
.In libkern/OSAtomic.h
.Ft int32_t
.Fn OSAtomicAdd32 "int32_t theAmount, int32_t *theValue"
.Ft int32_t
.Fn OSAtomicAdd32Barrier "int32_t theAmount, int32_t *theValue"
.Ft int32_t
.Fn OSAtomicIncrement32 "int32_t *theValue"
.Ft int32_t
.Fn OSAtomicIncrement32Barrier "int32_t *theValue"
.Ft int32_t
.Fn OSAtomicDecrement32 "int32_t *theValue"
.Ft int32_t
.Fn OSAtomicDecrement32Barrier "int32_t *theValue"
.Ft int32_t
.Fn OSAtomicOr32 "uint32_t theMask, uint32_t *theValue"
.Ft int32_t
.Fn OSAtomicOr32Barrier "uint32_t theMask, uint32_t *theValue"
.Ft int32_t
.Fn OSAtomicAnd32 "uint32_t theMask, uint32_t *theValue"
.Ft int32_t
.Fn OSAtomicAnd32Barrier "uint32_t theMask, uint32_t *theValue"
.Ft int32_t
.Fn OSAtomicXor32 "uint32_t theMask, uint32_t *theValue"
.Ft int32_t
.Fn OSAtomicXor32Barrier "uint32_t theMask, uint32_t *theValue"
.Ft int64_t
.Fn OSAtomicAdd64 "int64_t theAmount, int64_t *theValue"
.Ft int64_t
.Fn OSAtomicAdd64Barrier "int64_t theAmount, int64_t *theValue"
.Ft int64_t
.Fn OSAtomicIncrement64 "int64_t *theValue"
.Ft int64_t
.Fn OSAtomicIncrement64Barrier "int64_t *theValue"
.Ft int64_t
.Fn OSAtomicDecrement64 "int64_t *theValue"
.Ft int64_t
.Fn OSAtomicDecrement64Barrier "int64_t *theValue"
.Ft bool
.Fn OSAtomicCompareAndSwap32 "int32_t oldValue" "int32_t newValue" "int32_t *theValue"
.Ft bool
.Fn OSAtomicCompareAndSwap32Barrier "int32_t oldValue" "int32_t newValue" "int32_t *theValue"
.Ft bool
.Fn OSAtomicCompareAndSwap64 "int64_t oldValue" "int64_t newValue" "int64_t *theValue"
.Ft bool
.Fn OSAtomicCompareAndSwap64Barrier "int64_t oldValue" "int64_t newValue" "int64_t *theValue"
.Ft bool
.Fn OSAtomicTestAndSet "uint32_t n, void *theAddress"
.Ft bool
.Fn OSAtomicTestAndSetBarrier "uint32_t n, void *theAddress"
.Ft bool
.Fn OSAtomicTestAndClear "uint32_t n, void *theAddress"
.Ft bool
.Fn OSAtomicTestAndClearBarrier "uint32_t n, void *theAddress"
These functions are thread and multiprocessor safe.  For each function, there
is a version that does and anoother that does not incorporate a memory barrier.
Barriers strictly order memory access on a weakly-ordered
architecture such as PPC.  All loads and stores executed in sequential program
order before the barrier will complete before any load or store executed after
the barrier.  On a uniprocessor, the barrier operation is typically a nop.
On a multiprocessor, the barrier can be quite expensive.
Most code will want to use the barrier functions to insure that memory shared
between threads is properly synchronized.  For example, if you want to initialize
a shared data structure and then atomically increment a variable to indicate
that the initialization is complete, then you MUST use OSAtomicIncrement32Barrier()
to ensure that the stores to your data structure complete before the atomic add.
Likewise, the consumer of that data structure MUST use OSAtomicDecrement32Barrier(),
in order to ensure that their loads of the structure are not executed before
the atomic decrement.  On the other hand,
if you are simply incrementing a global counter, then it is safe and potentially much
faster to use OSAtomicIncrement32().  If you are unsure which version to use, prefer
the barrier variants as they are safer.
The logical (and, or, xor) and bit test operations are layered on top of the
.Fn OSAtomicCompareAndSwap
The memory address
.Fa theValue
must be naturally aligned, ie 32-bit aligned for 32-bit operations and 64-bit
aligned for 64-bit operations.
The 64-bit operations are only implemented for
64-bit processes.
.Fn OSAtomicCompareAndSwap32
.Fn OSAtomicCompareAndSwap64
.Fa oldValue
.Fa *theValue ,
and set
.Fa *theValue
.Fa newValue
if the comparison is equal.  The comparison and assignment
occur as one atomic operation.
.Fn OSAtomicTestAndSet
.Fn OSAtomicTestAndClear
operate on bit (0x80 >> (
.Fa n
& 7)) of byte ((char*)
.Fa theAddress
+ (
.Fa n
>> 3)).  They set the named bit to either 1 or 0, respectively.
.Fa theAddress
need not be aligned.
The arithmetic and logical operations return the new value, after the operation has been performed.
The compare-and-swap operations return true if the comparison was equal, ie if the swap occured.
The bit test and set/clear operations return the original value of the bit.
.Xr atomicqueue 3 ,
.Xr spinlock 3 ,
.Xr barrier 3