File indexing completed on 2025-09-17 08:34:05
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 #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 }
0073
0074
0075
0076
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
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
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
0105 if(atomic_read32(&this_module_singleton_initialized) != Initialized){
0106
0107
0108 ::boost::uint32_t previous_module_singleton_initialized = atomic_cas32
0109 (&this_module_singleton_initialized, Initializing, Uninitialized);
0110
0111
0112 if(previous_module_singleton_initialized == Destroyed){
0113
0114
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
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
0128
0129 initialize_global_map_handle();
0130
0131
0132
0133 ThreadSafeGlobalMap *const pmap = get_map_ptr();
0134 void *tmp = constructor(*pmap);
0135
0136
0137
0138 atomic_inc32(&this_module_singleton_count);
0139
0140
0141 atomic_write32(&this_module_singleton_initialized, Initializing);
0142
0143 ptr = tmp;
0144
0145
0146 atomic_write32(&this_module_singleton_initialized, Initialized);
0147 }
0148 BOOST_INTERPROCESS_CATCH(...){
0149
0150 atomic_write32(&this_module_singleton_initialized, Broken);
0151 BOOST_INTERPROCESS_RETHROW
0152 } BOOST_INTERPROCESS_CATCH_END
0153 }
0154
0155
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
0162 break;
0163 }
0164 else if(previous_module_singleton_initialized == Initializing){
0165 swait.yield();
0166 }
0167 else{
0168
0169 BOOST_ASSERT(0);
0170 }
0171 }
0172 }
0173 else if(previous_module_singleton_initialized == Initialized){
0174
0175 }
0176
0177
0178 else{
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
0188 if(ptr){
0189
0190
0191
0192 ThreadSafeGlobalMap * const pmap = get_map_ptr();
0193 destructor(ptr, *pmap);
0194 ptr = 0;
0195
0196
0197
0198 atomic_write32(&this_module_singleton_initialized, Destroyed);
0199
0200
0201
0202
0203
0204
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
0220 spin_wait swait;
0221 while(1){
0222
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
0232 else if(tmp == Initializing){
0233 swait.yield();
0234 }
0235 else{
0236
0237 BOOST_INTERPROCESS_TRY{
0238
0239 intermodule_singleton_helpers::thread_safe_global_map_dependant<ThreadSafeGlobalMap>::remove_old_gmem();
0240
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
0245
0246 typename intermodule_singleton_helpers::thread_safe_global_map_dependant<ThreadSafeGlobalMap>::
0247 lock_file_logic f(*pmap);
0248
0249
0250 if(f.retry()){
0251 pmap->~ThreadSafeGlobalMap();
0252 atomic_write32(&this_module_map_initialized, Destroyed);
0253 }
0254 else{
0255
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
0272
0273
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
0280 intermodule_singleton_helpers::thread_safe_global_map_dependant<ThreadSafeGlobalMap>::remove_old_gmem();
0281 }
0282 }
0283
0284
0285
0286 static volatile boost::uint32_t this_module_singleton_count;
0287
0288
0289
0290 static volatile boost::uint32_t this_module_map_initialized;
0291
0292
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
0311
0312
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
0320
0321 volatile boost::uint32_t singleton_ref_count;
0322 };
0323
0324
0325
0326
0327
0328 template<typename C, bool LazyInit, bool Phoenix, class ThreadSafeGlobalMap>
0329 class intermodule_singleton_impl
0330 {
0331 public:
0332
0333 static C& get()
0334 {
0335 if(!this_module_singleton_ptr){
0336 if(lifetime.dummy_function()){
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
0358
0359 static void* this_module_singleton_ptr;
0360
0361
0362
0363
0364 static volatile boost::uint32_t this_module_singleton_initialized;
0365
0366
0367 struct lifetime_type_lazy
0368 {
0369 bool dummy_function()
0370 { return m_dummy == 0; }
0371
0372 ~lifetime_type_lazy()
0373 {
0374
0375
0376
0377 }
0378
0379
0380
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
0397
0398
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
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
0438
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
0450 BOOST_ASSERT(rcount);
0451 BOOST_ASSERT(rcount->singleton_ref_count > 0);
0452
0453 if(atomic_dec32(&rcount->singleton_ref_count) == 1){
0454
0455 BOOST_ASSERT(rcount->ptr != 0);
0456 C *pc = static_cast<C*>(rcount->ptr);
0457
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
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
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
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 }
0502 }
0503 }
0504
0505 #include <boost/interprocess/detail/config_end.hpp>
0506
0507 #endif