273 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: no-threads10 11// <mutex>12 13// struct once_flag;14 15// template<class Callable, class ...Args>16// void call_once(once_flag& flag, Callable&& func, Args&&... args);17 18#include <mutex>19#include <thread>20#include <cassert>21 22#include "make_test_thread.h"23#include "test_macros.h"24#include "operator_hijacker.h"25 26typedef std::chrono::milliseconds ms;27 28std::once_flag flg0;29 30int init0_called = 0;31 32void init0()33{34 std::this_thread::sleep_for(ms(250));35 ++init0_called;36}37 38void f0()39{40 std::call_once(flg0, init0);41}42 43std::once_flag flg3;44 45int init3_called = 0;46int init3_completed = 0;47 48void init3()49{50 ++init3_called;51 std::this_thread::sleep_for(ms(250));52 if (init3_called == 1)53 TEST_THROW(1);54 ++init3_completed;55}56 57void f3()58{59#ifndef TEST_HAS_NO_EXCEPTIONS60 try61 {62 std::call_once(flg3, init3);63 }64 catch (...)65 {66 }67#endif68}69 70#if TEST_STD_VER >= 1171 72struct init173{74 static int called;75 76 void operator()(int i) {called += i;}77};78 79int init1::called = 0;80 81std::once_flag flg1;82 83void f1()84{85 std::call_once(flg1, init1(), 1);86}87 88struct init289{90 static int called;91 92 void operator()(int i, int j) const {called += i + j;}93};94 95int init2::called = 0;96 97std::once_flag flg2;98 99void f2()100{101 std::call_once(flg2, init2(), 2, 3);102 std::call_once(flg2, init2(), 4, 5);103}104 105#endif // TEST_STD_VER >= 11106 107std::once_flag flg41;108std::once_flag flg42;109 110int init41_called = 0;111int init42_called = 0;112 113void init42();114 115void init41()116{117 std::this_thread::sleep_for(ms(250));118 ++init41_called;119}120 121void init42()122{123 std::this_thread::sleep_for(ms(250));124 ++init42_called;125}126 127void f41()128{129 std::call_once(flg41, init41);130 std::call_once(flg42, init42);131}132 133void f42()134{135 std::call_once(flg42, init42);136 std::call_once(flg41, init41);137}138 139#if TEST_STD_VER >= 11140 141class MoveOnly142{143#if !defined(__clang__)144 // GCC 4.8 complains about the following being private145public:146 MoveOnly(const MoveOnly&)147 {148 }149#else150 MoveOnly(const MoveOnly&);151#endif152public:153 MoveOnly() {}154 MoveOnly(MoveOnly&&) {}155 156 void operator()(MoveOnly&&)157 {158 }159};160 161class NonCopyable162{163#if !defined(__clang__)164 // GCC 4.8 complains about the following being private165public:166 NonCopyable(const NonCopyable&)167 {168 }169#else170 NonCopyable(const NonCopyable&);171#endif172public:173 NonCopyable() {}174 175 void operator()(int&) {}176};177 178// reference qualifiers on functions are a C++11 extension179struct RefQual180{181 int lv_called, rv_called;182 183 RefQual() : lv_called(0), rv_called(0) {}184 185 void operator()() & { ++lv_called; }186 void operator()() && { ++rv_called; }187};188 189#endif // TEST_STD_VER >= 11190 191int main(int, char**)192{193 // check basic functionality194 {195 std::thread t0 = support::make_test_thread(f0);196 std::thread t1 = support::make_test_thread(f0);197 t0.join();198 t1.join();199 assert(init0_called == 1);200 }201#ifndef TEST_HAS_NO_EXCEPTIONS202 // check basic exception safety203 {204 std::thread t0 = support::make_test_thread(f3);205 std::thread t1 = support::make_test_thread(f3);206 t0.join();207 t1.join();208 assert(init3_called == 2);209 assert(init3_completed == 1);210 }211#endif212 // check deadlock avoidance213 {214 std::thread t0 = support::make_test_thread(f41);215 std::thread t1 = support::make_test_thread(f42);216 t0.join();217 t1.join();218 assert(init41_called == 1);219 assert(init42_called == 1);220 }221#if TEST_STD_VER >= 11222 // check functors with 1 arg223 {224 std::thread t0 = support::make_test_thread(f1);225 std::thread t1 = support::make_test_thread(f1);226 t0.join();227 t1.join();228 assert(init1::called == 1);229 }230 // check functors with 2 args231 {232 std::thread t0 = support::make_test_thread(f2);233 std::thread t1 = support::make_test_thread(f2);234 t0.join();235 t1.join();236 assert(init2::called == 5);237 }238 {239 std::once_flag f;240 std::call_once(f, MoveOnly(), MoveOnly());241 }242 // check LWG2442: call_once() shouldn't DECAY_COPY()243 {244 std::once_flag f;245 int i = 0;246 std::call_once(f, NonCopyable(), i);247 }248// reference qualifiers on functions are a C++11 extension249 {250 std::once_flag f1, f2;251 RefQual rq;252 std::call_once(f1, rq);253 assert(rq.lv_called == 1);254 std::call_once(f2, std::move(rq));255 assert(rq.rv_called == 1);256 }257 {258 std::once_flag flag;259 auto f = [](const operator_hijacker&) {};260 std::call_once(flag, f, operator_hijacker{});261 }262 263#endif // TEST_STD_VER >= 11264 265 {266 std::once_flag flag;267 operator_hijacker f;268 std::call_once(flag, f);269 }270 271 return 0;272}273