123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314 |
- //////////////////////////////////////////////////////////////////////////////
- //
- // (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 ↦
- }
- //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
|