blob: 9a497a683688a9e1349078e646c848bb47b65149 [file] [log] [blame]
Jeffrey Yasskin39370832010-05-03 19:29:34 +00001#ifndef Py_ATOMIC_H
2#define Py_ATOMIC_H
Victor Stinner6df29ad2015-09-18 15:06:34 +02003#ifdef Py_BUILD_CORE
Jeffrey Yasskin39370832010-05-03 19:29:34 +00004
5#include "dynamic_annotations.h"
6
Victor Stinner4f5366e2015-01-09 02:13:19 +01007#include "pyconfig.h"
8
Victor Stinner3b6d0ae2015-03-12 16:04:41 +01009#if defined(HAVE_STD_ATOMIC)
10#include <stdatomic.h>
11#endif
12
Pär Björklunde664d7f2017-08-12 11:19:30 +020013
Serhiy Storchaka13ad3b72017-09-14 09:38:36 +030014#if defined(_MSC_VER)
Pär Björklunde664d7f2017-08-12 11:19:30 +020015#include <intrin.h>
16#include <immintrin.h>
17#endif
18
Jeffrey Yasskin39370832010-05-03 19:29:34 +000019/* This is modeled after the atomics interface from C1x, according to
20 * the draft at
21 * http://www.open-std.org/JTC1/SC22/wg14/www/docs/n1425.pdf.
22 * Operations and types are named the same except with a _Py_ prefix
23 * and have the same semantics.
24 *
25 * Beware, the implementations here are deep magic.
26 */
27
Victor Stinner4f5366e2015-01-09 02:13:19 +010028#if defined(HAVE_STD_ATOMIC)
29
30typedef enum _Py_memory_order {
31 _Py_memory_order_relaxed = memory_order_relaxed,
32 _Py_memory_order_acquire = memory_order_acquire,
33 _Py_memory_order_release = memory_order_release,
34 _Py_memory_order_acq_rel = memory_order_acq_rel,
35 _Py_memory_order_seq_cst = memory_order_seq_cst
36} _Py_memory_order;
37
38typedef struct _Py_atomic_address {
Victor Stinnerb02ef712016-01-22 14:09:55 +010039 atomic_uintptr_t _value;
Victor Stinner4f5366e2015-01-09 02:13:19 +010040} _Py_atomic_address;
41
42typedef struct _Py_atomic_int {
43 atomic_int _value;
44} _Py_atomic_int;
45
46#define _Py_atomic_signal_fence(/*memory_order*/ ORDER) \
47 atomic_signal_fence(ORDER)
48
49#define _Py_atomic_thread_fence(/*memory_order*/ ORDER) \
50 atomic_thread_fence(ORDER)
51
52#define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \
53 atomic_store_explicit(&(ATOMIC_VAL)->_value, NEW_VAL, ORDER)
54
55#define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \
56 atomic_load_explicit(&(ATOMIC_VAL)->_value, ORDER)
57
58/* Use builtin atomic operations in GCC >= 4.7 */
59#elif defined(HAVE_BUILTIN_ATOMIC)
60
61typedef enum _Py_memory_order {
62 _Py_memory_order_relaxed = __ATOMIC_RELAXED,
63 _Py_memory_order_acquire = __ATOMIC_ACQUIRE,
64 _Py_memory_order_release = __ATOMIC_RELEASE,
65 _Py_memory_order_acq_rel = __ATOMIC_ACQ_REL,
66 _Py_memory_order_seq_cst = __ATOMIC_SEQ_CST
67} _Py_memory_order;
68
69typedef struct _Py_atomic_address {
Benjamin Petersonca470632016-09-06 13:47:26 -070070 uintptr_t _value;
Victor Stinner4f5366e2015-01-09 02:13:19 +010071} _Py_atomic_address;
72
73typedef struct _Py_atomic_int {
74 int _value;
75} _Py_atomic_int;
76
77#define _Py_atomic_signal_fence(/*memory_order*/ ORDER) \
78 __atomic_signal_fence(ORDER)
79
80#define _Py_atomic_thread_fence(/*memory_order*/ ORDER) \
81 __atomic_thread_fence(ORDER)
82
83#define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \
84 (assert((ORDER) == __ATOMIC_RELAXED \
85 || (ORDER) == __ATOMIC_SEQ_CST \
86 || (ORDER) == __ATOMIC_RELEASE), \
87 __atomic_store_n(&(ATOMIC_VAL)->_value, NEW_VAL, ORDER))
88
89#define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \
90 (assert((ORDER) == __ATOMIC_RELAXED \
91 || (ORDER) == __ATOMIC_SEQ_CST \
92 || (ORDER) == __ATOMIC_ACQUIRE \
93 || (ORDER) == __ATOMIC_CONSUME), \
94 __atomic_load_n(&(ATOMIC_VAL)->_value, ORDER))
95
Pär Björklunde664d7f2017-08-12 11:19:30 +020096/* Only support GCC (for expression statements) and x86 (for simple
97 * atomic semantics) and MSVC x86/x64/ARM */
98#elif defined(__GNUC__) && (defined(__i386__) || defined(__amd64))
Jeffrey Yasskin39370832010-05-03 19:29:34 +000099typedef enum _Py_memory_order {
100 _Py_memory_order_relaxed,
101 _Py_memory_order_acquire,
102 _Py_memory_order_release,
103 _Py_memory_order_acq_rel,
104 _Py_memory_order_seq_cst
105} _Py_memory_order;
106
107typedef struct _Py_atomic_address {
Benjamin Petersonca470632016-09-06 13:47:26 -0700108 uintptr_t _value;
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000109} _Py_atomic_address;
110
111typedef struct _Py_atomic_int {
112 int _value;
113} _Py_atomic_int;
114
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000115
116static __inline__ void
117_Py_atomic_signal_fence(_Py_memory_order order)
118{
119 if (order != _Py_memory_order_relaxed)
120 __asm__ volatile("":::"memory");
121}
122
123static __inline__ void
124_Py_atomic_thread_fence(_Py_memory_order order)
125{
126 if (order != _Py_memory_order_relaxed)
127 __asm__ volatile("mfence":::"memory");
128}
129
130/* Tell the race checker about this operation's effects. */
131static __inline__ void
132_Py_ANNOTATE_MEMORY_ORDER(const volatile void *address, _Py_memory_order order)
133{
Pär Björklunde664d7f2017-08-12 11:19:30 +0200134 (void)address; /* shut up -Wunused-parameter */
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000135 switch(order) {
136 case _Py_memory_order_release:
137 case _Py_memory_order_acq_rel:
138 case _Py_memory_order_seq_cst:
139 _Py_ANNOTATE_HAPPENS_BEFORE(address);
140 break;
Petri Lehtinen8d40f162011-11-19 22:03:10 +0200141 case _Py_memory_order_relaxed:
142 case _Py_memory_order_acquire:
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000143 break;
144 }
145 switch(order) {
146 case _Py_memory_order_acquire:
147 case _Py_memory_order_acq_rel:
148 case _Py_memory_order_seq_cst:
149 _Py_ANNOTATE_HAPPENS_AFTER(address);
150 break;
Petri Lehtinen8d40f162011-11-19 22:03:10 +0200151 case _Py_memory_order_relaxed:
152 case _Py_memory_order_release:
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000153 break;
154 }
155}
156
157#define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \
158 __extension__ ({ \
159 __typeof__(ATOMIC_VAL) atomic_val = ATOMIC_VAL; \
160 __typeof__(atomic_val->_value) new_val = NEW_VAL;\
161 volatile __typeof__(new_val) *volatile_data = &atomic_val->_value; \
162 _Py_memory_order order = ORDER; \
163 _Py_ANNOTATE_MEMORY_ORDER(atomic_val, order); \
164 \
165 /* Perform the operation. */ \
166 _Py_ANNOTATE_IGNORE_WRITES_BEGIN(); \
167 switch(order) { \
168 case _Py_memory_order_release: \
169 _Py_atomic_signal_fence(_Py_memory_order_release); \
170 /* fallthrough */ \
171 case _Py_memory_order_relaxed: \
172 *volatile_data = new_val; \
173 break; \
174 \
175 case _Py_memory_order_acquire: \
176 case _Py_memory_order_acq_rel: \
177 case _Py_memory_order_seq_cst: \
178 __asm__ volatile("xchg %0, %1" \
179 : "+r"(new_val) \
180 : "m"(atomic_val->_value) \
181 : "memory"); \
182 break; \
183 } \
184 _Py_ANNOTATE_IGNORE_WRITES_END(); \
185 })
186
187#define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \
188 __extension__ ({ \
189 __typeof__(ATOMIC_VAL) atomic_val = ATOMIC_VAL; \
190 __typeof__(atomic_val->_value) result; \
191 volatile __typeof__(result) *volatile_data = &atomic_val->_value; \
192 _Py_memory_order order = ORDER; \
193 _Py_ANNOTATE_MEMORY_ORDER(atomic_val, order); \
194 \
195 /* Perform the operation. */ \
196 _Py_ANNOTATE_IGNORE_READS_BEGIN(); \
197 switch(order) { \
198 case _Py_memory_order_release: \
199 case _Py_memory_order_acq_rel: \
200 case _Py_memory_order_seq_cst: \
201 /* Loads on x86 are not releases by default, so need a */ \
202 /* thread fence. */ \
203 _Py_atomic_thread_fence(_Py_memory_order_release); \
204 break; \
205 default: \
206 /* No fence */ \
207 break; \
208 } \
209 result = *volatile_data; \
210 switch(order) { \
211 case _Py_memory_order_acquire: \
212 case _Py_memory_order_acq_rel: \
213 case _Py_memory_order_seq_cst: \
214 /* Loads on x86 are automatically acquire operations so */ \
215 /* can get by with just a compiler fence. */ \
216 _Py_atomic_signal_fence(_Py_memory_order_acquire); \
217 break; \
218 default: \
219 /* No fence */ \
220 break; \
221 } \
222 _Py_ANNOTATE_IGNORE_READS_END(); \
223 result; \
224 })
225
Serhiy Storchaka13ad3b72017-09-14 09:38:36 +0300226#elif defined(_MSC_VER)
Pär Björklunde664d7f2017-08-12 11:19:30 +0200227/* _Interlocked* functions provide a full memory barrier and are therefore
228 enough for acq_rel and seq_cst. If the HLE variants aren't available
229 in hardware they will fall back to a full memory barrier as well.
230
231 This might affect performance but likely only in some very specific and
232 hard to meassure scenario.
233*/
234#if defined(_M_IX86) || defined(_M_X64)
235typedef enum _Py_memory_order {
236 _Py_memory_order_relaxed,
237 _Py_memory_order_acquire,
238 _Py_memory_order_release,
239 _Py_memory_order_acq_rel,
240 _Py_memory_order_seq_cst
241} _Py_memory_order;
242
243typedef struct _Py_atomic_address {
244 volatile uintptr_t _value;
245} _Py_atomic_address;
246
247typedef struct _Py_atomic_int {
248 volatile int _value;
249} _Py_atomic_int;
250
251
Serhiy Storchaka13ad3b72017-09-14 09:38:36 +0300252#if defined(_M_X64)
Pär Björklunde664d7f2017-08-12 11:19:30 +0200253#define _Py_atomic_store_64bit(ATOMIC_VAL, NEW_VAL, ORDER) \
254 switch (ORDER) { \
255 case _Py_memory_order_acquire: \
256 _InterlockedExchange64_HLEAcquire((__int64 volatile*)ATOMIC_VAL, (__int64)NEW_VAL); \
257 break; \
258 case _Py_memory_order_release: \
259 _InterlockedExchange64_HLERelease((__int64 volatile*)ATOMIC_VAL, (__int64)NEW_VAL); \
260 break; \
261 default: \
262 _InterlockedExchange64((__int64 volatile*)ATOMIC_VAL, (__int64)NEW_VAL); \
263 break; \
264 }
265#else
266#define _Py_atomic_store_64bit(ATOMIC_VAL, NEW_VAL, ORDER) ((void)0);
267#endif
268
269#define _Py_atomic_store_32bit(ATOMIC_VAL, NEW_VAL, ORDER) \
270 switch (ORDER) { \
271 case _Py_memory_order_acquire: \
272 _InterlockedExchange_HLEAcquire((volatile long*)ATOMIC_VAL, (int)NEW_VAL); \
273 break; \
274 case _Py_memory_order_release: \
275 _InterlockedExchange_HLERelease((volatile long*)ATOMIC_VAL, (int)NEW_VAL); \
276 break; \
277 default: \
278 _InterlockedExchange((volatile long*)ATOMIC_VAL, (int)NEW_VAL); \
279 break; \
280 }
281
282#if defined(_M_X64)
283/* This has to be an intptr_t for now.
284 gil_created() uses -1 as a sentinel value, if this returns
285 a uintptr_t it will do an unsigned compare and crash
286*/
287inline intptr_t _Py_atomic_load_64bit(volatile uintptr_t* value, int order) {
Steve Dower05f01d82017-09-07 11:49:23 -0700288 __int64 old;
Pär Björklunde664d7f2017-08-12 11:19:30 +0200289 switch (order) {
290 case _Py_memory_order_acquire:
291 {
292 do {
293 old = *value;
Steve Dower05f01d82017-09-07 11:49:23 -0700294 } while(_InterlockedCompareExchange64_HLEAcquire((volatile __int64*)value, old, old) != old);
Pär Björklunde664d7f2017-08-12 11:19:30 +0200295 break;
296 }
297 case _Py_memory_order_release:
298 {
299 do {
300 old = *value;
Steve Dower05f01d82017-09-07 11:49:23 -0700301 } while(_InterlockedCompareExchange64_HLERelease((volatile __int64*)value, old, old) != old);
Pär Björklunde664d7f2017-08-12 11:19:30 +0200302 break;
303 }
304 case _Py_memory_order_relaxed:
305 old = *value;
306 break;
307 default:
308 {
309 do {
310 old = *value;
Steve Dower05f01d82017-09-07 11:49:23 -0700311 } while(_InterlockedCompareExchange64((volatile __int64*)value, old, old) != old);
Pär Björklunde664d7f2017-08-12 11:19:30 +0200312 break;
313 }
314 }
Serhiy Storchaka13ad3b72017-09-14 09:38:36 +0300315 return old;
Pär Björklunde664d7f2017-08-12 11:19:30 +0200316}
317
318#else
319#define _Py_atomic_load_64bit(ATOMIC_VAL, ORDER) *ATOMIC_VAL
320#endif
321
322inline int _Py_atomic_load_32bit(volatile int* value, int order) {
Steve Dower05f01d82017-09-07 11:49:23 -0700323 long old;
Pär Björklunde664d7f2017-08-12 11:19:30 +0200324 switch (order) {
325 case _Py_memory_order_acquire:
326 {
327 do {
328 old = *value;
Steve Dower05f01d82017-09-07 11:49:23 -0700329 } while(_InterlockedCompareExchange_HLEAcquire((volatile long*)value, old, old) != old);
Pär Björklunde664d7f2017-08-12 11:19:30 +0200330 break;
331 }
332 case _Py_memory_order_release:
333 {
334 do {
335 old = *value;
Steve Dower05f01d82017-09-07 11:49:23 -0700336 } while(_InterlockedCompareExchange_HLERelease((volatile long*)value, old, old) != old);
Pär Björklunde664d7f2017-08-12 11:19:30 +0200337 break;
338 }
339 case _Py_memory_order_relaxed:
340 old = *value;
341 break;
342 default:
343 {
344 do {
345 old = *value;
Steve Dower05f01d82017-09-07 11:49:23 -0700346 } while(_InterlockedCompareExchange((volatile long*)value, old, old) != old);
Pär Björklunde664d7f2017-08-12 11:19:30 +0200347 break;
348 }
349 }
Serhiy Storchaka13ad3b72017-09-14 09:38:36 +0300350 return old;
Pär Björklunde664d7f2017-08-12 11:19:30 +0200351}
352
353#define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \
354 if (sizeof(*ATOMIC_VAL._value) == 8) { \
Segev Finer02671282017-08-21 01:45:46 +0300355 _Py_atomic_store_64bit((volatile long long*)ATOMIC_VAL._value, NEW_VAL, ORDER) } else { \
356 _Py_atomic_store_32bit((volatile long*)ATOMIC_VAL._value, NEW_VAL, ORDER) }
Pär Björklunde664d7f2017-08-12 11:19:30 +0200357
358#define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \
359 ( \
360 sizeof(*(ATOMIC_VAL._value)) == 8 ? \
Segev Finer02671282017-08-21 01:45:46 +0300361 _Py_atomic_load_64bit((volatile long long*)ATOMIC_VAL._value, ORDER) : \
362 _Py_atomic_load_32bit((volatile long*)ATOMIC_VAL._value, ORDER) \
Pär Björklunde664d7f2017-08-12 11:19:30 +0200363 )
364#elif defined(_M_ARM) || defined(_M_ARM64)
365typedef enum _Py_memory_order {
366 _Py_memory_order_relaxed,
367 _Py_memory_order_acquire,
368 _Py_memory_order_release,
369 _Py_memory_order_acq_rel,
370 _Py_memory_order_seq_cst
371} _Py_memory_order;
372
373typedef struct _Py_atomic_address {
374 volatile uintptr_t _value;
375} _Py_atomic_address;
376
377typedef struct _Py_atomic_int {
378 volatile int _value;
379} _Py_atomic_int;
380
381
Serhiy Storchaka13ad3b72017-09-14 09:38:36 +0300382#if defined(_M_ARM64)
Pär Björklunde664d7f2017-08-12 11:19:30 +0200383#define _Py_atomic_store_64bit(ATOMIC_VAL, NEW_VAL, ORDER) \
384 switch (ORDER) { \
385 case _Py_memory_order_acquire: \
386 _InterlockedExchange64_acq((__int64 volatile*)ATOMIC_VAL, (__int64)NEW_VAL); \
387 break; \
388 case _Py_memory_order_release: \
389 _InterlockedExchange64_rel((__int64 volatile*)ATOMIC_VAL, (__int64)NEW_VAL); \
390 break; \
391 default: \
392 _InterlockedExchange64((__int64 volatile*)ATOMIC_VAL, (__int64)NEW_VAL); \
393 break; \
394 }
395#else
396#define _Py_atomic_store_64bit(ATOMIC_VAL, NEW_VAL, ORDER) ((void)0);
397#endif
398
399#define _Py_atomic_store_32bit(ATOMIC_VAL, NEW_VAL, ORDER) \
400 switch (ORDER) { \
401 case _Py_memory_order_acquire: \
402 _InterlockedExchange_acq((volatile long*)ATOMIC_VAL, (int)NEW_VAL); \
403 break; \
404 case _Py_memory_order_release: \
405 _InterlockedExchange_rel((volatile long*)ATOMIC_VAL, (int)NEW_VAL); \
406 break; \
407 default: \
408 _InterlockedExchange((volatile long*)ATOMIC_VAL, (int)NEW_VAL); \
409 break; \
410 }
411
412#if defined(_M_ARM64)
413/* This has to be an intptr_t for now.
414 gil_created() uses -1 as a sentinel value, if this returns
415 a uintptr_t it will do an unsigned compare and crash
416*/
417inline intptr_t _Py_atomic_load_64bit(volatile uintptr_t* value, int order) {
418 uintptr_t old;
419 switch (order) {
420 case _Py_memory_order_acquire:
421 {
422 do {
423 old = *value;
424 } while(_InterlockedCompareExchange64_acq(value, old, old) != old);
425 break;
426 }
427 case _Py_memory_order_release:
428 {
429 do {
430 old = *value;
431 } while(_InterlockedCompareExchange64_rel(value, old, old) != old);
432 break;
433 }
434 case _Py_memory_order_relaxed:
435 old = *value;
436 break;
437 default:
438 {
439 do {
440 old = *value;
441 } while(_InterlockedCompareExchange64(value, old, old) != old);
442 break;
443 }
444 }
Serhiy Storchaka13ad3b72017-09-14 09:38:36 +0300445 return old;
Pär Björklunde664d7f2017-08-12 11:19:30 +0200446}
447
448#else
449#define _Py_atomic_load_64bit(ATOMIC_VAL, ORDER) *ATOMIC_VAL
450#endif
451
452inline int _Py_atomic_load_32bit(volatile int* value, int order) {
453 int old;
454 switch (order) {
455 case _Py_memory_order_acquire:
456 {
457 do {
458 old = *value;
459 } while(_InterlockedCompareExchange_acq(value, old, old) != old);
460 break;
461 }
462 case _Py_memory_order_release:
463 {
464 do {
465 old = *value;
466 } while(_InterlockedCompareExchange_rel(value, old, old) != old);
467 break;
468 }
469 case _Py_memory_order_relaxed:
470 old = *value;
471 break;
472 default:
473 {
474 do {
475 old = *value;
476 } while(_InterlockedCompareExchange(value, old, old) != old);
477 break;
478 }
479 }
Serhiy Storchaka13ad3b72017-09-14 09:38:36 +0300480 return old;
Pär Björklunde664d7f2017-08-12 11:19:30 +0200481}
482
483#define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \
484 if (sizeof(*ATOMIC_VAL._value) == 8) { \
485 _Py_atomic_store_64bit(ATOMIC_VAL._value, NEW_VAL, ORDER) } else { \
Serhiy Storchaka13ad3b72017-09-14 09:38:36 +0300486 _Py_atomic_store_32bit(ATOMIC_VAL._value, NEW_VAL, ORDER) }
Pär Björklunde664d7f2017-08-12 11:19:30 +0200487
488#define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \
489 ( \
490 sizeof(*(ATOMIC_VAL._value)) == 8 ? \
491 _Py_atomic_load_64bit(ATOMIC_VAL._value, ORDER) : \
492 _Py_atomic_load_32bit(ATOMIC_VAL._value, ORDER) \
493 )
494#endif
495#else /* !gcc x86 !_msc_ver */
496typedef enum _Py_memory_order {
497 _Py_memory_order_relaxed,
498 _Py_memory_order_acquire,
499 _Py_memory_order_release,
500 _Py_memory_order_acq_rel,
501 _Py_memory_order_seq_cst
502} _Py_memory_order;
503
504typedef struct _Py_atomic_address {
505 uintptr_t _value;
506} _Py_atomic_address;
507
508typedef struct _Py_atomic_int {
509 int _value;
510} _Py_atomic_int;
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000511/* Fall back to other compilers and processors by assuming that simple
512 volatile accesses are atomic. This is false, so people should port
513 this. */
514#define _Py_atomic_signal_fence(/*memory_order*/ ORDER) ((void)0)
515#define _Py_atomic_thread_fence(/*memory_order*/ ORDER) ((void)0)
516#define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \
517 ((ATOMIC_VAL)->_value = NEW_VAL)
518#define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \
519 ((ATOMIC_VAL)->_value)
Victor Stinner4f5366e2015-01-09 02:13:19 +0100520#endif
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000521
522/* Standardized shortcuts. */
523#define _Py_atomic_store(ATOMIC_VAL, NEW_VAL) \
524 _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, _Py_memory_order_seq_cst)
525#define _Py_atomic_load(ATOMIC_VAL) \
526 _Py_atomic_load_explicit(ATOMIC_VAL, _Py_memory_order_seq_cst)
527
528/* Python-local extensions */
529
530#define _Py_atomic_store_relaxed(ATOMIC_VAL, NEW_VAL) \
531 _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, _Py_memory_order_relaxed)
532#define _Py_atomic_load_relaxed(ATOMIC_VAL) \
533 _Py_atomic_load_explicit(ATOMIC_VAL, _Py_memory_order_relaxed)
Victor Stinner6df29ad2015-09-18 15:06:34 +0200534#endif /* Py_BUILD_CORE */
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000535#endif /* Py_ATOMIC_H */