Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:38:28

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