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 // <mutex>
11 
12 // struct once_flag;
13 
14 // template<class Callable, class ...Args>
15 //   void call_once(once_flag& flag, Callable func, Args&&... args);
16 
17 #include <mutex>
18 #include <thread>
19 #include <cassert>
20 
21 typedef std::chrono::milliseconds ms;
22 
23 std::once_flag flg0;
24 
25 int init0_called = 0;
26 
27 void init0()
28 {
29     std::this_thread::sleep_for(ms(250));
30     ++init0_called;
31 }
32 
33 void f0()
34 {
35     std::call_once(flg0, init0);
36 }
37 
38 std::once_flag flg3;
39 
40 int init3_called = 0;
41 int init3_completed = 0;
42 
43 void init3()
44 {
45     ++init3_called;
46     std::this_thread::sleep_for(ms(250));
47     if (init3_called == 1)
48         throw 1;
49     ++init3_completed;
50 }
51 
52 void f3()
53 {
54     try
55     {
56         std::call_once(flg3, init3);
57     }
58     catch (...)
59     {
60     }
61 }
62 
63 #ifndef _LIBCPP_HAS_NO_VARIADICS
64 
65 struct init1
66 {
67     static int called;
68 
69     void operator()(int i) {called += i;}
70 };
71 
72 int init1::called = 0;
73 
74 std::once_flag flg1;
75 
76 void f1()
77 {
78     std::call_once(flg1, init1(), 1);
79 }
80 
81 struct init2
82 {
83     static int called;
84 
85     void operator()(int i, int j) const {called += i + j;}
86 };
87 
88 int init2::called = 0;
89 
90 std::once_flag flg2;
91 
92 void f2()
93 {
94     std::call_once(flg2, init2(), 2, 3);
95     std::call_once(flg2, init2(), 4, 5);
96 }
97 
98 #endif  // _LIBCPP_HAS_NO_VARIADICS
99 
100 std::once_flag flg41;
101 std::once_flag flg42;
102 
103 int init41_called = 0;
104 int init42_called = 0;
105 
106 void init42();
107 
108 void init41()
109 {
110     std::this_thread::sleep_for(ms(250));
111     ++init41_called;
112 }
113 
114 void init42()
115 {
116     std::this_thread::sleep_for(ms(250));
117     ++init42_called;
118 }
119 
120 void f41()
121 {
122     std::call_once(flg41, init41);
123     std::call_once(flg42, init42);
124 }
125 
126 void f42()
127 {
128     std::call_once(flg42, init42);
129     std::call_once(flg41, init41);
130 }
131 
132 #ifndef _LIBCPP_HAS_NO_VARIADICS
133 
134 class MoveOnly
135 {
136     MoveOnly(const MoveOnly&);
137 public:
138     MoveOnly() {}
139     MoveOnly(MoveOnly&&) {}
140 
141     void operator()(MoveOnly&&)
142     {
143     }
144 };
145 
146 #endif
147 
148 int main()
149 {
150     // check basic functionality
151     {
152         std::thread t0(f0);
153         std::thread t1(f0);
154         t0.join();
155         t1.join();
156         assert(init0_called == 1);
157     }
158     // check basic exception safety
159     {
160         std::thread t0(f3);
161         std::thread t1(f3);
162         t0.join();
163         t1.join();
164         assert(init3_called == 2);
165         assert(init3_completed == 1);
166     }
167     // check deadlock avoidance
168     {
169         std::thread t0(f41);
170         std::thread t1(f42);
171         t0.join();
172         t1.join();
173         assert(init41_called == 1);
174         assert(init42_called == 1);
175     }
176 #ifndef _LIBCPP_HAS_NO_VARIADICS
177     // check functors with 1 arg
178     {
179         std::thread t0(f1);
180         std::thread t1(f1);
181         t0.join();
182         t1.join();
183         assert(init1::called == 1);
184     }
185     // check functors with 2 args
186     {
187         std::thread t0(f2);
188         std::thread t1(f2);
189         t0.join();
190         t1.join();
191         assert(init2::called == 5);
192     }
193     {
194         std::once_flag f;
195         std::call_once(f, MoveOnly(), MoveOnly());
196     }
197 #endif  // _LIBCPP_HAS_NO_VARIADICS
198 }
199