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