• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
init0()27 void init0()
28 {
29     std::this_thread::sleep_for(ms(250));
30     ++init0_called;
31 }
32 
f0()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 
init3()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 
f3()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 
operator ()init169     void operator()(int i) {called += i;}
70 };
71 
72 int init1::called = 0;
73 
74 std::once_flag flg1;
75 
f1()76 void f1()
77 {
78     std::call_once(flg1, init1(), 1);
79 }
80 
81 struct init2
82 {
83     static int called;
84 
operator ()init285     void operator()(int i, int j) const {called += i + j;}
86 };
87 
88 int init2::called = 0;
89 
90 std::once_flag flg2;
91 
f2()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 
init41()108 void init41()
109 {
110     std::this_thread::sleep_for(ms(250));
111     ++init41_called;
112 }
113 
init42()114 void init42()
115 {
116     std::this_thread::sleep_for(ms(250));
117     ++init42_called;
118 }
119 
f41()120 void f41()
121 {
122     std::call_once(flg41, init41);
123     std::call_once(flg42, init42);
124 }
125 
f42()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 #if !defined(__clang__)
137    // GCC 4.8 complains about the following being private
138 public:
MoveOnly(const MoveOnly &)139     MoveOnly(const MoveOnly&)
140     {
141     }
142 #else
143     MoveOnly(const MoveOnly&);
144 #endif
145 public:
MoveOnly()146     MoveOnly() {}
MoveOnly(MoveOnly &&)147     MoveOnly(MoveOnly&&) {}
148 
operator ()(MoveOnly &&)149     void operator()(MoveOnly&&)
150     {
151     }
152 };
153 
154 #endif
155 
main()156 int main()
157 {
158     // check basic functionality
159     {
160         std::thread t0(f0);
161         std::thread t1(f0);
162         t0.join();
163         t1.join();
164         assert(init0_called == 1);
165     }
166     // check basic exception safety
167     {
168         std::thread t0(f3);
169         std::thread t1(f3);
170         t0.join();
171         t1.join();
172         assert(init3_called == 2);
173         assert(init3_completed == 1);
174     }
175     // check deadlock avoidance
176     {
177         std::thread t0(f41);
178         std::thread t1(f42);
179         t0.join();
180         t1.join();
181         assert(init41_called == 1);
182         assert(init42_called == 1);
183     }
184 #ifndef _LIBCPP_HAS_NO_VARIADICS
185     // check functors with 1 arg
186     {
187         std::thread t0(f1);
188         std::thread t1(f1);
189         t0.join();
190         t1.join();
191         assert(init1::called == 1);
192     }
193     // check functors with 2 args
194     {
195         std::thread t0(f2);
196         std::thread t1(f2);
197         t0.join();
198         t1.join();
199         assert(init2::called == 5);
200     }
201     {
202         std::once_flag f;
203         std::call_once(f, MoveOnly(), MoveOnly());
204     }
205 #endif  // _LIBCPP_HAS_NO_VARIADICS
206 }
207