Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-03-31 08:05:00

0001 //////////////////////////////////////////////////////////////////////////////
0002 //
0003 // (C) Copyright Ion Gaztanaga 2009-2012. Distributed under the Boost
0004 // Software License, Version 1.0. (See accompanying file
0005 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 // See http://www.boost.org/libs/interprocess for documentation.
0008 //
0009 //////////////////////////////////////////////////////////////////////////////
0010 
0011 #ifndef BOOST_INTERPROCESS_WINDOWS_INTERMODULE_SINGLETON_HPP
0012 #define BOOST_INTERPROCESS_WINDOWS_INTERMODULE_SINGLETON_HPP
0013 
0014 #ifndef BOOST_CONFIG_HPP
0015 #  include <boost/config.hpp>
0016 #endif
0017 0018 ">#
0019 #if defined(BOOST_HAS_PRAGMA_ONCE)
0020 #pragma once
0021 #endif
0022 
0023 #include <boost/interprocess/detail/config_begin.hpp>
0024 #include <boost/interprocess/detail/workaround.hpp>
0025 #include <boost/container/string.hpp>
0026 
0027 #if !defined(BOOST_INTERPROCESS_WINDOWS)
0028    #error "This header can't be included from non-windows operating systems"
0029 #endif
0030 
0031 #include <boost/assert.hpp>
0032 #include <boost/interprocess/detail/intermodule_singleton_common.hpp>
0033 #include <boost/interprocess/sync/windows/winapi_semaphore_wrapper.hpp>
0034 #include <boost/interprocess/sync/windows/winapi_mutex_wrapper.hpp>
0035 #include <boost/interprocess/sync/scoped_lock.hpp>
0036 #include <boost/cstdint.hpp>
0037 #include <string>
0038 #include <boost/container/map.hpp>
0039 
0040 namespace boost{
0041 namespace interprocess{
0042 namespace ipcdetail{
0043 
0044 namespace intermodule_singleton_helpers {
0045 
0046 //This global map will be implemented using 3 sync primitives:
0047 //
0048 //1)  A named mutex that will implement global mutual exclusion between
0049 //    threads from different modules/dlls
0050 //
0051 //2)  A semaphore that will act as a global counter for modules attached to the global map
0052 //    so that the global map can be destroyed when the last module is detached.
0053 //
0054 //3)  A semaphore that will be hacked to hold the address of a heap-allocated map in the
0055 //    max and current semaphore count.
0056 class windows_semaphore_based_map
0057 {
0058    typedef boost::container::map<boost::container::string, ref_count_ptr> map_type;
0059 
0060    public:
0061    windows_semaphore_based_map()
0062    {
0063       map_type *m = new map_type;
0064       boost::uint32_t initial_count = 0;
0065       boost::uint32_t max_count = 0;
0066 
0067       //Windows user address space sizes:
0068       //32 bit windows: [32 bit processes] 2GB or 3GB (31/32 bits)
0069       //64 bit windows: [32 bit processes] 2GB or 4GB (31/32 bits)
0070       //                [64 bit processes] 2GB or 8TB (31/43 bits)
0071       //
0072       //Windows semaphores use 'long' parameters (32 bits in LLP64 data model) and
0073       //those values can't be negative, so we have 31 bits to store something
0074       //in max_count and initial count parameters.
0075       //Also, max count must be bigger than 0 and bigger or equal than initial count.
0076       if(sizeof(void*) == sizeof(boost::uint32_t)){
0077          //This means that for 32 bit processes, a semaphore count (31 usable bits) is
0078          //enough to store 4 byte aligned memory (4GB -> 32 bits - 2 bits = 30 bits).
0079          //The max count will hold the pointer value and current semaphore count
0080          //will be zero.
0081          //
0082          //Relying in UB with a cast through union, but all known windows compilers
0083          //accept this (C11 also accepts this).
0084          union caster_union
0085          {
0086             void *addr;
0087             boost::uint32_t addr_uint32;
0088          } caster;
0089          caster.addr = m;
0090          //memory is at least 4 byte aligned in windows
0091          BOOST_ASSERT((caster.addr_uint32 & boost::uint32_t(3)) == 0);
0092          max_count = caster.addr_uint32 >> 2;
0093       }
0094       else if(sizeof(void*) == sizeof(boost::uint64_t)){
0095          //Relying in UB with a cast through union, but all known windows compilers
0096          //accept this (C11 accepts this).
0097          union caster_union
0098          {
0099             void *addr;
0100             boost::uint64_t addr_uint64;
0101          } caster;
0102          caster.addr = m;
0103          //We'll encode the address using 30 bits in each 32 bit high and low parts.
0104          //High part will be the sem max count, low part will be the sem initial count.
0105          //(restrictions: max count > 0, initial count >= 0 and max count >= initial count):
0106          //
0107          // - Low part will be shifted two times (4 byte alignment) so that top
0108          //   two bits are cleared (the top one for sign, the next one to
0109          //   assure low part value is always less than the high part value.
0110          // - The top bit of the high part will be cleared and the next bit will be 1
0111          //   (so high part is always bigger than low part due to the quasi-top bit).
0112          //
0113          //   This means that the addresses we can store must be 4 byte aligned
0114          //   and less than 1 ExbiBytes ( 2^60 bytes, ~1 ExaByte). User-level address space in Windows 64
0115          //   is much less than this (8TB, 2^43 bytes): "1 EByte (or it was 640K?) ought to be enough for anybody" ;-).
0116          caster.addr = m;
0117          BOOST_ASSERT((caster.addr_uint64 & boost::uint64_t(3)) == 0);
0118          max_count = boost::uint32_t(caster.addr_uint64 >> 32);
0119          initial_count = boost::uint32_t(caster.addr_uint64 & boost::uint64_t(0x00000000FFFFFFFF));
0120          initial_count = initial_count/4;
0121          //Make sure top two bits are zero
0122          BOOST_ASSERT((max_count & boost::uint32_t(0xC0000000)) == 0);
0123          //Set quasi-top bit
0124          max_count |= boost::uint32_t(0x40000000);
0125       }
0126       bool created = false;
0127       const permissions & perm = permissions();
0128       std::string pid_creation_time, name;
0129       get_pid_creation_time_str(pid_creation_time);
0130       name = "bipc_gmap_sem_lock_";
0131       name += pid_creation_time;
0132       bool success = m_mtx_lock.open_or_create(name.c_str(), perm);
0133       name = "bipc_gmap_sem_count_";
0134       name += pid_creation_time;
0135       scoped_lock<winapi_mutex_wrapper> lck(m_mtx_lock);
0136       {
0137          success = success && m_sem_count.open_or_create
0138             ( name.c_str(), static_cast<long>(0), winapi_semaphore_wrapper::MaxCount, perm, created);
0139          name = "bipc_gmap_sem_map_";
0140          name += pid_creation_time;
0141          success = success && m_sem_map.open_or_create
0142             (name.c_str(), (long)initial_count, (long)max_count, perm, created);
0143          if(!success){
0144             delete m;
0145             //winapi_xxx wrappers do the cleanup...
0146             throw int(0);
0147          }
0148          if(!created){
0149             delete m;
0150          }
0151          else{
0152             BOOST_ASSERT(&get_map_unlocked() == m);
0153          }
0154          m_sem_count.post();
0155       }
0156    }
0157 
0158    map_type &get_map_unlocked()
0159    {
0160       if(sizeof(void*) == sizeof(boost::uint32_t)){
0161          union caster_union
0162          {
0163             void *addr;
0164             boost::uint32_t addr_uint32;
0165          } caster;
0166          caster.addr = 0;
0167          caster.addr_uint32 = boost::uint32_t(m_sem_map.limit());
0168          caster.addr_uint32 = caster.addr_uint32 << 2u;
0169          return *static_cast<map_type*>(caster.addr);
0170       }
0171       else{
0172          union caster_union
0173          {
0174             void *addr;
0175             boost::uint64_t addr_uint64;
0176          } caster;
0177          boost::uint32_t max_count(boost::uint32_t(m_sem_map.limit()))
0178                        , initial_count(boost::uint32_t(m_sem_map.value()));
0179          //Clear quasi-top bit
0180          max_count &= boost::uint32_t(0xBFFFFFFF);
0181          caster.addr_uint64 = max_count;
0182          caster.addr_uint64 =  caster.addr_uint64 << 32u;
0183          caster.addr_uint64 |= boost::uint64_t(initial_count) << 2;
0184          return *static_cast<map_type*>(caster.addr);
0185       }
0186    }
0187 
0188    ref_count_ptr *find(const char *name)
0189    {
0190       scoped_lock<winapi_mutex_wrapper> lck(m_mtx_lock);
0191       map_type &map = this->get_map_unlocked();
0192       map_type::iterator it = map.find(boost::container::string(name));
0193       if(it != map.end()){
0194          return &it->second;
0195       }
0196       else{
0197          return 0;
0198       }
0199    }
0200 
0201    ref_count_ptr * insert(const char *name, const ref_count_ptr &ref)
0202    {
0203       scoped_lock<winapi_mutex_wrapper> lck(m_mtx_lock);
0204       map_type &map = this->get_map_unlocked();
0205       map_type::iterator it = map.insert(map_type::value_type(boost::container::string(name), ref)).first;
0206       return &it->second;
0207    }
0208 
0209    bool erase(const char *name)
0210    {
0211       scoped_lock<winapi_mutex_wrapper> lck(m_mtx_lock);
0212       map_type &map = this->get_map_unlocked();
0213       return map.erase(boost::container::string(name)) != 0;
0214    }
0215 
0216    template<class F>
0217    void atomic_func(F &f)
0218    {
0219       scoped_lock<winapi_mutex_wrapper> lck(m_mtx_lock);
0220       f();
0221    }
0222 
0223    ~windows_semaphore_based_map()
0224    {
0225       scoped_lock<winapi_mutex_wrapper> lck(m_mtx_lock);
0226       m_sem_count.wait();
0227       if(0 == m_sem_count.value()){
0228          map_type &map = this->get_map_unlocked();
0229          BOOST_ASSERT(map.empty());
0230          delete &map;
0231       }
0232       //First close sems to protect this with the external mutex
0233       m_sem_map.close();
0234       m_sem_count.close();
0235       //Once scoped_lock unlocks the mutex, the destructor will close the handle...
0236    }
0237 
0238    private:
0239    winapi_mutex_wrapper     m_mtx_lock;
0240    winapi_semaphore_wrapper m_sem_map;
0241    winapi_semaphore_wrapper m_sem_count;
0242 };
0243 
0244 template<>
0245 struct thread_safe_global_map_dependant<windows_semaphore_based_map>
0246 {
0247    static void apply_gmem_erase_logic(const char *, const char *){}
0248 
0249    static bool remove_old_gmem()
0250    { return true; }
0251 
0252    struct lock_file_logic
0253    {
0254       lock_file_logic(windows_semaphore_based_map &)
0255          : retry_with_new_map(false)
0256       {}
0257 
0258       void operator()(void){}
0259       bool retry() const { return retry_with_new_map; }
0260       private:
0261       const bool retry_with_new_map;
0262    };
0263 
0264    static void construct_map(void *addr)
0265    {
0266       ::new (addr)windows_semaphore_based_map;
0267    }
0268 
0269    struct unlink_map_logic
0270    {
0271       unlink_map_logic(windows_semaphore_based_map &)
0272       {}
0273       void operator()(){}
0274    };
0275 
0276    static ref_count_ptr *find(windows_semaphore_based_map &map, const char *name)
0277    {
0278       return map.find(name);
0279    }
0280 
0281    static ref_count_ptr * insert(windows_semaphore_based_map &map, const char *name, const ref_count_ptr &ref)
0282    {
0283       return map.insert(name, ref);
0284    }
0285 
0286    static bool erase(windows_semaphore_based_map &map, const char *name)
0287    {
0288       return map.erase(name);
0289    }
0290 
0291    template<class F>
0292    static void atomic_func(windows_semaphore_based_map &map, F &f)
0293    {
0294       map.atomic_func(f);
0295    }
0296 };
0297 
0298 }  //namespace intermodule_singleton_helpers {
0299 
0300 template<typename C, bool LazyInit = true, bool Phoenix = false>
0301 class windows_intermodule_singleton
0302    : public intermodule_singleton_impl
0303       < C
0304       , LazyInit
0305       , Phoenix
0306       , intermodule_singleton_helpers::windows_semaphore_based_map
0307       >
0308 {};
0309 
0310 }  //namespace ipcdetail{
0311 }  //namespace interprocess{
0312 }  //namespace boost{
0313 
0314 #include <boost/interprocess/detail/config_end.hpp>
0315 
0316 #endif   //#ifndef BOOST_INTERPROCESS_WINDOWS_INTERMODULE_SINGLETON_HPP