|
1 #ifndef BOOST_THREAD_WIN32_ONCE_HPP |
|
2 #define BOOST_THREAD_WIN32_ONCE_HPP |
|
3 |
|
4 // once.hpp |
|
5 // |
|
6 // (C) Copyright 2005-7 Anthony Williams |
|
7 // (C) Copyright 2005 John Maddock |
|
8 // |
|
9 // Distributed under the Boost Software License, Version 1.0. (See |
|
10 // accompanying file LICENSE_1_0.txt or copy at |
|
11 // http://www.boost.org/LICENSE_1_0.txt) |
|
12 |
|
13 #include <cstring> |
|
14 #include <cstddef> |
|
15 #include <boost/assert.hpp> |
|
16 #include <boost/static_assert.hpp> |
|
17 #include <boost/detail/interlocked.hpp> |
|
18 #include <boost/thread/win32/thread_primitives.hpp> |
|
19 #include <boost/thread/win32/interlocked_read.hpp> |
|
20 |
|
21 #include <boost/config/abi_prefix.hpp> |
|
22 |
|
23 #ifdef BOOST_NO_STDC_NAMESPACE |
|
24 namespace std |
|
25 { |
|
26 using ::memcpy; |
|
27 using ::ptrdiff_t; |
|
28 } |
|
29 #endif |
|
30 |
|
31 namespace boost |
|
32 { |
|
33 typedef long once_flag; |
|
34 |
|
35 #define BOOST_ONCE_INIT 0 |
|
36 |
|
37 namespace detail |
|
38 { |
|
39 struct win32_mutex_scoped_lock |
|
40 { |
|
41 void* const mutex_handle; |
|
42 explicit win32_mutex_scoped_lock(void* mutex_handle_): |
|
43 mutex_handle(mutex_handle_) |
|
44 { |
|
45 BOOST_VERIFY(!win32::WaitForSingleObject(mutex_handle,win32::infinite)); |
|
46 } |
|
47 ~win32_mutex_scoped_lock() |
|
48 { |
|
49 BOOST_VERIFY(win32::ReleaseMutex(mutex_handle)!=0); |
|
50 } |
|
51 private: |
|
52 void operator=(win32_mutex_scoped_lock&); |
|
53 }; |
|
54 |
|
55 #ifdef BOOST_NO_ANSI_APIS |
|
56 template <class I> |
|
57 void int_to_string(I p, wchar_t* buf) |
|
58 { |
|
59 for(unsigned i=0; i < sizeof(I)*2; ++i,++buf) |
|
60 { |
|
61 *buf = L'A' + static_cast<wchar_t>((p >> (i*4)) & 0x0f); |
|
62 } |
|
63 *buf = 0; |
|
64 } |
|
65 #else |
|
66 template <class I> |
|
67 void int_to_string(I p, char* buf) |
|
68 { |
|
69 for(unsigned i=0; i < sizeof(I)*2; ++i,++buf) |
|
70 { |
|
71 *buf = 'A' + static_cast<char>((p >> (i*4)) & 0x0f); |
|
72 } |
|
73 *buf = 0; |
|
74 } |
|
75 #endif |
|
76 |
|
77 // create a named mutex. It doesn't really matter what this name is |
|
78 // as long as it is unique both to this process, and to the address of "flag": |
|
79 inline void* create_once_mutex(void* flag_address) |
|
80 { |
|
81 |
|
82 #ifdef BOOST_NO_ANSI_APIS |
|
83 typedef wchar_t char_type; |
|
84 static const char_type fixed_mutex_name[]=L"{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag"; |
|
85 #else |
|
86 typedef char char_type; |
|
87 static const char_type fixed_mutex_name[]="{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag"; |
|
88 #endif |
|
89 unsigned const once_mutex_name_fixed_buffer_size=sizeof(fixed_mutex_name)/sizeof(char_type); |
|
90 unsigned const once_mutex_name_fixed_length=once_mutex_name_fixed_buffer_size-1; |
|
91 unsigned const once_mutex_name_length=once_mutex_name_fixed_buffer_size+sizeof(void*)*2+sizeof(unsigned long)*2; |
|
92 char_type mutex_name[once_mutex_name_length]; |
|
93 |
|
94 std::memcpy(mutex_name,fixed_mutex_name,sizeof(fixed_mutex_name)); |
|
95 |
|
96 BOOST_STATIC_ASSERT(sizeof(void*) == sizeof(std::ptrdiff_t)); |
|
97 detail::int_to_string(reinterpret_cast<std::ptrdiff_t>(flag_address), mutex_name + once_mutex_name_fixed_length); |
|
98 detail::int_to_string(win32::GetCurrentProcessId(), mutex_name + once_mutex_name_fixed_length + sizeof(void*)*2); |
|
99 |
|
100 #ifdef BOOST_NO_ANSI_APIS |
|
101 return win32::CreateMutexW(0, 0, mutex_name); |
|
102 #else |
|
103 return win32::CreateMutexA(0, 0, mutex_name); |
|
104 #endif |
|
105 } |
|
106 |
|
107 |
|
108 } |
|
109 |
|
110 |
|
111 template<typename Function> |
|
112 void call_once(once_flag& flag,Function f) |
|
113 { |
|
114 // Try for a quick win: if the procedure has already been called |
|
115 // just skip through: |
|
116 long const function_complete_flag_value=0xc15730e2; |
|
117 |
|
118 if(::boost::detail::interlocked_read_acquire(&flag)!=function_complete_flag_value) |
|
119 { |
|
120 void* const mutex_handle(::boost::detail::create_once_mutex(&flag)); |
|
121 BOOST_ASSERT(mutex_handle); |
|
122 detail::win32::handle_manager const closer(mutex_handle); |
|
123 detail::win32_mutex_scoped_lock const lock(mutex_handle); |
|
124 |
|
125 if(flag!=function_complete_flag_value) |
|
126 { |
|
127 f(); |
|
128 BOOST_INTERLOCKED_EXCHANGE(&flag,function_complete_flag_value); |
|
129 } |
|
130 } |
|
131 } |
|
132 } |
|
133 |
|
134 #include <boost/config/abi_suffix.hpp> |
|
135 |
|
136 #endif |