]> git.saurik.com Git - apple/libdispatch.git/blob - src/shims/atomic.h
libdispatch-339.92.1.tar.gz
[apple/libdispatch.git] / src / shims / atomic.h
1 /*
2 * Copyright (c) 2008-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 /*
22 * IMPORTANT: This header file describes INTERNAL interfaces to libdispatch
23 * which are subject to change in future releases of Mac OS X. Any applications
24 * relying on these interfaces WILL break.
25 */
26
27 #ifndef __DISPATCH_SHIMS_ATOMIC__
28 #define __DISPATCH_SHIMS_ATOMIC__
29
30 // generate error during codegen
31 #define _dispatch_atomic_unimplemented() \
32 ({ __asm__(".err unimplemented"); })
33
34 #pragma mark -
35 #pragma mark memory_order
36
37 typedef enum _dispatch_atomic_memory_order
38 {
39 _dispatch_atomic_memory_order_relaxed,
40 _dispatch_atomic_memory_order_consume,
41 _dispatch_atomic_memory_order_acquire,
42 _dispatch_atomic_memory_order_release,
43 _dispatch_atomic_memory_order_acq_rel,
44 _dispatch_atomic_memory_order_seq_cst,
45 } _dispatch_atomic_memory_order;
46
47 #if !DISPATCH_ATOMIC_UP
48
49 #define dispatch_atomic_memory_order_relaxed \
50 _dispatch_atomic_memory_order_relaxed
51 #define dispatch_atomic_memory_order_acquire \
52 _dispatch_atomic_memory_order_acquire
53 #define dispatch_atomic_memory_order_release \
54 _dispatch_atomic_memory_order_release
55 #define dispatch_atomic_memory_order_acq_rel \
56 _dispatch_atomic_memory_order_acq_rel
57 #define dispatch_atomic_memory_order_seq_cst \
58 _dispatch_atomic_memory_order_seq_cst
59
60 #else // DISPATCH_ATOMIC_UP
61
62 #define dispatch_atomic_memory_order_relaxed \
63 _dispatch_atomic_memory_order_relaxed
64 #define dispatch_atomic_memory_order_acquire \
65 _dispatch_atomic_memory_order_relaxed
66 #define dispatch_atomic_memory_order_release \
67 _dispatch_atomic_memory_order_relaxed
68 #define dispatch_atomic_memory_order_acq_rel \
69 _dispatch_atomic_memory_order_relaxed
70 #define dispatch_atomic_memory_order_seq_cst \
71 _dispatch_atomic_memory_order_relaxed
72
73 #endif // DISPATCH_ATOMIC_UP
74
75 #if __has_extension(c_generic_selections)
76 #define _dispatch_atomic_basetypeof(p) \
77 typeof(*_Generic((p), \
78 int*: (int*)(p), \
79 volatile int*: (int*)(p), \
80 unsigned int*: (unsigned int*)(p), \
81 volatile unsigned int*: (unsigned int*)(p), \
82 long*: (long*)(p), \
83 volatile long*: (long*)(p), \
84 unsigned long*: (unsigned long*)(p), \
85 volatile unsigned long*: (unsigned long*)(p), \
86 long long*: (long long*)(p), \
87 volatile long long*: (long long*)(p), \
88 unsigned long long*: (unsigned long long*)(p), \
89 volatile unsigned long long*: (unsigned long long*)(p), \
90 default: (void**)(p)))
91 #endif
92
93 #if __has_extension(c_atomic) && __has_extension(c_generic_selections)
94 #pragma mark -
95 #pragma mark c11
96
97 #define _dispatch_atomic_c11_atomic(p) \
98 _Generic((p), \
99 int*: (_Atomic(int)*)(p), \
100 volatile int*: (volatile _Atomic(int)*)(p), \
101 unsigned int*: (_Atomic(unsigned int)*)(p), \
102 volatile unsigned int*: (volatile _Atomic(unsigned int)*)(p), \
103 long*: (_Atomic(long)*)(p), \
104 volatile long*: (volatile _Atomic(long)*)(p), \
105 unsigned long*: (_Atomic(unsigned long)*)(p), \
106 volatile unsigned long*: (volatile _Atomic(unsigned long)*)(p), \
107 long long*: (_Atomic(long long)*)(p), \
108 volatile long long*: (volatile _Atomic(long long)*)(p), \
109 unsigned long long*: (_Atomic(unsigned long long)*)(p), \
110 volatile unsigned long long*: \
111 (volatile _Atomic(unsigned long long)*)(p), \
112 default: (volatile _Atomic(void*)*)(p))
113
114 #define _dispatch_atomic_barrier(m) \
115 ({ __c11_atomic_thread_fence(dispatch_atomic_memory_order_##m); })
116 #define dispatch_atomic_load(p, m) \
117 ({ _dispatch_atomic_basetypeof(p) _r = \
118 __c11_atomic_load(_dispatch_atomic_c11_atomic(p), \
119 dispatch_atomic_memory_order_##m); (typeof(*(p)))_r; })
120 #define dispatch_atomic_store(p, v, m) \
121 ({ _dispatch_atomic_basetypeof(p) _v = (v); \
122 __c11_atomic_store(_dispatch_atomic_c11_atomic(p), _v, \
123 dispatch_atomic_memory_order_##m); })
124 #define dispatch_atomic_xchg(p, v, m) \
125 ({ _dispatch_atomic_basetypeof(p) _v = (v), _r = \
126 __c11_atomic_exchange(_dispatch_atomic_c11_atomic(p), _v, \
127 dispatch_atomic_memory_order_##m); (typeof(*(p)))_r; })
128 #define dispatch_atomic_cmpxchg(p, e, v, m) \
129 ({ _dispatch_atomic_basetypeof(p) _v = (v), _r = (e); \
130 __c11_atomic_compare_exchange_strong(_dispatch_atomic_c11_atomic(p), \
131 &_r, _v, dispatch_atomic_memory_order_##m, \
132 dispatch_atomic_memory_order_relaxed); })
133 #define dispatch_atomic_cmpxchgv(p, e, v, g, m) \
134 ({ _dispatch_atomic_basetypeof(p) _v = (v), _r = (e); _Bool _b = \
135 __c11_atomic_compare_exchange_strong(_dispatch_atomic_c11_atomic(p), \
136 &_r, _v, dispatch_atomic_memory_order_##m, \
137 dispatch_atomic_memory_order_relaxed); *(g) = (typeof(*(p)))_r; _b; })
138 #define dispatch_atomic_cmpxchgvw(p, e, v, g, m) \
139 ({ _dispatch_atomic_basetypeof(p) _v = (v), _r = (e); _Bool _b = \
140 __c11_atomic_compare_exchange_weak(_dispatch_atomic_c11_atomic(p), \
141 &_r, _v, dispatch_atomic_memory_order_##m, \
142 dispatch_atomic_memory_order_relaxed); *(g) = (typeof(*(p)))_r; _b; })
143 #define _dispatch_atomic_c11_op(p, v, m, o, op) \
144 ({ _dispatch_atomic_basetypeof(p) _v = (v), _r = \
145 __c11_atomic_fetch_##o(_dispatch_atomic_c11_atomic(p), _v, \
146 dispatch_atomic_memory_order_##m); (typeof(*(p)))(_r op _v); })
147 #define _dispatch_atomic_c11_op_orig(p, v, m, o, op) \
148 ({ _dispatch_atomic_basetypeof(p) _v = (v), _r = \
149 __c11_atomic_fetch_##o(_dispatch_atomic_c11_atomic(p), _v, \
150 dispatch_atomic_memory_order_##m); (typeof(*(p)))_r; })
151
152 #define dispatch_atomic_add(p, v, m) \
153 _dispatch_atomic_c11_op((p), (v), m, add, +)
154 #define dispatch_atomic_add_orig(p, v, m) \
155 _dispatch_atomic_c11_op_orig((p), (v), m, add, +)
156 #define dispatch_atomic_sub(p, v, m) \
157 _dispatch_atomic_c11_op((p), (v), m, sub, -)
158 #define dispatch_atomic_sub_orig(p, v, m) \
159 _dispatch_atomic_c11_op_orig((p), (v), m, sub, -)
160 #define dispatch_atomic_and(p, v, m) \
161 _dispatch_atomic_c11_op((p), (v), m, and, &)
162 #define dispatch_atomic_and_orig(p, v, m) \
163 _dispatch_atomic_c11_op_orig((p), (v), m, and, &)
164 #define dispatch_atomic_or(p, v, m) \
165 _dispatch_atomic_c11_op((p), (v), m, or, |)
166 #define dispatch_atomic_or_orig(p, v, m) \
167 _dispatch_atomic_c11_op_orig((p), (v), m, or, |)
168 #define dispatch_atomic_xor(p, v, m) \
169 _dispatch_atomic_c11_op((p), (v), m, xor, ^)
170 #define dispatch_atomic_xor_orig(p, v, m) \
171 _dispatch_atomic_c11_op_orig((p), (v), m, xor, ^)
172
173 #elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)
174 #pragma mark -
175 #pragma mark gnu99
176
177 #define _dispatch_atomic_full_barrier() \
178 __sync_synchronize()
179 #define _dispatch_atomic_barrier(m) \
180 ({ switch(dispatch_atomic_memory_order_##m) { \
181 case _dispatch_atomic_memory_order_relaxed: \
182 break; \
183 default: \
184 _dispatch_atomic_full_barrier(); break; \
185 } })
186 // Only emulate store seq_cst -> load seq_cst
187 #define dispatch_atomic_load(p, m) \
188 ({ switch(dispatch_atomic_memory_order_##m) { \
189 case _dispatch_atomic_memory_order_relaxed: \
190 case _dispatch_atomic_memory_order_seq_cst: \
191 break; \
192 default: \
193 _dispatch_atomic_unimplemented(); break; \
194 }; *(p); })
195 #define dispatch_atomic_store(p, v, m) \
196 ({ switch(dispatch_atomic_memory_order_##m) { \
197 case _dispatch_atomic_memory_order_release: \
198 _dispatch_atomic_barrier(m); /* fallthrough */ \
199 case _dispatch_atomic_memory_order_relaxed: \
200 case _dispatch_atomic_memory_order_seq_cst: \
201 *(p) = (v); break; \
202 default:\
203 _dispatch_atomic_unimplemented(); break; \
204 } switch(dispatch_atomic_memory_order_##m) { \
205 case _dispatch_atomic_memory_order_seq_cst: \
206 _dispatch_atomic_barrier(m); break; \
207 default: \
208 break; \
209 } })
210 #if __has_builtin(__sync_swap)
211 #define dispatch_atomic_xchg(p, v, m) \
212 ((typeof(*(p)))__sync_swap((p), (v)))
213 #else
214 #define dispatch_atomic_xchg(p, v, m) \
215 ((typeof(*(p)))__sync_lock_test_and_set((p), (v)))
216 #endif
217 #define dispatch_atomic_cmpxchg(p, e, v, m) \
218 __sync_bool_compare_and_swap((p), (e), (v))
219 #define dispatch_atomic_cmpxchgv(p, e, v, g, m) \
220 ({ typeof(*(g)) _e = (e), _r = \
221 __sync_val_compare_and_swap((p), _e, (v)); \
222 bool _b = (_e == _r); *(g) = _r; _b; })
223 #define dispatch_atomic_cmpxchgvw(p, e, v, g, m) \
224 dispatch_atomic_cmpxchgv((p), (e), (v), (g), m)
225
226 #define dispatch_atomic_add(p, v, m) \
227 __sync_add_and_fetch((p), (v))
228 #define dispatch_atomic_add_orig(p, v, m) \
229 __sync_fetch_and_add((p), (v))
230 #define dispatch_atomic_sub(p, v, m) \
231 __sync_sub_and_fetch((p), (v))
232 #define dispatch_atomic_sub_orig(p, v, m) \
233 __sync_fetch_and_sub((p), (v))
234 #define dispatch_atomic_and(p, v, m) \
235 __sync_and_and_fetch((p), (v))
236 #define dispatch_atomic_and_orig(p, v, m) \
237 __sync_fetch_and_and((p), (v))
238 #define dispatch_atomic_or(p, v, m) \
239 __sync_or_and_fetch((p), (v))
240 #define dispatch_atomic_or_orig(p, v, m) \
241 __sync_fetch_and_or((p), (v))
242 #define dispatch_atomic_xor(p, v, m) \
243 __sync_xor_and_fetch((p), (v))
244 #define dispatch_atomic_xor_orig(p, v, m) \
245 __sync_fetch_and_xor((p), (v))
246
247 #if defined(__x86_64__) || defined(__i386__)
248 // GCC emits nothing for __sync_synchronize() on x86_64 & i386
249 #undef _dispatch_atomic_full_barrier
250 #define _dispatch_atomic_full_barrier() \
251 ({ __asm__ __volatile__( \
252 "mfence" \
253 : : : "memory"); })
254 // xchg is faster than store + mfence
255 #undef dispatch_atomic_store
256 #define dispatch_atomic_store(p, v, m) \
257 ({ switch(dispatch_atomic_memory_order_##m) { \
258 case _dispatch_atomic_memory_order_relaxed: \
259 case _dispatch_atomic_memory_order_release: \
260 *(p) = (v); break; \
261 case _dispatch_atomic_memory_order_seq_cst: \
262 (void)dispatch_atomic_xchg((p), (v), m); break; \
263 default:\
264 _dispatch_atomic_unimplemented(); break; \
265 } })
266 #endif
267
268 #else
269 #error "Please upgrade to GCC 4.2 or newer."
270 #endif
271
272 #pragma mark -
273 #pragma mark generic
274
275 #define dispatch_hardware_pause() ({ __asm__(""); })
276 // assume atomic builtins provide barriers
277 #define dispatch_atomic_barrier(m)
278 // see comment in dispatch_once.c
279 #define dispatch_atomic_maximally_synchronizing_barrier() \
280 _dispatch_atomic_barrier(seq_cst)
281
282 #define dispatch_atomic_load2o(p, f, m) \
283 dispatch_atomic_load(&(p)->f, m)
284 #define dispatch_atomic_store2o(p, f, v, m) \
285 dispatch_atomic_store(&(p)->f, (v), m)
286 #define dispatch_atomic_xchg2o(p, f, v, m) \
287 dispatch_atomic_xchg(&(p)->f, (v), m)
288 #define dispatch_atomic_cmpxchg2o(p, f, e, v, m) \
289 dispatch_atomic_cmpxchg(&(p)->f, (e), (v), m)
290 #define dispatch_atomic_cmpxchgv2o(p, f, e, v, g, m) \
291 dispatch_atomic_cmpxchgv(&(p)->f, (e), (v), (g), m)
292 #define dispatch_atomic_cmpxchgvw2o(p, f, e, v, g, m) \
293 dispatch_atomic_cmpxchgvw(&(p)->f, (e), (v), (g), m)
294 #define dispatch_atomic_add2o(p, f, v, m) \
295 dispatch_atomic_add(&(p)->f, (v), m)
296 #define dispatch_atomic_add_orig2o(p, f, v, m) \
297 dispatch_atomic_add_orig(&(p)->f, (v), m)
298 #define dispatch_atomic_sub2o(p, f, v, m) \
299 dispatch_atomic_sub(&(p)->f, (v), m)
300 #define dispatch_atomic_sub_orig2o(p, f, v, m) \
301 dispatch_atomic_sub_orig(&(p)->f, (v), m)
302 #define dispatch_atomic_and2o(p, f, v, m) \
303 dispatch_atomic_and(&(p)->f, (v), m)
304 #define dispatch_atomic_and_orig2o(p, f, v, m) \
305 dispatch_atomic_and_orig(&(p)->f, (v), m)
306 #define dispatch_atomic_or2o(p, f, v, m) \
307 dispatch_atomic_or(&(p)->f, (v), m)
308 #define dispatch_atomic_or_orig2o(p, f, v, m) \
309 dispatch_atomic_or_orig(&(p)->f, (v), m)
310 #define dispatch_atomic_xor2o(p, f, v, m) \
311 dispatch_atomic_xor(&(p)->f, (v), m)
312 #define dispatch_atomic_xor_orig2o(p, f, v, m) \
313 dispatch_atomic_xor_orig(&(p)->f, (v), m)
314
315 #define dispatch_atomic_inc(p, m) \
316 dispatch_atomic_add((p), 1, m)
317 #define dispatch_atomic_inc_orig(p, m) \
318 dispatch_atomic_add_orig((p), 1, m)
319 #define dispatch_atomic_inc2o(p, f, m) \
320 dispatch_atomic_add2o(p, f, 1, m)
321 #define dispatch_atomic_inc_orig2o(p, f, m) \
322 dispatch_atomic_add_orig2o(p, f, 1, m)
323 #define dispatch_atomic_dec(p, m) \
324 dispatch_atomic_sub((p), 1, m)
325 #define dispatch_atomic_dec_orig(p, m) \
326 dispatch_atomic_sub_orig((p), 1, m)
327 #define dispatch_atomic_dec2o(p, f, m) \
328 dispatch_atomic_sub2o(p, f, 1, m)
329 #define dispatch_atomic_dec_orig2o(p, f, m) \
330 dispatch_atomic_sub_orig2o(p, f, 1, m)
331
332 #define dispatch_atomic_tsx_xacq_cmpxchgv(p, e, v, g) \
333 dispatch_atomic_cmpxchgv((p), (e), (v), (g), acquire)
334 #define dispatch_atomic_tsx_xrel_store(p, v) \
335 dispatch_atomic_store(p, v, release)
336 #define dispatch_atomic_tsx_xacq_cmpxchgv2o(p, f, e, v, g) \
337 dispatch_atomic_tsx_xacq_cmpxchgv(&(p)->f, (e), (v), (g))
338 #define dispatch_atomic_tsx_xrel_store2o(p, f, v) \
339 dispatch_atomic_tsx_xrel_store(&(p)->f, (v))
340
341 #if defined(__x86_64__) || defined(__i386__)
342 #pragma mark -
343 #pragma mark x86
344
345 #undef dispatch_hardware_pause
346 #define dispatch_hardware_pause() ({ __asm__("pause"); })
347
348 #undef dispatch_atomic_maximally_synchronizing_barrier
349 #ifdef __LP64__
350 #define dispatch_atomic_maximally_synchronizing_barrier() \
351 ({ unsigned long _clbr; __asm__ __volatile__( \
352 "cpuid" \
353 : "=a" (_clbr) : "0" (0) : "rbx", "rcx", "rdx", "cc", "memory"); })
354 #else
355 #ifdef __llvm__
356 #define dispatch_atomic_maximally_synchronizing_barrier() \
357 ({ unsigned long _clbr; __asm__ __volatile__( \
358 "cpuid" \
359 : "=a" (_clbr) : "0" (0) : "ebx", "ecx", "edx", "cc", "memory"); })
360 #else // gcc does not allow inline i386 asm to clobber ebx
361 #define dispatch_atomic_maximally_synchronizing_barrier() \
362 ({ unsigned long _clbr; __asm__ __volatile__( \
363 "pushl %%ebx\n\t" \
364 "cpuid\n\t" \
365 "popl %%ebx" \
366 : "=a" (_clbr) : "0" (0) : "ecx", "edx", "cc", "memory"); })
367 #endif
368 #endif
369
370
371 #endif
372
373
374 #endif // __DISPATCH_SHIMS_ATOMIC__