/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

  1. #ifndef BOOST_THREAD_WIN32_ONCE_HPP
  2. #define BOOST_THREAD_WIN32_ONCE_HPP
  3. // once.hpp
  4. //
  5. // (C) Copyright 2005-7 Anthony Williams
  6. // (C) Copyright 2005 John Maddock
  7. //
  8. // Distributed under the Boost Software License, Version 1.0. (See
  9. // accompanying file LICENSE_1_0.txt or copy at
  10. // http://www.boost.org/LICENSE_1_0.txt)
  11. #include <cstring>
  12. #include <cstddef>
  13. #include <boost/assert.hpp>
  14. #include <boost/static_assert.hpp>
  15. #include <boost/detail/interlocked.hpp>
  16. #include <boost/thread/win32/thread_primitives.hpp>
  17. #include <boost/thread/win32/interlocked_read.hpp>
  18. #include <boost/config/abi_prefix.hpp>
  19. #ifdef BOOST_NO_STDC_NAMESPACE
  20. namespace std
  21. {
  22. using ::memcpy;
  23. using ::ptrdiff_t;
  24. }
  25. #endif
  26. namespace boost
  27. {
  28. struct once_flag
  29. {
  30. long status;
  31. long count;
  32. };
  33. #define BOOST_ONCE_INIT {0,0}
  34. namespace detail
  35. {
  36. #ifdef BOOST_NO_ANSI_APIS
  37. typedef wchar_t once_char_type;
  38. #else
  39. typedef char once_char_type;
  40. #endif
  41. unsigned const once_mutex_name_fixed_length=54;
  42. unsigned const once_mutex_name_length=once_mutex_name_fixed_length+
  43. sizeof(void*)*2+sizeof(unsigned long)*2+1;
  44. template <class I>
  45. void int_to_string(I p, once_char_type* buf)
  46. {
  47. for(unsigned i=0; i < sizeof(I)*2; ++i,++buf)
  48. {
  49. #ifdef BOOST_NO_ANSI_APIS
  50. once_char_type const a=L'A';
  51. #else
  52. once_char_type const a='A';
  53. #endif
  54. *buf = a + static_cast<once_char_type>((p >> (i*4)) & 0x0f);
  55. }
  56. *buf = 0;
  57. }
  58. inline void name_once_mutex(once_char_type* mutex_name,void* flag_address)
  59. {
  60. #ifdef BOOST_NO_ANSI_APIS
  61. static const once_char_type fixed_mutex_name[]=L"Local\\{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag";
  62. #else
  63. static const once_char_type fixed_mutex_name[]="Local\\{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag";
  64. #endif
  65. BOOST_STATIC_ASSERT(sizeof(fixed_mutex_name) ==
  66. (sizeof(once_char_type)*(once_mutex_name_fixed_length+1)));
  67. std::memcpy(mutex_name,fixed_mutex_name,sizeof(fixed_mutex_name));
  68. detail::int_to_string(reinterpret_cast<std::ptrdiff_t>(flag_address),
  69. mutex_name + once_mutex_name_fixed_length);
  70. detail::int_to_string(win32::GetCurrentProcessId(),
  71. mutex_name + once_mutex_name_fixed_length + sizeof(void*)*2);
  72. }
  73. inline void* open_once_event(once_char_type* mutex_name,void* flag_address)
  74. {
  75. if(!*mutex_name)
  76. {
  77. name_once_mutex(mutex_name,flag_address);
  78. }
  79. #ifdef BOOST_NO_ANSI_APIS
  80. return ::boost::detail::win32::OpenEventW(
  81. #else
  82. return ::boost::detail::win32::OpenEventA(
  83. #endif
  84. ::boost::detail::win32::synchronize |
  85. ::boost::detail::win32::event_modify_state,
  86. false,
  87. mutex_name);
  88. }
  89. inline void* create_once_event(once_char_type* mutex_name,void* flag_address)
  90. {
  91. if(!*mutex_name)
  92. {
  93. name_once_mutex(mutex_name,flag_address);
  94. }
  95. #ifdef BOOST_NO_ANSI_APIS
  96. return ::boost::detail::win32::CreateEventW(
  97. #else
  98. return ::boost::detail::win32::CreateEventA(
  99. #endif
  100. 0,::boost::detail::win32::manual_reset_event,
  101. ::boost::detail::win32::event_initially_reset,
  102. mutex_name);
  103. }
  104. }
  105. template<typename Function>
  106. void call_once(once_flag& flag,Function f)
  107. {
  108. // Try for a quick win: if the procedure has already been called
  109. // just skip through:
  110. long const function_complete_flag_value=0xc15730e2;
  111. long const running_value=0x7f0725e3;
  112. long status;
  113. bool counted=false;
  114. detail::win32::handle_manager event_handle;
  115. detail::once_char_type mutex_name[detail::once_mutex_name_length];
  116. mutex_name[0]=0;
  117. while((status=::boost::detail::interlocked_read_acquire(&flag.status))
  118. !=function_complete_flag_value)
  119. {
  120. status=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&flag.status,running_value,0);
  121. if(!status)
  122. {
  123. try
  124. {
  125. if(!event_handle)
  126. {
  127. event_handle=detail::open_once_event(mutex_name,&flag);
  128. }
  129. if(event_handle)
  130. {
  131. ::boost::detail::win32::ResetEvent(event_handle);
  132. }
  133. f();
  134. if(!counted)
  135. {
  136. BOOST_INTERLOCKED_INCREMENT(&flag.count);
  137. counted=true;
  138. }
  139. BOOST_INTERLOCKED_EXCHANGE(&flag.status,function_complete_flag_value);
  140. if(!event_handle &&
  141. (::boost::detail::interlocked_read_acquire(&flag.count)>1))
  142. {
  143. event_handle=detail::create_once_event(mutex_name,&flag);
  144. }
  145. if(event_handle)
  146. {
  147. ::boost::detail::win32::SetEvent(event_handle);
  148. }
  149. break;
  150. }
  151. catch(...)
  152. {
  153. BOOST_INTERLOCKED_EXCHANGE(&flag.status,0);
  154. if(!event_handle)
  155. {
  156. event_handle=detail::open_once_event(mutex_name,&flag);
  157. }
  158. if(event_handle)
  159. {
  160. ::boost::detail::win32::SetEvent(event_handle);
  161. }
  162. throw;
  163. }
  164. }
  165. if(!counted)
  166. {
  167. BOOST_INTERLOCKED_INCREMENT(&flag.count);
  168. counted=true;
  169. status=::boost::detail::interlocked_read_acquire(&flag.status);
  170. if(status==function_complete_flag_value)
  171. {
  172. break;
  173. }
  174. if(!event_handle)
  175. {
  176. event_handle=detail::create_once_event(mutex_name,&flag);
  177. continue;
  178. }
  179. }
  180. BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
  181. event_handle,::boost::detail::win32::infinite));
  182. }
  183. }
  184. }
  185. #include <boost/config/abi_suffix.hpp>
  186. #endif