1 // RUN: %clangxx_tsan -O1 %s %link_libcxx_tsan -o %t && %deflake %env_tsan_opts=atexit_sleep_ms=50 %run %t 2>&1 | FileCheck --check-prefix=CHECK-REPORT %s 2 3 #include <atomic> 4 #include <cassert> 5 #include <stdio.h> 6 #include <thread> 7 8 #define NUM_ORDS 16 9 #define NUM_THREADS NUM_ORDS * 2 10 struct node { 11 int val; 12 }; 13 std::atomic<node *> _nodes[NUM_THREADS] = {}; 14 15 void f1(int i) { 16 auto n = new node(); 17 n->val = 42; 18 _nodes[i].store(n, std::memory_order_release); 19 } 20 21 template <int version> 22 void f2(int i, std::memory_order mo, std::memory_order fmo) { 23 node *expected = nullptr; 24 while (expected == nullptr) { 25 _nodes[i].compare_exchange_weak(expected, nullptr, mo, fmo); 26 }; 27 28 ++expected->val; 29 assert(expected->val == 43); 30 } 31 32 struct MemOrdSuccFail { 33 std::memory_order mo; 34 std::memory_order fmo; 35 }; 36 37 MemOrdSuccFail OrdList[NUM_ORDS] = { 38 {std::memory_order_release, std::memory_order_relaxed}, 39 {std::memory_order_release, std::memory_order_acquire}, 40 {std::memory_order_release, std::memory_order_consume}, 41 {std::memory_order_release, std::memory_order_seq_cst}, 42 43 {std::memory_order_acq_rel, std::memory_order_relaxed}, 44 {std::memory_order_acq_rel, std::memory_order_acquire}, 45 {std::memory_order_acq_rel, std::memory_order_consume}, 46 {std::memory_order_acq_rel, std::memory_order_seq_cst}, 47 48 {std::memory_order_seq_cst, std::memory_order_relaxed}, 49 {std::memory_order_seq_cst, std::memory_order_acquire}, 50 {std::memory_order_seq_cst, std::memory_order_consume}, 51 {std::memory_order_seq_cst, std::memory_order_seq_cst}, 52 53 {std::memory_order_relaxed, std::memory_order_relaxed}, 54 {std::memory_order_relaxed, std::memory_order_acquire}, 55 {std::memory_order_relaxed, std::memory_order_consume}, 56 {std::memory_order_relaxed, std::memory_order_seq_cst}, 57 }; 58 59 int main() { 60 std::thread threads[NUM_THREADS]; 61 int ords = 0; 62 63 // Instantiate a new f2 for each MO so we can dedup reports and actually 64 // make sure relaxed FMO triggers a warning for every different MO. 65 for (unsigned t = 0; t < 8; t += 2) { 66 threads[t] = std::thread(f1, t); 67 threads[t + 1] = std::thread(f2<0>, t, OrdList[ords].mo, OrdList[ords].fmo); 68 threads[t].join(); 69 threads[t + 1].join(); 70 ords++; 71 } 72 73 for (unsigned t = 8; t < 16; t += 2) { 74 threads[t] = std::thread(f1, t); 75 threads[t + 1] = std::thread(f2<1>, t, OrdList[ords].mo, OrdList[ords].fmo); 76 threads[t].join(); 77 threads[t + 1].join(); 78 ords++; 79 } 80 81 for (unsigned t = 16; t < 24; t += 2) { 82 threads[t] = std::thread(f1, t); 83 threads[t + 1] = std::thread(f2<2>, t, OrdList[ords].mo, OrdList[ords].fmo); 84 threads[t].join(); 85 threads[t + 1].join(); 86 ords++; 87 } 88 89 for (unsigned t = 24; t < 32; t += 2) { 90 threads[t] = std::thread(f1, t); 91 threads[t + 1] = std::thread(f2<3>, t, OrdList[ords].mo, OrdList[ords].fmo); 92 threads[t].join(); 93 threads[t + 1].join(); 94 ords++; 95 } 96 97 fprintf(stderr, "DONE\n"); 98 return 0; 99 } 100 101 // CHECK-REPORT: WARNING: ThreadSanitizer: data race 102 // CHECK-REPORT: WARNING: ThreadSanitizer: data race 103 // CHECK-REPORT: WARNING: ThreadSanitizer: data race 104 // CHECK-REPORT: WARNING: ThreadSanitizer: data race 105 // CHECK-REPORT: DONE 106 // CHECK-REPORT: ThreadSanitizer: reported 4 warnings 107