brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.0 KiB · 121705f Raw
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