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.
20namespace 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.
43namespace test2 {
44    static int run_count = 0;
45    int increment() {
46        ++run_count;
47        throw 0;
48    }
49    void helper() {
50        try {
51            static int a = increment();
52            assert(0);
53        } catch (...) {}
54    }
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.
64namespace test3 {
65    int zero() {
66        return 0;
67    }
68
69    int one() {
70        static int b = zero();
71        return 0;
72    }
73
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.
82namespace test4 {
83    static int run_count = 0;
84    int increment() {
85        ++run_count;
86        return 0;
87    }
88
89    void helper() {
90        static int a = increment();
91    }
92
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.
103namespace test5 {
104    static int run_count = 0;
105    int zero() {
106        ++run_count;
107        return 0;
108    }
109
110    int one() {
111        static int b = zero();
112        return 0;
113    }
114
115    void another_helper() {
116        static int a = one();
117    }
118
119    void helper() {
120        static int a = one();
121        std::thread t(another_helper);
122        t.join();
123    }
124
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
133int 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