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