• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef Py_ATOMIC_H
2 #define Py_ATOMIC_H
3 #ifdef Py_BUILD_CORE
4 
5 #include "dynamic_annotations.h"
6 
7 #include "pyconfig.h"
8 
9 #if defined(HAVE_STD_ATOMIC)
10 #include <stdatomic.h>
11 #endif
12 
13 /* This is modeled after the atomics interface from C1x, according to
14  * the draft at
15  * http://www.open-std.org/JTC1/SC22/wg14/www/docs/n1425.pdf.
16  * Operations and types are named the same except with a _Py_ prefix
17  * and have the same semantics.
18  *
19  * Beware, the implementations here are deep magic.
20  */
21 
22 #if defined(HAVE_STD_ATOMIC)
23 
24 typedef enum _Py_memory_order {
25     _Py_memory_order_relaxed = memory_order_relaxed,
26     _Py_memory_order_acquire = memory_order_acquire,
27     _Py_memory_order_release = memory_order_release,
28     _Py_memory_order_acq_rel = memory_order_acq_rel,
29     _Py_memory_order_seq_cst = memory_order_seq_cst
30 } _Py_memory_order;
31 
32 typedef struct _Py_atomic_address {
33     atomic_uintptr_t _value;
34 } _Py_atomic_address;
35 
36 typedef struct _Py_atomic_int {
37     atomic_int _value;
38 } _Py_atomic_int;
39 
40 #define _Py_atomic_signal_fence(/*memory_order*/ ORDER) \
41     atomic_signal_fence(ORDER)
42 
43 #define _Py_atomic_thread_fence(/*memory_order*/ ORDER) \
44     atomic_thread_fence(ORDER)
45 
46 #define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \
47     atomic_store_explicit(&(ATOMIC_VAL)->_value, NEW_VAL, ORDER)
48 
49 #define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \
50     atomic_load_explicit(&(ATOMIC_VAL)->_value, ORDER)
51 
52 /* Use builtin atomic operations in GCC >= 4.7 */
53 #elif defined(HAVE_BUILTIN_ATOMIC)
54 
55 typedef enum _Py_memory_order {
56     _Py_memory_order_relaxed = __ATOMIC_RELAXED,
57     _Py_memory_order_acquire = __ATOMIC_ACQUIRE,
58     _Py_memory_order_release = __ATOMIC_RELEASE,
59     _Py_memory_order_acq_rel = __ATOMIC_ACQ_REL,
60     _Py_memory_order_seq_cst = __ATOMIC_SEQ_CST
61 } _Py_memory_order;
62 
63 typedef struct _Py_atomic_address {
64     uintptr_t _value;
65 } _Py_atomic_address;
66 
67 typedef struct _Py_atomic_int {
68     int _value;
69 } _Py_atomic_int;
70 
71 #define _Py_atomic_signal_fence(/*memory_order*/ ORDER) \
72     __atomic_signal_fence(ORDER)
73 
74 #define _Py_atomic_thread_fence(/*memory_order*/ ORDER) \
75     __atomic_thread_fence(ORDER)
76 
77 #define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \
78     (assert((ORDER) == __ATOMIC_RELAXED                       \
79             || (ORDER) == __ATOMIC_SEQ_CST                    \
80             || (ORDER) == __ATOMIC_RELEASE),                  \
81      __atomic_store_n(&(ATOMIC_VAL)->_value, NEW_VAL, ORDER))
82 
83 #define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER)           \
84     (assert((ORDER) == __ATOMIC_RELAXED                       \
85             || (ORDER) == __ATOMIC_SEQ_CST                    \
86             || (ORDER) == __ATOMIC_ACQUIRE                    \
87             || (ORDER) == __ATOMIC_CONSUME),                  \
88      __atomic_load_n(&(ATOMIC_VAL)->_value, ORDER))
89 
90 #else
91 
92 typedef enum _Py_memory_order {
93     _Py_memory_order_relaxed,
94     _Py_memory_order_acquire,
95     _Py_memory_order_release,
96     _Py_memory_order_acq_rel,
97     _Py_memory_order_seq_cst
98 } _Py_memory_order;
99 
100 typedef struct _Py_atomic_address {
101     uintptr_t _value;
102 } _Py_atomic_address;
103 
104 typedef struct _Py_atomic_int {
105     int _value;
106 } _Py_atomic_int;
107 
108 /* Only support GCC (for expression statements) and x86 (for simple
109  * atomic semantics) for now */
110 #if defined(__GNUC__) && (defined(__i386__) || defined(__amd64))
111 
112 static __inline__ void
_Py_atomic_signal_fence(_Py_memory_order order)113 _Py_atomic_signal_fence(_Py_memory_order order)
114 {
115     if (order != _Py_memory_order_relaxed)
116         __asm__ volatile("":::"memory");
117 }
118 
119 static __inline__ void
_Py_atomic_thread_fence(_Py_memory_order order)120 _Py_atomic_thread_fence(_Py_memory_order order)
121 {
122     if (order != _Py_memory_order_relaxed)
123         __asm__ volatile("mfence":::"memory");
124 }
125 
126 /* Tell the race checker about this operation's effects. */
127 static __inline__ void
_Py_ANNOTATE_MEMORY_ORDER(const volatile void * address,_Py_memory_order order)128 _Py_ANNOTATE_MEMORY_ORDER(const volatile void *address, _Py_memory_order order)
129 {
130     (void)address;		/* shut up -Wunused-parameter */
131     switch(order) {
132     case _Py_memory_order_release:
133     case _Py_memory_order_acq_rel:
134     case _Py_memory_order_seq_cst:
135         _Py_ANNOTATE_HAPPENS_BEFORE(address);
136         break;
137     case _Py_memory_order_relaxed:
138     case _Py_memory_order_acquire:
139         break;
140     }
141     switch(order) {
142     case _Py_memory_order_acquire:
143     case _Py_memory_order_acq_rel:
144     case _Py_memory_order_seq_cst:
145         _Py_ANNOTATE_HAPPENS_AFTER(address);
146         break;
147     case _Py_memory_order_relaxed:
148     case _Py_memory_order_release:
149         break;
150     }
151 }
152 
153 #define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \
154     __extension__ ({ \
155         __typeof__(ATOMIC_VAL) atomic_val = ATOMIC_VAL; \
156         __typeof__(atomic_val->_value) new_val = NEW_VAL;\
157         volatile __typeof__(new_val) *volatile_data = &atomic_val->_value; \
158         _Py_memory_order order = ORDER; \
159         _Py_ANNOTATE_MEMORY_ORDER(atomic_val, order); \
160         \
161         /* Perform the operation. */ \
162         _Py_ANNOTATE_IGNORE_WRITES_BEGIN(); \
163         switch(order) { \
164         case _Py_memory_order_release: \
165             _Py_atomic_signal_fence(_Py_memory_order_release); \
166             /* fallthrough */ \
167         case _Py_memory_order_relaxed: \
168             *volatile_data = new_val; \
169             break; \
170         \
171         case _Py_memory_order_acquire: \
172         case _Py_memory_order_acq_rel: \
173         case _Py_memory_order_seq_cst: \
174             __asm__ volatile("xchg %0, %1" \
175                          : "+r"(new_val) \
176                          : "m"(atomic_val->_value) \
177                          : "memory"); \
178             break; \
179         } \
180         _Py_ANNOTATE_IGNORE_WRITES_END(); \
181     })
182 
183 #define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \
184     __extension__ ({  \
185         __typeof__(ATOMIC_VAL) atomic_val = ATOMIC_VAL; \
186         __typeof__(atomic_val->_value) result; \
187         volatile __typeof__(result) *volatile_data = &atomic_val->_value; \
188         _Py_memory_order order = ORDER; \
189         _Py_ANNOTATE_MEMORY_ORDER(atomic_val, order); \
190         \
191         /* Perform the operation. */ \
192         _Py_ANNOTATE_IGNORE_READS_BEGIN(); \
193         switch(order) { \
194         case _Py_memory_order_release: \
195         case _Py_memory_order_acq_rel: \
196         case _Py_memory_order_seq_cst: \
197             /* Loads on x86 are not releases by default, so need a */ \
198             /* thread fence. */ \
199             _Py_atomic_thread_fence(_Py_memory_order_release); \
200             break; \
201         default: \
202             /* No fence */ \
203             break; \
204         } \
205         result = *volatile_data; \
206         switch(order) { \
207         case _Py_memory_order_acquire: \
208         case _Py_memory_order_acq_rel: \
209         case _Py_memory_order_seq_cst: \
210             /* Loads on x86 are automatically acquire operations so */ \
211             /* can get by with just a compiler fence. */ \
212             _Py_atomic_signal_fence(_Py_memory_order_acquire); \
213             break; \
214         default: \
215             /* No fence */ \
216             break; \
217         } \
218         _Py_ANNOTATE_IGNORE_READS_END(); \
219         result; \
220     })
221 
222 #else  /* !gcc x86 */
223 /* Fall back to other compilers and processors by assuming that simple
224    volatile accesses are atomic.  This is false, so people should port
225    this. */
226 #define _Py_atomic_signal_fence(/*memory_order*/ ORDER) ((void)0)
227 #define _Py_atomic_thread_fence(/*memory_order*/ ORDER) ((void)0)
228 #define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \
229     ((ATOMIC_VAL)->_value = NEW_VAL)
230 #define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \
231     ((ATOMIC_VAL)->_value)
232 
233 #endif  /* !gcc x86 */
234 #endif
235 
236 /* Standardized shortcuts. */
237 #define _Py_atomic_store(ATOMIC_VAL, NEW_VAL) \
238     _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, _Py_memory_order_seq_cst)
239 #define _Py_atomic_load(ATOMIC_VAL) \
240     _Py_atomic_load_explicit(ATOMIC_VAL, _Py_memory_order_seq_cst)
241 
242 /* Python-local extensions */
243 
244 #define _Py_atomic_store_relaxed(ATOMIC_VAL, NEW_VAL) \
245     _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, _Py_memory_order_relaxed)
246 #define _Py_atomic_load_relaxed(ATOMIC_VAL) \
247     _Py_atomic_load_explicit(ATOMIC_VAL, _Py_memory_order_relaxed)
248 
249 #endif  /* Py_BUILD_CORE */
250 #endif  /* Py_ATOMIC_H */
251