ATOMIC(3) BSD Library Functions Manual ATOMIC(3)
NAME
OSAtomicAdd32, OSAtomicAdd32Barrier, OSAtomicIncrement32, OSAtomicIncrement32Barrier, OSAtomicDecrement32, OSAtomicDecrement32Barrier,
OSAtomicOr32, OSAtomicOr32Barrier, OSAtomicOr32Orig, OSAtomicOr32OrigBarrier, OSAtomicAnd32, OSAtomicAnd32Barrier, OSAtomicAnd32Orig,
OSAtomicAnd32OrigBarrier, OSAtomicXor32, OSAtomicXor32Barrier, OSAtomicXor32Orig, OSAtomicXor32OrigBarrier, OSAtomicAdd64,
OSAtomicAdd64Barrier, OSAtomicIncrement64, OSAtomicIncrement64Barrier, OSAtomicDecrement64, OSAtomicDecrement64Barrier,
OSAtomicCompareAndSwapInt, OSAtomicCompareAndSwapIntBarrier, OSAtomicCompareAndSwapLong, OSAtomicCompareAndSwapLongBarrier,
OSAtomicCompareAndSwapPtr, OSAtomicCompareAndSwapPtrBarrier, OSAtomicCompareAndSwap32, OSAtomicCompareAndSwap32Barrier,
OSAtomicCompareAndSwap64, OSAtomicCompareAndSwap64Barrier, OSAtomicTestAndSet, OSAtomicTestAndSetBarrier, OSAtomicTestAndClear,
OSAtomicTestAndClearBarrier, OSSpinLockTry, OSSpinLockLock, OSSpinLockUnlock, OSAtomicEnqueue, OSAtomicDequeue -- atomic add, increment,
decrement, or, and, xor, compare and swap, test and set, test and clear, spinlocks, and lockless queues
LIBRARY
Standard C Library (libc, -lc)
SYNOPSIS
#include <libkern/OSAtomic.h>
int32_t
OSAtomicAdd32(int32_t theAmount, volatile int32_t *theValue);
int32_t
OSAtomicAdd32Barrier(int32_t theAmount, volatile int32_t *theValue);
int32_t
OSAtomicIncrement32(volatile int32_t *theValue);
int32_t
OSAtomicIncrement32Barrier(volatile int32_t *theValue);
int32_t
OSAtomicDecrement32(volatile int32_t *theValue);
int32_t
OSAtomicDecrement32Barrier(volatile int32_t *theValue);
int32_t
OSAtomicOr32(uint32_t theMask, volatile uint32_t *theValue);
int32_t
OSAtomicOr32Barrier(uint32_t theMask, volatile uint32_t *theValue);
int32_t
OSAtomicAnd32(uint32_t theMask, volatile uint32_t *theValue);
int32_t
OSAtomicAnd32Barrier(uint32_t theMask, volatile uint32_t *theValue);
int32_t
OSAtomicXor32(uint32_t theMask, volatile uint32_t *theValue);
int32_t
OSAtomicXor32Barrier(uint32_t theMask, volatile uint32_t *theValue);
int32_t
OSAtomicOr32Orig(uint32_t theMask, volatile uint32_t *theValue);
int32_t
OSAtomicOr32OrigBarrier(uint32_t theMask, volatile uint32_t *theValue);
int32_t
OSAtomicAnd32Orig(uint32_t theMask, volatile uint32_t *theValue);
int32_t
OSAtomicAnd32OrigBarrier(uint32_t theMask, volatile uint32_t *theValue);
int32_t
OSAtomicXor32Orig(uint32_t theMask, volatile uint32_t *theValue);
int32_t
OSAtomicXor32OrigBarrier(uint32_t theMask, volatile uint32_t *theValue);
int64_t
OSAtomicAdd64(int64_t theAmount, volatile int64_t *theValue);
int64_t
OSAtomicAdd64Barrier(int64_t theAmount, volatile int64_t *theValue);
int64_t
OSAtomicIncrement64(volatile int64_t *theValue);
int64_t
OSAtomicIncrement64Barrier(volatile int64_t *theValue);
int64_t
OSAtomicDecrement64(volatile int64_t *theValue);
int64_t
OSAtomicDecrement64Barrier(volatile int64_t *theValue);
bool
OSAtomicCompareAndSwapInt(int oldValue, int newValue, volatile int *theValue);
bool
OSAtomicCompareAndSwapIntBarrier(int oldValue, int newValue, volatile int *theValue);
bool
OSAtomicCompareAndSwapLong(long oldValue, long newValue, volatile long *theValue);
bool
OSAtomicCompareAndSwapLongBarrier(long oldValue, long newValue, volatile long *theValue);
bool
OSAtomicCompareAndSwapPtr(void* oldValue, void* newValue, void* volatile *theValue);
bool
OSAtomicCompareAndSwapPtrBarrier(void* oldValue, void* newValue, void* volatile *theValue);
bool
OSAtomicCompareAndSwap32(int32_t oldValue, int32_t newValue, volatile int32_t *theValue);
bool
OSAtomicCompareAndSwap32Barrier(int32_t oldValue, int32_t newValue, volatile int32_t *theValue);
bool
OSAtomicCompareAndSwap64(int64_t oldValue, int64_t newValue, volatile int64_t *theValue);
bool
OSAtomicCompareAndSwap64Barrier(int64_t oldValue, int64_t newValue, volatile int64_t *theValue);
bool
OSAtomicTestAndSet(uint32_t n, volatile void *theAddress);
bool
OSAtomicTestAndSetBarrier(uint32_t n, volatile void *theAddress);
bool
OSAtomicTestAndClear(uint32_t n, volatile void *theAddress);
bool
OSAtomicTestAndClearBarrier(uint32_t n, volatile void *theAddress);
bool
OSSpinLockTry(OSSpinLock *lock);
void
OSSpinLockLock(OSSpinLock *lock);
void
OSSpinLockUnlock(OSSpinLock *lock);
void
OSAtomicEnqueue(OSQueueHead *list, void *new, size_t offset);
void*
OSAtomicDequeue(OSQueueHead *list, size_t offset);
DESCRIPTION
These functions are thread and multiprocessor safe. For each function, there is a version that does and another 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 bar-
rier operation is typically a nop. On a multiprocessor, the barrier can be quite expensive.
Most code will want to use the barrier functions to ensure 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 con-
sumer 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 OSAtomicCompareAndSwap() primitives. There are four versions of
each logical operation, depending on whether or not there is a barrier, and whether the return value is the result of the operation (eg,
OSAtomicOr32() ) or the original value before the operation (eg, OSAtomicOr32Orig() ).
The memory address 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 not implemented for 32-bit processes on PPC platforms.
The OSAtomicCompareAndSwap() operations compare oldValue to *theValue, and set *theValue to newValue if the comparison is equal. The compar-
ison and assignment occur as one atomic operation.
OSAtomicTestAndSet() and OSAtomicTestAndClear() operate on bit (0x80 >> ( n & 7)) of byte ((char*) theAddress + ( n >> 3)). They set the
named bit to either 1 or 0, respectively. theAddress need not be aligned.
The routines OSAtomicEnqueue() and OSAtomicDequeue() operate on singly linked LIFO queues. Ie, a dequeue operation will return the most
recently enqueued element, or NULL if the list is empty. The operations are lockless, and barriers are used as necessary to permit thread-
safe access to the queue element. offset is the offset in bytes to the link field in the queue element. For example:
typedef struct elem {
long data1;
struct elem *link;
int data2;
} elem_t;
elem_t fred, mary, *p;
OSQueueHead q = OS_ATOMIC_QUEUE_INIT;
OSAtomicEnqueue( &q, &fred, offsetof(elem_t,link) );
OSAtomicEnqueue( &q, &mary, offsetof(elem_t,link) );
p = OSAtomicDequeue( &q, offsetof(elem_t,link) );
In this example, the call of OSAtomicDequeue() will return a ptr to mary.
RETURN VALUES
The arithmetic operations return the new value, after the operation has been performed. The boolean operations come in two styles, one of
which returns the new value, and one of which (the "Orig" versions) returns the old. The compare-and-swap operations return true if the com-
parison was equal, ie if the swap occured. The bit test and set/clear operations return the original value of the bit. The dequeue opera-
tion returns the most recently enqueued element, or NULL if the list in empty.
SEE ALSO
spinlock(3), barrier(3)
HISTORY
Most of these functions first appeared in Mac OS 10.4 (Tiger). The "Orig" forms of the boolean operations, the "int", "long" and "ptr" forms
of compare-and-swap, and lockless enqueue/dequeue first appeared in Mac OS 10.5 (Leopard).
Darwin May 26, 2004 Darwin