| #ifndef BOOST_THREAD_WIN32_ONCE_HPP |
| #define BOOST_THREAD_WIN32_ONCE_HPP |
| |
| // once.hpp |
| // |
| // (C) Copyright 2005-7 Anthony Williams |
| // (C) Copyright 2005 John Maddock |
| // (C) Copyright 2011-2013 Vicente J. Botet Escriba |
| // |
| // Distributed under the Boost Software License, Version 1.0. (See |
| // accompanying file LICENSE_1_0.txt or copy at |
| // http://www.boost.org/LICENSE_1_0.txt) |
| |
| #include <cstring> |
| #include <cstddef> |
| #include <boost/assert.hpp> |
| #include <boost/static_assert.hpp> |
| #include <boost/detail/interlocked.hpp> |
| #include <boost/thread/win32/thread_primitives.hpp> |
| #include <boost/thread/win32/interlocked_read.hpp> |
| #include <boost/core/no_exceptions_support.hpp> |
| #include <boost/thread/detail/move.hpp> |
| #include <boost/thread/detail/invoke.hpp> |
| |
| #include <boost/bind.hpp> |
| |
| #include <boost/config/abi_prefix.hpp> |
| |
| #ifdef BOOST_NO_STDC_NAMESPACE |
| namespace std |
| { |
| using ::memcpy; |
| using ::ptrdiff_t; |
| } |
| #endif |
| |
| namespace boost |
| { |
| struct once_flag; |
| namespace detail |
| { |
| struct once_context; |
| |
| inline bool enter_once_region(once_flag& flag, once_context& ctx) BOOST_NOEXCEPT; |
| inline void commit_once_region(once_flag& flag, once_context& ctx) BOOST_NOEXCEPT; |
| inline void rollback_once_region(once_flag& flag, once_context& ctx) BOOST_NOEXCEPT; |
| } |
| |
| #ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11 |
| |
| struct once_flag |
| { |
| BOOST_THREAD_NO_COPYABLE(once_flag) |
| BOOST_CONSTEXPR once_flag() BOOST_NOEXCEPT |
| : status(0), count(0) |
| {} |
| long status; |
| long count; |
| private: |
| friend inline bool enter_once_region(once_flag& flag, detail::once_context& ctx) BOOST_NOEXCEPT; |
| friend inline void commit_once_region(once_flag& flag, detail::once_context& ctx) BOOST_NOEXCEPT; |
| friend inline void rollback_once_region(once_flag& flag, detail::once_context& ctx) BOOST_NOEXCEPT; |
| }; |
| |
| #define BOOST_ONCE_INIT once_flag() |
| #else // BOOST_THREAD_PROVIDES_ONCE_CXX11 |
| |
| struct once_flag |
| { |
| long status; |
| long count; |
| }; |
| |
| #define BOOST_ONCE_INIT {0,0} |
| #endif // BOOST_THREAD_PROVIDES_ONCE_CXX11 |
| |
| #if defined BOOST_THREAD_PROVIDES_INVOKE |
| #define BOOST_THREAD_INVOKE_RET_VOID detail::invoke |
| #define BOOST_THREAD_INVOKE_RET_VOID_CALL |
| #elif defined BOOST_THREAD_PROVIDES_INVOKE_RET |
| #define BOOST_THREAD_INVOKE_RET_VOID detail::invoke<void> |
| #define BOOST_THREAD_INVOKE_RET_VOID_CALL |
| #else |
| #define BOOST_THREAD_INVOKE_RET_VOID boost::bind |
| #define BOOST_THREAD_INVOKE_RET_VOID_CALL () |
| #endif |
| |
| namespace detail |
| { |
| #ifdef BOOST_NO_ANSI_APIS |
| typedef wchar_t once_char_type; |
| #else |
| typedef char once_char_type; |
| #endif |
| unsigned const once_mutex_name_fixed_length=54; |
| unsigned const once_mutex_name_length=once_mutex_name_fixed_length+ |
| sizeof(void*)*2+sizeof(unsigned long)*2+1; |
| |
| template <class I> |
| void int_to_string(I p, once_char_type* buf) |
| { |
| for(unsigned i=0; i < sizeof(I)*2; ++i,++buf) |
| { |
| #ifdef BOOST_NO_ANSI_APIS |
| once_char_type const a=L'A'; |
| #else |
| once_char_type const a='A'; |
| #endif |
| *buf = a + static_cast<once_char_type>((p >> (i*4)) & 0x0f); |
| } |
| *buf = 0; |
| } |
| |
| inline void name_once_mutex(once_char_type* mutex_name,void* flag_address) |
| { |
| #ifdef BOOST_NO_ANSI_APIS |
| static const once_char_type fixed_mutex_name[]=L"Local\\{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag"; |
| #else |
| static const once_char_type fixed_mutex_name[]="Local\\{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag"; |
| #endif |
| BOOST_STATIC_ASSERT(sizeof(fixed_mutex_name) == |
| (sizeof(once_char_type)*(once_mutex_name_fixed_length+1))); |
| |
| std::memcpy(mutex_name,fixed_mutex_name,sizeof(fixed_mutex_name)); |
| detail::int_to_string(reinterpret_cast<std::ptrdiff_t>(flag_address), |
| mutex_name + once_mutex_name_fixed_length); |
| detail::int_to_string(win32::GetCurrentProcessId(), |
| mutex_name + once_mutex_name_fixed_length + sizeof(void*)*2); |
| } |
| |
| inline void* open_once_event(once_char_type* mutex_name,void* flag_address) |
| { |
| if(!*mutex_name) |
| { |
| name_once_mutex(mutex_name,flag_address); |
| } |
| |
| #ifdef BOOST_NO_ANSI_APIS |
| return ::boost::detail::win32::OpenEventW( |
| #else |
| return ::boost::detail::win32::OpenEventA( |
| #endif |
| ::boost::detail::win32::synchronize | |
| ::boost::detail::win32::event_modify_state, |
| false, |
| mutex_name); |
| } |
| |
| inline void* create_once_event(once_char_type* mutex_name,void* flag_address) |
| { |
| if(!*mutex_name) |
| { |
| name_once_mutex(mutex_name,flag_address); |
| } |
| |
| return ::boost::detail::win32::create_event( |
| mutex_name, |
| ::boost::detail::win32::manual_reset_event, |
| ::boost::detail::win32::event_initially_reset); |
| } |
| |
| struct once_context { |
| long const function_complete_flag_value; |
| long const running_value; |
| bool counted; |
| detail::win32::handle_manager event_handle; |
| detail::once_char_type mutex_name[once_mutex_name_length]; |
| once_context() : |
| function_complete_flag_value(0xc15730e2), |
| running_value(0x7f0725e3), |
| counted(false) |
| { |
| mutex_name[0]=0; |
| } |
| }; |
| enum once_action {try_, break_, continue_}; |
| |
| inline bool enter_once_region(once_flag& flag, once_context& ctx) BOOST_NOEXCEPT |
| { |
| long status=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&flag.status,ctx.running_value,0); |
| if(!status) |
| { |
| if(!ctx.event_handle) |
| { |
| ctx.event_handle=detail::open_once_event(ctx.mutex_name,&flag); |
| } |
| if(ctx.event_handle) |
| { |
| ::boost::detail::win32::ResetEvent(ctx.event_handle); |
| } |
| return true; |
| } |
| return false; |
| } |
| inline void commit_once_region(once_flag& flag, once_context& ctx) BOOST_NOEXCEPT |
| { |
| if(!ctx.counted) |
| { |
| BOOST_INTERLOCKED_INCREMENT(&flag.count); |
| ctx.counted=true; |
| } |
| BOOST_INTERLOCKED_EXCHANGE(&flag.status,ctx.function_complete_flag_value); |
| if(!ctx.event_handle && |
| (::boost::detail::interlocked_read_acquire(&flag.count)>1)) |
| { |
| ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); |
| } |
| if(ctx.event_handle) |
| { |
| ::boost::detail::win32::SetEvent(ctx.event_handle); |
| } |
| } |
| inline void rollback_once_region(once_flag& flag, once_context& ctx) BOOST_NOEXCEPT |
| { |
| BOOST_INTERLOCKED_EXCHANGE(&flag.status,0); |
| if(!ctx.event_handle) |
| { |
| ctx.event_handle=detail::open_once_event(ctx.mutex_name,&flag); |
| } |
| if(ctx.event_handle) |
| { |
| ::boost::detail::win32::SetEvent(ctx.event_handle); |
| } |
| } |
| } |
| |
| #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) |
| //#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR) |
| inline void call_once(once_flag& flag, void (*f)()) |
| { |
| // Try for a quick win: if the procedure has already been called |
| // just skip through: |
| detail::once_context ctx; |
| while(::boost::detail::interlocked_read_acquire(&flag.status) |
| !=ctx.function_complete_flag_value) |
| { |
| if(detail::enter_once_region(flag, ctx)) |
| { |
| BOOST_TRY |
| { |
| f(); |
| } |
| BOOST_CATCH(...) |
| { |
| detail::rollback_once_region(flag, ctx); |
| BOOST_RETHROW |
| } |
| BOOST_CATCH_END |
| detail::commit_once_region(flag, ctx); |
| break; |
| } |
| if(!ctx.counted) |
| { |
| BOOST_INTERLOCKED_INCREMENT(&flag.count); |
| ctx.counted=true; |
| long status=::boost::detail::interlocked_read_acquire(&flag.status); |
| if(status==ctx.function_complete_flag_value) |
| { |
| break; |
| } |
| if(!ctx.event_handle) |
| { |
| ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); |
| continue; |
| } |
| } |
| BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( |
| ctx.event_handle,::boost::detail::win32::infinite, 0)); |
| } |
| } |
| //#endif |
| template<typename Function> |
| inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f) |
| { |
| // Try for a quick win: if the procedure has already been called |
| // just skip through: |
| detail::once_context ctx; |
| while(::boost::detail::interlocked_read_acquire(&flag.status) |
| !=ctx.function_complete_flag_value) |
| { |
| if(detail::enter_once_region(flag, ctx)) |
| { |
| BOOST_TRY |
| { |
| f(); |
| } |
| BOOST_CATCH(...) |
| { |
| detail::rollback_once_region(flag, ctx); |
| BOOST_RETHROW |
| } |
| BOOST_CATCH_END |
| detail::commit_once_region(flag, ctx); |
| break; |
| } |
| if(!ctx.counted) |
| { |
| BOOST_INTERLOCKED_INCREMENT(&flag.count); |
| ctx.counted=true; |
| long status=::boost::detail::interlocked_read_acquire(&flag.status); |
| if(status==ctx.function_complete_flag_value) |
| { |
| break; |
| } |
| if(!ctx.event_handle) |
| { |
| ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); |
| continue; |
| } |
| } |
| BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( |
| ctx.event_handle,::boost::detail::win32::infinite,0)); |
| } |
| } |
| template<typename Function, class A, class ...ArgTypes> |
| inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(A) a, BOOST_THREAD_RV_REF(ArgTypes)... args) |
| { |
| // Try for a quick win: if the procedure has already been called |
| // just skip through: |
| detail::once_context ctx; |
| while(::boost::detail::interlocked_read_acquire(&flag.status) |
| !=ctx.function_complete_flag_value) |
| { |
| if(detail::enter_once_region(flag, ctx)) |
| { |
| BOOST_TRY |
| { |
| BOOST_THREAD_INVOKE_RET_VOID( |
| thread_detail::decay_copy(boost::forward<Function>(f)), |
| thread_detail::decay_copy(boost::forward<A>(a)), |
| thread_detail::decay_copy(boost::forward<ArgTypes>(args))... |
| ) BOOST_THREAD_INVOKE_RET_VOID_CALL; |
| } |
| BOOST_CATCH(...) |
| { |
| detail::rollback_once_region(flag, ctx); |
| BOOST_RETHROW |
| } |
| BOOST_CATCH_END |
| detail::commit_once_region(flag, ctx); |
| break; |
| } |
| if(!ctx.counted) |
| { |
| BOOST_INTERLOCKED_INCREMENT(&flag.count); |
| ctx.counted=true; |
| long status=::boost::detail::interlocked_read_acquire(&flag.status); |
| if(status==ctx.function_complete_flag_value) |
| { |
| break; |
| } |
| if(!ctx.event_handle) |
| { |
| ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); |
| continue; |
| } |
| } |
| BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( |
| ctx.event_handle,::boost::detail::win32::infinite,0)); |
| } |
| } |
| #else |
| #if ! defined(BOOST_MSVC) && ! defined(BOOST_INTEL) |
| template<typename Function> |
| void call_once(once_flag& flag,Function f) |
| { |
| // Try for a quick win: if the procedure has already been called |
| // just skip through: |
| detail::once_context ctx; |
| while(::boost::detail::interlocked_read_acquire(&flag.status) |
| !=ctx.function_complete_flag_value) |
| { |
| if(detail::enter_once_region(flag, ctx)) |
| { |
| BOOST_TRY |
| { |
| f(); |
| } |
| BOOST_CATCH(...) |
| { |
| detail::rollback_once_region(flag, ctx); |
| BOOST_RETHROW |
| } |
| BOOST_CATCH_END |
| detail::commit_once_region(flag, ctx); |
| break; |
| } |
| if(!ctx.counted) |
| { |
| BOOST_INTERLOCKED_INCREMENT(&flag.count); |
| ctx.counted=true; |
| long status=::boost::detail::interlocked_read_acquire(&flag.status); |
| if(status==ctx.function_complete_flag_value) |
| { |
| break; |
| } |
| if(!ctx.event_handle) |
| { |
| ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); |
| continue; |
| } |
| } |
| BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( |
| ctx.event_handle,::boost::detail::win32::infinite,0)); |
| } |
| } |
| template<typename Function, typename T1> |
| void call_once(once_flag& flag,Function f, T1 p1) |
| { |
| // Try for a quick win: if the procedure has already been called |
| // just skip through: |
| detail::once_context ctx; |
| while(::boost::detail::interlocked_read_acquire(&flag.status) |
| !=ctx.function_complete_flag_value) |
| { |
| if(detail::enter_once_region(flag, ctx)) |
| { |
| BOOST_TRY |
| { |
| BOOST_THREAD_INVOKE_RET_VOID(f,p1) BOOST_THREAD_INVOKE_RET_VOID_CALL; |
| } |
| BOOST_CATCH(...) |
| { |
| detail::rollback_once_region(flag, ctx); |
| BOOST_RETHROW |
| } |
| BOOST_CATCH_END |
| detail::commit_once_region(flag, ctx); |
| break; |
| } |
| if(!ctx.counted) |
| { |
| BOOST_INTERLOCKED_INCREMENT(&flag.count); |
| ctx.counted=true; |
| long status=::boost::detail::interlocked_read_acquire(&flag.status); |
| if(status==ctx.function_complete_flag_value) |
| { |
| break; |
| } |
| if(!ctx.event_handle) |
| { |
| ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); |
| continue; |
| } |
| } |
| BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( |
| ctx.event_handle,::boost::detail::win32::infinite,0)); |
| } |
| } |
| template<typename Function, typename T1, typename T2> |
| void call_once(once_flag& flag,Function f, T1 p1, T2 p2) |
| { |
| // Try for a quick win: if the procedure has already been called |
| // just skip through: |
| detail::once_context ctx; |
| while(::boost::detail::interlocked_read_acquire(&flag.status) |
| !=ctx.function_complete_flag_value) |
| { |
| if(detail::enter_once_region(flag, ctx)) |
| { |
| BOOST_TRY |
| { |
| BOOST_THREAD_INVOKE_RET_VOID(f,p1,p2) BOOST_THREAD_INVOKE_RET_VOID_CALL; |
| } |
| BOOST_CATCH(...) |
| { |
| detail::rollback_once_region(flag, ctx); |
| BOOST_RETHROW |
| } |
| BOOST_CATCH_END |
| detail::commit_once_region(flag, ctx); |
| break; |
| } |
| if(!ctx.counted) |
| { |
| BOOST_INTERLOCKED_INCREMENT(&flag.count); |
| ctx.counted=true; |
| long status=::boost::detail::interlocked_read_acquire(&flag.status); |
| if(status==ctx.function_complete_flag_value) |
| { |
| break; |
| } |
| if(!ctx.event_handle) |
| { |
| ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); |
| continue; |
| } |
| } |
| BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( |
| ctx.event_handle,::boost::detail::win32::infinite,0)); |
| } |
| } |
| template<typename Function, typename T1, typename T2, typename T3> |
| void call_once(once_flag& flag,Function f, T1 p1, T2 p2, T3 p3) |
| { |
| // Try for a quick win: if the procedure has already been called |
| // just skip through: |
| detail::once_context ctx; |
| while(::boost::detail::interlocked_read_acquire(&flag.status) |
| !=ctx.function_complete_flag_value) |
| { |
| if(detail::enter_once_region(flag, ctx)) |
| { |
| BOOST_TRY |
| { |
| BOOST_THREAD_INVOKE_RET_VOID(f,p1,p2,p3) BOOST_THREAD_INVOKE_RET_VOID_CALL; |
| } |
| BOOST_CATCH(...) |
| { |
| detail::rollback_once_region(flag, ctx); |
| BOOST_RETHROW |
| } |
| BOOST_CATCH_END |
| detail::commit_once_region(flag, ctx); |
| break; |
| } |
| if(!ctx.counted) |
| { |
| BOOST_INTERLOCKED_INCREMENT(&flag.count); |
| ctx.counted=true; |
| long status=::boost::detail::interlocked_read_acquire(&flag.status); |
| if(status==ctx.function_complete_flag_value) |
| { |
| break; |
| } |
| if(!ctx.event_handle) |
| { |
| ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); |
| continue; |
| } |
| } |
| BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( |
| ctx.event_handle,::boost::detail::win32::infinite,0)); |
| } |
| } |
| #elif defined BOOST_NO_CXX11_RVALUE_REFERENCES |
| |
| template<typename Function> |
| void call_once(once_flag& flag,Function const&f) |
| { |
| // Try for a quick win: if the procedure has already been called |
| // just skip through: |
| detail::once_context ctx; |
| while(::boost::detail::interlocked_read_acquire(&flag.status) |
| !=ctx.function_complete_flag_value) |
| { |
| if(detail::enter_once_region(flag, ctx)) |
| { |
| BOOST_TRY |
| { |
| f(); |
| } |
| BOOST_CATCH(...) |
| { |
| detail::rollback_once_region(flag, ctx); |
| BOOST_RETHROW |
| } |
| BOOST_CATCH_END |
| detail::commit_once_region(flag, ctx); |
| break; |
| } |
| if(!ctx.counted) |
| { |
| BOOST_INTERLOCKED_INCREMENT(&flag.count); |
| ctx.counted=true; |
| long status=::boost::detail::interlocked_read_acquire(&flag.status); |
| if(status==ctx.function_complete_flag_value) |
| { |
| break; |
| } |
| if(!ctx.event_handle) |
| { |
| ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); |
| continue; |
| } |
| } |
| BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( |
| ctx.event_handle,::boost::detail::win32::infinite,0)); |
| } |
| } |
| template<typename Function, typename T1> |
| void call_once(once_flag& flag,Function const&f, T1 const&p1) |
| { |
| // Try for a quick win: if the procedure has already been called |
| // just skip through: |
| detail::once_context ctx; |
| while(::boost::detail::interlocked_read_acquire(&flag.status) |
| !=ctx.function_complete_flag_value) |
| { |
| if(detail::enter_once_region(flag, ctx)) |
| { |
| BOOST_TRY |
| { |
| BOOST_THREAD_INVOKE_RET_VOID(f,p1) BOOST_THREAD_INVOKE_RET_VOID_CALL; |
| } |
| BOOST_CATCH(...) |
| { |
| detail::rollback_once_region(flag, ctx); |
| BOOST_RETHROW |
| } |
| BOOST_CATCH_END |
| detail::commit_once_region(flag, ctx); |
| break; |
| } |
| if(!ctx.counted) |
| { |
| BOOST_INTERLOCKED_INCREMENT(&flag.count); |
| ctx.counted=true; |
| long status=::boost::detail::interlocked_read_acquire(&flag.status); |
| if(status==ctx.function_complete_flag_value) |
| { |
| break; |
| } |
| if(!ctx.event_handle) |
| { |
| ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); |
| continue; |
| } |
| } |
| BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( |
| ctx.event_handle,::boost::detail::win32::infinite,0)); |
| } |
| } |
| template<typename Function, typename T1, typename T2> |
| void call_once(once_flag& flag,Function const&f, T1 const&p1, T2 const&p2) |
| { |
| // Try for a quick win: if the procedure has already been called |
| // just skip through: |
| detail::once_context ctx; |
| while(::boost::detail::interlocked_read_acquire(&flag.status) |
| !=ctx.function_complete_flag_value) |
| { |
| if(detail::enter_once_region(flag, ctx)) |
| { |
| BOOST_TRY |
| { |
| BOOST_THREAD_INVOKE_RET_VOID(f,p1,p2) BOOST_THREAD_INVOKE_RET_VOID_CALL; |
| } |
| BOOST_CATCH(...) |
| { |
| detail::rollback_once_region(flag, ctx); |
| BOOST_RETHROW |
| } |
| BOOST_CATCH_END |
| detail::commit_once_region(flag, ctx); |
| break; |
| } |
| if(!ctx.counted) |
| { |
| BOOST_INTERLOCKED_INCREMENT(&flag.count); |
| ctx.counted=true; |
| long status=::boost::detail::interlocked_read_acquire(&flag.status); |
| if(status==ctx.function_complete_flag_value) |
| { |
| break; |
| } |
| if(!ctx.event_handle) |
| { |
| ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); |
| continue; |
| } |
| } |
| BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( |
| ctx.event_handle,::boost::detail::win32::infinite,0)); |
| } |
| } |
| template<typename Function, typename T1, typename T2, typename T3> |
| void call_once(once_flag& flag,Function const&f, T1 const&p1, T2 const&p2, T3 const&p3) |
| { |
| // Try for a quick win: if the procedure has already been called |
| // just skip through: |
| detail::once_context ctx; |
| while(::boost::detail::interlocked_read_acquire(&flag.status) |
| !=ctx.function_complete_flag_value) |
| { |
| if(detail::enter_once_region(flag, ctx)) |
| { |
| BOOST_TRY |
| { |
| BOOST_THREAD_INVOKE_RET_VOID(f,p1,p2,p3) BOOST_THREAD_INVOKE_RET_VOID_CALL; |
| } |
| BOOST_CATCH(...) |
| { |
| detail::rollback_once_region(flag, ctx); |
| BOOST_RETHROW |
| } |
| BOOST_CATCH_END |
| detail::commit_once_region(flag, ctx); |
| break; |
| } |
| if(!ctx.counted) |
| { |
| BOOST_INTERLOCKED_INCREMENT(&flag.count); |
| ctx.counted=true; |
| long status=::boost::detail::interlocked_read_acquire(&flag.status); |
| if(status==ctx.function_complete_flag_value) |
| { |
| break; |
| } |
| if(!ctx.event_handle) |
| { |
| ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); |
| continue; |
| } |
| } |
| BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( |
| ctx.event_handle,::boost::detail::win32::infinite,0)); |
| } |
| } |
| #endif |
| #if 1 |
| #if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR) |
| inline void call_once(once_flag& flag, void (*f)()) |
| { |
| // Try for a quick win: if the procedure has already been called |
| // just skip through: |
| detail::once_context ctx; |
| while(::boost::detail::interlocked_read_acquire(&flag.status) |
| !=ctx.function_complete_flag_value) |
| { |
| if(detail::enter_once_region(flag, ctx)) |
| { |
| BOOST_TRY |
| { |
| f(); |
| } |
| BOOST_CATCH(...) |
| { |
| detail::rollback_once_region(flag, ctx); |
| BOOST_RETHROW |
| } |
| BOOST_CATCH_END |
| detail::commit_once_region(flag, ctx); |
| break; |
| } |
| if(!ctx.counted) |
| { |
| BOOST_INTERLOCKED_INCREMENT(&flag.count); |
| ctx.counted=true; |
| long status=::boost::detail::interlocked_read_acquire(&flag.status); |
| if(status==ctx.function_complete_flag_value) |
| { |
| break; |
| } |
| if(!ctx.event_handle) |
| { |
| ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); |
| continue; |
| } |
| } |
| BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( |
| ctx.event_handle,::boost::detail::win32::infinite,0)); |
| } |
| } |
| template<typename T1> |
| void call_once(once_flag& flag,void (*f)(BOOST_THREAD_RV_REF(T1)), BOOST_THREAD_RV_REF(T1) p1) |
| { |
| // Try for a quick win: if the procedure has already been called |
| // just skip through: |
| detail::once_context ctx; |
| while(::boost::detail::interlocked_read_acquire(&flag.status) |
| !=ctx.function_complete_flag_value) |
| { |
| if(detail::enter_once_region(flag, ctx)) |
| { |
| BOOST_TRY |
| { |
| f( |
| thread_detail::decay_copy(boost::forward<T1>(p1)) |
| ); |
| } |
| BOOST_CATCH(...) |
| { |
| detail::rollback_once_region(flag, ctx); |
| BOOST_RETHROW |
| } |
| BOOST_CATCH_END |
| detail::commit_once_region(flag, ctx); |
| break; |
| } |
| if(!ctx.counted) |
| { |
| BOOST_INTERLOCKED_INCREMENT(&flag.count); |
| ctx.counted=true; |
| long status=::boost::detail::interlocked_read_acquire(&flag.status); |
| if(status==ctx.function_complete_flag_value) |
| { |
| break; |
| } |
| if(!ctx.event_handle) |
| { |
| ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); |
| continue; |
| } |
| } |
| BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( |
| ctx.event_handle,::boost::detail::win32::infinite,0)); |
| } |
| } |
| template<typename Function, typename T1, typename T2> |
| void call_once(once_flag& flag,void (*f)(BOOST_THREAD_RV_REF(T1),BOOST_THREAD_RV_REF(T2)), BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2) |
| { |
| // Try for a quick win: if the procedure has already been called |
| // just skip through: |
| detail::once_context ctx; |
| while(::boost::detail::interlocked_read_acquire(&flag.status) |
| !=ctx.function_complete_flag_value) |
| { |
| if(detail::enter_once_region(flag, ctx)) |
| { |
| BOOST_TRY |
| { |
| f( |
| thread_detail::decay_copy(boost::forward<T1>(p1)), |
| thread_detail::decay_copy(boost::forward<T2>(p2)) |
| ); |
| } |
| BOOST_CATCH(...) |
| { |
| detail::rollback_once_region(flag, ctx); |
| BOOST_RETHROW |
| } |
| BOOST_CATCH_END |
| detail::commit_once_region(flag, ctx); |
| break; |
| } |
| if(!ctx.counted) |
| { |
| BOOST_INTERLOCKED_INCREMENT(&flag.count); |
| ctx.counted=true; |
| long status=::boost::detail::interlocked_read_acquire(&flag.status); |
| if(status==ctx.function_complete_flag_value) |
| { |
| break; |
| } |
| if(!ctx.event_handle) |
| { |
| ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); |
| continue; |
| } |
| } |
| BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( |
| ctx.event_handle,::boost::detail::win32::infinite,0)); |
| } |
| } |
| template<typename Function, typename T1, typename T2, typename T3> |
| void call_once(once_flag& flag,void (*f)(BOOST_THREAD_RV_REF(T1),BOOST_THREAD_RV_REF(T2)), BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2, BOOST_THREAD_RV_REF(T3) p3) |
| { |
| // Try for a quick win: if the procedure has already been called |
| // just skip through: |
| detail::once_context ctx; |
| while(::boost::detail::interlocked_read_acquire(&flag.status) |
| !=ctx.function_complete_flag_value) |
| { |
| if(detail::enter_once_region(flag, ctx)) |
| { |
| BOOST_TRY |
| { |
| f( |
| thread_detail::decay_copy(boost::forward<T1>(p1)), |
| thread_detail::decay_copy(boost::forward<T2>(p2)), |
| thread_detail::decay_copy(boost::forward<T3>(p3)) |
| ); |
| } |
| BOOST_CATCH(...) |
| { |
| detail::rollback_once_region(flag, ctx); |
| BOOST_RETHROW |
| } |
| BOOST_CATCH_END |
| detail::commit_once_region(flag, ctx); |
| break; |
| } |
| if(!ctx.counted) |
| { |
| BOOST_INTERLOCKED_INCREMENT(&flag.count); |
| ctx.counted=true; |
| long status=::boost::detail::interlocked_read_acquire(&flag.status); |
| if(status==ctx.function_complete_flag_value) |
| { |
| break; |
| } |
| if(!ctx.event_handle) |
| { |
| ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); |
| continue; |
| } |
| } |
| BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( |
| ctx.event_handle,::boost::detail::win32::infinite,0)); |
| } |
| } |
| #endif |
| template<typename Function> |
| void call_once(once_flag& flag,BOOST_THREAD_RV_REF(Function) f) |
| { |
| // Try for a quick win: if the procedure has already been called |
| // just skip through: |
| detail::once_context ctx; |
| while(::boost::detail::interlocked_read_acquire(&flag.status) |
| !=ctx.function_complete_flag_value) |
| { |
| if(detail::enter_once_region(flag, ctx)) |
| { |
| BOOST_TRY |
| { |
| f(); |
| } |
| BOOST_CATCH(...) |
| { |
| detail::rollback_once_region(flag, ctx); |
| BOOST_RETHROW |
| } |
| BOOST_CATCH_END |
| detail::commit_once_region(flag, ctx); |
| break; |
| } |
| if(!ctx.counted) |
| { |
| BOOST_INTERLOCKED_INCREMENT(&flag.count); |
| ctx.counted=true; |
| long status=::boost::detail::interlocked_read_acquire(&flag.status); |
| if(status==ctx.function_complete_flag_value) |
| { |
| break; |
| } |
| if(!ctx.event_handle) |
| { |
| ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); |
| continue; |
| } |
| } |
| BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( |
| ctx.event_handle,::boost::detail::win32::infinite,0)); |
| } |
| } |
| |
| template<typename Function, typename T1> |
| void call_once(once_flag& flag,BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1) |
| { |
| // Try for a quick win: if the procedure has already been called |
| // just skip through: |
| detail::once_context ctx; |
| while(::boost::detail::interlocked_read_acquire(&flag.status) |
| !=ctx.function_complete_flag_value) |
| { |
| if(detail::enter_once_region(flag, ctx)) |
| { |
| BOOST_TRY |
| { |
| BOOST_THREAD_INVOKE_RET_VOID( |
| thread_detail::decay_copy(boost::forward<Function>(f)), |
| thread_detail::decay_copy(boost::forward<T1>(p1)) |
| ) BOOST_THREAD_INVOKE_RET_VOID_CALL; |
| } |
| BOOST_CATCH(...) |
| { |
| detail::rollback_once_region(flag, ctx); |
| BOOST_RETHROW |
| } |
| BOOST_CATCH_END |
| detail::commit_once_region(flag, ctx); |
| break; |
| } |
| if(!ctx.counted) |
| { |
| BOOST_INTERLOCKED_INCREMENT(&flag.count); |
| ctx.counted=true; |
| long status=::boost::detail::interlocked_read_acquire(&flag.status); |
| if(status==ctx.function_complete_flag_value) |
| { |
| break; |
| } |
| if(!ctx.event_handle) |
| { |
| ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); |
| continue; |
| } |
| } |
| BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( |
| ctx.event_handle,::boost::detail::win32::infinite,0)); |
| } |
| } |
| template<typename Function, typename T1, typename T2> |
| void call_once(once_flag& flag,BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2) |
| { |
| // Try for a quick win: if the procedure has already been called |
| // just skip through: |
| detail::once_context ctx; |
| while(::boost::detail::interlocked_read_acquire(&flag.status) |
| !=ctx.function_complete_flag_value) |
| { |
| if(detail::enter_once_region(flag, ctx)) |
| { |
| BOOST_TRY |
| { |
| BOOST_THREAD_INVOKE_RET_VOID( |
| thread_detail::decay_copy(boost::forward<Function>(f)), |
| thread_detail::decay_copy(boost::forward<T1>(p1)), |
| thread_detail::decay_copy(boost::forward<T2>(p2)) |
| ) BOOST_THREAD_INVOKE_RET_VOID_CALL; |
| } |
| BOOST_CATCH(...) |
| { |
| detail::rollback_once_region(flag, ctx); |
| BOOST_RETHROW |
| } |
| BOOST_CATCH_END |
| detail::commit_once_region(flag, ctx); |
| break; |
| } |
| if(!ctx.counted) |
| { |
| BOOST_INTERLOCKED_INCREMENT(&flag.count); |
| ctx.counted=true; |
| long status=::boost::detail::interlocked_read_acquire(&flag.status); |
| if(status==ctx.function_complete_flag_value) |
| { |
| break; |
| } |
| if(!ctx.event_handle) |
| { |
| ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); |
| continue; |
| } |
| } |
| BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( |
| ctx.event_handle,::boost::detail::win32::infinite,0)); |
| } |
| } |
| template<typename Function, typename T1, typename T2, typename T3> |
| 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) |
| { |
| // Try for a quick win: if the procedure has already been called |
| // just skip through: |
| detail::once_context ctx; |
| while(::boost::detail::interlocked_read_acquire(&flag.status) |
| !=ctx.function_complete_flag_value) |
| { |
| if(detail::enter_once_region(flag, ctx)) |
| { |
| BOOST_TRY |
| { |
| BOOST_THREAD_INVOKE_RET_VOID( |
| thread_detail::decay_copy(boost::forward<Function>(f)), |
| thread_detail::decay_copy(boost::forward<T1>(p1)), |
| thread_detail::decay_copy(boost::forward<T2>(p2)), |
| thread_detail::decay_copy(boost::forward<T3>(p3)) |
| ) BOOST_THREAD_INVOKE_RET_VOID_CALL; |
| |
| } |
| BOOST_CATCH(...) |
| { |
| detail::rollback_once_region(flag, ctx); |
| BOOST_RETHROW |
| } |
| BOOST_CATCH_END |
| detail::commit_once_region(flag, ctx); |
| break; |
| } |
| if(!ctx.counted) |
| { |
| BOOST_INTERLOCKED_INCREMENT(&flag.count); |
| ctx.counted=true; |
| long status=::boost::detail::interlocked_read_acquire(&flag.status); |
| if(status==ctx.function_complete_flag_value) |
| { |
| break; |
| } |
| if(!ctx.event_handle) |
| { |
| ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); |
| continue; |
| } |
| } |
| BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( |
| ctx.event_handle,::boost::detail::win32::infinite,0)); |
| } |
| } |
| |
| #endif |
| #endif |
| } |
| |
| #include <boost/config/abi_suffix.hpp> |
| |
| #endif |