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 // ThreadSanitizer atomic operations are based on C++11/C1x standards.
15 // For background see C++11 standard. A slightly older, publicly
16 // available draft of the standard (not entirely up-to-date, but close enough
17 // for casual browsing) is available here:
18 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf
19 // The following page contains more background information:
20 // http://www.hpl.hp.com/personal/Hans_Boehm/c++mm/
21
22 #include "sanitizer_common/sanitizer_placement_new.h"
23 #include "sanitizer_common/sanitizer_stacktrace.h"
24 #include "sanitizer_common/sanitizer_mutex.h"
25 #include "tsan_flags.h"
26 #include "tsan_rtl.h"
27
28 using namespace __tsan; // NOLINT
29
30 #define SCOPED_ATOMIC(func, ...) \
31 const uptr callpc = (uptr)__builtin_return_address(0); \
32 uptr pc = __sanitizer::StackTrace::GetCurrentPc(); \
33 mo = flags()->force_seq_cst_atomics ? (morder)mo_seq_cst : mo; \
34 ThreadState *const thr = cur_thread(); \
35 if (thr->ignore_interceptors) \
36 return NoTsanAtomic##func(__VA_ARGS__); \
37 AtomicStatInc(thr, sizeof(*a), mo, StatAtomic##func); \
38 ScopedAtomic sa(thr, callpc, a, mo, __func__); \
39 return Atomic##func(thr, pc, __VA_ARGS__); \
40 /**/
41
42 // These should match declarations from public tsan_interface_atomic.h header.
43 typedef unsigned char a8;
44 typedef unsigned short a16; // NOLINT
45 typedef unsigned int a32;
46 typedef unsigned long long a64; // NOLINT
47 #if defined(__SIZEOF_INT128__) \
48 || (__clang_major__ * 100 + __clang_minor__ >= 302)
49 __extension__ typedef __int128 a128;
50 # define __TSAN_HAS_INT128 1
51 #else
52 # define __TSAN_HAS_INT128 0
53 #endif
54
55 // Protects emulation of 128-bit atomic operations.
56 static StaticSpinMutex mutex128;
57
58 // Part of ABI, do not change.
59 // http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/atomic?view=markup
60 typedef enum {
61 mo_relaxed,
62 mo_consume,
63 mo_acquire,
64 mo_release,
65 mo_acq_rel,
66 mo_seq_cst
67 } morder;
68
69 class ScopedAtomic {
70 public:
ScopedAtomic(ThreadState * thr,uptr pc,const volatile void * a,morder mo,const char * func)71 ScopedAtomic(ThreadState *thr, uptr pc, const volatile void *a,
72 morder mo, const char *func)
73 : thr_(thr) {
74 FuncEntry(thr_, pc);
75 DPrintf("#%d: %s(%p, %d)\n", thr_->tid, func, a, mo);
76 }
~ScopedAtomic()77 ~ScopedAtomic() {
78 ProcessPendingSignals(thr_);
79 FuncExit(thr_);
80 }
81 private:
82 ThreadState *thr_;
83 };
84
AtomicStatInc(ThreadState * thr,uptr size,morder mo,StatType t)85 static void AtomicStatInc(ThreadState *thr, uptr size, morder mo, StatType t) {
86 StatInc(thr, StatAtomic);
87 StatInc(thr, t);
88 StatInc(thr, size == 1 ? StatAtomic1
89 : size == 2 ? StatAtomic2
90 : size == 4 ? StatAtomic4
91 : size == 8 ? StatAtomic8
92 : StatAtomic16);
93 StatInc(thr, mo == mo_relaxed ? StatAtomicRelaxed
94 : mo == mo_consume ? StatAtomicConsume
95 : mo == mo_acquire ? StatAtomicAcquire
96 : mo == mo_release ? StatAtomicRelease
97 : mo == mo_acq_rel ? StatAtomicAcq_Rel
98 : StatAtomicSeq_Cst);
99 }
100
IsLoadOrder(morder mo)101 static bool IsLoadOrder(morder mo) {
102 return mo == mo_relaxed || mo == mo_consume
103 || mo == mo_acquire || mo == mo_seq_cst;
104 }
105
IsStoreOrder(morder mo)106 static bool IsStoreOrder(morder mo) {
107 return mo == mo_relaxed || mo == mo_release || mo == mo_seq_cst;
108 }
109
IsReleaseOrder(morder mo)110 static bool IsReleaseOrder(morder mo) {
111 return mo == mo_release || mo == mo_acq_rel || mo == mo_seq_cst;
112 }
113
IsAcquireOrder(morder mo)114 static bool IsAcquireOrder(morder mo) {
115 return mo == mo_consume || mo == mo_acquire
116 || mo == mo_acq_rel || mo == mo_seq_cst;
117 }
118
IsAcqRelOrder(morder mo)119 static bool IsAcqRelOrder(morder mo) {
120 return mo == mo_acq_rel || mo == mo_seq_cst;
121 }
122
func_xchg(volatile T * v,T op)123 template<typename T> T func_xchg(volatile T *v, T op) {
124 T res = __sync_lock_test_and_set(v, op);
125 // __sync_lock_test_and_set does not contain full barrier.
126 __sync_synchronize();
127 return res;
128 }
129
func_add(volatile T * v,T op)130 template<typename T> T func_add(volatile T *v, T op) {
131 return __sync_fetch_and_add(v, op);
132 }
133
func_sub(volatile T * v,T op)134 template<typename T> T func_sub(volatile T *v, T op) {
135 return __sync_fetch_and_sub(v, op);
136 }
137
func_and(volatile T * v,T op)138 template<typename T> T func_and(volatile T *v, T op) {
139 return __sync_fetch_and_and(v, op);
140 }
141
func_or(volatile T * v,T op)142 template<typename T> T func_or(volatile T *v, T op) {
143 return __sync_fetch_and_or(v, op);
144 }
145
func_xor(volatile T * v,T op)146 template<typename T> T func_xor(volatile T *v, T op) {
147 return __sync_fetch_and_xor(v, op);
148 }
149
func_nand(volatile T * v,T op)150 template<typename T> T func_nand(volatile T *v, T op) {
151 // clang does not support __sync_fetch_and_nand.
152 T cmp = *v;
153 for (;;) {
154 T newv = ~(cmp & op);
155 T cur = __sync_val_compare_and_swap(v, cmp, newv);
156 if (cmp == cur)
157 return cmp;
158 cmp = cur;
159 }
160 }
161
func_cas(volatile T * v,T cmp,T xch)162 template<typename T> T func_cas(volatile T *v, T cmp, T xch) {
163 return __sync_val_compare_and_swap(v, cmp, xch);
164 }
165
166 // clang does not support 128-bit atomic ops.
167 // Atomic ops are executed under tsan internal mutex,
168 // here we assume that the atomic variables are not accessed
169 // from non-instrumented code.
170 #ifndef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16
func_xchg(volatile a128 * v,a128 op)171 a128 func_xchg(volatile a128 *v, a128 op) {
172 SpinMutexLock lock(&mutex128);
173 a128 cmp = *v;
174 *v = op;
175 return cmp;
176 }
177
func_add(volatile a128 * v,a128 op)178 a128 func_add(volatile a128 *v, a128 op) {
179 SpinMutexLock lock(&mutex128);
180 a128 cmp = *v;
181 *v = cmp + op;
182 return cmp;
183 }
184
func_sub(volatile a128 * v,a128 op)185 a128 func_sub(volatile a128 *v, a128 op) {
186 SpinMutexLock lock(&mutex128);
187 a128 cmp = *v;
188 *v = cmp - op;
189 return cmp;
190 }
191
func_and(volatile a128 * v,a128 op)192 a128 func_and(volatile a128 *v, a128 op) {
193 SpinMutexLock lock(&mutex128);
194 a128 cmp = *v;
195 *v = cmp & op;
196 return cmp;
197 }
198
func_or(volatile a128 * v,a128 op)199 a128 func_or(volatile a128 *v, a128 op) {
200 SpinMutexLock lock(&mutex128);
201 a128 cmp = *v;
202 *v = cmp | op;
203 return cmp;
204 }
205
func_xor(volatile a128 * v,a128 op)206 a128 func_xor(volatile a128 *v, a128 op) {
207 SpinMutexLock lock(&mutex128);
208 a128 cmp = *v;
209 *v = cmp ^ op;
210 return cmp;
211 }
212
func_nand(volatile a128 * v,a128 op)213 a128 func_nand(volatile a128 *v, a128 op) {
214 SpinMutexLock lock(&mutex128);
215 a128 cmp = *v;
216 *v = ~(cmp & op);
217 return cmp;
218 }
219
func_cas(volatile a128 * v,a128 cmp,a128 xch)220 a128 func_cas(volatile a128 *v, a128 cmp, a128 xch) {
221 SpinMutexLock lock(&mutex128);
222 a128 cur = *v;
223 if (cur == cmp)
224 *v = xch;
225 return cur;
226 }
227 #endif
228
229 template<typename T>
SizeLog()230 static int SizeLog() {
231 if (sizeof(T) <= 1)
232 return kSizeLog1;
233 else if (sizeof(T) <= 2)
234 return kSizeLog2;
235 else if (sizeof(T) <= 4)
236 return kSizeLog4;
237 else
238 return kSizeLog8;
239 // For 16-byte atomics we also use 8-byte memory access,
240 // this leads to false negatives only in very obscure cases.
241 }
242
to_atomic(const volatile a8 * a)243 static atomic_uint8_t *to_atomic(const volatile a8 *a) {
244 return (atomic_uint8_t*)a;
245 }
246
to_atomic(const volatile a16 * a)247 static atomic_uint16_t *to_atomic(const volatile a16 *a) {
248 return (atomic_uint16_t*)a;
249 }
250
to_atomic(const volatile a32 * a)251 static atomic_uint32_t *to_atomic(const volatile a32 *a) {
252 return (atomic_uint32_t*)a;
253 }
254
to_atomic(const volatile a64 * a)255 static atomic_uint64_t *to_atomic(const volatile a64 *a) {
256 return (atomic_uint64_t*)a;
257 }
258
to_mo(morder mo)259 static memory_order to_mo(morder mo) {
260 switch (mo) {
261 case mo_relaxed: return memory_order_relaxed;
262 case mo_consume: return memory_order_consume;
263 case mo_acquire: return memory_order_acquire;
264 case mo_release: return memory_order_release;
265 case mo_acq_rel: return memory_order_acq_rel;
266 case mo_seq_cst: return memory_order_seq_cst;
267 }
268 CHECK(0);
269 return memory_order_seq_cst;
270 }
271
272 template<typename T>
NoTsanAtomicLoad(const volatile T * a,morder mo)273 static T NoTsanAtomicLoad(const volatile T *a, morder mo) {
274 return atomic_load(to_atomic(a), to_mo(mo));
275 }
276
277 #if __TSAN_HAS_INT128
NoTsanAtomicLoad(const volatile a128 * a,morder mo)278 static a128 NoTsanAtomicLoad(const volatile a128 *a, morder mo) {
279 SpinMutexLock lock(&mutex128);
280 return *a;
281 }
282 #endif
283
284 template<typename T>
AtomicLoad(ThreadState * thr,uptr pc,const volatile T * a,morder mo)285 static T AtomicLoad(ThreadState *thr, uptr pc, const volatile T *a,
286 morder mo) {
287 CHECK(IsLoadOrder(mo));
288 // This fast-path is critical for performance.
289 // Assume the access is atomic.
290 if (!IsAcquireOrder(mo)) {
291 MemoryReadAtomic(thr, pc, (uptr)a, SizeLog<T>());
292 return NoTsanAtomicLoad(a, mo);
293 }
294 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, (uptr)a, false);
295 AcquireImpl(thr, pc, &s->clock);
296 T v = NoTsanAtomicLoad(a, mo);
297 s->mtx.ReadUnlock();
298 MemoryReadAtomic(thr, pc, (uptr)a, SizeLog<T>());
299 return v;
300 }
301
302 template<typename T>
NoTsanAtomicStore(volatile T * a,T v,morder mo)303 static void NoTsanAtomicStore(volatile T *a, T v, morder mo) {
304 atomic_store(to_atomic(a), v, to_mo(mo));
305 }
306
307 #if __TSAN_HAS_INT128
NoTsanAtomicStore(volatile a128 * a,a128 v,morder mo)308 static void NoTsanAtomicStore(volatile a128 *a, a128 v, morder mo) {
309 SpinMutexLock lock(&mutex128);
310 *a = v;
311 }
312 #endif
313
314 template<typename T>
AtomicStore(ThreadState * thr,uptr pc,volatile T * a,T v,morder mo)315 static void AtomicStore(ThreadState *thr, uptr pc, volatile T *a, T v,
316 morder mo) {
317 CHECK(IsStoreOrder(mo));
318 MemoryWriteAtomic(thr, pc, (uptr)a, SizeLog<T>());
319 // This fast-path is critical for performance.
320 // Assume the access is atomic.
321 // Strictly saying even relaxed store cuts off release sequence,
322 // so must reset the clock.
323 if (!IsReleaseOrder(mo)) {
324 NoTsanAtomicStore(a, v, mo);
325 return;
326 }
327 __sync_synchronize();
328 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, (uptr)a, true);
329 thr->fast_state.IncrementEpoch();
330 // Can't increment epoch w/o writing to the trace as well.
331 TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
332 ReleaseImpl(thr, pc, &s->clock);
333 NoTsanAtomicStore(a, v, mo);
334 s->mtx.Unlock();
335 }
336
337 template<typename T, T (*F)(volatile T *v, T op)>
AtomicRMW(ThreadState * thr,uptr pc,volatile T * a,T v,morder mo)338 static T AtomicRMW(ThreadState *thr, uptr pc, volatile T *a, T v, morder mo) {
339 MemoryWriteAtomic(thr, pc, (uptr)a, SizeLog<T>());
340 SyncVar *s = 0;
341 if (mo != mo_relaxed) {
342 s = ctx->metamap.GetOrCreateAndLock(thr, pc, (uptr)a, true);
343 thr->fast_state.IncrementEpoch();
344 // Can't increment epoch w/o writing to the trace as well.
345 TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
346 if (IsAcqRelOrder(mo))
347 AcquireReleaseImpl(thr, pc, &s->clock);
348 else if (IsReleaseOrder(mo))
349 ReleaseImpl(thr, pc, &s->clock);
350 else if (IsAcquireOrder(mo))
351 AcquireImpl(thr, pc, &s->clock);
352 }
353 v = F(a, v);
354 if (s)
355 s->mtx.Unlock();
356 return v;
357 }
358
359 template<typename T>
NoTsanAtomicExchange(volatile T * a,T v,morder mo)360 static T NoTsanAtomicExchange(volatile T *a, T v, morder mo) {
361 return func_xchg(a, v);
362 }
363
364 template<typename T>
NoTsanAtomicFetchAdd(volatile T * a,T v,morder mo)365 static T NoTsanAtomicFetchAdd(volatile T *a, T v, morder mo) {
366 return func_add(a, v);
367 }
368
369 template<typename T>
NoTsanAtomicFetchSub(volatile T * a,T v,morder mo)370 static T NoTsanAtomicFetchSub(volatile T *a, T v, morder mo) {
371 return func_sub(a, v);
372 }
373
374 template<typename T>
NoTsanAtomicFetchAnd(volatile T * a,T v,morder mo)375 static T NoTsanAtomicFetchAnd(volatile T *a, T v, morder mo) {
376 return func_and(a, v);
377 }
378
379 template<typename T>
NoTsanAtomicFetchOr(volatile T * a,T v,morder mo)380 static T NoTsanAtomicFetchOr(volatile T *a, T v, morder mo) {
381 return func_or(a, v);
382 }
383
384 template<typename T>
NoTsanAtomicFetchXor(volatile T * a,T v,morder mo)385 static T NoTsanAtomicFetchXor(volatile T *a, T v, morder mo) {
386 return func_xor(a, v);
387 }
388
389 template<typename T>
NoTsanAtomicFetchNand(volatile T * a,T v,morder mo)390 static T NoTsanAtomicFetchNand(volatile T *a, T v, morder mo) {
391 return func_nand(a, v);
392 }
393
394 template<typename T>
AtomicExchange(ThreadState * thr,uptr pc,volatile T * a,T v,morder mo)395 static T AtomicExchange(ThreadState *thr, uptr pc, volatile T *a, T v,
396 morder mo) {
397 return AtomicRMW<T, func_xchg>(thr, pc, a, v, mo);
398 }
399
400 template<typename T>
AtomicFetchAdd(ThreadState * thr,uptr pc,volatile T * a,T v,morder mo)401 static T AtomicFetchAdd(ThreadState *thr, uptr pc, volatile T *a, T v,
402 morder mo) {
403 return AtomicRMW<T, func_add>(thr, pc, a, v, mo);
404 }
405
406 template<typename T>
AtomicFetchSub(ThreadState * thr,uptr pc,volatile T * a,T v,morder mo)407 static T AtomicFetchSub(ThreadState *thr, uptr pc, volatile T *a, T v,
408 morder mo) {
409 return AtomicRMW<T, func_sub>(thr, pc, a, v, mo);
410 }
411
412 template<typename T>
AtomicFetchAnd(ThreadState * thr,uptr pc,volatile T * a,T v,morder mo)413 static T AtomicFetchAnd(ThreadState *thr, uptr pc, volatile T *a, T v,
414 morder mo) {
415 return AtomicRMW<T, func_and>(thr, pc, a, v, mo);
416 }
417
418 template<typename T>
AtomicFetchOr(ThreadState * thr,uptr pc,volatile T * a,T v,morder mo)419 static T AtomicFetchOr(ThreadState *thr, uptr pc, volatile T *a, T v,
420 morder mo) {
421 return AtomicRMW<T, func_or>(thr, pc, a, v, mo);
422 }
423
424 template<typename T>
AtomicFetchXor(ThreadState * thr,uptr pc,volatile T * a,T v,morder mo)425 static T AtomicFetchXor(ThreadState *thr, uptr pc, volatile T *a, T v,
426 morder mo) {
427 return AtomicRMW<T, func_xor>(thr, pc, a, v, mo);
428 }
429
430 template<typename T>
AtomicFetchNand(ThreadState * thr,uptr pc,volatile T * a,T v,morder mo)431 static T AtomicFetchNand(ThreadState *thr, uptr pc, volatile T *a, T v,
432 morder mo) {
433 return AtomicRMW<T, func_nand>(thr, pc, a, v, mo);
434 }
435
436 template<typename T>
NoTsanAtomicCAS(volatile T * a,T * c,T v,morder mo,morder fmo)437 static bool NoTsanAtomicCAS(volatile T *a, T *c, T v, morder mo, morder fmo) {
438 return atomic_compare_exchange_strong(to_atomic(a), c, v, to_mo(mo));
439 }
440
441 #if __TSAN_HAS_INT128
NoTsanAtomicCAS(volatile a128 * a,a128 * c,a128 v,morder mo,morder fmo)442 static bool NoTsanAtomicCAS(volatile a128 *a, a128 *c, a128 v,
443 morder mo, morder fmo) {
444 a128 old = *c;
445 a128 cur = func_cas(a, old, v);
446 if (cur == old)
447 return true;
448 *c = cur;
449 return false;
450 }
451 #endif
452
453 template<typename T>
NoTsanAtomicCAS(volatile T * a,T c,T v,morder mo,morder fmo)454 static bool NoTsanAtomicCAS(volatile T *a, T c, T v, morder mo, morder fmo) {
455 return NoTsanAtomicCAS(a, &c, v, mo, fmo);
456 }
457
458 template<typename T>
AtomicCAS(ThreadState * thr,uptr pc,volatile T * a,T * c,T v,morder mo,morder fmo)459 static bool AtomicCAS(ThreadState *thr, uptr pc,
460 volatile T *a, T *c, T v, morder mo, morder fmo) {
461 (void)fmo; // Unused because llvm does not pass it yet.
462 MemoryWriteAtomic(thr, pc, (uptr)a, SizeLog<T>());
463 SyncVar *s = 0;
464 bool write_lock = mo != mo_acquire && mo != mo_consume;
465 if (mo != mo_relaxed) {
466 s = ctx->metamap.GetOrCreateAndLock(thr, pc, (uptr)a, write_lock);
467 thr->fast_state.IncrementEpoch();
468 // Can't increment epoch w/o writing to the trace as well.
469 TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
470 if (IsAcqRelOrder(mo))
471 AcquireReleaseImpl(thr, pc, &s->clock);
472 else if (IsReleaseOrder(mo))
473 ReleaseImpl(thr, pc, &s->clock);
474 else if (IsAcquireOrder(mo))
475 AcquireImpl(thr, pc, &s->clock);
476 }
477 T cc = *c;
478 T pr = func_cas(a, cc, v);
479 if (s) {
480 if (write_lock)
481 s->mtx.Unlock();
482 else
483 s->mtx.ReadUnlock();
484 }
485 if (pr == cc)
486 return true;
487 *c = pr;
488 return false;
489 }
490
491 template<typename T>
AtomicCAS(ThreadState * thr,uptr pc,volatile T * a,T c,T v,morder mo,morder fmo)492 static T AtomicCAS(ThreadState *thr, uptr pc,
493 volatile T *a, T c, T v, morder mo, morder fmo) {
494 AtomicCAS(thr, pc, a, &c, v, mo, fmo);
495 return c;
496 }
497
NoTsanAtomicFence(morder mo)498 static void NoTsanAtomicFence(morder mo) {
499 __sync_synchronize();
500 }
501
AtomicFence(ThreadState * thr,uptr pc,morder mo)502 static void AtomicFence(ThreadState *thr, uptr pc, morder mo) {
503 // FIXME(dvyukov): not implemented.
504 __sync_synchronize();
505 }
506
507 extern "C" {
508 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic8_load(const volatile a8 * a,morder mo)509 a8 __tsan_atomic8_load(const volatile a8 *a, morder mo) {
510 SCOPED_ATOMIC(Load, a, mo);
511 }
512
513 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic16_load(const volatile a16 * a,morder mo)514 a16 __tsan_atomic16_load(const volatile a16 *a, morder mo) {
515 SCOPED_ATOMIC(Load, a, mo);
516 }
517
518 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic32_load(const volatile a32 * a,morder mo)519 a32 __tsan_atomic32_load(const volatile a32 *a, morder mo) {
520 SCOPED_ATOMIC(Load, a, mo);
521 }
522
523 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic64_load(const volatile a64 * a,morder mo)524 a64 __tsan_atomic64_load(const volatile a64 *a, morder mo) {
525 SCOPED_ATOMIC(Load, a, mo);
526 }
527
528 #if __TSAN_HAS_INT128
529 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic128_load(const volatile a128 * a,morder mo)530 a128 __tsan_atomic128_load(const volatile a128 *a, morder mo) {
531 SCOPED_ATOMIC(Load, a, mo);
532 }
533 #endif
534
535 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic8_store(volatile a8 * a,a8 v,morder mo)536 void __tsan_atomic8_store(volatile a8 *a, a8 v, morder mo) {
537 SCOPED_ATOMIC(Store, a, v, mo);
538 }
539
540 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic16_store(volatile a16 * a,a16 v,morder mo)541 void __tsan_atomic16_store(volatile a16 *a, a16 v, morder mo) {
542 SCOPED_ATOMIC(Store, a, v, mo);
543 }
544
545 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic32_store(volatile a32 * a,a32 v,morder mo)546 void __tsan_atomic32_store(volatile a32 *a, a32 v, morder mo) {
547 SCOPED_ATOMIC(Store, a, v, mo);
548 }
549
550 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic64_store(volatile a64 * a,a64 v,morder mo)551 void __tsan_atomic64_store(volatile a64 *a, a64 v, morder mo) {
552 SCOPED_ATOMIC(Store, a, v, mo);
553 }
554
555 #if __TSAN_HAS_INT128
556 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic128_store(volatile a128 * a,a128 v,morder mo)557 void __tsan_atomic128_store(volatile a128 *a, a128 v, morder mo) {
558 SCOPED_ATOMIC(Store, a, v, mo);
559 }
560 #endif
561
562 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic8_exchange(volatile a8 * a,a8 v,morder mo)563 a8 __tsan_atomic8_exchange(volatile a8 *a, a8 v, morder mo) {
564 SCOPED_ATOMIC(Exchange, a, v, mo);
565 }
566
567 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic16_exchange(volatile a16 * a,a16 v,morder mo)568 a16 __tsan_atomic16_exchange(volatile a16 *a, a16 v, morder mo) {
569 SCOPED_ATOMIC(Exchange, a, v, mo);
570 }
571
572 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic32_exchange(volatile a32 * a,a32 v,morder mo)573 a32 __tsan_atomic32_exchange(volatile a32 *a, a32 v, morder mo) {
574 SCOPED_ATOMIC(Exchange, a, v, mo);
575 }
576
577 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic64_exchange(volatile a64 * a,a64 v,morder mo)578 a64 __tsan_atomic64_exchange(volatile a64 *a, a64 v, morder mo) {
579 SCOPED_ATOMIC(Exchange, a, v, mo);
580 }
581
582 #if __TSAN_HAS_INT128
583 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic128_exchange(volatile a128 * a,a128 v,morder mo)584 a128 __tsan_atomic128_exchange(volatile a128 *a, a128 v, morder mo) {
585 SCOPED_ATOMIC(Exchange, a, v, mo);
586 }
587 #endif
588
589 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic8_fetch_add(volatile a8 * a,a8 v,morder mo)590 a8 __tsan_atomic8_fetch_add(volatile a8 *a, a8 v, morder mo) {
591 SCOPED_ATOMIC(FetchAdd, a, v, mo);
592 }
593
594 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic16_fetch_add(volatile a16 * a,a16 v,morder mo)595 a16 __tsan_atomic16_fetch_add(volatile a16 *a, a16 v, morder mo) {
596 SCOPED_ATOMIC(FetchAdd, a, v, mo);
597 }
598
599 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic32_fetch_add(volatile a32 * a,a32 v,morder mo)600 a32 __tsan_atomic32_fetch_add(volatile a32 *a, a32 v, morder mo) {
601 SCOPED_ATOMIC(FetchAdd, a, v, mo);
602 }
603
604 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic64_fetch_add(volatile a64 * a,a64 v,morder mo)605 a64 __tsan_atomic64_fetch_add(volatile a64 *a, a64 v, morder mo) {
606 SCOPED_ATOMIC(FetchAdd, a, v, mo);
607 }
608
609 #if __TSAN_HAS_INT128
610 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic128_fetch_add(volatile a128 * a,a128 v,morder mo)611 a128 __tsan_atomic128_fetch_add(volatile a128 *a, a128 v, morder mo) {
612 SCOPED_ATOMIC(FetchAdd, a, v, mo);
613 }
614 #endif
615
616 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic8_fetch_sub(volatile a8 * a,a8 v,morder mo)617 a8 __tsan_atomic8_fetch_sub(volatile a8 *a, a8 v, morder mo) {
618 SCOPED_ATOMIC(FetchSub, a, v, mo);
619 }
620
621 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic16_fetch_sub(volatile a16 * a,a16 v,morder mo)622 a16 __tsan_atomic16_fetch_sub(volatile a16 *a, a16 v, morder mo) {
623 SCOPED_ATOMIC(FetchSub, a, v, mo);
624 }
625
626 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic32_fetch_sub(volatile a32 * a,a32 v,morder mo)627 a32 __tsan_atomic32_fetch_sub(volatile a32 *a, a32 v, morder mo) {
628 SCOPED_ATOMIC(FetchSub, a, v, mo);
629 }
630
631 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic64_fetch_sub(volatile a64 * a,a64 v,morder mo)632 a64 __tsan_atomic64_fetch_sub(volatile a64 *a, a64 v, morder mo) {
633 SCOPED_ATOMIC(FetchSub, a, v, mo);
634 }
635
636 #if __TSAN_HAS_INT128
637 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic128_fetch_sub(volatile a128 * a,a128 v,morder mo)638 a128 __tsan_atomic128_fetch_sub(volatile a128 *a, a128 v, morder mo) {
639 SCOPED_ATOMIC(FetchSub, a, v, mo);
640 }
641 #endif
642
643 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic8_fetch_and(volatile a8 * a,a8 v,morder mo)644 a8 __tsan_atomic8_fetch_and(volatile a8 *a, a8 v, morder mo) {
645 SCOPED_ATOMIC(FetchAnd, a, v, mo);
646 }
647
648 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic16_fetch_and(volatile a16 * a,a16 v,morder mo)649 a16 __tsan_atomic16_fetch_and(volatile a16 *a, a16 v, morder mo) {
650 SCOPED_ATOMIC(FetchAnd, a, v, mo);
651 }
652
653 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic32_fetch_and(volatile a32 * a,a32 v,morder mo)654 a32 __tsan_atomic32_fetch_and(volatile a32 *a, a32 v, morder mo) {
655 SCOPED_ATOMIC(FetchAnd, a, v, mo);
656 }
657
658 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic64_fetch_and(volatile a64 * a,a64 v,morder mo)659 a64 __tsan_atomic64_fetch_and(volatile a64 *a, a64 v, morder mo) {
660 SCOPED_ATOMIC(FetchAnd, a, v, mo);
661 }
662
663 #if __TSAN_HAS_INT128
664 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic128_fetch_and(volatile a128 * a,a128 v,morder mo)665 a128 __tsan_atomic128_fetch_and(volatile a128 *a, a128 v, morder mo) {
666 SCOPED_ATOMIC(FetchAnd, a, v, mo);
667 }
668 #endif
669
670 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic8_fetch_or(volatile a8 * a,a8 v,morder mo)671 a8 __tsan_atomic8_fetch_or(volatile a8 *a, a8 v, morder mo) {
672 SCOPED_ATOMIC(FetchOr, a, v, mo);
673 }
674
675 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic16_fetch_or(volatile a16 * a,a16 v,morder mo)676 a16 __tsan_atomic16_fetch_or(volatile a16 *a, a16 v, morder mo) {
677 SCOPED_ATOMIC(FetchOr, a, v, mo);
678 }
679
680 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic32_fetch_or(volatile a32 * a,a32 v,morder mo)681 a32 __tsan_atomic32_fetch_or(volatile a32 *a, a32 v, morder mo) {
682 SCOPED_ATOMIC(FetchOr, a, v, mo);
683 }
684
685 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic64_fetch_or(volatile a64 * a,a64 v,morder mo)686 a64 __tsan_atomic64_fetch_or(volatile a64 *a, a64 v, morder mo) {
687 SCOPED_ATOMIC(FetchOr, a, v, mo);
688 }
689
690 #if __TSAN_HAS_INT128
691 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic128_fetch_or(volatile a128 * a,a128 v,morder mo)692 a128 __tsan_atomic128_fetch_or(volatile a128 *a, a128 v, morder mo) {
693 SCOPED_ATOMIC(FetchOr, a, v, mo);
694 }
695 #endif
696
697 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic8_fetch_xor(volatile a8 * a,a8 v,morder mo)698 a8 __tsan_atomic8_fetch_xor(volatile a8 *a, a8 v, morder mo) {
699 SCOPED_ATOMIC(FetchXor, a, v, mo);
700 }
701
702 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic16_fetch_xor(volatile a16 * a,a16 v,morder mo)703 a16 __tsan_atomic16_fetch_xor(volatile a16 *a, a16 v, morder mo) {
704 SCOPED_ATOMIC(FetchXor, a, v, mo);
705 }
706
707 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic32_fetch_xor(volatile a32 * a,a32 v,morder mo)708 a32 __tsan_atomic32_fetch_xor(volatile a32 *a, a32 v, morder mo) {
709 SCOPED_ATOMIC(FetchXor, a, v, mo);
710 }
711
712 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic64_fetch_xor(volatile a64 * a,a64 v,morder mo)713 a64 __tsan_atomic64_fetch_xor(volatile a64 *a, a64 v, morder mo) {
714 SCOPED_ATOMIC(FetchXor, a, v, mo);
715 }
716
717 #if __TSAN_HAS_INT128
718 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic128_fetch_xor(volatile a128 * a,a128 v,morder mo)719 a128 __tsan_atomic128_fetch_xor(volatile a128 *a, a128 v, morder mo) {
720 SCOPED_ATOMIC(FetchXor, a, v, mo);
721 }
722 #endif
723
724 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic8_fetch_nand(volatile a8 * a,a8 v,morder mo)725 a8 __tsan_atomic8_fetch_nand(volatile a8 *a, a8 v, morder mo) {
726 SCOPED_ATOMIC(FetchNand, a, v, mo);
727 }
728
729 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic16_fetch_nand(volatile a16 * a,a16 v,morder mo)730 a16 __tsan_atomic16_fetch_nand(volatile a16 *a, a16 v, morder mo) {
731 SCOPED_ATOMIC(FetchNand, a, v, mo);
732 }
733
734 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic32_fetch_nand(volatile a32 * a,a32 v,morder mo)735 a32 __tsan_atomic32_fetch_nand(volatile a32 *a, a32 v, morder mo) {
736 SCOPED_ATOMIC(FetchNand, a, v, mo);
737 }
738
739 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic64_fetch_nand(volatile a64 * a,a64 v,morder mo)740 a64 __tsan_atomic64_fetch_nand(volatile a64 *a, a64 v, morder mo) {
741 SCOPED_ATOMIC(FetchNand, a, v, mo);
742 }
743
744 #if __TSAN_HAS_INT128
745 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic128_fetch_nand(volatile a128 * a,a128 v,morder mo)746 a128 __tsan_atomic128_fetch_nand(volatile a128 *a, a128 v, morder mo) {
747 SCOPED_ATOMIC(FetchNand, a, v, mo);
748 }
749 #endif
750
751 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic8_compare_exchange_strong(volatile a8 * a,a8 * c,a8 v,morder mo,morder fmo)752 int __tsan_atomic8_compare_exchange_strong(volatile a8 *a, a8 *c, a8 v,
753 morder mo, morder fmo) {
754 SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
755 }
756
757 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic16_compare_exchange_strong(volatile a16 * a,a16 * c,a16 v,morder mo,morder fmo)758 int __tsan_atomic16_compare_exchange_strong(volatile a16 *a, a16 *c, a16 v,
759 morder mo, morder fmo) {
760 SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
761 }
762
763 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic32_compare_exchange_strong(volatile a32 * a,a32 * c,a32 v,morder mo,morder fmo)764 int __tsan_atomic32_compare_exchange_strong(volatile a32 *a, a32 *c, a32 v,
765 morder mo, morder fmo) {
766 SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
767 }
768
769 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic64_compare_exchange_strong(volatile a64 * a,a64 * c,a64 v,morder mo,morder fmo)770 int __tsan_atomic64_compare_exchange_strong(volatile a64 *a, a64 *c, a64 v,
771 morder mo, morder fmo) {
772 SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
773 }
774
775 #if __TSAN_HAS_INT128
776 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic128_compare_exchange_strong(volatile a128 * a,a128 * c,a128 v,morder mo,morder fmo)777 int __tsan_atomic128_compare_exchange_strong(volatile a128 *a, a128 *c, a128 v,
778 morder mo, morder fmo) {
779 SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
780 }
781 #endif
782
783 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic8_compare_exchange_weak(volatile a8 * a,a8 * c,a8 v,morder mo,morder fmo)784 int __tsan_atomic8_compare_exchange_weak(volatile a8 *a, a8 *c, a8 v,
785 morder mo, morder fmo) {
786 SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
787 }
788
789 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic16_compare_exchange_weak(volatile a16 * a,a16 * c,a16 v,morder mo,morder fmo)790 int __tsan_atomic16_compare_exchange_weak(volatile a16 *a, a16 *c, a16 v,
791 morder mo, morder fmo) {
792 SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
793 }
794
795 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic32_compare_exchange_weak(volatile a32 * a,a32 * c,a32 v,morder mo,morder fmo)796 int __tsan_atomic32_compare_exchange_weak(volatile a32 *a, a32 *c, a32 v,
797 morder mo, morder fmo) {
798 SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
799 }
800
801 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic64_compare_exchange_weak(volatile a64 * a,a64 * c,a64 v,morder mo,morder fmo)802 int __tsan_atomic64_compare_exchange_weak(volatile a64 *a, a64 *c, a64 v,
803 morder mo, morder fmo) {
804 SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
805 }
806
807 #if __TSAN_HAS_INT128
808 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic128_compare_exchange_weak(volatile a128 * a,a128 * c,a128 v,morder mo,morder fmo)809 int __tsan_atomic128_compare_exchange_weak(volatile a128 *a, a128 *c, a128 v,
810 morder mo, morder fmo) {
811 SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
812 }
813 #endif
814
815 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic8_compare_exchange_val(volatile a8 * a,a8 c,a8 v,morder mo,morder fmo)816 a8 __tsan_atomic8_compare_exchange_val(volatile a8 *a, a8 c, a8 v,
817 morder mo, morder fmo) {
818 SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
819 }
820
821 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic16_compare_exchange_val(volatile a16 * a,a16 c,a16 v,morder mo,morder fmo)822 a16 __tsan_atomic16_compare_exchange_val(volatile a16 *a, a16 c, a16 v,
823 morder mo, morder fmo) {
824 SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
825 }
826
827 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic32_compare_exchange_val(volatile a32 * a,a32 c,a32 v,morder mo,morder fmo)828 a32 __tsan_atomic32_compare_exchange_val(volatile a32 *a, a32 c, a32 v,
829 morder mo, morder fmo) {
830 SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
831 }
832
833 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic64_compare_exchange_val(volatile a64 * a,a64 c,a64 v,morder mo,morder fmo)834 a64 __tsan_atomic64_compare_exchange_val(volatile a64 *a, a64 c, a64 v,
835 morder mo, morder fmo) {
836 SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
837 }
838
839 #if __TSAN_HAS_INT128
840 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic128_compare_exchange_val(volatile a128 * a,a128 c,a128 v,morder mo,morder fmo)841 a128 __tsan_atomic128_compare_exchange_val(volatile a128 *a, a128 c, a128 v,
842 morder mo, morder fmo) {
843 SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
844 }
845 #endif
846
847 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic_thread_fence(morder mo)848 void __tsan_atomic_thread_fence(morder mo) {
849 char* a = 0;
850 SCOPED_ATOMIC(Fence, mo);
851 }
852
853 SANITIZER_INTERFACE_ATTRIBUTE
__tsan_atomic_signal_fence(morder mo)854 void __tsan_atomic_signal_fence(morder mo) {
855 }
856 } // extern "C"
857