1 #include <pthread.h> 2 #include <stdio.h> 3 #include <unistd.h> 4 5 int Global; 6 7 void __attribute__((noinline)) foo1() { 8 Global = 42; 9 } 10 11 void __attribute__((noinline)) bar1() { 12 volatile int tmp = 42; (void)tmp; 13 foo1(); 14 } 15 16 void __attribute__((noinline)) foo2() { 17 volatile int v = Global; (void)v; 18 } 19 20 void __attribute__((noinline)) bar2() { 21 volatile int tmp = 42; (void)tmp; 22 foo2(); 23 } 24 25 void *Thread1(void *x) { 26 usleep(1000000); 27 bar1(); 28 return NULL; 29 } 30 31 void *Thread2(void *x) { 32 bar2(); 33 return NULL; 34 } 35 36 void StartThread(pthread_t *t, void *(*f)(void*)) { 37 pthread_create(t, NULL, f, NULL); 38 } 39 40 int main() { 41 pthread_t t[2]; 42 StartThread(&t[0], Thread1); 43 StartThread(&t[1], Thread2); 44 pthread_join(t[0], NULL); 45 pthread_join(t[1], NULL); 46 return 0; 47 } 48 49 // CHECK: WARNING: ThreadSanitizer: data race 50 // CHECK-NEXT: Write of size 4 at {{.*}} by thread 1: 51 // CHECK-NEXT: #0 foo1{{.*}} {{.*}}simple_stack.c:8{{(:3)?}} ({{.*}}) 52 // CHECK-NEXT: #1 bar1{{.*}} {{.*}}simple_stack.c:13{{(:3)?}} ({{.*}}) 53 // CHECK-NEXT: #2 Thread1{{.*}} {{.*}}simple_stack.c:27{{(:3)?}} ({{.*}}) 54 // CHECK: Previous read of size 4 at {{.*}} by thread 2: 55 // CHECK-NEXT: #0 foo2{{.*}} {{.*}}simple_stack.c:17{{(:26)?}} ({{.*}}) 56 // CHECK-NEXT: #1 bar2{{.*}} {{.*}}simple_stack.c:22{{(:3)?}} ({{.*}}) 57 // CHECK-NEXT: #2 Thread2{{.*}} {{.*}}simple_stack.c:32{{(:3)?}} ({{.*}}) 58 // CHECK: Thread 1 (running) created at: 59 // CHECK-NEXT: #0 pthread_create {{.*}} ({{.*}}) 60 // CHECK-NEXT: #1 StartThread{{.*}} {{.*}}simple_stack.c:37{{(:3)?}} ({{.*}}) 61 // CHECK-NEXT: #2 main{{.*}} {{.*}}simple_stack.c:42{{(:3)?}} ({{.*}}) 62 // CHECK: Thread 2 ({{.*}}) created at: 63 // CHECK-NEXT: #0 pthread_create {{.*}} ({{.*}}) 64 // CHECK-NEXT: #1 StartThread{{.*}} {{.*}}simple_stack.c:37{{(:3)?}} ({{.*}}) 65 // CHECK-NEXT: #2 main{{.*}} {{.*}}simple_stack.c:43{{(:3)?}} ({{.*}}) 66