1 // RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
2 #include "test.h"
3 
4 const int kTestCount = 3;
5 typedef long long T;
6 T data[kTestCount];
7 T atomics[kTestCount];
8 
9 void *Thread(void *p) {
10   for (int i = 0; i < kTestCount; i++) {
11     barrier_wait(&barrier);
12     while (__atomic_load_n(&atomics[i], __ATOMIC_ACQUIRE) == 0) {
13     }
14     data[i]++;
15   }
16   return 0;
17 }
18 
19 int main() {
20   barrier_init(&barrier, 2);
21   pthread_t t;
22   pthread_create(&t, 0, Thread, 0);
23   for (int i = 0; i < kTestCount; i++) {
24     barrier_wait(&barrier);
25     // We want the release to happen while the other thread
26     // spins calling load-acquire. This can expose some
27     // interesting interleavings of release and acquire.
28     usleep(100 * 1000);
29     data[i] = 1;
30     switch (i) {
31     case 0:
32       __atomic_store_n(&atomics[i], 1, __ATOMIC_RELEASE);
33       break;
34     case 1:
35       __atomic_fetch_add(&atomics[1], 1, __ATOMIC_RELEASE);
36       break;
37     case 2:
38       T cmp = 0;
39       __atomic_compare_exchange_n(&atomics[2], &cmp, 1, false, __ATOMIC_RELEASE, __ATOMIC_RELAXED);
40       break;
41     }
42   }
43   pthread_join(t, 0);
44   fprintf(stderr, "DONE\n");
45 }
46 
47 // CHECK-NOT: ThreadSanitizer: data race
48 // CHECK: DONE
49