]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/thread/include/boost/thread/pthread/once.hpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / thread / include / boost / thread / pthread / once.hpp
1 #ifndef BOOST_THREAD_PTHREAD_ONCE_HPP
2 #define BOOST_THREAD_PTHREAD_ONCE_HPP
3
4 // once.hpp
5 //
6 // (C) Copyright 2007-8 Anthony Williams
7 // (C) Copyright 2011-2012 Vicente J. Botet Escriba
8 //
9 // Distributed under the Boost Software License, Version 1.0. (See
10 // accompanying file LICENSE_1_0.txt or copy at
11 // http://www.boost.org/LICENSE_1_0.txt)
12
13 #include <boost/thread/detail/config.hpp>
14 #include <boost/thread/detail/move.hpp>
15 #include <boost/thread/detail/invoke.hpp>
16
17 #include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
18 #include <boost/thread/detail/delete.hpp>
19 #include <boost/core/no_exceptions_support.hpp>
20
21 #include <boost/bind.hpp>
22 #include <boost/assert.hpp>
23 #include <boost/config/abi_prefix.hpp>
24
25 #include <boost/cstdint.hpp>
26 #include <pthread.h>
27 #include <csignal>
28
29 namespace boost
30 {
31
32 struct once_flag;
33
34 #define BOOST_ONCE_INITIAL_FLAG_VALUE 0
35
36 namespace thread_detail
37 {
38 typedef boost::uint32_t uintmax_atomic_t;
39 #define BOOST_THREAD_DETAIL_UINTMAX_ATOMIC_C2(value) value##u
40 #define BOOST_THREAD_DETAIL_UINTMAX_ATOMIC_MAX_C BOOST_THREAD_DETAIL_UINTMAX_ATOMIC_C2(~0)
41
42 }
43
44 #ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
45 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
46 template<typename Function, class ...ArgTypes>
47 inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(ArgTypes)... args);
48 #else
49 template<typename Function>
50 inline void call_once(once_flag& flag, Function f);
51 template<typename Function, typename T1>
52 inline void call_once(once_flag& flag, Function f, T1 p1);
53 template<typename Function, typename T1, typename T2>
54 inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2);
55 template<typename Function, typename T1, typename T2, typename T3>
56 inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2, T3 p3);
57 #endif
58
59 struct once_flag
60 {
61 BOOST_THREAD_NO_COPYABLE(once_flag)
62 BOOST_CONSTEXPR once_flag() BOOST_NOEXCEPT
63 : epoch(BOOST_ONCE_INITIAL_FLAG_VALUE)
64 {}
65 private:
66 volatile thread_detail::uintmax_atomic_t epoch;
67
68 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
69 template<typename Function, class ...ArgTypes>
70 friend void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(ArgTypes)... args);
71 #else
72 template<typename Function>
73 friend void call_once(once_flag& flag, Function f);
74 template<typename Function, typename T1>
75 friend void call_once(once_flag& flag, Function f, T1 p1);
76 template<typename Function, typename T1, typename T2>
77 friend void call_once(once_flag& flag, Function f, T1 p1, T2 p2);
78 template<typename Function, typename T1, typename T2, typename T3>
79 friend void call_once(once_flag& flag, Function f, T1 p1, T2 p2, T3 p3);
80
81 #endif
82
83 };
84
85 #define BOOST_ONCE_INIT once_flag()
86
87 #else // BOOST_THREAD_PROVIDES_ONCE_CXX11
88
89 struct once_flag
90 {
91 volatile thread_detail::uintmax_atomic_t epoch;
92 };
93
94 #define BOOST_ONCE_INIT {BOOST_ONCE_INITIAL_FLAG_VALUE}
95 #endif // BOOST_THREAD_PROVIDES_ONCE_CXX11
96
97
98 #if defined BOOST_THREAD_PROVIDES_INVOKE
99 #define BOOST_THREAD_INVOKE_RET_VOID detail::invoke
100 #define BOOST_THREAD_INVOKE_RET_VOID_CALL
101 #elif defined BOOST_THREAD_PROVIDES_INVOKE_RET
102 #define BOOST_THREAD_INVOKE_RET_VOID detail::invoke<void>
103 #define BOOST_THREAD_INVOKE_RET_VOID_CALL
104 #else
105 #define BOOST_THREAD_INVOKE_RET_VOID boost::bind
106 #define BOOST_THREAD_INVOKE_RET_VOID_CALL ()
107 #endif
108
109 namespace thread_detail
110 {
111 BOOST_THREAD_DECL uintmax_atomic_t& get_once_per_thread_epoch();
112 BOOST_THREAD_DECL extern uintmax_atomic_t once_global_epoch;
113 BOOST_THREAD_DECL extern pthread_mutex_t once_epoch_mutex;
114 BOOST_THREAD_DECL extern pthread_cond_t once_epoch_cv;
115 }
116
117 // Based on Mike Burrows fast_pthread_once algorithm as described in
118 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2444.html
119
120
121 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
122
123
124 template<typename Function, class ...ArgTypes>
125 inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(ArgTypes)... args)
126 {
127 static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
128 static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1;
129 thread_detail::uintmax_atomic_t const epoch=flag.epoch;
130 thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch();
131
132 if(epoch<this_thread_epoch)
133 {
134 pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
135
136 while(flag.epoch<=being_initialized)
137 {
138 if(flag.epoch==uninitialized_flag)
139 {
140 flag.epoch=being_initialized;
141 BOOST_TRY
142 {
143 pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
144 BOOST_THREAD_INVOKE_RET_VOID(
145 thread_detail::decay_copy(boost::forward<Function>(f)),
146 thread_detail::decay_copy(boost::forward<ArgTypes>(args))...
147 ) BOOST_THREAD_INVOKE_RET_VOID_CALL;
148 }
149 BOOST_CATCH (...)
150 {
151 flag.epoch=uninitialized_flag;
152 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
153 BOOST_RETHROW
154 }
155 BOOST_CATCH_END
156 flag.epoch=--thread_detail::once_global_epoch;
157 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
158 }
159 else
160 {
161 while(flag.epoch==being_initialized)
162 {
163 BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
164 }
165 }
166 }
167 this_thread_epoch=thread_detail::once_global_epoch;
168
169 }
170 }
171 #else
172 template<typename Function>
173 inline void call_once(once_flag& flag, Function f)
174 {
175 static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
176 static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1;
177 thread_detail::uintmax_atomic_t const epoch=flag.epoch;
178 thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch();
179
180 if(epoch<this_thread_epoch)
181 {
182 pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
183
184 while(flag.epoch<=being_initialized)
185 {
186 if(flag.epoch==uninitialized_flag)
187 {
188 flag.epoch=being_initialized;
189 BOOST_TRY
190 {
191 pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
192 f();
193 }
194 BOOST_CATCH (...)
195 {
196 flag.epoch=uninitialized_flag;
197 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
198 BOOST_RETHROW
199 }
200 BOOST_CATCH_END
201 flag.epoch=--thread_detail::once_global_epoch;
202 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
203 }
204 else
205 {
206 while(flag.epoch==being_initialized)
207 {
208 BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
209 }
210 }
211 }
212 this_thread_epoch=thread_detail::once_global_epoch;
213 }
214 }
215
216 template<typename Function, typename T1>
217 inline void call_once(once_flag& flag, Function f, T1 p1)
218 {
219 static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
220 static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1;
221 thread_detail::uintmax_atomic_t const epoch=flag.epoch;
222 thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch();
223
224 if(epoch<this_thread_epoch)
225 {
226 pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
227
228 while(flag.epoch<=being_initialized)
229 {
230 if(flag.epoch==uninitialized_flag)
231 {
232 flag.epoch=being_initialized;
233 BOOST_TRY
234 {
235 pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
236 BOOST_THREAD_INVOKE_RET_VOID(f,p1) BOOST_THREAD_INVOKE_RET_VOID_CALL;
237 }
238 BOOST_CATCH (...)
239 {
240 flag.epoch=uninitialized_flag;
241 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
242 BOOST_RETHROW
243 }
244 BOOST_CATCH_END
245 flag.epoch=--thread_detail::once_global_epoch;
246 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
247 }
248 else
249 {
250 while(flag.epoch==being_initialized)
251 {
252 BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
253 }
254 }
255 }
256 this_thread_epoch=thread_detail::once_global_epoch;
257 }
258 }
259 template<typename Function, typename T1, typename T2>
260 inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2)
261 {
262 static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
263 static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1;
264 thread_detail::uintmax_atomic_t const epoch=flag.epoch;
265 thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch();
266
267 if(epoch<this_thread_epoch)
268 {
269 pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
270
271 while(flag.epoch<=being_initialized)
272 {
273 if(flag.epoch==uninitialized_flag)
274 {
275 flag.epoch=being_initialized;
276 BOOST_TRY
277 {
278 pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
279 BOOST_THREAD_INVOKE_RET_VOID(f,p1, p2) BOOST_THREAD_INVOKE_RET_VOID_CALL;
280 }
281 BOOST_CATCH (...)
282 {
283 flag.epoch=uninitialized_flag;
284 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
285 BOOST_RETHROW
286 }
287 BOOST_CATCH_END
288 flag.epoch=--thread_detail::once_global_epoch;
289 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
290 }
291 else
292 {
293 while(flag.epoch==being_initialized)
294 {
295 BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
296 }
297 }
298 }
299 this_thread_epoch=thread_detail::once_global_epoch;
300 }
301 }
302
303 template<typename Function, typename T1, typename T2, typename T3>
304 inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2, T3 p3)
305 {
306 static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
307 static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1;
308 thread_detail::uintmax_atomic_t const epoch=flag.epoch;
309 thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch();
310
311 if(epoch<this_thread_epoch)
312 {
313 pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
314
315 while(flag.epoch<=being_initialized)
316 {
317 if(flag.epoch==uninitialized_flag)
318 {
319 flag.epoch=being_initialized;
320 BOOST_TRY
321 {
322 pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
323 BOOST_THREAD_INVOKE_RET_VOID(f,p1, p2, p3) BOOST_THREAD_INVOKE_RET_VOID_CALL;
324 }
325 BOOST_CATCH (...)
326 {
327 flag.epoch=uninitialized_flag;
328 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
329 BOOST_RETHROW
330 }
331 BOOST_CATCH_END
332 flag.epoch=--thread_detail::once_global_epoch;
333 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
334 }
335 else
336 {
337 while(flag.epoch==being_initialized)
338 {
339 BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
340 }
341 }
342 }
343 this_thread_epoch=thread_detail::once_global_epoch;
344 }
345 }
346
347 template<typename Function>
348 inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f)
349 {
350 static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
351 static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1;
352 thread_detail::uintmax_atomic_t const epoch=flag.epoch;
353 thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch();
354
355 if(epoch<this_thread_epoch)
356 {
357 pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
358
359 while(flag.epoch<=being_initialized)
360 {
361 if(flag.epoch==uninitialized_flag)
362 {
363 flag.epoch=being_initialized;
364 BOOST_TRY
365 {
366 pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
367 f();
368 }
369 BOOST_CATCH (...)
370 {
371 flag.epoch=uninitialized_flag;
372 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
373 BOOST_RETHROW
374 }
375 BOOST_CATCH_END
376 flag.epoch=--thread_detail::once_global_epoch;
377 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
378 }
379 else
380 {
381 while(flag.epoch==being_initialized)
382 {
383 BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
384 }
385 }
386 }
387 this_thread_epoch=thread_detail::once_global_epoch;
388 }
389 }
390
391 template<typename Function, typename T1>
392 inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1)
393 {
394 static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
395 static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1;
396 thread_detail::uintmax_atomic_t const epoch=flag.epoch;
397 thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch();
398
399 if(epoch<this_thread_epoch)
400 {
401 pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
402
403 while(flag.epoch<=being_initialized)
404 {
405 if(flag.epoch==uninitialized_flag)
406 {
407 flag.epoch=being_initialized;
408 BOOST_TRY
409 {
410 pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
411 BOOST_THREAD_INVOKE_RET_VOID(
412 thread_detail::decay_copy(boost::forward<Function>(f)),
413 thread_detail::decay_copy(boost::forward<T1>(p1))
414 ) BOOST_THREAD_INVOKE_RET_VOID_CALL;
415 }
416 BOOST_CATCH (...)
417 {
418 flag.epoch=uninitialized_flag;
419 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
420 BOOST_RETHROW
421 }
422 BOOST_CATCH_END
423 flag.epoch=--thread_detail::once_global_epoch;
424 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
425 }
426 else
427 {
428 while(flag.epoch==being_initialized)
429 {
430 BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
431 }
432 }
433 }
434 this_thread_epoch=thread_detail::once_global_epoch;
435 }
436 }
437 template<typename Function, typename T1, typename T2>
438 inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2)
439 {
440 static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
441 static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1;
442 thread_detail::uintmax_atomic_t const epoch=flag.epoch;
443 thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch();
444
445 if(epoch<this_thread_epoch)
446 {
447 pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
448
449 while(flag.epoch<=being_initialized)
450 {
451 if(flag.epoch==uninitialized_flag)
452 {
453 flag.epoch=being_initialized;
454 BOOST_TRY
455 {
456 pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
457 BOOST_THREAD_INVOKE_RET_VOID(
458 thread_detail::decay_copy(boost::forward<Function>(f)),
459 thread_detail::decay_copy(boost::forward<T1>(p1)),
460 thread_detail::decay_copy(boost::forward<T1>(p2))
461 ) BOOST_THREAD_INVOKE_RET_VOID_CALL;
462 }
463 BOOST_CATCH (...)
464 {
465 flag.epoch=uninitialized_flag;
466 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
467 BOOST_RETHROW
468 }
469 BOOST_CATCH_END
470 flag.epoch=--thread_detail::once_global_epoch;
471 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
472 }
473 else
474 {
475 while(flag.epoch==being_initialized)
476 {
477 BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
478 }
479 }
480 }
481 this_thread_epoch=thread_detail::once_global_epoch;
482 }
483 }
484
485 template<typename Function, typename T1, typename T2, typename T3>
486 inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2, BOOST_THREAD_RV_REF(T3) p3)
487 {
488 static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
489 static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1;
490 thread_detail::uintmax_atomic_t const epoch=flag.epoch;
491 thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch();
492
493 if(epoch<this_thread_epoch)
494 {
495 pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
496
497 while(flag.epoch<=being_initialized)
498 {
499 if(flag.epoch==uninitialized_flag)
500 {
501 flag.epoch=being_initialized;
502 BOOST_TRY
503 {
504 pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
505 BOOST_THREAD_INVOKE_RET_VOID(
506 thread_detail::decay_copy(boost::forward<Function>(f)),
507 thread_detail::decay_copy(boost::forward<T1>(p1)),
508 thread_detail::decay_copy(boost::forward<T1>(p2)),
509 thread_detail::decay_copy(boost::forward<T1>(p3))
510 ) BOOST_THREAD_INVOKE_RET_VOID_CALL;
511 }
512 BOOST_CATCH (...)
513 {
514 flag.epoch=uninitialized_flag;
515 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
516 BOOST_RETHROW
517 }
518 BOOST_CATCH_END
519 flag.epoch=--thread_detail::once_global_epoch;
520 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
521 }
522 else
523 {
524 while(flag.epoch==being_initialized)
525 {
526 BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
527 }
528 }
529 }
530 this_thread_epoch=thread_detail::once_global_epoch;
531 }
532 }
533
534 #endif
535
536 }
537
538 #include <boost/config/abi_suffix.hpp>
539
540 #endif