Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:34:05

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_INTERMODULE_SINGLETON_COMMON_HPP
0012 #define BOOST_INTERPROCESS_INTERMODULE_SINGLETON_COMMON_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 
0025 #include <boost/interprocess/detail/atomic.hpp>
0026 #include <boost/interprocess/detail/os_thread_functions.hpp>
0027 #include <boost/interprocess/exceptions.hpp>
0028 #include <boost/container/detail/type_traits.hpp>  //alignment_of, aligned_storage
0029 #include <boost/interprocess/detail/mpl.hpp>
0030 #include <boost/interprocess/sync/spin/wait.hpp>
0031 #include <boost/assert.hpp>
0032 #include <cstddef>
0033 #include <cstdio>
0034 #include <cstdlib>
0035 #include <cstring>
0036 #include <string>
0037 #include <typeinfo>
0038 #include <sstream>
0039 
0040 namespace boost{
0041 namespace interprocess{
0042 namespace ipcdetail{
0043 
0044 namespace intermodule_singleton_helpers {
0045 
0046 inline void get_pid_creation_time_str(std::string &s)
0047 {
0048    std::stringstream stream;
0049    stream << get_current_process_id() << '_';
0050    const unsigned long long total_microsecs = get_current_process_creation_time();
0051    const unsigned long secs  = static_cast<unsigned long>(total_microsecs/1000000ul);
0052    const unsigned long usecs = static_cast<unsigned long>(total_microsecs%1000000ul);
0053    stream << secs << '.' << usecs;
0054    s = stream.str();
0055 }
0056 
0057 inline const char *get_map_base_name()
0058 {  return "bip.gmem.map.";  }
0059 
0060 inline void get_map_name(std::string &map_name)
0061 {
0062    get_pid_creation_time_str(map_name);
0063    map_name.insert(0, get_map_base_name());
0064 }
0065 
0066 inline std::size_t get_map_size()
0067 {  return 65536;  }
0068 
0069 template<class ThreadSafeGlobalMap>
0070 struct thread_safe_global_map_dependant;
0071 
0072 }  //namespace intermodule_singleton_helpers {
0073 
0074 //This class contains common code for all singleton types, so that we instantiate this
0075 //code just once per module. This class also holds a thread soafe global map
0076 //to be used by all instances protected with a reference count
0077 template<class ThreadSafeGlobalMap>
0078 class intermodule_singleton_common
0079 {
0080    public:
0081    typedef void*(singleton_constructor_t)(ThreadSafeGlobalMap &);
0082    typedef void (singleton_destructor_t)(void *, ThreadSafeGlobalMap &);
0083 
0084    static const ::boost::uint32_t Uninitialized       = 0u;
0085    static const ::boost::uint32_t Initializing        = 1u;
0086    static const ::boost::uint32_t Initialized         = 2u;
0087    static const ::boost::uint32_t Broken              = 3u;
0088    static const ::boost::uint32_t Destroyed           = 4u;
0089 
0090    //Initialize this_module_singleton_ptr, creates the global map if needed and also creates an unique
0091    //opaque type in global map through a singleton_constructor_t function call,
0092    //initializing the passed pointer to that unique instance.
0093    //
0094    //We have two concurrency types here. a)the global map/singleton creation must
0095    //be safe between threads of this process but in different modules/dlls. b)
0096    //the pointer to the singleton is per-module, so we have to protect this
0097    //initization between threads of the same module.
0098    //
0099    //All static variables declared here are shared between inside a module
0100    //so atomic operations will synchronize only threads of the same module.
0101    static void initialize_singleton_logic
0102       (void *&ptr, volatile boost::uint32_t &this_module_singleton_initialized, singleton_constructor_t constructor, bool phoenix)
0103    {
0104       //If current module is not initialized enter to lock free logic
0105       if(atomic_read32(&this_module_singleton_initialized) != Initialized){
0106          //Now a single thread of the module will succeed in this CAS.
0107          //trying to pass from Uninitialized to Initializing
0108          ::boost::uint32_t previous_module_singleton_initialized = atomic_cas32
0109             (&this_module_singleton_initialized, Initializing, Uninitialized);
0110          //If the thread succeeded the CAS (winner) it will compete with other
0111          //winner threads from other modules to create the global map
0112          if(previous_module_singleton_initialized == Destroyed){
0113             //Trying to resurrect a dead Phoenix singleton. Just try to
0114             //mark it as uninitialized and start again
0115             if(phoenix){
0116                atomic_cas32(&this_module_singleton_initialized, Uninitialized, Destroyed);
0117                previous_module_singleton_initialized = atomic_cas32
0118                   (&this_module_singleton_initialized, Initializing, Uninitialized);
0119             }
0120             //Trying to resurrect a non-Phoenix dead singleton is an error
0121             else{
0122                throw interprocess_exception("Boost.Interprocess: Dead reference on non-Phoenix singleton of type");
0123             }
0124          }
0125          if(previous_module_singleton_initialized == Uninitialized){
0126             BOOST_INTERPROCESS_TRY{
0127                //Now initialize the global map, this function must solve concurrency
0128                //issues between threads of several modules
0129                initialize_global_map_handle();
0130                //Now try to create the singleton in global map.
0131                //This function solves concurrency issues
0132                //between threads of several modules
0133                ThreadSafeGlobalMap *const pmap = get_map_ptr();
0134                void *tmp = constructor(*pmap);
0135                //Increment the module reference count that reflects how many
0136                //singletons this module holds, so that we can safely destroy
0137                //module global map object when no singleton is left
0138                atomic_inc32(&this_module_singleton_count);
0139                //Insert a barrier before assigning the pointer to
0140                //make sure this assignment comes after the initialization
0141                atomic_write32(&this_module_singleton_initialized, Initializing);
0142                //Assign the singleton address to the module-local pointer
0143                ptr = tmp;
0144                //Memory barrier inserted, all previous operations should complete
0145                //before this one. Now marked as initialized
0146                atomic_write32(&this_module_singleton_initialized, Initialized);
0147             }
0148             BOOST_INTERPROCESS_CATCH(...){
0149                //Mark singleton failed to initialize
0150                atomic_write32(&this_module_singleton_initialized, Broken);
0151                BOOST_INTERPROCESS_RETHROW
0152             } BOOST_INTERPROCESS_CATCH_END
0153          }
0154          //If previous state was initializing, this means that another winner thread is
0155          //trying to initialize the singleton. Just wait until completes its work.
0156          else if(previous_module_singleton_initialized == Initializing){
0157             spin_wait swait;
0158             while(1){
0159                previous_module_singleton_initialized = atomic_read32(&this_module_singleton_initialized);
0160                if(previous_module_singleton_initialized >= Initialized){
0161                   //Already initialized, or exception thrown by initializer thread
0162                   break;
0163                }
0164                else if(previous_module_singleton_initialized == Initializing){
0165                   swait.yield();
0166                }
0167                else{
0168                   //This can't be happening!
0169                   BOOST_ASSERT(0);
0170                }
0171             }
0172          }
0173          else if(previous_module_singleton_initialized == Initialized){
0174             //Nothing to do here, the singleton is ready
0175          }
0176          //If previous state was greater than initialized, then memory is broken
0177          //trying to initialize the singleton.
0178          else{//(previous_module_singleton_initialized > Initialized)
0179             throw interprocess_exception("boost::interprocess::intermodule_singleton initialization failed");
0180          }
0181       }
0182       BOOST_ASSERT(ptr != 0);
0183    }
0184 
0185    static void finalize_singleton_logic(void *&ptr, volatile boost::uint32_t &this_module_singleton_initialized, singleton_destructor_t destructor)
0186    {
0187       //Protect destruction against lazy singletons not initialized in this execution
0188       if(ptr){
0189          //Note: this destructor might provoke a Phoenix singleton
0190          //resurrection. This means that this_module_singleton_count
0191          //might change after this call.
0192          ThreadSafeGlobalMap * const pmap = get_map_ptr();
0193          destructor(ptr, *pmap);
0194          ptr = 0;
0195 
0196          //Memory barrier to make sure pointer is nulled.
0197          //Mark this singleton as destroyed.
0198          atomic_write32(&this_module_singleton_initialized, Destroyed);
0199 
0200          //If this is the last singleton of this module
0201          //apply map destruction.
0202          //Note: singletons are destroyed when the module is unloaded
0203          //so no threads should be executing or holding references
0204          //to this module
0205          if(1 == atomic_dec32(&this_module_singleton_count)){
0206             destroy_global_map_handle();
0207          }
0208       }
0209    }
0210 
0211    private:
0212    static ThreadSafeGlobalMap *get_map_ptr()
0213    {
0214       return static_cast<ThreadSafeGlobalMap *>(static_cast<void*>(mem_holder.map_mem));
0215    }
0216 
0217    static void initialize_global_map_handle()
0218    {
0219       //Obtain unique map name and size
0220       spin_wait swait;
0221       while(1){
0222          //Try to pass map state to initializing
0223          ::boost::uint32_t tmp = atomic_cas32(&this_module_map_initialized, Initializing, Uninitialized);
0224          if(tmp == Initialized || tmp == Broken){
0225             break;
0226          }
0227          else if(tmp == Destroyed){
0228             tmp = atomic_cas32(&this_module_map_initialized, Uninitialized, Destroyed);
0229             continue;
0230          }
0231          //If some other thread is doing the work wait
0232          else if(tmp == Initializing){
0233             swait.yield();
0234          }
0235          else{ //(tmp == Uninitialized)
0236             //If not initialized try it again?
0237             BOOST_INTERPROCESS_TRY{
0238                //Remove old global map from the system
0239                intermodule_singleton_helpers::thread_safe_global_map_dependant<ThreadSafeGlobalMap>::remove_old_gmem();
0240                //in-place construction of the global map class
0241                ThreadSafeGlobalMap * const pmap = get_map_ptr();
0242                intermodule_singleton_helpers::thread_safe_global_map_dependant
0243                   <ThreadSafeGlobalMap>::construct_map(static_cast<void*>(pmap));
0244                //Use global map's internal lock to initialize the lock file
0245                //that will mark this gmem as "in use".
0246                typename intermodule_singleton_helpers::thread_safe_global_map_dependant<ThreadSafeGlobalMap>::
0247                   lock_file_logic f(*pmap);
0248                //If function failed (maybe a competing process has erased the shared
0249                //memory between creation and file locking), retry with a new instance.
0250                if(f.retry()){
0251                   pmap->~ThreadSafeGlobalMap();
0252                   atomic_write32(&this_module_map_initialized, Destroyed);
0253                }
0254                else{
0255                   //Locking succeeded, so this global map module-instance is ready
0256                   atomic_write32(&this_module_map_initialized, Initialized);
0257                   break;
0258                }
0259             }
0260             BOOST_INTERPROCESS_CATCH(...){
0261                //
0262                BOOST_INTERPROCESS_RETHROW
0263             } BOOST_INTERPROCESS_CATCH_END
0264          }
0265       }
0266    }
0267 
0268    static void destroy_global_map_handle()
0269    {
0270       if(!atomic_read32(&this_module_singleton_count)){
0271          //This module is being unloaded, so destroy
0272          //the global map object of this module
0273          //and unlink the global map if it's the last
0274          ThreadSafeGlobalMap * const pmap = get_map_ptr();
0275          typename intermodule_singleton_helpers::thread_safe_global_map_dependant<ThreadSafeGlobalMap>::
0276             unlink_map_logic f(*pmap);
0277          pmap->~ThreadSafeGlobalMap();
0278          atomic_write32(&this_module_map_initialized, Destroyed);
0279          //Do some cleanup for other processes old gmem instances
0280          intermodule_singleton_helpers::thread_safe_global_map_dependant<ThreadSafeGlobalMap>::remove_old_gmem();
0281       }
0282    }
0283 
0284    //Static data, zero-initalized without any dependencies
0285    //this_module_singleton_count is the number of singletons used by this module
0286    static volatile boost::uint32_t this_module_singleton_count;
0287 
0288    //this_module_map_initialized is the state of this module's map class object.
0289    //Values: Uninitialized, Initializing, Initialized, Broken
0290    static volatile boost::uint32_t this_module_map_initialized;
0291 
0292    //Raw memory to construct the global map manager
0293    static union mem_holder_t
0294    {
0295       unsigned char map_mem [sizeof(ThreadSafeGlobalMap)];
0296       ::boost::container::dtl::max_align_t aligner;
0297    } mem_holder;
0298 };
0299 
0300 template<class ThreadSafeGlobalMap>
0301 volatile boost::uint32_t intermodule_singleton_common<ThreadSafeGlobalMap>::this_module_singleton_count;
0302 
0303 template<class ThreadSafeGlobalMap>
0304 volatile boost::uint32_t intermodule_singleton_common<ThreadSafeGlobalMap>::this_module_map_initialized;
0305 
0306 template<class ThreadSafeGlobalMap>
0307 typename intermodule_singleton_common<ThreadSafeGlobalMap>::mem_holder_t
0308    intermodule_singleton_common<ThreadSafeGlobalMap>::mem_holder;
0309 
0310 //A reference count to be stored in global map holding the number
0311 //of singletons (one per module) attached to the instance pointed by
0312 //the internal ptr.
0313 struct ref_count_ptr
0314 {
0315    ref_count_ptr(void *p, boost::uint32_t count)
0316       : ptr(p), singleton_ref_count(count)
0317    {}
0318    void *ptr;
0319    //This reference count serves to count the number of attached
0320    //modules to this singleton
0321    volatile boost::uint32_t singleton_ref_count;
0322 };
0323 
0324 
0325 //Now this class is a singleton, initializing the singleton in
0326 //the first get() function call if LazyInit is true. If false
0327 //then the singleton will be initialized when loading the module.
0328 template<typename C, bool LazyInit, bool Phoenix, class ThreadSafeGlobalMap>
0329 class intermodule_singleton_impl
0330 {
0331    public:
0332 
0333    static C& get()   //Let's make inlining easy
0334    {
0335       if(!this_module_singleton_ptr){
0336          if(lifetime.dummy_function()){  //This forces lifetime instantiation, for reference counted destruction
0337             atentry_work();
0338          }
0339       }
0340       return *static_cast<C*>(this_module_singleton_ptr);
0341    }
0342 
0343    private:
0344 
0345    static void atentry_work()
0346    {
0347       intermodule_singleton_common<ThreadSafeGlobalMap>::initialize_singleton_logic
0348          (this_module_singleton_ptr, this_module_singleton_initialized, singleton_constructor, Phoenix);
0349    }
0350 
0351    static void atexit_work()
0352    {
0353       intermodule_singleton_common<ThreadSafeGlobalMap>::finalize_singleton_logic
0354          (this_module_singleton_ptr, this_module_singleton_initialized, singleton_destructor);
0355    }
0356 
0357    //These statics will be zero-initialized without any constructor call dependency
0358    //this_module_singleton_ptr will be a module-local pointer to the singleton
0359    static void*                      this_module_singleton_ptr;
0360 
0361    //this_module_singleton_count will be used to synchronize threads of the same module
0362    //for access to a singleton instance, and to flag the state of the
0363    //singleton.
0364    static volatile boost::uint32_t   this_module_singleton_initialized;
0365 
0366    //This class destructor will trigger singleton destruction
0367    struct lifetime_type_lazy
0368    {
0369       bool dummy_function()
0370       {  return m_dummy == 0; }
0371 
0372       ~lifetime_type_lazy()
0373       {
0374          //if(!Phoenix){
0375             //atexit_work();
0376          //}
0377       }
0378 
0379       //Dummy volatile so that the compiler can't resolve its value at compile-time
0380       //and can't avoid lifetime_type instantiation if dummy_function() is called.
0381       static volatile int m_dummy;
0382    };
0383 
0384    struct lifetime_type_static
0385       : public lifetime_type_lazy
0386    {
0387       lifetime_type_static()
0388       {  atentry_work();  }
0389    };
0390 
0391    typedef typename if_c
0392       <LazyInit, lifetime_type_lazy, lifetime_type_static>::type lifetime_type;
0393 
0394    static lifetime_type lifetime;
0395 
0396    //A functor to be executed inside global map lock that just
0397    //searches for the singleton in map and if not present creates a new one.
0398    //If singleton constructor throws, the exception is propagated
0399    struct init_atomic_func
0400    {
0401       init_atomic_func(ThreadSafeGlobalMap &m)
0402          : m_map(m), ret_ptr()
0403       {}
0404 
0405       void operator()()
0406       {
0407          ref_count_ptr *rcount = intermodule_singleton_helpers::thread_safe_global_map_dependant
0408             <ThreadSafeGlobalMap>::find(m_map, typeid(C).name());
0409          if(!rcount){
0410             C *p = new C;
0411             BOOST_INTERPROCESS_TRY{
0412                ref_count_ptr val(p, 0u);
0413                rcount = intermodule_singleton_helpers::thread_safe_global_map_dependant
0414                            <ThreadSafeGlobalMap>::insert(m_map, typeid(C).name(), val);
0415             }
0416             BOOST_INTERPROCESS_CATCH(...){
0417                intermodule_singleton_helpers::thread_safe_global_map_dependant
0418                            <ThreadSafeGlobalMap>::erase(m_map, typeid(C).name());
0419                delete p;
0420                BOOST_INTERPROCESS_RETHROW
0421             } BOOST_INTERPROCESS_CATCH_END
0422          }
0423          //if(Phoenix){
0424             std::atexit(&atexit_work);
0425          //}
0426          atomic_inc32(&rcount->singleton_ref_count);
0427          ret_ptr = rcount->ptr;
0428       }
0429       void *data() const
0430          { return ret_ptr;  }
0431 
0432       private:
0433       ThreadSafeGlobalMap &m_map;
0434       void *ret_ptr;
0435    };
0436 
0437    //A functor to be executed inside global map lock that just
0438    //deletes the singleton in map if the attached count reaches to zero
0439    struct fini_atomic_func
0440    {
0441       fini_atomic_func(ThreadSafeGlobalMap &m)
0442          : m_map(m)
0443       {}
0444 
0445       void operator()()
0446       {
0447          ref_count_ptr *rcount = intermodule_singleton_helpers::thread_safe_global_map_dependant
0448             <ThreadSafeGlobalMap>::find(m_map, typeid(C).name());
0449             //The object must exist
0450          BOOST_ASSERT(rcount);
0451          BOOST_ASSERT(rcount->singleton_ref_count > 0);
0452          //Check if last reference
0453          if(atomic_dec32(&rcount->singleton_ref_count) == 1){
0454             //If last, destroy the object
0455             BOOST_ASSERT(rcount->ptr != 0);
0456             C *pc = static_cast<C*>(rcount->ptr);
0457             //Now destroy map entry
0458             bool destroyed = intermodule_singleton_helpers::thread_safe_global_map_dependant
0459                         <ThreadSafeGlobalMap>::erase(m_map, typeid(C).name());
0460             (void)destroyed;  BOOST_ASSERT(destroyed == true);
0461             delete pc;
0462          }
0463       }
0464 
0465       private:
0466       ThreadSafeGlobalMap &m_map;
0467    };
0468 
0469    //A wrapper to execute init_atomic_func
0470    static void *singleton_constructor(ThreadSafeGlobalMap &map)
0471    {
0472       init_atomic_func f(map);
0473       intermodule_singleton_helpers::thread_safe_global_map_dependant
0474                   <ThreadSafeGlobalMap>::atomic_func(map, f);
0475       return f.data();
0476    }
0477 
0478    //A wrapper to execute fini_atomic_func
0479    static void singleton_destructor(void *p, ThreadSafeGlobalMap &map)
0480    {  (void)p;
0481       fini_atomic_func f(map);
0482       intermodule_singleton_helpers::thread_safe_global_map_dependant
0483                   <ThreadSafeGlobalMap>::atomic_func(map, f);
0484    }
0485 };
0486 
0487 template <typename C, bool L, bool P, class ThreadSafeGlobalMap>
0488 volatile int intermodule_singleton_impl<C, L, P, ThreadSafeGlobalMap>::lifetime_type_lazy::m_dummy = 0;
0489 
0490 //These will be zero-initialized by the loader
0491 template <typename C, bool L, bool P, class ThreadSafeGlobalMap>
0492 void *intermodule_singleton_impl<C, L, P, ThreadSafeGlobalMap>::this_module_singleton_ptr = 0;
0493 
0494 template <typename C, bool L, bool P, class ThreadSafeGlobalMap>
0495 volatile boost::uint32_t intermodule_singleton_impl<C, L, P, ThreadSafeGlobalMap>::this_module_singleton_initialized = 0;
0496 
0497 template <typename C, bool L, bool P, class ThreadSafeGlobalMap>
0498 typename intermodule_singleton_impl<C, L, P, ThreadSafeGlobalMap>::lifetime_type
0499    intermodule_singleton_impl<C, L, P, ThreadSafeGlobalMap>::lifetime;
0500 
0501 }  //namespace ipcdetail{
0502 }  //namespace interprocess{
0503 }  //namespace boost{
0504 
0505 #include <boost/interprocess/detail/config_end.hpp>
0506 
0507 #endif   //#ifndef BOOST_INTERPROCESS_INTERMODULE_SINGLETON_COMMON_HPP