1 #ifndef BOOST_THREAD_PTHREAD_ONCE_ATOMIC_HPP
2 #define BOOST_THREAD_PTHREAD_ONCE_ATOMIC_HPP
3 
4 //  once.hpp
5 //
6 //  (C) Copyright 2013 Andrey Semashev
7 //  (C) Copyright 2013 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 
15 #include <boost/cstdint.hpp>
16 #include <boost/thread/detail/move.hpp>
17 #include <boost/thread/detail/invoke.hpp>
18 #include <boost/core/no_exceptions_support.hpp>
19 #include <boost/bind.hpp>
20 #include <boost/atomic.hpp>
21 
22 #include <boost/config/abi_prefix.hpp>
23 
24 namespace boost
25 {
26 
27   struct once_flag;
28 
29   namespace thread_detail
30   {
31 
32 #if BOOST_ATOMIC_INT_LOCK_FREE == 2
33     typedef unsigned int atomic_int_type;
34 #elif BOOST_ATOMIC_SHORT_LOCK_FREE == 2
35     typedef unsigned short atomic_int_type;
36 #elif BOOST_ATOMIC_CHAR_LOCK_FREE == 2
37     typedef unsigned char atomic_int_type;
38 #elif BOOST_ATOMIC_LONG_LOCK_FREE == 2
39     typedef unsigned long atomic_int_type;
40 #elif defined(BOOST_HAS_LONG_LONG) && BOOST_ATOMIC_LLONG_LOCK_FREE == 2
41     typedef ulong_long_type atomic_int_type;
42 #else
43     // All tested integer types are not atomic, the spinlock pool will be used
44     typedef unsigned int atomic_int_type;
45 #endif
46 
47     typedef boost::atomic<atomic_int_type> atomic_type;
48 
49     BOOST_THREAD_DECL bool enter_once_region(once_flag& flag) BOOST_NOEXCEPT;
50     BOOST_THREAD_DECL void commit_once_region(once_flag& flag) BOOST_NOEXCEPT;
51     BOOST_THREAD_DECL void rollback_once_region(once_flag& flag) BOOST_NOEXCEPT;
52     inline atomic_type& get_atomic_storage(once_flag& flag)  BOOST_NOEXCEPT;
53   }
54 
55 #ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
56 
57   struct once_flag
58   {
BOOST_THREAD_NO_COPYABLEboost::once_flag59     BOOST_THREAD_NO_COPYABLE(once_flag)
60     BOOST_CONSTEXPR once_flag() BOOST_NOEXCEPT : storage(0)
61     {
62     }
63 
64   private:
65     thread_detail::atomic_type storage;
66 
67     friend BOOST_THREAD_DECL bool thread_detail::enter_once_region(once_flag& flag) BOOST_NOEXCEPT;
68     friend BOOST_THREAD_DECL void thread_detail::commit_once_region(once_flag& flag) BOOST_NOEXCEPT;
69     friend BOOST_THREAD_DECL void thread_detail::rollback_once_region(once_flag& flag) BOOST_NOEXCEPT;
70     friend thread_detail::atomic_type& thread_detail::get_atomic_storage(once_flag& flag) BOOST_NOEXCEPT;
71   };
72 
73 #define BOOST_ONCE_INIT boost::once_flag()
74 
75   namespace thread_detail
76   {
get_atomic_storage(once_flag & flag)77     inline atomic_type& get_atomic_storage(once_flag& flag) BOOST_NOEXCEPT
78     {
79       //return reinterpret_cast< atomic_type& >(flag.storage);
80       return flag.storage;
81     }
82   }
83 
84 #else // BOOST_THREAD_PROVIDES_ONCE_CXX11
85   struct once_flag
86   {
87     // The thread_detail::atomic_int_type storage is marked
88     // with this attribute in order to let the compiler know that it will alias this member
89     // and silence compilation warnings.
90     BOOST_THREAD_ATTRIBUTE_MAY_ALIAS thread_detail::atomic_int_type storage;
91   };
92 
93   #define BOOST_ONCE_INIT {0}
94 
95   namespace thread_detail
96   {
get_atomic_storage(once_flag & flag)97     inline atomic_type& get_atomic_storage(once_flag& flag) BOOST_NOEXCEPT
98     {
99       return reinterpret_cast< atomic_type& >(flag.storage);
100     }
101 
102   }
103 
104 #endif // BOOST_THREAD_PROVIDES_ONCE_CXX11
105 
106 #if defined BOOST_THREAD_PROVIDES_INVOKE
107 #define BOOST_THREAD_INVOKE_RET_VOID detail::invoke
108 #define BOOST_THREAD_INVOKE_RET_VOID_CALL
109 #elif defined BOOST_THREAD_PROVIDES_INVOKE_RET
110 #define BOOST_THREAD_INVOKE_RET_VOID detail::invoke<void>
111 #define BOOST_THREAD_INVOKE_RET_VOID_CALL
112 #else
113 #define BOOST_THREAD_INVOKE_RET_VOID boost::bind
114 #define BOOST_THREAD_INVOKE_RET_VOID_CALL ()
115 #endif
116 
117 
118 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
119 
120   template<typename Function, class ...ArgTypes>
call_once(once_flag & flag,BOOST_THREAD_RV_REF (Function)f,BOOST_THREAD_RV_REF (ArgTypes)...args)121   inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(ArgTypes)... args)
122   {
123     if (thread_detail::enter_once_region(flag))
124     {
125       BOOST_TRY
126       {
127         BOOST_THREAD_INVOKE_RET_VOID(
128                         thread_detail::decay_copy(boost::forward<Function>(f)),
129                         thread_detail::decay_copy(boost::forward<ArgTypes>(args))...
130         ) BOOST_THREAD_INVOKE_RET_VOID_CALL;
131       }
132       BOOST_CATCH (...)
133       {
134         thread_detail::rollback_once_region(flag);
135         BOOST_RETHROW
136       }
137       BOOST_CATCH_END
138       thread_detail::commit_once_region(flag);
139     }
140   }
141 #else
142   template<typename Function>
call_once(once_flag & flag,Function f)143   inline void call_once(once_flag& flag, Function f)
144   {
145     if (thread_detail::enter_once_region(flag))
146     {
147       BOOST_TRY
148       {
149         f();
150       }
151       BOOST_CATCH (...)
152       {
153         thread_detail::rollback_once_region(flag);
154         BOOST_RETHROW
155       }
156       BOOST_CATCH_END
157       thread_detail::commit_once_region(flag);
158     }
159   }
160 
161   template<typename Function, typename T1>
call_once(once_flag & flag,Function f,T1 p1)162   inline void call_once(once_flag& flag, Function f, T1 p1)
163   {
164     if (thread_detail::enter_once_region(flag))
165     {
166       BOOST_TRY
167       {
168         BOOST_THREAD_INVOKE_RET_VOID(f, p1) BOOST_THREAD_INVOKE_RET_VOID_CALL;
169       }
170       BOOST_CATCH (...)
171       {
172         thread_detail::rollback_once_region(flag);
173         BOOST_RETHROW
174       }
175       BOOST_CATCH_END
176       thread_detail::commit_once_region(flag);
177     }
178   }
179 
180   template<typename Function, typename T1, typename T2>
call_once(once_flag & flag,Function f,T1 p1,T2 p2)181   inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2)
182   {
183     if (thread_detail::enter_once_region(flag))
184     {
185       BOOST_TRY
186       {
187         BOOST_THREAD_INVOKE_RET_VOID(f, p1, p2) BOOST_THREAD_INVOKE_RET_VOID_CALL;
188       }
189       BOOST_CATCH (...)
190       {
191         thread_detail::rollback_once_region(flag);
192         BOOST_RETHROW
193       }
194       BOOST_CATCH_END
195       thread_detail::commit_once_region(flag);
196     }
197   }
198 
199   template<typename Function, typename T1, typename T2, typename T3>
call_once(once_flag & flag,Function f,T1 p1,T2 p2,T3 p3)200   inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2, T3 p3)
201   {
202     if (thread_detail::enter_once_region(flag))
203     {
204       BOOST_TRY
205       {
206         BOOST_THREAD_INVOKE_RET_VOID(f, p1, p2, p3) BOOST_THREAD_INVOKE_RET_VOID_CALL;
207       }
208       BOOST_CATCH (...)
209       {
210         thread_detail::rollback_once_region(flag);
211         BOOST_RETHROW
212       }
213       BOOST_CATCH_END
214       thread_detail::commit_once_region(flag);
215     }
216   }
217 
218   template<typename Function>
call_once(once_flag & flag,BOOST_THREAD_RV_REF (Function)f)219   inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f)
220   {
221     if (thread_detail::enter_once_region(flag))
222     {
223       BOOST_TRY
224       {
225         f();
226       }
227       BOOST_CATCH (...)
228       {
229         thread_detail::rollback_once_region(flag);
230         BOOST_RETHROW
231       }
232       BOOST_CATCH_END
233       thread_detail::commit_once_region(flag);
234     }
235   }
236 
237   template<typename Function, typename T1>
call_once(once_flag & flag,BOOST_THREAD_RV_REF (Function)f,BOOST_THREAD_RV_REF (T1)p1)238   inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1)
239   {
240     if (thread_detail::enter_once_region(flag))
241     {
242       BOOST_TRY
243       {
244         BOOST_THREAD_INVOKE_RET_VOID(
245             thread_detail::decay_copy(boost::forward<Function>(f)),
246             thread_detail::decay_copy(boost::forward<T1>(p1))
247         ) BOOST_THREAD_INVOKE_RET_VOID_CALL;
248       }
249       BOOST_CATCH (...)
250       {
251         thread_detail::rollback_once_region(flag);
252         BOOST_RETHROW
253       }
254       BOOST_CATCH_END
255       thread_detail::commit_once_region(flag);
256     }
257   }
258   template<typename Function, typename T1, typename T2>
call_once(once_flag & flag,BOOST_THREAD_RV_REF (Function)f,BOOST_THREAD_RV_REF (T1)p1,BOOST_THREAD_RV_REF (T2)p2)259   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)
260   {
261     if (thread_detail::enter_once_region(flag))
262     {
263       BOOST_TRY
264       {
265         BOOST_THREAD_INVOKE_RET_VOID(
266             thread_detail::decay_copy(boost::forward<Function>(f)),
267             thread_detail::decay_copy(boost::forward<T1>(p1)),
268             thread_detail::decay_copy(boost::forward<T1>(p2))
269         ) BOOST_THREAD_INVOKE_RET_VOID_CALL;
270       }
271       BOOST_CATCH (...)
272       {
273         thread_detail::rollback_once_region(flag);
274         BOOST_RETHROW
275       }
276       BOOST_CATCH_END
277       thread_detail::commit_once_region(flag);
278     }
279   }
280   template<typename Function, typename T1, typename T2, typename T3>
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)281   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)
282   {
283     if (thread_detail::enter_once_region(flag))
284     {
285       BOOST_TRY
286       {
287         BOOST_THREAD_INVOKE_RET_VOID(
288             thread_detail::decay_copy(boost::forward<Function>(f)),
289             thread_detail::decay_copy(boost::forward<T1>(p1)),
290             thread_detail::decay_copy(boost::forward<T1>(p2)),
291             thread_detail::decay_copy(boost::forward<T1>(p3))
292         ) BOOST_THREAD_INVOKE_RET_VOID_CALL;
293 
294       }
295       BOOST_CATCH (...)
296       {
297         thread_detail::rollback_once_region(flag);
298         BOOST_RETHROW
299       }
300       BOOST_CATCH_END
301       thread_detail::commit_once_region(flag);
302     }
303   }
304 
305 
306 
307 #endif
308 }
309 
310 #include <boost/config/abi_suffix.hpp>
311 
312 #endif
313 
314