ATOMIC(3) BSD Library Functions Manual ATOMIC(3)
NAMEOSAtomicAdd32, 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, incre-ment, increment,
ment, 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_tOSAtomicAdd32(int32_ttheAmount, volatileint32_t*theValue);
int32_tOSAtomicAdd32Barrier(int32_ttheAmount, volatileint32_t*theValue);
int32_tOSAtomicIncrement32(volatileint32_t*theValue);
int32_tOSAtomicIncrement32Barrier(volatileint32_t*theValue);
int32_tOSAtomicDecrement32(volatileint32_t*theValue);
int32_tOSAtomicDecrement32Barrier(volatileint32_t*theValue);
int32_tOSAtomicOr32(uint32_ttheMask, volatileuint32_t*theValue);
int32_tOSAtomicOr32Barrier(uint32_ttheMask, volatileuint32_t*theValue);
int32_tOSAtomicAnd32(uint32_ttheMask, volatileuint32_t*theValue);
int32_tOSAtomicAnd32Barrier(uint32_ttheMask, volatileuint32_t*theValue);
int32_tOSAtomicXor32(uint32_ttheMask, volatileuint32_t*theValue);
int32_tOSAtomicXor32Barrier(uint32_ttheMask, volatileuint32_t*theValue);
int32_tOSAtomicOr32Orig(uint32_ttheMask, volatileuint32_t*theValue);
int32_tOSAtomicOr32OrigBarrier(uint32_ttheMask, volatileuint32_t*theValue);
int32_tOSAtomicAnd32Orig(uint32_ttheMask, volatileuint32_t*theValue);
int32_tOSAtomicAnd32OrigBarrier(uint32_ttheMask, volatileuint32_t*theValue);
int32_tOSAtomicXor32Orig(uint32_ttheMask, volatileuint32_t*theValue);
int32_tOSAtomicXor32OrigBarrier(uint32_ttheMask, volatileuint32_t*theValue);
int64_tOSAtomicAdd64(int64_ttheAmount, volatileint64_t*theValue);
int64_tOSAtomicAdd64Barrier(int64_ttheAmount, volatileint64_t*theValue);
int64_tOSAtomicIncrement64(volatileint64_t*theValue);
int64_tOSAtomicIncrement64Barrier(volatileint64_t*theValue);
int64_tOSAtomicDecrement64(volatileint64_t*theValue);
int64_tOSAtomicDecrement64Barrier(volatileint64_t*theValue);
boolOSAtomicCompareAndSwapInt(intoldValue, intnewValue, volatileint*theValue);
boolOSAtomicCompareAndSwapIntBarrier(intoldValue, intnewValue, volatileint*theValue);
boolOSAtomicCompareAndSwapLong(longoldValue, longnewValue, volatilelong*theValue);
boolOSAtomicCompareAndSwapLongBarrier(longoldValue, longnewValue, volatilelong*theValue);
boolOSAtomicCompareAndSwapPtr(void*oldValue, void*newValue, void*volatile*theValue);
boolOSAtomicCompareAndSwapPtrBarrier(void*oldValue, void*newValue, void*volatile*theValue);
boolOSAtomicCompareAndSwap32(int32_toldValue, int32_tnewValue, volatileint32_t*theValue);
boolOSAtomicCompareAndSwap32Barrier(int32_toldValue, int32_tnewValue, volatileint32_t*theValue);
boolOSAtomicCompareAndSwap64(int64_toldValue, int64_tnewValue, volatileint64_t*theValue);
boolOSAtomicCompareAndSwap64Barrier(int64_toldValue, int64_tnewValue, volatileint64_t*theValue);
boolOSAtomicTestAndSet(uint32_tn, volatilevoid*theAddress);
boolOSAtomicTestAndSetBarrier(uint32_tn, volatilevoid*theAddress);
boolOSAtomicTestAndClear(uint32_tn, volatilevoid*theAddress);
boolOSAtomicTestAndClearBarrier(uint32_tn, volatilevoid*theAddress);
boolOSSpinLockTry(OSSpinLock*lock);
voidOSSpinLockLock(OSSpinLock*lock);
voidOSSpinLockUnlock(OSSpinLock*lock);
voidOSAtomicEnqueue(OSQueueHead*list, void*new, size_toffset);
void*OSAtomicDequeue(OSQueueHead*list, size_toffset);
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 uniproces-sor, uniprocessor,
sor, the barrier operation is typically a nop. On a multiprocessor, the barrier can be quite expen-sive. expensive.
sive.
Most code will want to use the barrier functions to ensure that memory shared between threads is prop-erly properly
erly 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 OSAtomicIncre-ment32Barrier() OSAtomicIncrement32Barrier()
ment32Barrier() to ensure that the stores to your data structure complete before the atomic add. Like-wise, Likewise,
wise, 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 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 orig-inal original
inal 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 comparison 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.
RETURNVALUES
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" ver-sions) versions)
sions) returns the old. 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. The
dequeue operation returns the most recently enqueued element, or NULL if the list in empty.
SEEALSOspinlock(3), barrier(3)HISTORY
Most of these functions first appeared in Mac OS 10.4 (Tiger). The "Orig" forms of the boolean opera-tions, operations,
tions, 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

Reporting Problems

The way to report a problem with this manual page depends on the type of problem:

Content errors

Report errors in the content of this documentation with the feedback links below.

Bug reports

Report bugs in the functionality of the described tool or API through Bug Reporter.

Formatting problems

Report formatting mistakes in the online version of these pages with the feedback links below.