annotate DEPENDENCIES/generic/include/boost/interprocess/detail/windows_intermodule_singleton.hpp @ 125:34e428693f5d vext

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