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 // Copyright (C) 2013 Vicente J. Botet Escriba
11 //
12 //  Distributed under the Boost Software License, Version 1.0. (See accompanying
13 //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
14 
15 // <boost/thread/once.hpp>
16 
17 // struct once_flag;
18 
19 // template<class Callable, class ...Args>
20 //   void call_once(once_flag& flag, Callable&& func, Args&&... args);
21 
22 //#define BOOST_THREAD_VERSION 4
23 #define BOOST_THREAD_USES_MOVE
24 #define BOOST_THREAD_PROVIDES_ONCE_CXX11
25 
26 #include <boost/thread/once.hpp>
27 #include <boost/thread/thread.hpp>
28 #include <boost/detail/lightweight_test.hpp>
29 
30 #ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
31 #define BOOST_INIT_ONCE_INIT
32 #else
33 #define BOOST_INIT_ONCE_INIT =BOOST_ONCE_INIT
34 #endif
35 
36 typedef boost::chrono::milliseconds ms;
37 
38 boost::once_flag flg0 BOOST_INIT_ONCE_INIT;
39 
40 int init0_called = 0;
41 
init0()42 void init0()
43 {
44     boost::this_thread::sleep_for(ms(250));
45     ++init0_called;
46 }
47 
f0()48 void f0()
49 {
50     boost::call_once(flg0, init0);
51 }
52 
53 boost::once_flag flg3 BOOST_INIT_ONCE_INIT;
54 
55 int init3_called = 0;
56 int init3_completed = 0;
57 
init3()58 void init3()
59 {
60     ++init3_called;
61     boost::this_thread::sleep_for(ms(250));
62     if (init3_called == 1)
63         throw 1;
64     ++init3_completed;
65 }
66 
f3()67 void f3()
68 {
69     try
70     {
71         boost::call_once(flg3, init3);
72     }
73     catch (...)
74     {
75     }
76 }
77 
78 struct init1
79 {
80     static int called;
81     typedef void result_type;
82 
operator ()init183     void operator()(int i) {called += i;}
operator ()init184     void operator()(int i) const {called += i;}
85 };
86 
87 int init1::called = 0;
88 
89 boost::once_flag flg1 BOOST_INIT_ONCE_INIT;
90 
f1()91 void f1()
92 {
93     boost::call_once(flg1, init1(), 1);
94 }
95 
96 boost::once_flag flg1_member BOOST_INIT_ONCE_INIT;
97 
98 struct init1_member
99 {
100     static int called;
101     typedef void result_type;
callinit1_member102     void call(int i) {
103       called += i;
104     }
105 };
106 int init1_member::called = 0;
107 
f1_member_l()108 void f1_member_l()
109 {
110     init1_member o;
111     int i=1;
112     boost::call_once(flg1_member, &init1_member::call, o, i);
113 }
f1_member_r()114 void f1_member_r()
115 {
116     init1_member o;
117     boost::call_once(flg1_member, &init1_member::call, o, 1);
118 }
119 struct init2
120 {
121     static int called;
122     typedef void result_type;
123 
operator ()init2124     void operator()(int i, int j) {called += i + j;}
operator ()init2125     void operator()(int i, int j) const {called += i + j;}
126 };
127 
128 int init2::called = 0;
129 
130 boost::once_flag flg2 BOOST_INIT_ONCE_INIT;
131 
f2()132 void f2()
133 {
134     boost::call_once(flg2, init2(), 2, 3);
135     boost::call_once(flg2, init2(), 4, 5);
136 }
137 
138 boost::once_flag flg41 BOOST_INIT_ONCE_INIT;
139 boost::once_flag flg42 BOOST_INIT_ONCE_INIT;
140 
141 int init41_called = 0;
142 int init42_called = 0;
143 
144 void init42();
145 
init41()146 void init41()
147 {
148     boost::this_thread::sleep_for(ms(250));
149     ++init41_called;
150 }
151 
init42()152 void init42()
153 {
154     boost::this_thread::sleep_for(ms(250));
155     ++init42_called;
156 }
157 
f41()158 void f41()
159 {
160     boost::call_once(flg41, init41);
161     boost::call_once(flg42, init42);
162 }
163 
f42()164 void f42()
165 {
166     boost::call_once(flg42, init42);
167     boost::call_once(flg41, init41);
168 }
169 
170 class MoveOnly
171 {
172 public:
173   typedef void result_type;
174 
175   BOOST_THREAD_MOVABLE_ONLY(MoveOnly)
MoveOnly()176   MoveOnly()
177   {
178   }
MoveOnly(BOOST_THREAD_RV_REF (MoveOnly))179   MoveOnly(BOOST_THREAD_RV_REF(MoveOnly))
180   {}
181 
operator ()(BOOST_THREAD_RV_REF (MoveOnly))182   void operator()(BOOST_THREAD_RV_REF(MoveOnly))
183   {
184   }
operator ()(int)185   void operator()(int)
186   {
187   }
operator ()()188   void operator()()
189   {
190   }
191 };
192 
193 
194 struct id_string
195 {
196     static boost::once_flag flag;
do_initid_string197     static void do_init(id_string & )
198     {}
operator ()id_string199     void operator()()
200     {
201       boost::call_once(flag, &id_string::do_init, boost::ref(*this));
202     }
203 //    void operator()(int,int)
204 //    {
205 //      // This should fail but works with gcc-4.6.3
206 //      //std::bind(&id_string::do_init, *this)();
207 //      std::bind(&id_string::do_init, std::ref(*this))();
208 //    }
209 //    void operator()(int) const
210 //    {
211 //      //std::bind(&id_string::do_init, *this)();
212 //    }
213 };
214 
215 
216 boost::once_flag id_string::flag BOOST_INIT_ONCE_INIT;
217 
main()218 int main()
219 {
220 
221   //
222   {
223     id_string id;
224     id();
225     //id(1,1);
226   }
227     // check basic functionality
228     {
229         boost::thread t0(f0);
230         boost::thread t1(f0);
231         t0.join();
232         t1.join();
233         BOOST_TEST(init0_called == 1);
234     }
235     // check basic exception safety
236     {
237         boost::thread t0(f3);
238         boost::thread t1(f3);
239         t0.join();
240         t1.join();
241         BOOST_TEST(init3_called == 2);
242         BOOST_TEST(init3_completed == 1);
243     }
244     // check deadlock avoidance
245     {
246         boost::thread t0(f41);
247         boost::thread t1(f42);
248         t0.join();
249         t1.join();
250         BOOST_TEST(init41_called == 1);
251         BOOST_TEST(init42_called == 1);
252     }
253     // check functors with 1 arg
254     {
255         boost::thread t0(f1);
256         boost::thread t1(f1);
257         t0.join();
258         t1.join();
259         BOOST_TEST(init1::called == 1);
260     }
261     // check functors with 2 args
262     {
263         boost::thread t0(f2);
264         boost::thread t1(f2);
265         t0.join();
266         t1.join();
267         BOOST_TEST(init2::called == 5);
268     }
269 
270     // check member function with 1 arg
271     {
272         boost::thread t0(f1_member_l);
273         boost::thread t1(f1_member_r);
274         t0.join();
275         t1.join();
276         BOOST_TEST(init1_member::called == 1);
277     }
278 #if defined BOOST_THREAD_PLATFORM_PTHREAD || (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__ > 40600)
279     {
280         boost::once_flag f BOOST_INIT_ONCE_INIT;
281         boost::call_once(f, MoveOnly());
282     }
283 #endif
284 #if defined BOOST_THREAD_PROVIDES_INVOKE
285     {
286         boost::once_flag f BOOST_INIT_ONCE_INIT;
287         boost::call_once(f, MoveOnly(), 1);
288     }
289     {
290         boost::once_flag f BOOST_INIT_ONCE_INIT;
291         boost::call_once(f, MoveOnly(), MoveOnly());
292     }
293 #endif  // BOOST_THREAD_PLATFORM_PTHREAD
294     return boost::report_errors();
295 }
296 
297 
298