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