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

source code of libcxx/test/std/thread/thread.mutex/thread.once/thread.once.callonce/call_once.pass.cpp