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