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