]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/interprocess/detail/windows_intermodule_singleton.hpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / boost / interprocess / detail / windows_intermodule_singleton.hpp
1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Ion Gaztanaga 2009-2012. Distributed under the Boost
4 // Software License, Version 1.0. (See accompanying file
5 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // See http://www.boost.org/libs/interprocess for documentation.
8 //
9 //////////////////////////////////////////////////////////////////////////////
10
11 #ifndef BOOST_INTERPROCESS_WINDOWS_INTERMODULE_SINGLETON_HPP
12 #define BOOST_INTERPROCESS_WINDOWS_INTERMODULE_SINGLETON_HPP
13
14 #ifndef BOOST_CONFIG_HPP
15 # include <boost/config.hpp>
16 #endif
17 #
18 #if defined(BOOST_HAS_PRAGMA_ONCE)
19 #pragma once
20 #endif
21
22 #include <boost/interprocess/detail/config_begin.hpp>
23 #include <boost/interprocess/detail/workaround.hpp>
24 #include <boost/container/string.hpp>
25
26 #if !defined(BOOST_INTERPROCESS_WINDOWS)
27 #error "This header can't be included from non-windows operating systems"
28 #endif
29
30 #include <boost/assert.hpp>
31 #include <boost/interprocess/detail/intermodule_singleton_common.hpp>
32 #include <boost/interprocess/sync/windows/winapi_semaphore_wrapper.hpp>
33 #include <boost/interprocess/sync/windows/winapi_mutex_wrapper.hpp>
34 #include <boost/interprocess/sync/scoped_lock.hpp>
35 #include <boost/cstdint.hpp>
36 #include <string>
37 #include <boost/container/map.hpp>
38
39 namespace boost{
40 namespace interprocess{
41 namespace ipcdetail{
42
43 namespace intermodule_singleton_helpers {
44
45 //This global map will be implemented using 3 sync primitives:
46 //
47 //1) A named mutex that will implement global mutual exclusion between
48 // threads from different modules/dlls
49 //
50 //2) A semaphore that will act as a global counter for modules attached to the global map
51 // so that the global map can be destroyed when the last module is detached.
52 //
53 //3) A semaphore that will be hacked to hold the address of a heap-allocated map in the
54 // max and current semaphore count.
55 class windows_semaphore_based_map
56 {
57 typedef boost::container::map<boost::container::string, ref_count_ptr> map_type;
58
59 public:
60 windows_semaphore_based_map()
61 {
62 map_type *m = new map_type;
63 boost::uint32_t initial_count = 0;
64 boost::uint32_t max_count = 0;
65
66 //Windows user address space sizes:
67 //32 bit windows: [32 bit processes] 2GB or 3GB (31/32 bits)
68 //64 bit windows: [32 bit processes] 2GB or 4GB (31/32 bits)
69 // [64 bit processes] 2GB or 8TB (31/43 bits)
70 //
71 //Windows semaphores use 'long' parameters (32 bits in LLP64 data model) and
72 //those values can't be negative, so we have 31 bits to store something
73 //in max_count and initial count parameters.
74 //Also, max count must be bigger than 0 and bigger or equal than initial count.
75 if(sizeof(void*) == sizeof(boost::uint32_t)){
76 //This means that for 32 bit processes, a semaphore count (31 usable bits) is
77 //enough to store 4 byte aligned memory (4GB -> 32 bits - 2 bits = 30 bits).
78 //The max count will hold the pointer value and current semaphore count
79 //will be zero.
80 //
81 //Relying in UB with a cast through union, but all known windows compilers
82 //accept this (C11 also accepts this).
83 union caster_union
84 {
85 void *addr;
86 boost::uint32_t addr_uint32;
87 } caster;
88 caster.addr = m;
89 //memory is at least 4 byte aligned in windows
90 BOOST_ASSERT((caster.addr_uint32 & boost::uint32_t(3)) == 0);
91 max_count = caster.addr_uint32 >> 2;
92 }
93 else if(sizeof(void*) == sizeof(boost::uint64_t)){
94 //Relying in UB with a cast through union, but all known windows compilers
95 //accept this (C11 accepts this).
96 union caster_union
97 {
98 void *addr;
99 boost::uint64_t addr_uint64;
100 } caster;
101 caster.addr = m;
102 //We'll encode the address using 30 bits in each 32 bit high and low parts.
103 //High part will be the sem max count, low part will be the sem initial count.
104 //(restrictions: max count > 0, initial count >= 0 and max count >= initial count):
105 //
106 // - Low part will be shifted two times (4 byte alignment) so that top
107 // two bits are cleared (the top one for sign, the next one to
108 // assure low part value is always less than the high part value.
109 // - The top bit of the high part will be cleared and the next bit will be 1
110 // (so high part is always bigger than low part due to the quasi-top bit).
111 //
112 // This means that the addresses we can store must be 4 byte aligned
113 // and less than 1 ExbiBytes ( 2^60 bytes, ~1 ExaByte). User-level address space in Windows 64
114 // is much less than this (8TB, 2^43 bytes): "1 EByte (or it was 640K?) ought to be enough for anybody" ;-).
115 caster.addr = m;
116 BOOST_ASSERT((caster.addr_uint64 & boost::uint64_t(3)) == 0);
117 max_count = boost::uint32_t(caster.addr_uint64 >> 32);
118 initial_count = boost::uint32_t(caster.addr_uint64);
119 initial_count = initial_count/4;
120 //Make sure top two bits are zero
121 BOOST_ASSERT((max_count & boost::uint32_t(0xC0000000)) == 0);
122 //Set quasi-top bit
123 max_count |= boost::uint32_t(0x40000000);
124 }
125 bool created = false;
126 const permissions & perm = permissions();
127 std::string pid_creation_time, name;
128 get_pid_creation_time_str(pid_creation_time);
129 name = "bipc_gmap_sem_lock_";
130 name += pid_creation_time;
131 bool success = m_mtx_lock.open_or_create(name.c_str(), perm);
132 name = "bipc_gmap_sem_count_";
133 name += pid_creation_time;
134 scoped_lock<winapi_mutex_wrapper> lck(m_mtx_lock);
135 {
136 success = success && m_sem_count.open_or_create
137 ( name.c_str(), static_cast<long>(0), winapi_semaphore_wrapper::MaxCount, perm, created);
138 name = "bipc_gmap_sem_map_";
139 name += pid_creation_time;
140 success = success && m_sem_map.open_or_create
141 (name.c_str(), (long)initial_count, (long)max_count, perm, created);
142 if(!success){
143 delete m;
144 //winapi_xxx wrappers do the cleanup...
145 throw int(0);
146 }
147 if(!created){
148 delete m;
149 }
150 else{
151 BOOST_ASSERT(&get_map_unlocked() == m);
152 }
153 m_sem_count.post();
154 }
155 }
156
157 map_type &get_map_unlocked()
158 {
159 if(sizeof(void*) == sizeof(boost::uint32_t)){
160 union caster_union
161 {
162 void *addr;
163 boost::uint32_t addr_uint32;
164 } caster;
165 caster.addr = 0;
166 caster.addr_uint32 = boost::uint32_t(m_sem_map.limit());
167 caster.addr_uint32 = caster.addr_uint32 << 2u;
168 return *static_cast<map_type*>(caster.addr);
169 }
170 else{
171 union caster_union
172 {
173 void *addr;
174 boost::uint64_t addr_uint64;
175 } caster;
176 boost::uint32_t max_count(boost::uint32_t(m_sem_map.limit()))
177 , initial_count(boost::uint32_t(m_sem_map.value()));
178 //Clear quasi-top bit
179 max_count &= boost::uint32_t(0xBFFFFFFF);
180 caster.addr_uint64 = max_count;
181 caster.addr_uint64 = caster.addr_uint64 << 32u;
182 caster.addr_uint64 |= boost::uint64_t(initial_count) << 2;
183 return *static_cast<map_type*>(caster.addr);
184 }
185 }
186
187 ref_count_ptr *find(const char *name)
188 {
189 scoped_lock<winapi_mutex_wrapper> lck(m_mtx_lock);
190 map_type &map = this->get_map_unlocked();
191 map_type::iterator it = map.find(boost::container::string(name));
192 if(it != map.end()){
193 return &it->second;
194 }
195 else{
196 return 0;
197 }
198 }
199
200 ref_count_ptr * insert(const char *name, const ref_count_ptr &ref)
201 {
202 scoped_lock<winapi_mutex_wrapper> lck(m_mtx_lock);
203 map_type &map = this->get_map_unlocked();
204 map_type::iterator it = map.insert(map_type::value_type(boost::container::string(name), ref)).first;
205 return &it->second;
206 }
207
208 bool erase(const char *name)
209 {
210 scoped_lock<winapi_mutex_wrapper> lck(m_mtx_lock);
211 map_type &map = this->get_map_unlocked();
212 return map.erase(boost::container::string(name)) != 0;
213 }
214
215 template<class F>
216 void atomic_func(F &f)
217 {
218 scoped_lock<winapi_mutex_wrapper> lck(m_mtx_lock);
219 f();
220 }
221
222 ~windows_semaphore_based_map()
223 {
224 scoped_lock<winapi_mutex_wrapper> lck(m_mtx_lock);
225 m_sem_count.wait();
226 if(0 == m_sem_count.value()){
227 map_type &map = this->get_map_unlocked();
228 BOOST_ASSERT(map.empty());
229 delete &map;
230 }
231 //First close sems to protect this with the external mutex
232 m_sem_map.close();
233 m_sem_count.close();
234 //Once scoped_lock unlocks the mutex, the destructor will close the handle...
235 }
236
237 private:
238 winapi_mutex_wrapper m_mtx_lock;
239 winapi_semaphore_wrapper m_sem_map;
240 winapi_semaphore_wrapper m_sem_count;
241 };
242
243 template<>
244 struct thread_safe_global_map_dependant<windows_semaphore_based_map>
245 {
246 static void apply_gmem_erase_logic(const char *, const char *){}
247
248 static bool remove_old_gmem()
249 { return true; }
250
251 struct lock_file_logic
252 {
253 lock_file_logic(windows_semaphore_based_map &)
254 : retry_with_new_map(false)
255 {}
256
257 void operator()(void){}
258 bool retry() const { return retry_with_new_map; }
259 private:
260 const bool retry_with_new_map;
261 };
262
263 static void construct_map(void *addr)
264 {
265 ::new (addr)windows_semaphore_based_map;
266 }
267
268 struct unlink_map_logic
269 {
270 unlink_map_logic(windows_semaphore_based_map &)
271 {}
272 void operator()(){}
273 };
274
275 static ref_count_ptr *find(windows_semaphore_based_map &map, const char *name)
276 {
277 return map.find(name);
278 }
279
280 static ref_count_ptr * insert(windows_semaphore_based_map &map, const char *name, const ref_count_ptr &ref)
281 {
282 return map.insert(name, ref);
283 }
284
285 static bool erase(windows_semaphore_based_map &map, const char *name)
286 {
287 return map.erase(name);
288 }
289
290 template<class F>
291 static void atomic_func(windows_semaphore_based_map &map, F &f)
292 {
293 map.atomic_func(f);
294 }
295 };
296
297 } //namespace intermodule_singleton_helpers {
298
299 template<typename C, bool LazyInit = true, bool Phoenix = false>
300 class windows_intermodule_singleton
301 : public intermodule_singleton_impl
302 < C
303 , LazyInit
304 , Phoenix
305 , intermodule_singleton_helpers::windows_semaphore_based_map
306 >
307 {};
308
309 } //namespace ipcdetail{
310 } //namespace interprocess{
311 } //namespace boost{
312
313 #include <boost/interprocess/detail/config_end.hpp>
314
315 #endif //#ifndef BOOST_INTERPROCESS_WINDOWS_INTERMODULE_SINGLETON_HPP