1 //===-- tsan_interface_atomic.cc ------------------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file is a part of ThreadSanitizer (TSan), a race detector. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "sanitizer_common/sanitizer_placement_new.h" 15 #include "tsan_interface_atomic.h" 16 #include "tsan_flags.h" 17 #include "tsan_rtl.h" 18 19 using namespace __tsan; // NOLINT 20 21 class ScopedAtomic { 22 public: 23 ScopedAtomic(ThreadState *thr, uptr pc, const char *func) 24 : thr_(thr) { 25 CHECK_EQ(thr_->in_rtl, 1); // 1 due to our own ScopedInRtl member. 26 DPrintf("#%d: %s\n", thr_->tid, func); 27 } 28 ~ScopedAtomic() { 29 CHECK_EQ(thr_->in_rtl, 1); 30 } 31 private: 32 ThreadState *thr_; 33 ScopedInRtl in_rtl_; 34 }; 35 36 // Some shortcuts. 37 typedef __tsan_memory_order morder; 38 typedef __tsan_atomic8 a8; 39 typedef __tsan_atomic16 a16; 40 typedef __tsan_atomic32 a32; 41 typedef __tsan_atomic64 a64; 42 const int mo_relaxed = __tsan_memory_order_relaxed; 43 const int mo_consume = __tsan_memory_order_consume; 44 const int mo_acquire = __tsan_memory_order_acquire; 45 const int mo_release = __tsan_memory_order_release; 46 const int mo_acq_rel = __tsan_memory_order_acq_rel; 47 const int mo_seq_cst = __tsan_memory_order_seq_cst; 48 49 static void AtomicStatInc(ThreadState *thr, uptr size, morder mo, StatType t) { 50 StatInc(thr, StatAtomic); 51 StatInc(thr, t); 52 StatInc(thr, size == 1 ? StatAtomic1 53 : size == 2 ? StatAtomic2 54 : size == 4 ? StatAtomic4 55 : StatAtomic8); 56 StatInc(thr, mo == mo_relaxed ? StatAtomicRelaxed 57 : mo == mo_consume ? StatAtomicConsume 58 : mo == mo_acquire ? StatAtomicAcquire 59 : mo == mo_release ? StatAtomicRelease 60 : mo == mo_acq_rel ? StatAtomicAcq_Rel 61 : StatAtomicSeq_Cst); 62 } 63 64 #define SCOPED_ATOMIC(func, ...) \ 65 mo = flags()->force_seq_cst_atomics ? (morder)mo_seq_cst : mo; \ 66 ThreadState *const thr = cur_thread(); \ 67 const uptr pc = (uptr)__builtin_return_address(0); \ 68 AtomicStatInc(thr, sizeof(*a), mo, StatAtomic##func); \ 69 ScopedAtomic sa(thr, pc, __FUNCTION__); \ 70 return Atomic##func(thr, pc, __VA_ARGS__); \ 71 /**/ 72 73 template<typename T> 74 static T AtomicLoad(ThreadState *thr, uptr pc, const volatile T *a, 75 morder mo) { 76 CHECK(mo & (mo_relaxed | mo_consume | mo_acquire | mo_seq_cst)); 77 T v = *a; 78 if (mo & (mo_consume | mo_acquire | mo_seq_cst)) 79 Acquire(thr, pc, (uptr)a); 80 return v; 81 } 82 83 template<typename T> 84 static void AtomicStore(ThreadState *thr, uptr pc, volatile T *a, T v, 85 morder mo) { 86 CHECK(mo & (mo_relaxed | mo_release | mo_seq_cst)); 87 if (mo & (mo_release | mo_seq_cst)) 88 ReleaseStore(thr, pc, (uptr)a); 89 *a = v; 90 } 91 92 template<typename T> 93 static T AtomicExchange(ThreadState *thr, uptr pc, volatile T *a, T v, 94 morder mo) { 95 if (mo & (mo_release | mo_acq_rel | mo_seq_cst)) 96 Release(thr, pc, (uptr)a); 97 v = __sync_lock_test_and_set(a, v); 98 if (mo & (mo_consume | mo_acquire | mo_acq_rel | mo_seq_cst)) 99 Acquire(thr, pc, (uptr)a); 100 return v; 101 } 102 103 template<typename T> 104 static T AtomicFetchAdd(ThreadState *thr, uptr pc, volatile T *a, T v, 105 morder mo) { 106 if (mo & (mo_release | mo_acq_rel | mo_seq_cst)) 107 Release(thr, pc, (uptr)a); 108 v = __sync_fetch_and_add(a, v); 109 if (mo & (mo_consume | mo_acquire | mo_acq_rel | mo_seq_cst)) 110 Acquire(thr, pc, (uptr)a); 111 return v; 112 } 113 114 template<typename T> 115 static T AtomicFetchAnd(ThreadState *thr, uptr pc, volatile T *a, T v, 116 morder mo) { 117 if (mo & (mo_release | mo_acq_rel | mo_seq_cst)) 118 Release(thr, pc, (uptr)a); 119 v = __sync_fetch_and_and(a, v); 120 if (mo & (mo_consume | mo_acquire | mo_acq_rel | mo_seq_cst)) 121 Acquire(thr, pc, (uptr)a); 122 return v; 123 } 124 125 template<typename T> 126 static T AtomicFetchOr(ThreadState *thr, uptr pc, volatile T *a, T v, 127 morder mo) { 128 if (mo & (mo_release | mo_acq_rel | mo_seq_cst)) 129 Release(thr, pc, (uptr)a); 130 v = __sync_fetch_and_or(a, v); 131 if (mo & (mo_consume | mo_acquire | mo_acq_rel | mo_seq_cst)) 132 Acquire(thr, pc, (uptr)a); 133 return v; 134 } 135 136 template<typename T> 137 static T AtomicFetchXor(ThreadState *thr, uptr pc, volatile T *a, T v, 138 morder mo) { 139 if (mo & (mo_release | mo_acq_rel | mo_seq_cst)) 140 Release(thr, pc, (uptr)a); 141 v = __sync_fetch_and_xor(a, v); 142 if (mo & (mo_consume | mo_acquire | mo_acq_rel | mo_seq_cst)) 143 Acquire(thr, pc, (uptr)a); 144 return v; 145 } 146 147 template<typename T> 148 static bool AtomicCAS(ThreadState *thr, uptr pc, 149 volatile T *a, T *c, T v, morder mo) { 150 if (mo & (mo_release | mo_acq_rel | mo_seq_cst)) 151 Release(thr, pc, (uptr)a); 152 T cc = *c; 153 T pr = __sync_val_compare_and_swap(a, cc, v); 154 if (mo & (mo_consume | mo_acquire | mo_acq_rel | mo_seq_cst)) 155 Acquire(thr, pc, (uptr)a); 156 if (pr == cc) 157 return true; 158 *c = pr; 159 return false; 160 } 161 162 static void AtomicFence(ThreadState *thr, uptr pc, morder mo) { 163 __sync_synchronize(); 164 } 165 166 a8 __tsan_atomic8_load(const volatile a8 *a, morder mo) { 167 SCOPED_ATOMIC(Load, a, mo); 168 } 169 170 a16 __tsan_atomic16_load(const volatile a16 *a, morder mo) { 171 SCOPED_ATOMIC(Load, a, mo); 172 } 173 174 a32 __tsan_atomic32_load(const volatile a32 *a, morder mo) { 175 SCOPED_ATOMIC(Load, a, mo); 176 } 177 178 a64 __tsan_atomic64_load(const volatile a64 *a, morder mo) { 179 SCOPED_ATOMIC(Load, a, mo); 180 } 181 182 void __tsan_atomic8_store(volatile a8 *a, a8 v, morder mo) { 183 SCOPED_ATOMIC(Store, a, v, mo); 184 } 185 186 void __tsan_atomic16_store(volatile a16 *a, a16 v, morder mo) { 187 SCOPED_ATOMIC(Store, a, v, mo); 188 } 189 190 void __tsan_atomic32_store(volatile a32 *a, a32 v, morder mo) { 191 SCOPED_ATOMIC(Store, a, v, mo); 192 } 193 194 void __tsan_atomic64_store(volatile a64 *a, a64 v, morder mo) { 195 SCOPED_ATOMIC(Store, a, v, mo); 196 } 197 198 a8 __tsan_atomic8_exchange(volatile a8 *a, a8 v, morder mo) { 199 SCOPED_ATOMIC(Exchange, a, v, mo); 200 } 201 202 a16 __tsan_atomic16_exchange(volatile a16 *a, a16 v, morder mo) { 203 SCOPED_ATOMIC(Exchange, a, v, mo); 204 } 205 206 a32 __tsan_atomic32_exchange(volatile a32 *a, a32 v, morder mo) { 207 SCOPED_ATOMIC(Exchange, a, v, mo); 208 } 209 210 a64 __tsan_atomic64_exchange(volatile a64 *a, a64 v, morder mo) { 211 SCOPED_ATOMIC(Exchange, a, v, mo); 212 } 213 214 a8 __tsan_atomic8_fetch_add(volatile a8 *a, a8 v, morder mo) { 215 SCOPED_ATOMIC(FetchAdd, a, v, mo); 216 } 217 218 a16 __tsan_atomic16_fetch_add(volatile a16 *a, a16 v, morder mo) { 219 SCOPED_ATOMIC(FetchAdd, a, v, mo); 220 } 221 222 a32 __tsan_atomic32_fetch_add(volatile a32 *a, a32 v, morder mo) { 223 SCOPED_ATOMIC(FetchAdd, a, v, mo); 224 } 225 226 a64 __tsan_atomic64_fetch_add(volatile a64 *a, a64 v, morder mo) { 227 SCOPED_ATOMIC(FetchAdd, a, v, mo); 228 } 229 230 a8 __tsan_atomic8_fetch_and(volatile a8 *a, a8 v, morder mo) { 231 SCOPED_ATOMIC(FetchAnd, a, v, mo); 232 } 233 234 a16 __tsan_atomic16_fetch_and(volatile a16 *a, a16 v, morder mo) { 235 SCOPED_ATOMIC(FetchAnd, a, v, mo); 236 } 237 238 a32 __tsan_atomic32_fetch_and(volatile a32 *a, a32 v, morder mo) { 239 SCOPED_ATOMIC(FetchAnd, a, v, mo); 240 } 241 242 a64 __tsan_atomic64_fetch_and(volatile a64 *a, a64 v, morder mo) { 243 SCOPED_ATOMIC(FetchAnd, a, v, mo); 244 } 245 246 a8 __tsan_atomic8_fetch_or(volatile a8 *a, a8 v, morder mo) { 247 SCOPED_ATOMIC(FetchOr, a, v, mo); 248 } 249 250 a16 __tsan_atomic16_fetch_or(volatile a16 *a, a16 v, morder mo) { 251 SCOPED_ATOMIC(FetchOr, a, v, mo); 252 } 253 254 a32 __tsan_atomic32_fetch_or(volatile a32 *a, a32 v, morder mo) { 255 SCOPED_ATOMIC(FetchOr, a, v, mo); 256 } 257 258 a64 __tsan_atomic64_fetch_or(volatile a64 *a, a64 v, morder mo) { 259 SCOPED_ATOMIC(FetchOr, a, v, mo); 260 } 261 262 a8 __tsan_atomic8_fetch_xor(volatile a8 *a, a8 v, morder mo) { 263 SCOPED_ATOMIC(FetchXor, a, v, mo); 264 } 265 266 a16 __tsan_atomic16_fetch_xor(volatile a16 *a, a16 v, morder mo) { 267 SCOPED_ATOMIC(FetchXor, a, v, mo); 268 } 269 270 a32 __tsan_atomic32_fetch_xor(volatile a32 *a, a32 v, morder mo) { 271 SCOPED_ATOMIC(FetchXor, a, v, mo); 272 } 273 274 a64 __tsan_atomic64_fetch_xor(volatile a64 *a, a64 v, morder mo) { 275 SCOPED_ATOMIC(FetchXor, a, v, mo); 276 } 277 278 int __tsan_atomic8_compare_exchange_strong(volatile a8 *a, a8 *c, a8 v, 279 morder mo) { 280 SCOPED_ATOMIC(CAS, a, c, v, mo); 281 } 282 283 int __tsan_atomic16_compare_exchange_strong(volatile a16 *a, a16 *c, a16 v, 284 morder mo) { 285 SCOPED_ATOMIC(CAS, a, c, v, mo); 286 } 287 288 int __tsan_atomic32_compare_exchange_strong(volatile a32 *a, a32 *c, a32 v, 289 morder mo) { 290 SCOPED_ATOMIC(CAS, a, c, v, mo); 291 } 292 293 int __tsan_atomic64_compare_exchange_strong(volatile a64 *a, a64 *c, a64 v, 294 morder mo) { 295 SCOPED_ATOMIC(CAS, a, c, v, mo); 296 } 297 298 int __tsan_atomic8_compare_exchange_weak(volatile a8 *a, a8 *c, a8 v, 299 morder mo) { 300 SCOPED_ATOMIC(CAS, a, c, v, mo); 301 } 302 303 int __tsan_atomic16_compare_exchange_weak(volatile a16 *a, a16 *c, a16 v, 304 morder mo) { 305 SCOPED_ATOMIC(CAS, a, c, v, mo); 306 } 307 308 int __tsan_atomic32_compare_exchange_weak(volatile a32 *a, a32 *c, a32 v, 309 morder mo) { 310 SCOPED_ATOMIC(CAS, a, c, v, mo); 311 } 312 313 int __tsan_atomic64_compare_exchange_weak(volatile a64 *a, a64 *c, a64 v, 314 morder mo) { 315 SCOPED_ATOMIC(CAS, a, c, v, mo); 316 } 317 318 void __tsan_atomic_thread_fence(morder mo) { 319 char* a; 320 SCOPED_ATOMIC(Fence, mo); 321 } 322