]>
Commit | Line | Data |
---|---|---|
1 | .Dd May 26, 2004 | |
2 | .Dt ATOMIC 3 | |
3 | .Os Darwin | |
4 | .Sh NAME | |
5 | .Nm OSAtomicAdd32 , | |
6 | .Nm OSAtomicAdd32Barrier , | |
7 | .Nm OSAtomicIncrement32 , | |
8 | .Nm OSAtomicIncrement32Barrier , | |
9 | .Nm OSAtomicDecrement32 , | |
10 | .Nm OSAtomicDecrement32Barrier , | |
11 | .Nm OSAtomicOr32 , | |
12 | .Nm OSAtomicOr32Barrier , | |
13 | .Nm OSAtomicOr32Orig , | |
14 | .Nm OSAtomicOr32OrigBarrier , | |
15 | .Nm OSAtomicAnd32 , | |
16 | .Nm OSAtomicAnd32Barrier , | |
17 | .Nm OSAtomicAnd32Orig , | |
18 | .Nm OSAtomicAnd32OrigBarrier , | |
19 | .Nm OSAtomicXor32 , | |
20 | .Nm OSAtomicXor32Barrier , | |
21 | .Nm OSAtomicXor32Orig , | |
22 | .Nm OSAtomicXor32OrigBarrier , | |
23 | .Nm OSAtomicAdd64 , | |
24 | .Nm OSAtomicAdd64Barrier , | |
25 | .Nm OSAtomicIncrement64 , | |
26 | .Nm OSAtomicIncrement64Barrier , | |
27 | .Nm OSAtomicDecrement64 , | |
28 | .Nm OSAtomicDecrement64Barrier , | |
29 | .Nm OSAtomicCompareAndSwapInt , | |
30 | .Nm OSAtomicCompareAndSwapIntBarrier , | |
31 | .Nm OSAtomicCompareAndSwapLong , | |
32 | .Nm OSAtomicCompareAndSwapLongBarrier , | |
33 | .Nm OSAtomicCompareAndSwapPtr , | |
34 | .Nm OSAtomicCompareAndSwapPtrBarrier , | |
35 | .Nm OSAtomicCompareAndSwap32 , | |
36 | .Nm OSAtomicCompareAndSwap32Barrier , | |
37 | .Nm OSAtomicCompareAndSwap64 , | |
38 | .Nm OSAtomicCompareAndSwap64Barrier , | |
39 | .Nm OSAtomicTestAndSet , | |
40 | .Nm OSAtomicTestAndSetBarrier , | |
41 | .Nm OSAtomicTestAndClear , | |
42 | .Nm OSAtomicTestAndClearBarrier , | |
43 | .Nm OSSpinLockTry , | |
44 | .Nm OSSpinLockLock , | |
45 | .Nm OSSpinLockUnlock , | |
46 | .Nm OSAtomicEnqueue , | |
47 | .Nm OSAtomicDequeue | |
48 | .Nd atomic add, increment, decrement, or, and, xor, compare and swap, test and set, test and clear, spinlocks, and lockless queues | |
49 | .Sh LIBRARY | |
50 | .Lb libc | |
51 | .Sh SYNOPSIS | |
52 | .In libkern/OSAtomic.h | |
53 | .Ft int32_t | |
54 | .Fn OSAtomicAdd32 "int32_t theAmount" "volatile int32_t *theValue" | |
55 | .Ft int32_t | |
56 | .Fn OSAtomicAdd32Barrier "int32_t theAmount" "volatile int32_t *theValue" | |
57 | .Ft int32_t | |
58 | .Fn OSAtomicIncrement32 "volatile int32_t *theValue" | |
59 | .Ft int32_t | |
60 | .Fn OSAtomicIncrement32Barrier "volatile int32_t *theValue" | |
61 | .Ft int32_t | |
62 | .Fn OSAtomicDecrement32 "volatile int32_t *theValue" | |
63 | .Ft int32_t | |
64 | .Fn OSAtomicDecrement32Barrier "volatile int32_t *theValue" | |
65 | .Ft int32_t | |
66 | .Fn OSAtomicOr32 "uint32_t theMask" "volatile uint32_t *theValue" | |
67 | .Ft int32_t | |
68 | .Fn OSAtomicOr32Barrier "uint32_t theMask" "volatile uint32_t *theValue" | |
69 | .Ft int32_t | |
70 | .Fn OSAtomicAnd32 "uint32_t theMask" "volatile uint32_t *theValue" | |
71 | .Ft int32_t | |
72 | .Fn OSAtomicAnd32Barrier "uint32_t theMask" "volatile uint32_t *theValue" | |
73 | .Ft int32_t | |
74 | .Fn OSAtomicXor32 "uint32_t theMask" "volatile uint32_t *theValue" | |
75 | .Ft int32_t | |
76 | .Fn OSAtomicXor32Barrier "uint32_t theMask" "volatile uint32_t *theValue" | |
77 | .Ft int32_t | |
78 | .Fn OSAtomicOr32Orig "uint32_t theMask" "volatile uint32_t *theValue" | |
79 | .Ft int32_t | |
80 | .Fn OSAtomicOr32OrigBarrier "uint32_t theMask" "volatile uint32_t *theValue" | |
81 | .Ft int32_t | |
82 | .Fn OSAtomicAnd32Orig "uint32_t theMask" "volatile uint32_t *theValue" | |
83 | .Ft int32_t | |
84 | .Fn OSAtomicAnd32OrigBarrier "uint32_t theMask" "volatile uint32_t *theValue" | |
85 | .Ft int32_t | |
86 | .Fn OSAtomicXor32Orig "uint32_t theMask" "volatile uint32_t *theValue" | |
87 | .Ft int32_t | |
88 | .Fn OSAtomicXor32OrigBarrier "uint32_t theMask" "volatile uint32_t *theValue" | |
89 | .Ft int64_t | |
90 | .Fn OSAtomicAdd64 "int64_t theAmount" "volatile int64_t *theValue" | |
91 | .Ft int64_t | |
92 | .Fn OSAtomicAdd64Barrier "int64_t theAmount" "volatile int64_t *theValue" | |
93 | .Ft int64_t | |
94 | .Fn OSAtomicIncrement64 "volatile int64_t *theValue" | |
95 | .Ft int64_t | |
96 | .Fn OSAtomicIncrement64Barrier "volatile int64_t *theValue" | |
97 | .Ft int64_t | |
98 | .Fn OSAtomicDecrement64 "volatile int64_t *theValue" | |
99 | .Ft int64_t | |
100 | .Fn OSAtomicDecrement64Barrier "volatile int64_t *theValue" | |
101 | .Ft bool | |
102 | .Fn OSAtomicCompareAndSwapInt "int oldValue" "int newValue" "volatile int *theValue" | |
103 | .Ft bool | |
104 | .Fn OSAtomicCompareAndSwapIntBarrier "int oldValue" "int newValue" "volatile int *theValue" | |
105 | .Ft bool | |
106 | .Fn OSAtomicCompareAndSwapLong "long oldValue" "long newValue" "volatile long *theValue" | |
107 | .Ft bool | |
108 | .Fn OSAtomicCompareAndSwapLongBarrier "long oldValue" "long newValue" "volatile long *theValue" | |
109 | .Ft bool | |
110 | .Fn OSAtomicCompareAndSwapPtr "void* oldValue" "void* newValue" "void* volatile *theValue" | |
111 | .Ft bool | |
112 | .Fn OSAtomicCompareAndSwapPtrBarrier "void* oldValue" "void* newValue" "void* volatile *theValue" | |
113 | .Ft bool | |
114 | .Fn OSAtomicCompareAndSwap32 "int32_t oldValue" "int32_t newValue" "volatile int32_t *theValue" | |
115 | .Ft bool | |
116 | .Fn OSAtomicCompareAndSwap32Barrier "int32_t oldValue" "int32_t newValue" "volatile int32_t *theValue" | |
117 | .Ft bool | |
118 | .Fn OSAtomicCompareAndSwap64 "int64_t oldValue" "int64_t newValue" "volatile int64_t *theValue" | |
119 | .Ft bool | |
120 | .Fn OSAtomicCompareAndSwap64Barrier "int64_t oldValue" "int64_t newValue" "volatile int64_t *theValue" | |
121 | .Ft bool | |
122 | .Fn OSAtomicTestAndSet "uint32_t n" "volatile void *theAddress" | |
123 | .Ft bool | |
124 | .Fn OSAtomicTestAndSetBarrier "uint32_t n" "volatile void *theAddress" | |
125 | .Ft bool | |
126 | .Fn OSAtomicTestAndClear "uint32_t n" "volatile void *theAddress" | |
127 | .Ft bool | |
128 | .Fn OSAtomicTestAndClearBarrier "uint32_t n" "volatile void *theAddress" | |
129 | .Ft bool | |
130 | .Fn OSSpinLockTry "OSSpinLock *lock" | |
131 | .Ft void | |
132 | .Fn OSSpinLockLock "OSSpinLock *lock" | |
133 | .Ft void | |
134 | .Fn OSSpinLockUnlock "OSSpinLock *lock" | |
135 | .Ft void | |
136 | .Fn OSAtomicEnqueue "OSQueueHead *list" "void *new" "size_t offset" | |
137 | .Ft void* | |
138 | .Fn OSAtomicDequeue "OSQueueHead *list" "size_t offset" | |
139 | .Sh DESCRIPTION | |
140 | These functions are thread and multiprocessor safe. For each function, there | |
141 | is a version that does and another that does not incorporate a memory barrier. | |
142 | Barriers strictly order memory access on a weakly-ordered | |
143 | architecture such as PPC. All loads and stores executed in sequential program | |
144 | order before the barrier will complete before any load or store executed after | |
145 | the barrier. On a uniprocessor, the barrier operation is typically a nop. | |
146 | On a multiprocessor, the barrier can be quite expensive. | |
147 | .Pp | |
148 | Most code will want to use the barrier functions to insure that memory shared | |
149 | between threads is properly synchronized. For example, if you want to initialize | |
150 | a shared data structure and then atomically increment a variable to indicate | |
151 | that the initialization is complete, then you must use OSAtomicIncrement32Barrier() | |
152 | to ensure that the stores to your data structure complete before the atomic add. | |
153 | Likewise, the consumer of that data structure must use OSAtomicDecrement32Barrier(), | |
154 | in order to ensure that their loads of the structure are not executed before | |
155 | the atomic decrement. On the other hand, | |
156 | if you are simply incrementing a global counter, then it is safe and potentially much | |
157 | faster to use OSAtomicIncrement32(). If you are unsure which version to use, prefer | |
158 | the barrier variants as they are safer. | |
159 | .Pp | |
160 | The logical (and, or, xor) and bit test operations are layered on top of the | |
161 | .Fn OSAtomicCompareAndSwap | |
162 | primitives. There are four versions of each logical operation, depending on whether | |
163 | or not there is a barrier, and whether the return value is the result of the | |
164 | operation (eg, | |
165 | .Fn OSAtomicOr32 | |
166 | ) or the original value before the operation (eg, | |
167 | .Fn OSAtomicOr32Orig | |
168 | ). | |
169 | .Pp | |
170 | The memory address | |
171 | .Fa theValue | |
172 | must be naturally aligned, ie 32-bit aligned for 32-bit operations and 64-bit | |
173 | aligned for 64-bit operations. | |
174 | .Pp | |
175 | The 64-bit operations are not implemented for 32-bit processes on PPC platforms. | |
176 | .Pp | |
177 | The | |
178 | .Fn OSAtomicCompareAndSwap | |
179 | operations compare | |
180 | .Fa oldValue | |
181 | to | |
182 | .Fa *theValue , | |
183 | and set | |
184 | .Fa *theValue | |
185 | to | |
186 | .Fa newValue | |
187 | if the comparison is equal. The comparison and assignment | |
188 | occur as one atomic operation. | |
189 | .Pp | |
190 | .Fn OSAtomicTestAndSet | |
191 | and | |
192 | .Fn OSAtomicTestAndClear | |
193 | operate on bit (0x80 >> ( | |
194 | .Fa n | |
195 | & 7)) of byte ((char*) | |
196 | .Fa theAddress | |
197 | + ( | |
198 | .Fa n | |
199 | >> 3)). They set the named bit to either 1 or 0, respectively. | |
200 | .Fa theAddress | |
201 | need not be aligned. | |
202 | .Pp | |
203 | The routines | |
204 | .Fn OSAtomicEnqueue | |
205 | and | |
206 | .Fn OSAtomicDequeue | |
207 | operate on singly linked LIFO queues. Ie, a dequeue operation will return the | |
208 | most recently enqueued element, or NULL if the list is empty. The operations | |
209 | are lockless, and barriers are used as necessary to permit thread-safe access to | |
210 | the queue element. | |
211 | .Fa offset | |
212 | is the offset in bytes to the link field in the queue element. For example: | |
213 | .Bd -literal -offset indent | |
214 | typedef struct elem { | |
215 | long data1; | |
216 | struct elem *link; | |
217 | int data2; | |
218 | } elem_t; | |
219 | ||
220 | elem_t fred, mary, *p; | |
221 | ||
222 | OSQueueHead q = OS_ATOMIC_QUEUE_INIT; | |
223 | ||
224 | OSAtomicEnqueue( &q, &fred, offsetof(elem_t,link) ); | |
225 | OSAtomicEnqueue( &q, &mary, offsetof(elem_t,link) ); | |
226 | ||
227 | p = OSAtomicDequeue( &q, offsetof(elem_t,link) ); | |
228 | ||
229 | .Ed | |
230 | In this example, the call of | |
231 | .Fn OSAtomicDequeue | |
232 | will return a ptr to mary. | |
233 | .Sh RETURN VALUES | |
234 | The arithmetic operations return the new value, after the operation has been performed. | |
235 | The boolean operations come in two styles, one of which returns the new value, and one | |
236 | of which (the "Orig" versions) returns the old. | |
237 | The compare-and-swap operations return true if the comparison was equal, ie if the swap occured. | |
238 | The bit test and set/clear operations return the original value of the bit. | |
239 | The dequeue operation returns the most recently enqueued element, or NULL if the list in empty. | |
240 | .Sh SEE ALSO | |
241 | .Xr spinlock 3 , | |
242 | .Xr barrier 3 | |
243 | .Sh HISTORY | |
244 | Most of these functions first appeared in Mac OS 10.4 (Tiger). The "Orig" forms of the | |
245 | boolean operations, the "int", "long" and "ptr" forms of compare-and-swap, and lockless | |
246 | enqueue/dequeue first appeared in Mac OS 10.5 (Leopard). |