Imported Upstream version 1.57.0
[platform/upstream/boost.git] / 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