1*25c94eb1SDmitry Vyukov // RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
2*25c94eb1SDmitry Vyukov #include "test.h"
3*25c94eb1SDmitry Vyukov
4*25c94eb1SDmitry Vyukov // We want to establish the following sequence of accesses to X:
5*25c94eb1SDmitry Vyukov // - main thread writes X
6*25c94eb1SDmitry Vyukov // - thread2 reads X, this read happens-before the write in main thread
7*25c94eb1SDmitry Vyukov // - thread1 reads X, this read is concurrent with the write in main thread
8*25c94eb1SDmitry Vyukov // Write in main thread and read in thread1 should be detected as a race.
9*25c94eb1SDmitry Vyukov // Previously tsan replaced write by main thread with read by thread1,
10*25c94eb1SDmitry Vyukov // as the result the race was not detected.
11*25c94eb1SDmitry Vyukov
12*25c94eb1SDmitry Vyukov volatile long X, Y, Z;
13*25c94eb1SDmitry Vyukov
Thread1(void * x)14*25c94eb1SDmitry Vyukov void *Thread1(void *x) {
15*25c94eb1SDmitry Vyukov barrier_wait(&barrier);
16*25c94eb1SDmitry Vyukov barrier_wait(&barrier);
17*25c94eb1SDmitry Vyukov Y = X;
18*25c94eb1SDmitry Vyukov return NULL;
19*25c94eb1SDmitry Vyukov }
20*25c94eb1SDmitry Vyukov
Thread2(void * x)21*25c94eb1SDmitry Vyukov void *Thread2(void *x) {
22*25c94eb1SDmitry Vyukov Z = X;
23*25c94eb1SDmitry Vyukov barrier_wait(&barrier);
24*25c94eb1SDmitry Vyukov return NULL;
25*25c94eb1SDmitry Vyukov }
26*25c94eb1SDmitry Vyukov
main()27*25c94eb1SDmitry Vyukov int main() {
28*25c94eb1SDmitry Vyukov barrier_init(&barrier, 2);
29*25c94eb1SDmitry Vyukov pthread_t t[2];
30*25c94eb1SDmitry Vyukov pthread_create(&t[0], 0, Thread1, 0);
31*25c94eb1SDmitry Vyukov X = 42;
32*25c94eb1SDmitry Vyukov barrier_wait(&barrier);
33*25c94eb1SDmitry Vyukov pthread_create(&t[1], 0, Thread2, 0);
34*25c94eb1SDmitry Vyukov pthread_join(t[0], 0);
35*25c94eb1SDmitry Vyukov pthread_join(t[1], 0);
36*25c94eb1SDmitry Vyukov return 0;
37*25c94eb1SDmitry Vyukov }
38*25c94eb1SDmitry Vyukov
39*25c94eb1SDmitry Vyukov // CHECK: WARNING: ThreadSanitizer: data race
40*25c94eb1SDmitry Vyukov
41