Line data Source code
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 : {
59 : 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 : {
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 : {
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>
121 357 : inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(ArgTypes)... args)
122 : {
123 357 : if (thread_detail::enter_once_region(flag))
124 : {
125 : BOOST_TRY
126 : {
127 357 : BOOST_THREAD_INVOKE_RET_VOID(
128 357 : 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 0 : BOOST_CATCH (...)
133 : {
134 0 : thread_detail::rollback_once_region(flag);
135 0 : BOOST_RETHROW
136 : }
137 : BOOST_CATCH_END
138 357 : thread_detail::commit_once_region(flag);
139 : }
140 357 : }
141 : #else
142 : template<typename Function>
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>
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>
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>
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 : #if !(defined(__SUNPRO_CC) && BOOST_WORKAROUND(__SUNPRO_CC, <= 0x5130))
218 : template<typename Function>
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>
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>
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>
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 : #endif // __SUNPRO_CC
306 :
307 : #endif
308 : }
309 :
310 : #include <boost/config/abi_suffix.hpp>
311 :
312 : #endif
313 :
|