]> git.saurik.com Git - apple/libplatform.git/blame - src/os/atomic.c
libplatform-254.40.4.tar.gz
[apple/libplatform.git] / src / os / atomic.c
CommitLineData
ada7c492
A
1/*
2 * Copyright (c) 2013 Apple Inc. All rights reserved.
3 *
4 * @APPLE_APACHE_LICENSE_HEADER_START@
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * @APPLE_APACHE_LICENSE_HEADER_END@
19 */
20
21#include "os/internal.h"
ada7c492 22#include "resolver.h"
e45b4692 23#include "libkern/OSAtomic.h"
ada7c492 24
442fbc9d 25#if defined(__arm__) || defined(__arm64__)
ada7c492 26
e45b4692
A
27OS_ATOMIC_EXPORT
28int32_t OSAtomicAdd32(int32_t v, volatile int32_t *p);
ada7c492
A
29OS_ATOMIC_EXPORT
30int32_t OSAtomicAdd32Barrier(int32_t v, volatile int32_t *p);
31OS_ATOMIC_EXPORT
e45b4692
A
32int32_t OSAtomicIncrement32(volatile int32_t *p);
33OS_ATOMIC_EXPORT
ada7c492
A
34int32_t OSAtomicIncrement32Barrier(volatile int32_t *p);
35OS_ATOMIC_EXPORT
e45b4692
A
36int32_t OSAtomicDecrement32(volatile int32_t *p);
37OS_ATOMIC_EXPORT
ada7c492
A
38int32_t OSAtomicDecrement32Barrier(volatile int32_t *p);
39OS_ATOMIC_EXPORT
e45b4692
A
40int64_t OSAtomicAdd64(int64_t v, volatile int64_t *p);
41OS_ATOMIC_EXPORT
ada7c492
A
42int64_t OSAtomicAdd64Barrier(int64_t v, volatile int64_t *p);
43OS_ATOMIC_EXPORT
e45b4692
A
44int64_t OSAtomicIncrement64(volatile int64_t *p);
45OS_ATOMIC_EXPORT
ada7c492
A
46int64_t OSAtomicIncrement64Barrier(volatile int64_t *p);
47OS_ATOMIC_EXPORT
e45b4692
A
48int64_t OSAtomicDecrement64(volatile int64_t *p);
49OS_ATOMIC_EXPORT
ada7c492
A
50int64_t OSAtomicDecrement64Barrier(volatile int64_t *p);
51OS_ATOMIC_EXPORT
e45b4692
A
52int32_t OSAtomicAnd32(uint32_t v, volatile uint32_t *p);
53OS_ATOMIC_EXPORT
ada7c492
A
54int32_t OSAtomicAnd32Barrier(uint32_t v, volatile uint32_t *p);
55OS_ATOMIC_EXPORT
e45b4692
A
56int32_t OSAtomicAnd32Orig(uint32_t v, volatile uint32_t *p);
57OS_ATOMIC_EXPORT
ada7c492
A
58int32_t OSAtomicAnd32OrigBarrier(uint32_t v, volatile uint32_t *p);
59OS_ATOMIC_EXPORT
e45b4692
A
60int32_t OSAtomicOr32(uint32_t v, volatile uint32_t *p);
61OS_ATOMIC_EXPORT
ada7c492
A
62int32_t OSAtomicOr32Barrier(uint32_t v, volatile uint32_t *p);
63OS_ATOMIC_EXPORT
e45b4692
A
64int32_t OSAtomicOr32Orig(uint32_t v, volatile uint32_t *p);
65OS_ATOMIC_EXPORT
ada7c492
A
66int32_t OSAtomicOr32OrigBarrier(uint32_t v, volatile uint32_t *p);
67OS_ATOMIC_EXPORT
e45b4692
A
68int32_t OSAtomicXor32(uint32_t v, volatile uint32_t *p);
69OS_ATOMIC_EXPORT
ada7c492
A
70int32_t OSAtomicXor32Barrier(uint32_t v, volatile uint32_t *p);
71OS_ATOMIC_EXPORT
e45b4692
A
72int32_t OSAtomicXor32Orig(uint32_t v, volatile uint32_t *p);
73OS_ATOMIC_EXPORT
ada7c492
A
74int32_t OSAtomicXor32OrigBarrier(uint32_t v, volatile uint32_t *p);
75OS_ATOMIC_EXPORT
e45b4692
A
76bool OSAtomicCompareAndSwap32(int32_t o, int32_t n, volatile int32_t *p);
77OS_ATOMIC_EXPORT
ada7c492
A
78bool OSAtomicCompareAndSwap32Barrier(int32_t o, int32_t n, volatile int32_t *p);
79OS_ATOMIC_EXPORT
e45b4692
A
80bool OSAtomicCompareAndSwapPtr(void *o, void *n, void * volatile *p);
81OS_ATOMIC_EXPORT
82bool OSAtomicCompareAndSwapPtrBarrier(void *o, void *n, void * volatile *p);
83OS_ATOMIC_EXPORT
84bool OSAtomicCompareAndSwapInt(int o, int n, volatile int *p);
85OS_ATOMIC_EXPORT
86bool OSAtomicCompareAndSwapIntBarrier(int o, int n, volatile int *p);
87OS_ATOMIC_EXPORT
88bool OSAtomicCompareAndSwapLong(long o, long n, volatile long *p);
89OS_ATOMIC_EXPORT
90bool OSAtomicCompareAndSwapLongBarrier(long o, long n, volatile long *p);
91OS_ATOMIC_EXPORT
92bool OSAtomicCompareAndSwap64(int64_t o, int64_t n, volatile int64_t *p);
93OS_ATOMIC_EXPORT
ada7c492
A
94bool OSAtomicCompareAndSwap64Barrier(int64_t o, int64_t n, volatile int64_t *p);
95OS_ATOMIC_EXPORT
e45b4692
A
96bool OSAtomicTestAndSet(uint32_t n, volatile void * p);
97OS_ATOMIC_EXPORT
ada7c492
A
98bool OSAtomicTestAndSetBarrier(uint32_t n, volatile void * p);
99OS_ATOMIC_EXPORT
e45b4692
A
100bool OSAtomicTestAndClear(uint32_t n, volatile void * p);
101OS_ATOMIC_EXPORT
ada7c492
A
102bool OSAtomicTestAndClearBarrier(uint32_t n, volatile void * p);
103OS_ATOMIC_EXPORT
104void OSAtomicEnqueue(OSQueueHead *list, void *new, size_t offset);
105OS_ATOMIC_EXPORT
106void* OSAtomicDequeue(OSQueueHead *list, size_t offset);
107OS_ATOMIC_EXPORT
108void OSMemoryBarrier(void);
109
e45b4692
A
110int32_t
111OSAtomicAdd32(int32_t v, volatile int32_t *p)
112{
113 int32_t r = os_atomic_add(p, v, relaxed);
114 return r;
115}
ada7c492
A
116
117int32_t
118OSAtomicAdd32Barrier(int32_t v, volatile int32_t *p)
119{
e45b4692
A
120 int32_t r = os_atomic_add(p, v, seq_cst);
121 return r;
122}
123
124int32_t
125OSAtomicIncrement32(volatile int32_t *p)
126{
127 int32_t r = os_atomic_add(p, 1, relaxed);
ada7c492
A
128 return r;
129}
130
131int32_t
132OSAtomicIncrement32Barrier(volatile int32_t *p)
133{
e45b4692
A
134 int32_t r = os_atomic_add(p, 1, seq_cst);
135 return r;
136}
137
138int32_t
139OSAtomicDecrement32(volatile int32_t *p)
140{
141 int32_t r = os_atomic_add(p, -1, relaxed);
ada7c492
A
142 return r;
143}
144
145int32_t
146OSAtomicDecrement32Barrier(volatile int32_t *p)
147{
e45b4692
A
148 int32_t r = os_atomic_add(p, -1, seq_cst);
149 return r;
150}
151
152int64_t
153OSAtomicAdd64(int64_t v, volatile int64_t *p)
154{
155 int64_t r = os_atomic_add(p, v, relaxed);
ada7c492
A
156 return r;
157}
158
159int64_t
160OSAtomicAdd64Barrier(int64_t v, volatile int64_t *p)
161{
e45b4692
A
162 int64_t r = os_atomic_add(p, v, seq_cst);
163 return r;
164}
165
166int64_t
167OSAtomicIncrement64(volatile int64_t *p)
168{
169 int64_t r = os_atomic_add(p, 1, relaxed);
ada7c492
A
170 return r;
171}
172
173int64_t
174OSAtomicIncrement64Barrier(volatile int64_t *p)
175{
e45b4692
A
176 int64_t r = os_atomic_add(p, 1, seq_cst);
177 return r;
178}
179
180int64_t
181OSAtomicDecrement64(volatile int64_t *p)
182{
183 int64_t r = os_atomic_add(p, -1, relaxed);
ada7c492
A
184 return r;
185}
186
187int64_t
188OSAtomicDecrement64Barrier(volatile int64_t *p)
189{
e45b4692 190 int64_t r = os_atomic_add(p, -1, seq_cst);
ada7c492
A
191 return r;
192}
193
e45b4692
A
194int32_t
195OSAtomicAnd32(uint32_t v, volatile uint32_t *p)
196{
197 uint32_t r = os_atomic_and(p, v, relaxed);
198 return (int32_t)r;
199}
200
ada7c492
A
201int32_t
202OSAtomicAnd32Barrier(uint32_t v, volatile uint32_t *p)
203{
e45b4692
A
204 uint32_t r = os_atomic_and(p, v, seq_cst);
205 return (int32_t)r;
206}
207
208int32_t
209OSAtomicAnd32Orig(uint32_t v, volatile uint32_t *p)
210{
211 uint32_t r = os_atomic_and_orig(p, v, relaxed);
ada7c492
A
212 return (int32_t)r;
213}
214
215int32_t
216OSAtomicAnd32OrigBarrier(uint32_t v, volatile uint32_t *p)
217{
e45b4692
A
218 uint32_t r = os_atomic_and_orig(p, v, seq_cst);
219 return (int32_t)r;
220}
221
222int32_t
223OSAtomicOr32(uint32_t v, volatile uint32_t *p)
224{
225 uint32_t r = os_atomic_or(p, v, relaxed);
ada7c492
A
226 return (int32_t)r;
227}
228
229int32_t
230OSAtomicOr32Barrier(uint32_t v, volatile uint32_t *p)
231{
e45b4692
A
232 uint32_t r = os_atomic_or(p, v, seq_cst);
233 return (int32_t)r;
234}
235
236int32_t
237OSAtomicOr32Orig(uint32_t v, volatile uint32_t *p)
238{
239 uint32_t r = os_atomic_or_orig(p, v, relaxed);
ada7c492
A
240 return (int32_t)r;
241}
242
243int32_t
244OSAtomicOr32OrigBarrier(uint32_t v, volatile uint32_t *p)
245{
e45b4692
A
246 uint32_t r = os_atomic_or_orig(p, v, seq_cst);
247 return (int32_t)r;
248}
249
250int32_t
251OSAtomicXor32(uint32_t v, volatile uint32_t *p)
252{
253 uint32_t r = os_atomic_xor(p, v, relaxed);
ada7c492
A
254 return (int32_t)r;
255}
256
257int32_t
258OSAtomicXor32Barrier(uint32_t v, volatile uint32_t *p)
259{
e45b4692
A
260 uint32_t r = os_atomic_xor(p, v, seq_cst);
261 return (int32_t)r;
262}
263
264int32_t
265OSAtomicXor32Orig(uint32_t v, volatile uint32_t *p)
266{
267 uint32_t r = os_atomic_xor_orig(p, v, relaxed);
ada7c492
A
268 return (int32_t)r;
269}
270
271int32_t
272OSAtomicXor32OrigBarrier(uint32_t v, volatile uint32_t *p)
273{
e45b4692 274 uint32_t r = os_atomic_xor_orig(p, v, seq_cst);
ada7c492
A
275 return (int32_t)r;
276}
277
e45b4692
A
278bool
279OSAtomicCompareAndSwap32(int32_t o, int32_t n, volatile int32_t *p)
280{
281 return os_atomic_cmpxchg(p, o, n, relaxed);
282}
283
ada7c492
A
284bool
285OSAtomicCompareAndSwap32Barrier(int32_t o, int32_t n, volatile int32_t *p)
286{
e45b4692
A
287 return os_atomic_cmpxchg(p, o, n, seq_cst);
288}
289
290bool
291OSAtomicCompareAndSwapPtr(void *o, void *n, void * volatile *p)
292{
293 return os_atomic_cmpxchg(p, o, n, relaxed);
294}
295
296bool
297OSAtomicCompareAndSwapPtrBarrier(void *o, void *n, void * volatile *p)
298{
299 return os_atomic_cmpxchg(p, o, n, seq_cst);
300}
301
302bool
303OSAtomicCompareAndSwapInt(int o, int n, volatile int *p)
304{
305 return os_atomic_cmpxchg(p, o, n, relaxed);
306}
307
308bool
309OSAtomicCompareAndSwapIntBarrier(int o, int n, volatile int *p)
310{
311 return os_atomic_cmpxchg(p, o, n, seq_cst);
312}
313
314bool
315OSAtomicCompareAndSwapLong(long o, long n, volatile long *p)
316{
317 return os_atomic_cmpxchg(p, o, n, relaxed);
318}
319
320bool
321OSAtomicCompareAndSwapLongBarrier(long o, long n, volatile long *p)
322{
323 return os_atomic_cmpxchg(p, o, n, seq_cst);
324}
325
326bool
327OSAtomicCompareAndSwap64(int64_t o, int64_t n, volatile int64_t *p)
328{
329 return os_atomic_cmpxchg(p, o, n, relaxed);
ada7c492
A
330}
331
332bool
333OSAtomicCompareAndSwap64Barrier(int64_t o, int64_t n, volatile int64_t *p)
334{
e45b4692 335 return os_atomic_cmpxchg(p, o, n, seq_cst);
ada7c492
A
336}
337
338static inline uint32_t*
339_OSAtomicTestPtrVal(uint32_t bit, volatile void *addr, uint32_t *vp)
340{
341 uintptr_t a = (uintptr_t)addr;
342 if (a & 3) {
343 // 32-bit align addr and adjust bit to compensate <rdar://12927920>
344 bit += (a & 3) * 8;
345 a &= ~3ull;
346 }
347 *vp = (0x80u >> (bit & 7)) << (bit & ~7u & 31);
348 return (uint32_t*)((char*)a + 4 * (bit / 32));
349}
350
e45b4692
A
351bool
352OSAtomicTestAndSet(uint32_t bit, volatile void *addr)
353{
354 uint32_t v;
355 volatile uint32_t *p = _OSAtomicTestPtrVal(bit, addr, &v);
356 uint32_t r = os_atomic_or_orig(p, v, relaxed);
357 return (r & v);
358}
359
ada7c492
A
360bool
361OSAtomicTestAndSetBarrier(uint32_t bit, volatile void *addr)
362{
ada7c492
A
363 uint32_t v;
364 volatile uint32_t *p = _OSAtomicTestPtrVal(bit, addr, &v);
e45b4692 365 uint32_t r = os_atomic_or_orig(p, v, seq_cst);
ada7c492
A
366 return (r & v);
367}
368
369bool
e45b4692 370OSAtomicTestAndClear(uint32_t bit, volatile void *addr)
ada7c492 371{
ada7c492
A
372 uint32_t v;
373 volatile uint32_t *p = _OSAtomicTestPtrVal(bit, addr, &v);
e45b4692 374 uint32_t r = os_atomic_and_orig(p, ~v, relaxed);
ada7c492
A
375 return (r & v);
376}
377
e45b4692
A
378bool
379OSAtomicTestAndClearBarrier(uint32_t bit, volatile void *addr)
380{
381 uint32_t v;
382 volatile uint32_t *p = _OSAtomicTestPtrVal(bit, addr, &v);
383 uint32_t r = os_atomic_and_orig(p, ~v, seq_cst);
384 return (r & v);
385}
ada7c492 386
e45b4692
A
387typedef struct {
388 void *item;
389 long gencount;
ada7c492
A
390} _OSQueueHead;
391
442fbc9d
A
392OS_ALWAYS_INLINE
393static inline void
394_OSAtomicEnqueue_llsc(OSQueueHead *list, void *new, size_t offset)
ada7c492
A
395{
396 void * volatile *headptr = &(((_OSQueueHead*)list)->item);
397 void * volatile *nextptr = (void*)((char*)new + offset);
442fbc9d 398 void *head, *tmp, *next;
e45b4692
A
399
400 head = os_atomic_load(headptr, relaxed);
401 next = new;
ada7c492 402 do {
442fbc9d
A
403 *nextptr = tmp = head;
404 head = os_atomic_load_exclusive(headptr, relaxed);
405 } while (tmp != head || !os_atomic_store_exclusive(headptr, next, release));
ada7c492
A
406}
407
442fbc9d
A
408OS_ALWAYS_INLINE
409static inline void *
410_OSAtomicDequeue_llsc(OSQueueHead *list, size_t offset)
ada7c492
A
411{
412 void * volatile *headptr = &(((_OSQueueHead*)list)->item);
413 void * volatile *nextptr;
414 void *head, *next;
e45b4692 415
442fbc9d
A
416 do {
417 head = os_atomic_load_exclusive(headptr, acquire);
418 if (!head) {
419 os_atomic_clear_exclusive();
420 break;
421 }
ada7c492
A
422 nextptr = (void*)((char*)head + offset);
423 next = *nextptr;
442fbc9d
A
424 } while (unlikely(!os_atomic_store_exclusive(headptr, next, relaxed)));
425
ada7c492
A
426 return head;
427}
428
e45b4692 429
442fbc9d
A
430void
431OSAtomicEnqueue(OSQueueHead *list, void *new, size_t offset)
432{
433 return _OSAtomicEnqueue_llsc(list, new, offset);
434}
435
436void*
437OSAtomicDequeue(OSQueueHead *list, size_t offset)
438{
439 return _OSAtomicDequeue_llsc(list, offset);
440}
441
442
ada7c492
A
443void
444OSMemoryBarrier(void)
445{
446 os_atomic_thread_fence(seq_cst);
447}
448
442fbc9d 449#endif // defined(__arm__) || defined(__arm64__)
ada7c492
A
450
451struct _os_empty_files_are_not_c_files;