blob: 89b99348459be646432c2aad702bdf259b75b2cb [file] [log] [blame]
Howard Hinnantbc8d3f92010-05-11 19:42:16 +00001//===----------------------------------------------------------------------===//
2//
Howard Hinnantf5256e12010-05-11 21:36:01 +00003// The LLVM Compiler Infrastructure
Howard Hinnantbc8d3f92010-05-11 19:42:16 +00004//
Howard Hinnantb64f8b02010-11-16 22:09:02 +00005// This file is dual licensed under the MIT and the University of Illinois Open
6// Source Licenses. See LICENSE.TXT for details.
Howard Hinnantbc8d3f92010-05-11 19:42:16 +00007//
8//===----------------------------------------------------------------------===//
Jonathan Roelofs8d86b2e2014-09-05 19:45:05 +00009//
10// UNSUPPORTED: libcpp-has-no-threads
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000011
12// <mutex>
13
14// struct once_flag;
15
16// template<class Callable, class ...Args>
Eric Fiselierbc1e44d2015-06-13 02:23:00 +000017// void call_once(once_flag& flag, Callable&& func, Args&&... args);
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000018
19#include <mutex>
20#include <thread>
21#include <cassert>
22
23typedef std::chrono::milliseconds ms;
24
25std::once_flag flg0;
26
27int init0_called = 0;
28
29void init0()
30{
31 std::this_thread::sleep_for(ms(250));
32 ++init0_called;
33}
34
35void f0()
36{
37 std::call_once(flg0, init0);
38}
39
40std::once_flag flg3;
41
42int init3_called = 0;
43int init3_completed = 0;
44
45void 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
54void 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
67struct init1
68{
69 static int called;
70
71 void operator()(int i) {called += i;}
72};
73
74int init1::called = 0;
75
76std::once_flag flg1;
77
78void f1()
79{
80 std::call_once(flg1, init1(), 1);
81}
82
83struct init2
84{
85 static int called;
86
87 void operator()(int i, int j) const {called += i + j;}
88};
89
90int init2::called = 0;
91
92std::once_flag flg2;
93
94void f2()
95{
96 std::call_once(flg2, init2(), 2, 3);
97 std::call_once(flg2, init2(), 4, 5);
98}
99
Howard Hinnantf11ea142010-08-22 00:50:25 +0000100#endif // _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000101
102std::once_flag flg41;
103std::once_flag flg42;
104
105int init41_called = 0;
106int init42_called = 0;
107
108void init42();
109
110void init41()
111{
112 std::this_thread::sleep_for(ms(250));
113 ++init41_called;
114}
115
116void init42()
117{
118 std::this_thread::sleep_for(ms(250));
119 ++init42_called;
120}
121
122void f41()
123{
124 std::call_once(flg41, init41);
125 std::call_once(flg42, init42);
126}
127
128void f42()
129{
130 std::call_once(flg42, init42);
131 std::call_once(flg41, init41);
132}
133
Howard Hinnantad935d52011-05-16 19:05:11 +0000134#ifndef _LIBCPP_HAS_NO_VARIADICS
135
136class MoveOnly
137{
Jonathan Roelofs8d86b2e2014-09-05 19:45:05 +0000138#if !defined(__clang__)
139 // GCC 4.8 complains about the following being private
140public:
141 MoveOnly(const MoveOnly&)
142 {
143 }
144#else
Howard Hinnantad935d52011-05-16 19:05:11 +0000145 MoveOnly(const MoveOnly&);
Jonathan Roelofs8d86b2e2014-09-05 19:45:05 +0000146#endif
Howard Hinnantad935d52011-05-16 19:05:11 +0000147public:
148 MoveOnly() {}
149 MoveOnly(MoveOnly&&) {}
150
151 void operator()(MoveOnly&&)
152 {
153 }
154};
155
Eric Fiselierbc1e44d2015-06-13 02:23:00 +0000156class NonCopyable
157{
158#if !defined(__clang__)
159 // GCC 4.8 complains about the following being private
160public:
161 NonCopyable(const NonCopyable&)
162 {
163 }
164#else
165 NonCopyable(const NonCopyable&);
166#endif
167public:
168 NonCopyable() {}
169
170 void operator()(int&) {}
171};
172
173#if __cplusplus >= 201103L
174// reference qualifiers on functions are a C++11 extension
175struct 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
Howard Hinnantad935d52011-05-16 19:05:11 +0000185#endif
186
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000187int 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 }
Howard Hinnantad935d52011-05-16 19:05:11 +0000232 {
233 std::once_flag f;
234 std::call_once(f, MoveOnly(), MoveOnly());
235 }
Eric Fiselierbc1e44d2015-06-13 02:23:00 +0000236 // 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
Howard Hinnantf11ea142010-08-22 00:50:25 +0000253#endif // _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000254}