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