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 "cxxabi.h"
11 
12 #include <cassert>
13 
14 #ifndef _LIBCXXABI_HAS_NO_THREADS
15 #include <thread>
16 #endif
17 
18 // Ensure that we initialize each variable once and only once.
19 namespace test1 {
20     static int run_count = 0;
increment()21     int increment() {
22         ++run_count;
23         return 0;
24     }
helper()25     void helper() {
26         static int a = increment();
27         ((void)a);
28     }
test()29     void test() {
30         static int a = increment(); ((void)a);
31         assert(run_count == 1);
32         static int b = increment(); ((void)b);
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 #ifndef LIBCXXABI_HAS_NO_EXCEPTIONS
45     static int run_count = 0;
increment()46     int increment() {
47         ++run_count;
48         throw 0;
49     }
helper()50     void helper() {
51         try {
52             static int a = increment();
53             assert(false);
54             ((void)a);
55         } catch (...) {}
56     }
test()57     void test() {
58         helper();
59         assert(run_count == 1);
60         helper();
61         assert(run_count == 2);
62     }
63 #else
64    void test() {}
65 #endif
66 }
67 
68 // Check that we can initialize a second value while initializing a first.
69 namespace test3 {
zero()70     int zero() {
71         return 0;
72     }
73 
one()74     int one() {
75         static int b = zero(); ((void)b);
76         return 0;
77     }
78 
test()79     void test() {
80         static int a = one(); ((void)a);
81     }
82 }
83 
84 #ifndef _LIBCXXABI_HAS_NO_THREADS
85 // A simple thread test of two threads racing to initialize a variable. This
86 // isn't guaranteed to catch any particular threading problems.
87 namespace test4 {
88     static int run_count = 0;
increment()89     int increment() {
90         ++run_count;
91         return 0;
92     }
93 
helper()94     void helper() {
95         static int a = increment(); ((void)a);
96     }
97 
test()98     void test() {
99         std::thread t1(helper), t2(helper);
100         t1.join();
101         t2.join();
102         assert(run_count == 1);
103     }
104 }
105 
106 // Check that we don't re-initialize a static variable even when it's
107 // encountered from two different threads.
108 namespace test5 {
109     static int run_count = 0;
zero()110     int zero() {
111         ++run_count;
112         return 0;
113     }
114 
one()115     int one() {
116         static int b = zero(); ((void)b);
117         return 0;
118     }
119 
another_helper()120     void another_helper() {
121         static int a = one(); ((void)a);
122     }
123 
helper()124     void helper() {
125         static int a = one(); ((void)a);
126         std::thread t(another_helper);
127         t.join();
128     }
129 
test()130     void test() {
131         std::thread t(helper);
132         t.join();
133         assert(run_count == 1);
134     }
135 }
136 #endif /* _LIBCXXABI_HAS_NO_THREADS */
137 
main()138 int main()
139 {
140     test1::test();
141     test2::test();
142     test3::test();
143 #ifndef _LIBCXXABI_HAS_NO_THREADS
144     test4::test();
145     test5::test();
146 #endif
147 }
148