YouCompleteMe/cpp/BoostParts/boost/thread/win32/once.hpp

1091 lines
39 KiB
C++
Raw Normal View History

2012-05-10 00:45:30 -04:00
#ifndef BOOST_THREAD_WIN32_ONCE_HPP
#define BOOST_THREAD_WIN32_ONCE_HPP
// once.hpp
//
2012-07-21 14:37:40 -04:00
// (C) Copyright 2005-7 Anthony Williams
2012-05-10 00:45:30 -04:00
// (C) Copyright 2005 John Maddock
2013-08-25 17:35:47 -04:00
// (C) Copyright 2011-2013 Vicente J. Botet Escriba
2012-05-10 00:45:30 -04:00
//
// 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>
2013-02-13 23:03:52 -05:00
#include <boost/detail/no_exceptions_support.hpp>
2013-08-25 17:35:47 -04:00
#include <boost/thread/detail/move.hpp>
#include <boost/thread/detail/invoke.hpp>
#include <boost/bind.hpp>
2012-05-10 00:45:30 -04:00
#include <boost/config/abi_prefix.hpp>
#ifdef BOOST_NO_STDC_NAMESPACE
namespace std
{
using ::memcpy;
using ::ptrdiff_t;
}
#endif
namespace boost
{
2013-08-25 17:35:47 -04:00
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;
}
2012-07-21 14:37:40 -04:00
#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;
2013-08-25 17:35:47 -04:00
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;
2012-07-21 14:37:40 -04:00
};
#define BOOST_ONCE_INIT once_flag()
#else // BOOST_THREAD_PROVIDES_ONCE_CXX11
2012-05-10 00:45:30 -04:00
struct once_flag
{
long status;
long count;
};
#define BOOST_ONCE_INIT {0,0}
2012-07-21 14:37:40 -04:00
#endif // BOOST_THREAD_PROVIDES_ONCE_CXX11
2012-05-10 00:45:30 -04:00
2013-08-25 17:35:47 -04:00
#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
2012-05-10 00:45:30 -04:00
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
2012-07-21 14:37:40 -04:00
BOOST_STATIC_ASSERT(sizeof(fixed_mutex_name) ==
2012-05-10 00:45:30 -04:00
(sizeof(once_char_type)*(once_mutex_name_fixed_length+1)));
2012-07-21 14:37:40 -04:00
2012-05-10 00:45:30 -04:00
std::memcpy(mutex_name,fixed_mutex_name,sizeof(fixed_mutex_name));
2012-07-21 14:37:40 -04:00
detail::int_to_string(reinterpret_cast<std::ptrdiff_t>(flag_address),
2012-05-10 00:45:30 -04:00
mutex_name + once_mutex_name_fixed_length);
2012-07-21 14:37:40 -04:00
detail::int_to_string(win32::GetCurrentProcessId(),
2012-05-10 00:45:30 -04:00
mutex_name + once_mutex_name_fixed_length + sizeof(void*)*2);
}
2012-07-21 14:37:40 -04:00
2012-05-10 00:45:30 -04:00
inline void* open_once_event(once_char_type* mutex_name,void* flag_address)
{
if(!*mutex_name)
{
name_once_mutex(mutex_name,flag_address);
}
2012-07-21 14:37:40 -04:00
#ifdef BOOST_NO_ANSI_APIS
2012-05-10 00:45:30 -04:00
return ::boost::detail::win32::OpenEventW(
#else
return ::boost::detail::win32::OpenEventA(
#endif
2012-07-21 14:37:40 -04:00
::boost::detail::win32::synchronize |
2012-05-10 00:45:30 -04:00
::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);
}
2012-07-21 14:37:40 -04:00
#ifdef BOOST_NO_ANSI_APIS
2012-05-10 00:45:30 -04:00
return ::boost::detail::win32::CreateEventW(
#else
return ::boost::detail::win32::CreateEventA(
#endif
0,::boost::detail::win32::manual_reset_event,
::boost::detail::win32::event_initially_reset,
mutex_name);
}
2012-07-21 14:37:40 -04:00
2013-08-25 17:35:47 -04:00
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_};
2012-05-10 00:45:30 -04:00
2013-08-25 17:35:47 -04:00
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);
}
}
}
#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
//#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::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
}
}
//#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::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
}
}
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::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
}
}
#else
#ifndef BOOST_MSVC
2012-05-10 00:45:30 -04:00
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:
2013-08-25 17:35:47 -04:00
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::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
}
}
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::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
}
}
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::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
}
}
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::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
}
}
#elif defined BOOST_NO_CXX11_RVALUE_REFERENCES
2012-05-10 00:45:30 -04:00
2013-08-25 17:35:47 -04:00
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)
2012-05-10 00:45:30 -04:00
{
2013-08-25 17:35:47 -04:00
if(detail::enter_once_region(flag, ctx))
2012-05-10 00:45:30 -04:00
{
2013-02-13 23:03:52 -05:00
BOOST_TRY
2012-05-10 00:45:30 -04:00
{
2013-08-25 17:35:47 -04:00
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::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
}
}
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::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
}
}
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::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
}
}
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::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
}
}
#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
2012-05-10 00:45:30 -04:00
{
2013-08-25 17:35:47 -04:00
f();
2012-05-10 00:45:30 -04:00
}
2013-08-25 17:35:47 -04:00
BOOST_CATCH(...)
2012-05-10 00:45:30 -04:00
{
2013-08-25 17:35:47 -04:00
detail::rollback_once_region(flag, ctx);
BOOST_RETHROW
2012-05-10 00:45:30 -04:00
}
2013-08-25 17:35:47 -04:00
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)
2012-05-10 00:45:30 -04:00
{
2013-08-25 17:35:47 -04:00
ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
continue;
2012-05-10 00:45:30 -04:00
}
2013-08-25 17:35:47 -04:00
}
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
}
}
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
2012-05-10 00:45:30 -04:00
{
2013-08-25 17:35:47 -04:00
f(
thread_detail::decay_copy(boost::forward<T1>(p1))
);
2012-05-10 00:45:30 -04:00
}
2013-08-25 17:35:47 -04:00
BOOST_CATCH(...)
2012-05-10 00:45:30 -04:00
{
2013-08-25 17:35:47 -04:00
detail::rollback_once_region(flag, ctx);
BOOST_RETHROW
2012-05-10 00:45:30 -04:00
}
2013-08-25 17:35:47 -04:00
BOOST_CATCH_END
detail::commit_once_region(flag, ctx);
2012-05-10 00:45:30 -04:00
break;
}
2013-08-25 17:35:47 -04:00
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::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
}
}
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::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
}
}
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))
2012-05-10 00:45:30 -04:00
{
2013-08-25 17:35:47 -04:00
BOOST_TRY
2012-05-10 00:45:30 -04:00
{
2013-08-25 17:35:47 -04:00
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))
);
2012-05-10 00:45:30 -04:00
}
2013-08-25 17:35:47 -04:00
BOOST_CATCH(...)
2012-05-10 00:45:30 -04:00
{
2013-08-25 17:35:47 -04:00
detail::rollback_once_region(flag, ctx);
BOOST_RETHROW
2012-05-10 00:45:30 -04:00
}
2013-08-25 17:35:47 -04:00
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::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
}
}
#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::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
}
}
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);
2013-02-13 23:03:52 -05:00
BOOST_RETHROW
2012-05-10 00:45:30 -04:00
}
2013-02-13 23:03:52 -05:00
BOOST_CATCH_END
2013-08-25 17:35:47 -04:00
detail::commit_once_region(flag, ctx);
break;
2012-05-10 00:45:30 -04:00
}
2013-08-25 17:35:47 -04:00
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::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
}
}
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::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
}
}
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;
2012-05-10 00:45:30 -04:00
2013-08-25 17:35:47 -04:00
}
BOOST_CATCH(...)
{
detail::rollback_once_region(flag, ctx);
BOOST_RETHROW
}
BOOST_CATCH_END
detail::commit_once_region(flag, ctx);
break;
}
if(!ctx.counted)
2012-05-10 00:45:30 -04:00
{
BOOST_INTERLOCKED_INCREMENT(&flag.count);
2013-08-25 17:35:47 -04:00
ctx.counted=true;
long status=::boost::detail::interlocked_read_acquire(&flag.status);
if(status==ctx.function_complete_flag_value)
2012-05-10 00:45:30 -04:00
{
break;
}
2013-08-25 17:35:47 -04:00
if(!ctx.event_handle)
2012-05-10 00:45:30 -04:00
{
2013-08-25 17:35:47 -04:00
ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag);
2012-05-10 00:45:30 -04:00
continue;
}
}
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
2013-08-25 17:35:47 -04:00
ctx.event_handle,::boost::detail::win32::infinite));
2012-05-10 00:45:30 -04:00
}
}
2013-08-25 17:35:47 -04:00
#endif
#endif
2012-05-10 00:45:30 -04:00
}
#include <boost/config/abi_suffix.hpp>
#endif