File indexing completed on 2026-05-07 08:22:00
0001
0002
0003
0004
0005
0006
0007
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 ">#
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
0026 #include <boost/interprocess/detail/atomic.hpp>
0027 #include <boost/interprocess/detail/os_thread_functions.hpp>
0028 #include <boost/interprocess/exceptions.hpp>
0029 #include <boost/container/detail/type_traits.hpp> //alignment_of, aligned_storage
0030 #include <boost/interprocess/detail/mpl.hpp>
0031 #include <boost/interprocess/sync/spin/wait.hpp>
0032 #include <boost/assert.hpp>
0033 #include <cstddef>
0034 #include <cstdio>
0035 #include <cstdlib>
0036 #include <cstring>
0037 #include <string>
0038 #include <typeinfo>
0039 #include <sstream>
0040
0041 namespace boost{
0042 namespace interprocess{
0043 namespace ipcdetail{
0044
0045 namespace intermodule_singleton_helpers {
0046
0047 inline void get_pid_creation_time_str(std::string &s)
0048 {
0049 std::stringstream stream;
0050 stream << get_current_process_id() << '_';
0051 const unsigned long long total_microsecs = get_current_process_creation_time();
0052 const unsigned long secs = static_cast<unsigned long>(total_microsecs/1000000ul);
0053 const unsigned long usecs = static_cast<unsigned long>(total_microsecs%1000000ul);
0054 stream << secs << '.' << usecs;
0055 s = stream.str();
0056 }
0057
0058 inline const char *get_map_base_name()
0059 { return "bip.gmem.map."; }
0060
0061 inline void get_map_name(std::string &map_name)
0062 {
0063 get_pid_creation_time_str(map_name);
0064 map_name.insert(0, get_map_base_name());
0065 }
0066
0067 inline std::size_t get_map_size()
0068 { return 65536; }
0069
0070 template<class ThreadSafeGlobalMap>
0071 struct thread_safe_global_map_dependant;
0072
0073 }
0074
0075
0076
0077
0078 template<class ThreadSafeGlobalMap>
0079 class intermodule_singleton_common
0080 {
0081 public:
0082 typedef void*(singleton_constructor_t)(ThreadSafeGlobalMap &);
0083 typedef void (singleton_destructor_t)(void *, ThreadSafeGlobalMap &);
0084
0085 static const ::boost::uint32_t Uninitialized = 0u;
0086 static const ::boost::uint32_t Initializing = 1u;
0087 static const ::boost::uint32_t Initialized = 2u;
0088 static const ::boost::uint32_t Broken = 3u;
0089 static const ::boost::uint32_t Destroyed = 4u;
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102 static void initialize_singleton_logic
0103 (void *&ptr, volatile boost::uint32_t &this_module_singleton_initialized, singleton_constructor_t constructor, bool phoenix)
0104 {
0105
0106 if(atomic_read32(&this_module_singleton_initialized) != Initialized){
0107
0108
0109 ::boost::uint32_t previous_module_singleton_initialized = atomic_cas32
0110 (&this_module_singleton_initialized, Initializing, Uninitialized);
0111
0112
0113 if(previous_module_singleton_initialized == Destroyed){
0114
0115
0116 if(phoenix){
0117 atomic_cas32(&this_module_singleton_initialized, Uninitialized, Destroyed);
0118 previous_module_singleton_initialized = atomic_cas32
0119 (&this_module_singleton_initialized, Initializing, Uninitialized);
0120 }
0121
0122 else{
0123 throw interprocess_exception("Boost.Interprocess: Dead reference on non-Phoenix singleton of type");
0124 }
0125 }
0126 if(previous_module_singleton_initialized == Uninitialized){
0127 BOOST_INTERPROCESS_TRY{
0128
0129
0130 initialize_global_map_handle();
0131
0132
0133
0134 ThreadSafeGlobalMap *const pmap = get_map_ptr();
0135 void *tmp = constructor(*pmap);
0136
0137
0138
0139 atomic_inc32(&this_module_singleton_count);
0140
0141
0142 atomic_write32(&this_module_singleton_initialized, Initializing);
0143
0144 ptr = tmp;
0145
0146
0147 atomic_write32(&this_module_singleton_initialized, Initialized);
0148 }
0149 BOOST_INTERPROCESS_CATCH(...){
0150
0151 atomic_write32(&this_module_singleton_initialized, Broken);
0152 BOOST_INTERPROCESS_RETHROW
0153 } BOOST_INTERPROCESS_CATCH_END
0154 }
0155
0156
0157 else if(previous_module_singleton_initialized == Initializing){
0158 spin_wait swait;
0159 while(1){
0160 previous_module_singleton_initialized = atomic_read32(&this_module_singleton_initialized);
0161 if(previous_module_singleton_initialized >= Initialized){
0162
0163 break;
0164 }
0165 else if(previous_module_singleton_initialized == Initializing){
0166 swait.yield();
0167 }
0168 else{
0169
0170 BOOST_ASSERT(0);
0171 }
0172 }
0173 }
0174 else if(previous_module_singleton_initialized == Initialized){
0175
0176 }
0177
0178
0179 else{
0180 throw interprocess_exception("boost::interprocess::intermodule_singleton initialization failed");
0181 }
0182 }
0183 BOOST_ASSERT(ptr != 0);
0184 }
0185
0186 static void finalize_singleton_logic(void *&ptr, volatile boost::uint32_t &this_module_singleton_initialized, singleton_destructor_t destructor)
0187 {
0188
0189 if(ptr){
0190
0191
0192
0193 ThreadSafeGlobalMap * const pmap = get_map_ptr();
0194 destructor(ptr, *pmap);
0195 ptr = 0;
0196
0197
0198
0199 atomic_write32(&this_module_singleton_initialized, Destroyed);
0200
0201
0202
0203
0204
0205
0206 if(1 == atomic_dec32(&this_module_singleton_count)){
0207 destroy_global_map_handle();
0208 }
0209 }
0210 }
0211
0212 private:
0213 static ThreadSafeGlobalMap *get_map_ptr()
0214 {
0215 return static_cast<ThreadSafeGlobalMap *>(static_cast<void*>(mem_holder.map_mem));
0216 }
0217
0218 static void initialize_global_map_handle()
0219 {
0220
0221 spin_wait swait;
0222 while(1){
0223
0224 ::boost::uint32_t tmp = atomic_cas32(&this_module_map_initialized, Initializing, Uninitialized);
0225 if(tmp == Initialized || tmp == Broken){
0226 break;
0227 }
0228 else if(tmp == Destroyed){
0229 tmp = atomic_cas32(&this_module_map_initialized, Uninitialized, Destroyed);
0230 continue;
0231 }
0232
0233 else if(tmp == Initializing){
0234 swait.yield();
0235 }
0236 else{
0237
0238 BOOST_INTERPROCESS_TRY{
0239
0240 intermodule_singleton_helpers::thread_safe_global_map_dependant<ThreadSafeGlobalMap>::remove_old_gmem();
0241
0242 ThreadSafeGlobalMap * const pmap = get_map_ptr();
0243 intermodule_singleton_helpers::thread_safe_global_map_dependant
0244 <ThreadSafeGlobalMap>::construct_map(static_cast<void*>(pmap));
0245
0246
0247 typename intermodule_singleton_helpers::thread_safe_global_map_dependant<ThreadSafeGlobalMap>::
0248 lock_file_logic f(*pmap);
0249
0250
0251 if(f.retry()){
0252 pmap->~ThreadSafeGlobalMap();
0253 atomic_write32(&this_module_map_initialized, Destroyed);
0254 }
0255 else{
0256
0257 atomic_write32(&this_module_map_initialized, Initialized);
0258 break;
0259 }
0260 }
0261 BOOST_INTERPROCESS_CATCH(...){
0262
0263 BOOST_INTERPROCESS_RETHROW
0264 } BOOST_INTERPROCESS_CATCH_END
0265 }
0266 }
0267 }
0268
0269 static void destroy_global_map_handle()
0270 {
0271 if(!atomic_read32(&this_module_singleton_count)){
0272
0273
0274
0275 ThreadSafeGlobalMap * const pmap = get_map_ptr();
0276 typename intermodule_singleton_helpers::thread_safe_global_map_dependant<ThreadSafeGlobalMap>::
0277 unlink_map_logic f(*pmap);
0278 pmap->~ThreadSafeGlobalMap();
0279 atomic_write32(&this_module_map_initialized, Destroyed);
0280
0281 intermodule_singleton_helpers::thread_safe_global_map_dependant<ThreadSafeGlobalMap>::remove_old_gmem();
0282 }
0283 }
0284
0285
0286
0287 static volatile boost::uint32_t this_module_singleton_count;
0288
0289
0290
0291 static volatile boost::uint32_t this_module_map_initialized;
0292
0293
0294 static union mem_holder_t
0295 {
0296 unsigned char map_mem [sizeof(ThreadSafeGlobalMap)];
0297 ::boost::container::dtl::max_align_t aligner;
0298 } mem_holder;
0299 };
0300
0301 template<class ThreadSafeGlobalMap>
0302 volatile boost::uint32_t intermodule_singleton_common<ThreadSafeGlobalMap>::this_module_singleton_count;
0303
0304 template<class ThreadSafeGlobalMap>
0305 volatile boost::uint32_t intermodule_singleton_common<ThreadSafeGlobalMap>::this_module_map_initialized;
0306
0307 template<class ThreadSafeGlobalMap>
0308 typename intermodule_singleton_common<ThreadSafeGlobalMap>::mem_holder_t
0309 intermodule_singleton_common<ThreadSafeGlobalMap>::mem_holder;
0310
0311
0312
0313
0314 struct ref_count_ptr
0315 {
0316 ref_count_ptr(void *p, boost::uint32_t count)
0317 : ptr(p), singleton_ref_count(count)
0318 {}
0319 void *ptr;
0320
0321
0322 volatile boost::uint32_t singleton_ref_count;
0323 };
0324
0325
0326
0327
0328
0329 template<typename C, bool LazyInit, bool Phoenix, class ThreadSafeGlobalMap>
0330 class intermodule_singleton_impl
0331 {
0332 public:
0333
0334 static C& get()
0335 {
0336 if(!this_module_singleton_ptr){
0337 if(lifetime.dummy_function()){
0338 atentry_work();
0339 }
0340 }
0341 return *static_cast<C*>(this_module_singleton_ptr);
0342 }
0343
0344 private:
0345
0346 static void atentry_work()
0347 {
0348 intermodule_singleton_common<ThreadSafeGlobalMap>::initialize_singleton_logic
0349 (this_module_singleton_ptr, this_module_singleton_initialized, singleton_constructor, Phoenix);
0350 }
0351
0352 static void atexit_work()
0353 {
0354 intermodule_singleton_common<ThreadSafeGlobalMap>::finalize_singleton_logic
0355 (this_module_singleton_ptr, this_module_singleton_initialized, singleton_destructor);
0356 }
0357
0358
0359
0360 static void* this_module_singleton_ptr;
0361
0362
0363
0364
0365 static volatile boost::uint32_t this_module_singleton_initialized;
0366
0367
0368 struct lifetime_type_lazy
0369 {
0370 bool dummy_function()
0371 { return m_dummy == 0; }
0372
0373 ~lifetime_type_lazy()
0374 {
0375
0376
0377
0378 }
0379
0380
0381
0382 static volatile int m_dummy;
0383 };
0384
0385 struct lifetime_type_static
0386 : public lifetime_type_lazy
0387 {
0388 lifetime_type_static()
0389 { atentry_work(); }
0390 };
0391
0392 typedef typename if_c
0393 <LazyInit, lifetime_type_lazy, lifetime_type_static>::type lifetime_type;
0394
0395 static lifetime_type lifetime;
0396
0397
0398
0399
0400 struct init_atomic_func
0401 {
0402 init_atomic_func(ThreadSafeGlobalMap &m)
0403 : m_map(m), ret_ptr()
0404 {}
0405
0406 void operator()()
0407 {
0408 ref_count_ptr *rcount = intermodule_singleton_helpers::thread_safe_global_map_dependant
0409 <ThreadSafeGlobalMap>::find(m_map, typeid(C).name());
0410 if(!rcount){
0411 C *p = new C;
0412 BOOST_INTERPROCESS_TRY{
0413 ref_count_ptr val(p, 0u);
0414 rcount = intermodule_singleton_helpers::thread_safe_global_map_dependant
0415 <ThreadSafeGlobalMap>::insert(m_map, typeid(C).name(), val);
0416 }
0417 BOOST_INTERPROCESS_CATCH(...){
0418 intermodule_singleton_helpers::thread_safe_global_map_dependant
0419 <ThreadSafeGlobalMap>::erase(m_map, typeid(C).name());
0420 delete p;
0421 BOOST_INTERPROCESS_RETHROW
0422 } BOOST_INTERPROCESS_CATCH_END
0423 }
0424
0425 std::atexit(&atexit_work);
0426
0427 atomic_inc32(&rcount->singleton_ref_count);
0428 ret_ptr = rcount->ptr;
0429 }
0430 void *data() const
0431 { return ret_ptr; }
0432
0433 private:
0434 ThreadSafeGlobalMap &m_map;
0435 void *ret_ptr;
0436 };
0437
0438
0439
0440 struct fini_atomic_func
0441 {
0442 fini_atomic_func(ThreadSafeGlobalMap &m)
0443 : m_map(m)
0444 {}
0445
0446 void operator()()
0447 {
0448 ref_count_ptr *rcount = intermodule_singleton_helpers::thread_safe_global_map_dependant
0449 <ThreadSafeGlobalMap>::find(m_map, typeid(C).name());
0450
0451 BOOST_ASSERT(rcount);
0452 BOOST_ASSERT(rcount->singleton_ref_count > 0);
0453
0454 if(atomic_dec32(&rcount->singleton_ref_count) == 1){
0455
0456 BOOST_ASSERT(rcount->ptr != 0);
0457 C *pc = static_cast<C*>(rcount->ptr);
0458
0459 bool destroyed = intermodule_singleton_helpers::thread_safe_global_map_dependant
0460 <ThreadSafeGlobalMap>::erase(m_map, typeid(C).name());
0461 (void)destroyed; BOOST_ASSERT(destroyed == true);
0462 delete pc;
0463 }
0464 }
0465
0466 private:
0467 ThreadSafeGlobalMap &m_map;
0468 };
0469
0470
0471 static void *singleton_constructor(ThreadSafeGlobalMap &map)
0472 {
0473 init_atomic_func f(map);
0474 intermodule_singleton_helpers::thread_safe_global_map_dependant
0475 <ThreadSafeGlobalMap>::atomic_func(map, f);
0476 return f.data();
0477 }
0478
0479
0480 static void singleton_destructor(void *p, ThreadSafeGlobalMap &map)
0481 { (void)p;
0482 fini_atomic_func f(map);
0483 intermodule_singleton_helpers::thread_safe_global_map_dependant
0484 <ThreadSafeGlobalMap>::atomic_func(map, f);
0485 }
0486 };
0487
0488 template <typename C, bool L, bool P, class ThreadSafeGlobalMap>
0489 volatile int intermodule_singleton_impl<C, L, P, ThreadSafeGlobalMap>::lifetime_type_lazy::m_dummy = 0;
0490
0491
0492 template <typename C, bool L, bool P, class ThreadSafeGlobalMap>
0493 void *intermodule_singleton_impl<C, L, P, ThreadSafeGlobalMap>::this_module_singleton_ptr = 0;
0494
0495 template <typename C, bool L, bool P, class ThreadSafeGlobalMap>
0496 volatile boost::uint32_t intermodule_singleton_impl<C, L, P, ThreadSafeGlobalMap>::this_module_singleton_initialized = 0;
0497
0498 template <typename C, bool L, bool P, class ThreadSafeGlobalMap>
0499 typename intermodule_singleton_impl<C, L, P, ThreadSafeGlobalMap>::lifetime_type
0500 intermodule_singleton_impl<C, L, P, ThreadSafeGlobalMap>::lifetime;
0501
0502 }
0503 }
0504 }
0505
0506 #include <boost/interprocess/detail/config_end.hpp>
0507
0508 #endif