/Src/Dependencies/Boost/boost/thread/win32/once.hpp
http://hadesmem.googlecode.com/ · C++ Header · 205 lines · 176 code · 19 blank · 10 comment · 17 complexity · a133dfb6b6be3fbc049ee25bc7f3272e MD5 · raw file
- #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
- //
- // 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/config/abi_prefix.hpp>
- #ifdef BOOST_NO_STDC_NAMESPACE
- namespace std
- {
- using ::memcpy;
- using ::ptrdiff_t;
- }
- #endif
- namespace boost
- {
- struct once_flag
- {
- long status;
- long count;
- };
- #define BOOST_ONCE_INIT {0,0}
- 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);
- }
- #ifdef BOOST_NO_ANSI_APIS
- 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);
- }
- }
-
- 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:
- long const function_complete_flag_value=0xc15730e2;
- long const running_value=0x7f0725e3;
- long status;
- bool counted=false;
- detail::win32::handle_manager event_handle;
- detail::once_char_type mutex_name[detail::once_mutex_name_length];
- mutex_name[0]=0;
- while((status=::boost::detail::interlocked_read_acquire(&flag.status))
- !=function_complete_flag_value)
- {
- status=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&flag.status,running_value,0);
- if(!status)
- {
- try
- {
- if(!event_handle)
- {
- event_handle=detail::open_once_event(mutex_name,&flag);
- }
- if(event_handle)
- {
- ::boost::detail::win32::ResetEvent(event_handle);
- }
- f();
- if(!counted)
- {
- BOOST_INTERLOCKED_INCREMENT(&flag.count);
- counted=true;
- }
- BOOST_INTERLOCKED_EXCHANGE(&flag.status,function_complete_flag_value);
- if(!event_handle &&
- (::boost::detail::interlocked_read_acquire(&flag.count)>1))
- {
- event_handle=detail::create_once_event(mutex_name,&flag);
- }
- if(event_handle)
- {
- ::boost::detail::win32::SetEvent(event_handle);
- }
- break;
- }
- catch(...)
- {
- BOOST_INTERLOCKED_EXCHANGE(&flag.status,0);
- if(!event_handle)
- {
- event_handle=detail::open_once_event(mutex_name,&flag);
- }
- if(event_handle)
- {
- ::boost::detail::win32::SetEvent(event_handle);
- }
- throw;
- }
- }
- if(!counted)
- {
- BOOST_INTERLOCKED_INCREMENT(&flag.count);
- counted=true;
- status=::boost::detail::interlocked_read_acquire(&flag.status);
- if(status==function_complete_flag_value)
- {
- break;
- }
- if(!event_handle)
- {
- event_handle=detail::create_once_event(mutex_name,&flag);
- continue;
- }
- }
- BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
- event_handle,::boost::detail::win32::infinite));
- }
- }
- }
- #include <boost/config/abi_suffix.hpp>
- #endif