1// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
2
3#include "test.h"
4#include <assert.h>
5#include <sanitizer/tsan_interface.h>
6#include <stdio.h>
7
8// We only enter a potentially blocking region on thread contention. To reliably
9// trigger this, we force the initialization function to block until another
10// thread has entered the potentially blocking region.
11
12static bool init_done = false;
13
14namespace __tsan {
15
16#if (__APPLE__)
17__attribute__((weak))
18#endif
19void OnPotentiallyBlockingRegionBegin() {
20 assert(!init_done);
21 printf(format: "Enter potentially blocking region\n");
22 // Signal the other thread to finish initialization.
23 barrier_wait(barrier: &barrier);
24}
25
26#if (__APPLE__)
27__attribute__((weak))
28#endif
29void OnPotentiallyBlockingRegionEnd() {
30 printf(format: "Exit potentially blocking region\n");
31}
32
33} // namespace __tsan
34
35struct LazyInit {
36 LazyInit() {
37 assert(!init_done);
38 printf(format: "Enter constructor\n");
39 // Wait for the other thread to get to the blocking region.
40 barrier_wait(barrier: &barrier);
41 printf(format: "Exit constructor\n");
42 }
43};
44
45const LazyInit &get_lazy_init() {
46 static const LazyInit lazy_init;
47 return lazy_init;
48}
49
50void *thread(void *arg) {
51 get_lazy_init();
52 return nullptr;
53}
54
55struct LazyInit2 {
56 LazyInit2() { printf(format: "Enter constructor 2\n"); }
57};
58
59const LazyInit2 &get_lazy_init2() {
60 static const LazyInit2 lazy_init2;
61 return lazy_init2;
62}
63
64int main(int argc, char **argv) {
65 // CHECK: Enter main
66 printf(format: "Enter main\n");
67
68 // If initialization is contended, the blocked thread should enter a
69 // potentially blocking region.
70 //
71 // CHECK-NEXT: Enter constructor
72 // CHECK-NEXT: Enter potentially blocking region
73 // CHECK-NEXT: Exit constructor
74 // CHECK-NEXT: Exit potentially blocking region
75 barrier_init(barrier: &barrier, count: 2);
76 pthread_t th1, th2;
77 pthread_create(newthread: &th1, attr: nullptr, start_routine: thread, arg: nullptr);
78 pthread_create(newthread: &th2, attr: nullptr, start_routine: thread, arg: nullptr);
79 pthread_join(th: th1, thread_return: nullptr);
80 pthread_join(th: th2, thread_return: nullptr);
81
82 // Now that the value has been initialized, subsequent calls should not enter
83 // a potentially blocking region.
84 init_done = true;
85 get_lazy_init();
86
87 // If uncontended, there is no potentially blocking region.
88 //
89 // CHECK-NEXT: Enter constructor 2
90 get_lazy_init2();
91 get_lazy_init2();
92
93 // CHECK-NEXT: Exit main
94 printf(format: "Exit main\n");
95 return 0;
96}
97

source code of compiler-rt/test/tsan/cxa_guard_acquire.cpp