summaryrefslogtreecommitdiff
path: root/src/third_party/boost-1.60.0/boost/interprocess/detail/windows_intermodule_singleton.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/third_party/boost-1.60.0/boost/interprocess/detail/windows_intermodule_singleton.hpp')
-rw-r--r--src/third_party/boost-1.60.0/boost/interprocess/detail/windows_intermodule_singleton.hpp314
1 files changed, 314 insertions, 0 deletions
diff --git a/src/third_party/boost-1.60.0/boost/interprocess/detail/windows_intermodule_singleton.hpp b/src/third_party/boost-1.60.0/boost/interprocess/detail/windows_intermodule_singleton.hpp
new file mode 100644
index 00000000000..12ad2015e3a
--- /dev/null
+++ b/src/third_party/boost-1.60.0/boost/interprocess/detail/windows_intermodule_singleton.hpp
@@ -0,0 +1,314 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (C) Copyright Ion Gaztanaga 2009-2012. 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)
+//
+// See http://www.boost.org/libs/interprocess for documentation.
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#ifndef BOOST_INTERPROCESS_WINDOWS_INTERMODULE_SINGLETON_HPP
+#define BOOST_INTERPROCESS_WINDOWS_INTERMODULE_SINGLETON_HPP
+
+#ifndef BOOST_CONFIG_HPP
+# include <boost/config.hpp>
+#endif
+#
+#if defined(BOOST_HAS_PRAGMA_ONCE)
+#pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+#include <boost/container/string.hpp>
+
+#if !defined(BOOST_INTERPROCESS_WINDOWS)
+ #error "This header can't be included from non-windows operating systems"
+#endif
+
+#include <boost/assert.hpp>
+#include <boost/interprocess/detail/intermodule_singleton_common.hpp>
+#include <boost/interprocess/sync/windows/winapi_semaphore_wrapper.hpp>
+#include <boost/interprocess/sync/windows/winapi_mutex_wrapper.hpp>
+#include <boost/interprocess/sync/scoped_lock.hpp>
+#include <boost/cstdint.hpp>
+#include <string>
+#include <boost/container/map.hpp>
+
+namespace boost{
+namespace interprocess{
+namespace ipcdetail{
+
+namespace intermodule_singleton_helpers {
+
+//This global map will be implemented using 3 sync primitives:
+//
+//1) A named mutex that will implement global mutual exclusion between
+// threads from different modules/dlls
+//
+//2) A semaphore that will act as a global counter for modules attached to the global map
+// so that the global map can be destroyed when the last module is detached.
+//
+//3) A semaphore that will be hacked to hold the address of a heap-allocated map in the
+// max and current semaphore count.
+class windows_semaphore_based_map
+{
+ typedef boost::container::map<boost::container::string, ref_count_ptr> map_type;
+
+ public:
+ windows_semaphore_based_map()
+ {
+ map_type *m = new map_type;
+ boost::uint32_t initial_count = 0;
+ boost::uint32_t max_count = 0;
+
+ //Windows user address space sizes:
+ //32 bit windows: [32 bit processes] 2GB or 3GB (31/32 bits)
+ //64 bit windows: [32 bit processes] 2GB or 4GB (31/32 bits)
+ // [64 bit processes] 2GB or 8TB (31/43 bits)
+ //
+ //Windows semaphores use 'long' parameters (32 bits in LLP64 data model) and
+ //those values can't be negative, so we have 31 bits to store something
+ //in max_count and initial count parameters.
+ //Also, max count must be bigger than 0 and bigger or equal than initial count.
+ if(sizeof(void*) == sizeof(boost::uint32_t)){
+ //This means that for 32 bit processes, a semaphore count (31 usable bits) is
+ //enough to store 4 byte aligned memory (4GB -> 32 bits - 2 bits = 30 bits).
+ //The max count will hold the pointer value and current semaphore count
+ //will be zero.
+ //
+ //Relying in UB with a cast through union, but all known windows compilers
+ //accept this (C11 also accepts this).
+ union caster_union
+ {
+ void *addr;
+ boost::uint32_t addr_uint32;
+ } caster;
+ caster.addr = m;
+ //memory is at least 4 byte aligned in windows
+ BOOST_ASSERT((caster.addr_uint32 & boost::uint32_t(3)) == 0);
+ max_count = caster.addr_uint32 >> 2;
+ }
+ else if(sizeof(void*) == sizeof(boost::uint64_t)){
+ //Relying in UB with a cast through union, but all known windows compilers
+ //accept this (C11 accepts this).
+ union caster_union
+ {
+ void *addr;
+ boost::uint64_t addr_uint64;
+ } caster;
+ caster.addr = m;
+ //We'll encode the address using 30 bits in each 32 bit high and low parts.
+ //High part will be the sem max count, low part will be the sem initial count.
+ //(restrictions: max count > 0, initial count >= 0 and max count >= initial count):
+ //
+ // - Low part will be shifted two times (4 byte alignment) so that top
+ // two bits are cleared (the top one for sign, the next one to
+ // assure low part value is always less than the high part value.
+ // - The top bit of the high part will be cleared and the next bit will be 1
+ // (so high part is always bigger than low part due to the quasi-top bit).
+ //
+ // This means that the addresses we can store must be 4 byte aligned
+ // and less than 1 ExbiBytes ( 2^60 bytes, ~1 ExaByte). User-level address space in Windows 64
+ // is much less than this (8TB, 2^43 bytes): "1 EByte (or it was 640K?) ought to be enough for anybody" ;-).
+ caster.addr = m;
+ BOOST_ASSERT((caster.addr_uint64 & boost::uint64_t(3)) == 0);
+ max_count = boost::uint32_t(caster.addr_uint64 >> 32);
+ initial_count = boost::uint32_t(caster.addr_uint64);
+ initial_count = initial_count/4;
+ //Make sure top two bits are zero
+ BOOST_ASSERT((max_count & boost::uint32_t(0xC0000000)) == 0);
+ //Set quasi-top bit
+ max_count |= boost::uint32_t(0x40000000);
+ }
+ bool created = false;
+ const permissions & perm = permissions();
+ std::string pid_creation_time, name;
+ get_pid_creation_time_str(pid_creation_time);
+ name = "bipc_gmap_sem_lock_";
+ name += pid_creation_time;
+ bool success = m_mtx_lock.open_or_create(name.c_str(), perm);
+ name = "bipc_gmap_sem_count_";
+ name += pid_creation_time;
+ scoped_lock<winapi_mutex_wrapper> lck(m_mtx_lock);
+ {
+ success = success && m_sem_count.open_or_create
+ ( name.c_str(), static_cast<long>(0), winapi_semaphore_wrapper::MaxCount, perm, created);
+ name = "bipc_gmap_sem_map_";
+ name += pid_creation_time;
+ success = success && m_sem_map.open_or_create
+ (name.c_str(), initial_count, max_count, perm, created);
+ if(!success){
+ delete m;
+ //winapi_xxx wrappers do the cleanup...
+ throw int(0);
+ }
+ if(!created){
+ delete m;
+ }
+ else{
+ BOOST_ASSERT(&get_map_unlocked() == m);
+ }
+ m_sem_count.post();
+ }
+ }
+
+ map_type &get_map_unlocked()
+ {
+ if(sizeof(void*) == sizeof(boost::uint32_t)){
+ union caster_union
+ {
+ void *addr;
+ boost::uint32_t addr_uint32;
+ } caster;
+ caster.addr = 0;
+ caster.addr_uint32 = m_sem_map.limit();
+ caster.addr_uint32 = caster.addr_uint32 << 2;
+ return *static_cast<map_type*>(caster.addr);
+ }
+ else{
+ union caster_union
+ {
+ void *addr;
+ boost::uint64_t addr_uint64;
+ } caster;
+ boost::uint32_t max_count(m_sem_map.limit()), initial_count(m_sem_map.value());
+ //Clear quasi-top bit
+ max_count &= boost::uint32_t(0xBFFFFFFF);
+ caster.addr_uint64 = max_count;
+ caster.addr_uint64 = caster.addr_uint64 << 32;
+ caster.addr_uint64 |= boost::uint64_t(initial_count) << 2;
+ return *static_cast<map_type*>(caster.addr);
+ }
+ }
+
+ ref_count_ptr *find(const char *name)
+ {
+ scoped_lock<winapi_mutex_wrapper> lck(m_mtx_lock);
+ map_type &map = this->get_map_unlocked();
+ map_type::iterator it = map.find(boost::container::string(name));
+ if(it != map.end()){
+ return &it->second;
+ }
+ else{
+ return 0;
+ }
+ }
+
+ ref_count_ptr * insert(const char *name, const ref_count_ptr &ref)
+ {
+ scoped_lock<winapi_mutex_wrapper> lck(m_mtx_lock);
+ map_type &map = this->get_map_unlocked();
+ map_type::iterator it = map.insert(map_type::value_type(boost::container::string(name), ref)).first;
+ return &it->second;
+ }
+
+ bool erase(const char *name)
+ {
+ scoped_lock<winapi_mutex_wrapper> lck(m_mtx_lock);
+ map_type &map = this->get_map_unlocked();
+ return map.erase(boost::container::string(name)) != 0;
+ }
+
+ template<class F>
+ void atomic_func(F &f)
+ {
+ scoped_lock<winapi_mutex_wrapper> lck(m_mtx_lock);
+ f();
+ }
+
+ ~windows_semaphore_based_map()
+ {
+ scoped_lock<winapi_mutex_wrapper> lck(m_mtx_lock);
+ m_sem_count.wait();
+ if(0 == m_sem_count.value()){
+ map_type &map = this->get_map_unlocked();
+ BOOST_ASSERT(map.empty());
+ delete &map;
+ }
+ //First close sems to protect this with the external mutex
+ m_sem_map.close();
+ m_sem_count.close();
+ //Once scoped_lock unlocks the mutex, the destructor will close the handle...
+ }
+
+ private:
+ winapi_mutex_wrapper m_mtx_lock;
+ winapi_semaphore_wrapper m_sem_map;
+ winapi_semaphore_wrapper m_sem_count;
+};
+
+template<>
+struct thread_safe_global_map_dependant<windows_semaphore_based_map>
+{
+ static void apply_gmem_erase_logic(const char *, const char *){}
+
+ static bool remove_old_gmem()
+ { return true; }
+
+ struct lock_file_logic
+ {
+ lock_file_logic(windows_semaphore_based_map &)
+ : retry_with_new_map(false)
+ {}
+
+ void operator()(void){}
+ bool retry() const { return retry_with_new_map; }
+ private:
+ const bool retry_with_new_map;
+ };
+
+ static void construct_map(void *addr)
+ {
+ ::new (addr)windows_semaphore_based_map;
+ }
+
+ struct unlink_map_logic
+ {
+ unlink_map_logic(windows_semaphore_based_map &)
+ {}
+ void operator()(){}
+ };
+
+ static ref_count_ptr *find(windows_semaphore_based_map &map, const char *name)
+ {
+ return map.find(name);
+ }
+
+ static ref_count_ptr * insert(windows_semaphore_based_map &map, const char *name, const ref_count_ptr &ref)
+ {
+ return map.insert(name, ref);
+ }
+
+ static bool erase(windows_semaphore_based_map &map, const char *name)
+ {
+ return map.erase(name);
+ }
+
+ template<class F>
+ static void atomic_func(windows_semaphore_based_map &map, F &f)
+ {
+ map.atomic_func(f);
+ }
+};
+
+} //namespace intermodule_singleton_helpers {
+
+template<typename C, bool LazyInit = true, bool Phoenix = false>
+class windows_intermodule_singleton
+ : public intermodule_singleton_impl
+ < C
+ , LazyInit
+ , Phoenix
+ , intermodule_singleton_helpers::windows_semaphore_based_map
+ >
+{};
+
+} //namespace ipcdetail{
+} //namespace interprocess{
+} //namespace boost{
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //#ifndef BOOST_INTERPROCESS_WINDOWS_INTERMODULE_SINGLETON_HPP