1 //===----------------------------------------------------------------------===// 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 // UNSUPPORTED: libcpp-has-no-threads 11 12 // <mutex> 13 14 // struct once_flag; 15 16 // template<class Callable, class ...Args> 17 // void call_once(once_flag& flag, Callable&& func, Args&&... args); 18 19 #include <mutex> 20 #include <thread> 21 #include <cassert> 22 23 typedef std::chrono::milliseconds ms; 24 25 std::once_flag flg0; 26 27 int init0_called = 0; 28 29 void init0() 30 { 31 std::this_thread::sleep_for(ms(250)); 32 ++init0_called; 33 } 34 35 void f0() 36 { 37 std::call_once(flg0, init0); 38 } 39 40 std::once_flag flg3; 41 42 int init3_called = 0; 43 int init3_completed = 0; 44 45 void init3() 46 { 47 ++init3_called; 48 std::this_thread::sleep_for(ms(250)); 49 if (init3_called == 1) 50 throw 1; 51 ++init3_completed; 52 } 53 54 void f3() 55 { 56 try 57 { 58 std::call_once(flg3, init3); 59 } 60 catch (...) 61 { 62 } 63 } 64 65 #ifndef _LIBCPP_HAS_NO_VARIADICS 66 67 struct init1 68 { 69 static int called; 70 71 void operator()(int i) {called += i;} 72 }; 73 74 int init1::called = 0; 75 76 std::once_flag flg1; 77 78 void f1() 79 { 80 std::call_once(flg1, init1(), 1); 81 } 82 83 struct init2 84 { 85 static int called; 86 87 void operator()(int i, int j) const {called += i + j;} 88 }; 89 90 int init2::called = 0; 91 92 std::once_flag flg2; 93 94 void f2() 95 { 96 std::call_once(flg2, init2(), 2, 3); 97 std::call_once(flg2, init2(), 4, 5); 98 } 99 100 #endif // _LIBCPP_HAS_NO_VARIADICS 101 102 std::once_flag flg41; 103 std::once_flag flg42; 104 105 int init41_called = 0; 106 int init42_called = 0; 107 108 void init42(); 109 110 void init41() 111 { 112 std::this_thread::sleep_for(ms(250)); 113 ++init41_called; 114 } 115 116 void init42() 117 { 118 std::this_thread::sleep_for(ms(250)); 119 ++init42_called; 120 } 121 122 void f41() 123 { 124 std::call_once(flg41, init41); 125 std::call_once(flg42, init42); 126 } 127 128 void f42() 129 { 130 std::call_once(flg42, init42); 131 std::call_once(flg41, init41); 132 } 133 134 #ifndef _LIBCPP_HAS_NO_VARIADICS 135 136 class MoveOnly 137 { 138 #if !defined(__clang__) 139 // GCC 4.8 complains about the following being private 140 public: 141 MoveOnly(const MoveOnly&) 142 { 143 } 144 #else 145 MoveOnly(const MoveOnly&); 146 #endif 147 public: 148 MoveOnly() {} 149 MoveOnly(MoveOnly&&) {} 150 151 void operator()(MoveOnly&&) 152 { 153 } 154 }; 155 156 class NonCopyable 157 { 158 #if !defined(__clang__) 159 // GCC 4.8 complains about the following being private 160 public: 161 NonCopyable(const NonCopyable&) 162 { 163 } 164 #else 165 NonCopyable(const NonCopyable&); 166 #endif 167 public: 168 NonCopyable() {} 169 170 void operator()(int&) {} 171 }; 172 173 #if __cplusplus >= 201103L 174 // reference qualifiers on functions are a C++11 extension 175 struct RefQual 176 { 177 int lv_called, rv_called; 178 179 RefQual() : lv_called(0), rv_called(0) {} 180 181 void operator()() & { ++lv_called; } 182 void operator()() && { ++rv_called; } 183 }; 184 #endif 185 #endif 186 187 int main() 188 { 189 // check basic functionality 190 { 191 std::thread t0(f0); 192 std::thread t1(f0); 193 t0.join(); 194 t1.join(); 195 assert(init0_called == 1); 196 } 197 // check basic exception safety 198 { 199 std::thread t0(f3); 200 std::thread t1(f3); 201 t0.join(); 202 t1.join(); 203 assert(init3_called == 2); 204 assert(init3_completed == 1); 205 } 206 // check deadlock avoidance 207 { 208 std::thread t0(f41); 209 std::thread t1(f42); 210 t0.join(); 211 t1.join(); 212 assert(init41_called == 1); 213 assert(init42_called == 1); 214 } 215 #ifndef _LIBCPP_HAS_NO_VARIADICS 216 // check functors with 1 arg 217 { 218 std::thread t0(f1); 219 std::thread t1(f1); 220 t0.join(); 221 t1.join(); 222 assert(init1::called == 1); 223 } 224 // check functors with 2 args 225 { 226 std::thread t0(f2); 227 std::thread t1(f2); 228 t0.join(); 229 t1.join(); 230 assert(init2::called == 5); 231 } 232 { 233 std::once_flag f; 234 std::call_once(f, MoveOnly(), MoveOnly()); 235 } 236 // check LWG2442: call_once() shouldn't DECAY_COPY() 237 { 238 std::once_flag f; 239 int i = 0; 240 std::call_once(f, NonCopyable(), i); 241 } 242 #if __cplusplus >= 201103L 243 // reference qualifiers on functions are a C++11 extension 244 { 245 std::once_flag f1, f2; 246 RefQual rq; 247 std::call_once(f1, rq); 248 assert(rq.lv_called == 1); 249 std::call_once(f2, std::move(rq)); 250 assert(rq.rv_called == 1); 251 } 252 #endif 253 #endif // _LIBCPP_HAS_NO_VARIADICS 254 } 255