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 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 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 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