1 //===----------------------------- test_guard.cpp -------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is dual licensed under the MIT and the University of Illinois Open
6 // Source Licenses. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "../src/config.h"
11 #include "cxxabi.h"
12 
13 #include <cassert>
14 
15 #if !LIBCXXABI_HAS_NO_THREADS
16 #include <thread>
17 #endif
18 
19 // Ensure that we initialize each variable once and only once.
20 namespace test1 {
21     static int run_count = 0;
increment()22     int increment() {
23         ++run_count;
24         return 0;
25     }
helper()26     void helper() {
27         static int a = increment();
28     }
test()29     void test() {
30         static int a = increment();
31         assert(run_count == 1);
32         static int b = increment();
33         assert(run_count == 2);
34         helper();
35         assert(run_count == 3);
36         helper();
37         assert(run_count == 3);
38     }
39 }
40 
41 // When initialization fails, ensure that we try to initialize it again next
42 // time.
43 namespace test2 {
44     static int run_count = 0;
increment()45     int increment() {
46         ++run_count;
47         throw 0;
48     }
helper()49     void helper() {
50         try {
51             static int a = increment();
52             assert(0);
53         } catch (...) {}
54     }
test()55     void test() {
56         helper();
57         assert(run_count == 1);
58         helper();
59         assert(run_count == 2);
60     }
61 }
62 
63 // Check that we can initialize a second value while initializing a first.
64 namespace test3 {
zero()65     int zero() {
66         return 0;
67     }
68 
one()69     int one() {
70         static int b = zero();
71         return 0;
72     }
73 
test()74     void test() {
75         static int a = one();
76     }
77 }
78 
79 #if !LIBCXXABI_HAS_NO_THREADS
80 // A simple thread test of two threads racing to initialize a variable. This
81 // isn't guaranteed to catch any particular threading problems.
82 namespace test4 {
83     static int run_count = 0;
increment()84     int increment() {
85         ++run_count;
86         return 0;
87     }
88 
helper()89     void helper() {
90         static int a = increment();
91     }
92 
test()93     void test() {
94         std::thread t1(helper), t2(helper);
95         t1.join();
96         t2.join();
97         assert(run_count == 1);
98     }
99 }
100 
101 // Check that we don't re-initialize a static variable even when it's
102 // encountered from two different threads.
103 namespace test5 {
104     static int run_count = 0;
zero()105     int zero() {
106         ++run_count;
107         return 0;
108     }
109 
one()110     int one() {
111         static int b = zero();
112         return 0;
113     }
114 
another_helper()115     void another_helper() {
116         static int a = one();
117     }
118 
helper()119     void helper() {
120         static int a = one();
121         std::thread t(another_helper);
122         t.join();
123     }
124 
test()125     void test() {
126         std::thread t(helper);
127         t.join();
128         assert(run_count == 1);
129     }
130 }
131 #endif /* LIBCXXABI_HAS_NO_THREADS */
132 
main()133 int main()
134 {
135     test1::test();
136     test2::test();
137     test3::test();
138 #if !LIBCXXABI_HAS_NO_THREADS
139     test4::test();
140     test5::test();
141 #endif
142 }
143