1 #ifndef BOOST_THREAD_PTHREAD_ONCE_HPP
2 #define BOOST_THREAD_PTHREAD_ONCE_HPP
6 // (C) Copyright 2007-8 Anthony Williams
7 // (C) Copyright 2011-2012 Vicente J. Botet Escriba
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)
13 #include <boost/thread/detail/config.hpp>
14 #include <boost/thread/detail/move.hpp>
15 #include <boost/thread/detail/invoke.hpp>
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>
21 #include <boost/bind.hpp>
22 #include <boost/assert.hpp>
23 #include <boost/config/abi_prefix.hpp>
25 #include <boost/cstdint.hpp>
34 #define BOOST_ONCE_INITIAL_FLAG_VALUE 0
36 namespace thread_detail
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)
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);
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);
61 BOOST_THREAD_NO_COPYABLE(once_flag)
62 BOOST_CONSTEXPR once_flag() BOOST_NOEXCEPT
63 : epoch(BOOST_ONCE_INITIAL_FLAG_VALUE)
66 volatile thread_detail::uintmax_atomic_t epoch;
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);
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);
85 #define BOOST_ONCE_INIT once_flag()
87 #else // BOOST_THREAD_PROVIDES_ONCE_CXX11
91 volatile thread_detail::uintmax_atomic_t epoch;
94 #define BOOST_ONCE_INIT {BOOST_ONCE_INITIAL_FLAG_VALUE}
95 #endif // BOOST_THREAD_PROVIDES_ONCE_CXX11
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
105 #define BOOST_THREAD_INVOKE_RET_VOID boost::bind
106 #define BOOST_THREAD_INVOKE_RET_VOID_CALL ()
109 namespace thread_detail
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;
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
121 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
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)
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();
132 if(epoch<this_thread_epoch)
134 pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
136 while(flag.epoch<=being_initialized)
138 if(flag.epoch==uninitialized_flag)
140 flag.epoch=being_initialized;
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;
151 flag.epoch=uninitialized_flag;
152 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
156 flag.epoch=--thread_detail::once_global_epoch;
157 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
161 while(flag.epoch==being_initialized)
163 BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
167 this_thread_epoch=thread_detail::once_global_epoch;
172 template<typename Function>
173 inline void call_once(once_flag& flag, Function f)
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();
180 if(epoch<this_thread_epoch)
182 pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
184 while(flag.epoch<=being_initialized)
186 if(flag.epoch==uninitialized_flag)
188 flag.epoch=being_initialized;
191 pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
196 flag.epoch=uninitialized_flag;
197 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
201 flag.epoch=--thread_detail::once_global_epoch;
202 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
206 while(flag.epoch==being_initialized)
208 BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
212 this_thread_epoch=thread_detail::once_global_epoch;
216 template<typename Function, typename T1>
217 inline void call_once(once_flag& flag, Function f, T1 p1)
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();
224 if(epoch<this_thread_epoch)
226 pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
228 while(flag.epoch<=being_initialized)
230 if(flag.epoch==uninitialized_flag)
232 flag.epoch=being_initialized;
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;
240 flag.epoch=uninitialized_flag;
241 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
245 flag.epoch=--thread_detail::once_global_epoch;
246 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
250 while(flag.epoch==being_initialized)
252 BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
256 this_thread_epoch=thread_detail::once_global_epoch;
259 template<typename Function, typename T1, typename T2>
260 inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2)
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();
267 if(epoch<this_thread_epoch)
269 pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
271 while(flag.epoch<=being_initialized)
273 if(flag.epoch==uninitialized_flag)
275 flag.epoch=being_initialized;
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;
283 flag.epoch=uninitialized_flag;
284 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
288 flag.epoch=--thread_detail::once_global_epoch;
289 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
293 while(flag.epoch==being_initialized)
295 BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
299 this_thread_epoch=thread_detail::once_global_epoch;
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)
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();
311 if(epoch<this_thread_epoch)
313 pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
315 while(flag.epoch<=being_initialized)
317 if(flag.epoch==uninitialized_flag)
319 flag.epoch=being_initialized;
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;
327 flag.epoch=uninitialized_flag;
328 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
332 flag.epoch=--thread_detail::once_global_epoch;
333 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
337 while(flag.epoch==being_initialized)
339 BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
343 this_thread_epoch=thread_detail::once_global_epoch;
347 template<typename Function>
348 inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f)
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();
355 if(epoch<this_thread_epoch)
357 pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
359 while(flag.epoch<=being_initialized)
361 if(flag.epoch==uninitialized_flag)
363 flag.epoch=being_initialized;
366 pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
371 flag.epoch=uninitialized_flag;
372 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
376 flag.epoch=--thread_detail::once_global_epoch;
377 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
381 while(flag.epoch==being_initialized)
383 BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
387 this_thread_epoch=thread_detail::once_global_epoch;
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)
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();
399 if(epoch<this_thread_epoch)
401 pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
403 while(flag.epoch<=being_initialized)
405 if(flag.epoch==uninitialized_flag)
407 flag.epoch=being_initialized;
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;
418 flag.epoch=uninitialized_flag;
419 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
423 flag.epoch=--thread_detail::once_global_epoch;
424 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
428 while(flag.epoch==being_initialized)
430 BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
434 this_thread_epoch=thread_detail::once_global_epoch;
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)
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();
445 if(epoch<this_thread_epoch)
447 pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
449 while(flag.epoch<=being_initialized)
451 if(flag.epoch==uninitialized_flag)
453 flag.epoch=being_initialized;
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;
465 flag.epoch=uninitialized_flag;
466 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
470 flag.epoch=--thread_detail::once_global_epoch;
471 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
475 while(flag.epoch==being_initialized)
477 BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
481 this_thread_epoch=thread_detail::once_global_epoch;
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)
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();
493 if(epoch<this_thread_epoch)
495 pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
497 while(flag.epoch<=being_initialized)
499 if(flag.epoch==uninitialized_flag)
501 flag.epoch=being_initialized;
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;
514 flag.epoch=uninitialized_flag;
515 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
519 flag.epoch=--thread_detail::once_global_epoch;
520 BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
524 while(flag.epoch==being_initialized)
526 BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
530 this_thread_epoch=thread_detail::once_global_epoch;
538 #include <boost/config/abi_suffix.hpp>