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 #ifndef _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         ((void)a);
29     }
test()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 LIBCXXABI_HAS_NO_EXCEPTIONS
46     static int run_count = 0;
increment()47     int increment() {
48         ++run_count;
49         throw 0;
50     }
helper()51     void helper() {
52         try {
53             static int a = increment();
54             assert(false);
55             ((void)a);
56         } catch (...) {}
57     }
test()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 {
zero()71     int zero() {
72         return 0;
73     }
74 
one()75     int one() {
76         static int b = zero(); ((void)b);
77         return 0;
78     }
79 
test()80     void test() {
81         static int a = one(); ((void)a);
82     }
83 }
84 
85 #ifndef _LIBCXXABI_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;
increment()90     int increment() {
91         ++run_count;
92         return 0;
93     }
94 
helper()95     void helper() {
96         static int a = increment(); ((void)a);
97     }
98 
test()99     void test() {
100         std::thread t1(helper), t2(helper);
101         t1.join();
102         t2.join();
103         assert(run_count == 1);
104     }
105 }
106 
107 // Check that we don't re-initialize a static variable even when it's
108 // encountered from two different threads.
109 namespace test5 {
110     static int run_count = 0;
zero()111     int zero() {
112         ++run_count;
113         return 0;
114     }
115 
one()116     int one() {
117         static int b = zero(); ((void)b);
118         return 0;
119     }
120 
another_helper()121     void another_helper() {
122         static int a = one(); ((void)a);
123     }
124 
helper()125     void helper() {
126         static int a = one(); ((void)a);
127         std::thread t(another_helper);
128         t.join();
129     }
130 
test()131     void test() {
132         std::thread t(helper);
133         t.join();
134         assert(run_count == 1);
135     }
136 }
137 #endif /* _LIBCXXABI_HAS_NO_THREADS */
138 
main()139 int main()
140 {
141     test1::test();
142     test2::test();
143     test3::test();
144 #ifndef _LIBCXXABI_HAS_NO_THREADS
145     test4::test();
146     test5::test();
147 #endif
148 }
149