File indexing completed on 2026-09-20 08:50:14
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_IMPL
0012 #define BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_IMPL
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/os_thread_functions.hpp>
0025 #include <boost/interprocess/detail/os_file_functions.hpp>
0026 #include <boost/interprocess/creation_tags.hpp>
0027 #include <boost/interprocess/mapped_region.hpp>
0028 #include <boost/interprocess/detail/utilities.hpp>
0029 #include <boost/interprocess/detail/type_traits.hpp>
0030 #include <boost/interprocess/detail/atomic.hpp>
0031 #include <boost/interprocess/detail/interprocess_tester.hpp>
0032 #include <boost/interprocess/anonymous_shared_memory.hpp>
0033 #include <boost/interprocess/creation_tags.hpp>
0034 #include <boost/interprocess/detail/mpl.hpp>
0035 #include <boost/interprocess/permissions.hpp>
0036 #include <boost/container/detail/type_traits.hpp> //alignment_of, aligned_storage
0037 #include <boost/interprocess/sync/spin/wait.hpp>
0038 #include <boost/interprocess/timed_utils.hpp>
0039 #include <boost/move/move.hpp>
0040 #include <boost/cstdint.hpp>
0041
0042 namespace boost {
0043 namespace interprocess {
0044 namespace ipcdetail {
0045
0046 template <bool StoreDevice, class DeviceAbstraction>
0047 class managed_open_or_create_impl_device_holder
0048 {
0049 public:
0050 DeviceAbstraction &get_device()
0051 { static DeviceAbstraction dev; return dev; }
0052
0053 const DeviceAbstraction &get_device() const
0054 { static DeviceAbstraction dev; return dev; }
0055 };
0056
0057 template <class DeviceAbstraction>
0058 class managed_open_or_create_impl_device_holder<true, DeviceAbstraction>
0059 {
0060 public:
0061 DeviceAbstraction &get_device()
0062 { return dev; }
0063
0064 const DeviceAbstraction &get_device() const
0065 { return dev; }
0066
0067 private:
0068 DeviceAbstraction dev;
0069 };
0070
0071 template<class DeviceAbstraction, std::size_t MemAlignment, bool FileBased, bool StoreDevice>
0072 class managed_open_or_create_impl
0073 : public managed_open_or_create_impl_device_holder<StoreDevice, DeviceAbstraction>
0074 {
0075
0076 BOOST_MOVABLE_BUT_NOT_COPYABLE(managed_open_or_create_impl)
0077 typedef bool_<FileBased> file_like_t;
0078
0079 static const unsigned MaxCreateOrOpenTries = BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_INITIALIZE_MAX_TRIES;
0080 static const unsigned MaxInitializeTimeSec = BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_INITIALIZE_TIMEOUT_SEC;
0081
0082 typedef managed_open_or_create_impl_device_holder<StoreDevice, DeviceAbstraction> DevHolder;
0083 enum
0084 {
0085 UninitializedSegment,
0086 InitializingSegment,
0087 InitializedSegment,
0088 CorruptedSegment
0089 };
0090
0091 static const std::size_t RequiredAlignment =
0092 MemAlignment ? MemAlignment
0093 : boost::container::dtl::alignment_of< boost::container::dtl::max_align_t >::value
0094 ;
0095
0096 public:
0097 static const std::size_t ManagedOpenOrCreateUserOffset =
0098 ct_rounded_size<sizeof(boost::uint32_t), RequiredAlignment>::value;
0099
0100 managed_open_or_create_impl()
0101 {}
0102
0103 template <class DeviceId>
0104 managed_open_or_create_impl(create_only_t,
0105 const DeviceId & id,
0106 std::size_t size,
0107 mode_t mode,
0108 const void *addr,
0109 const permissions &perm)
0110 {
0111 priv_open_or_create
0112 ( DoCreate
0113 , id
0114 , size
0115 , mode
0116 , addr
0117 , perm
0118 , null_mapped_region_function());
0119 }
0120
0121 template <class DeviceId>
0122 managed_open_or_create_impl(open_only_t,
0123 const DeviceId & id,
0124 mode_t mode,
0125 const void *addr)
0126 {
0127 priv_open_or_create
0128 ( DoOpen
0129 , id
0130 , 0
0131 , mode
0132 , addr
0133 , permissions()
0134 , null_mapped_region_function());
0135 }
0136
0137 template <class DeviceId>
0138 managed_open_or_create_impl(open_or_create_t,
0139 const DeviceId & id,
0140 std::size_t size,
0141 mode_t mode,
0142 const void *addr,
0143 const permissions &perm)
0144 {
0145 priv_open_or_create
0146 ( DoOpenOrCreate
0147 , id
0148 , size
0149 , mode
0150 , addr
0151 , perm
0152 , null_mapped_region_function());
0153 }
0154
0155 template <class DeviceId, class ConstructFunc>
0156 managed_open_or_create_impl(create_only_t,
0157 const DeviceId & id,
0158 std::size_t size,
0159 mode_t mode,
0160 const void *addr,
0161 const ConstructFunc &construct_func,
0162 const permissions &perm)
0163 {
0164 priv_open_or_create
0165 (DoCreate
0166 , id
0167 , size
0168 , mode
0169 , addr
0170 , perm
0171 , construct_func);
0172 }
0173
0174 template <class DeviceId, class ConstructFunc>
0175 managed_open_or_create_impl(open_only_t,
0176 const DeviceId & id,
0177 mode_t mode,
0178 const void *addr,
0179 const ConstructFunc &construct_func)
0180 {
0181 priv_open_or_create
0182 ( DoOpen
0183 , id
0184 , 0
0185 , mode
0186 , addr
0187 , permissions()
0188 , construct_func);
0189 }
0190
0191 template <class DeviceId, class ConstructFunc>
0192 managed_open_or_create_impl(open_or_create_t,
0193 const DeviceId & id,
0194 std::size_t size,
0195 mode_t mode,
0196 const void *addr,
0197 const ConstructFunc &construct_func,
0198 const permissions &perm)
0199 {
0200 priv_open_or_create
0201 ( DoOpenOrCreate
0202 , id
0203 , size
0204 , mode
0205 , addr
0206 , perm
0207 , construct_func);
0208 }
0209
0210 template <class ConstructFunc>
0211 managed_open_or_create_impl(std::size_t size, void *addr, const ConstructFunc &construct_func)
0212 {
0213 priv_map_anonymous
0214 ( size
0215 , addr
0216 , construct_func);
0217 }
0218
0219 managed_open_or_create_impl(BOOST_RV_REF(managed_open_or_create_impl) moved)
0220 { this->swap(moved); }
0221
0222 managed_open_or_create_impl &operator=(BOOST_RV_REF(managed_open_or_create_impl) moved)
0223 {
0224 managed_open_or_create_impl tmp(boost::move(moved));
0225 this->swap(tmp);
0226 return *this;
0227 }
0228
0229 ~managed_open_or_create_impl()
0230 {}
0231
0232 std::size_t get_user_size() const
0233 { return m_mapped_region.get_size() - ManagedOpenOrCreateUserOffset; }
0234
0235 void *get_user_address() const
0236 { return static_cast<char*>(m_mapped_region.get_address()) + ManagedOpenOrCreateUserOffset; }
0237
0238 std::size_t get_real_size() const
0239 { return m_mapped_region.get_size(); }
0240
0241 void *get_real_address() const
0242 { return m_mapped_region.get_address(); }
0243
0244 void swap(managed_open_or_create_impl &other)
0245 {
0246 this->m_mapped_region.swap(other.m_mapped_region);
0247 }
0248
0249 bool flush()
0250 { return m_mapped_region.flush(); }
0251
0252 const mapped_region &get_mapped_region() const
0253 { return m_mapped_region; }
0254
0255 DeviceAbstraction &get_device()
0256 { return this->DevHolder::get_device(); }
0257
0258 const DeviceAbstraction &get_device() const
0259 { return this->DevHolder::get_device(); }
0260
0261 private:
0262
0263
0264 template<bool dummy>
0265 static void truncate_device(DeviceAbstraction &, offset_t, false_)
0266 {}
0267
0268 template<bool dummy>
0269 static void truncate_device(DeviceAbstraction &dev, offset_t size, true_)
0270 { dev.truncate(size); }
0271
0272
0273 template<bool dummy>
0274 static bool check_offset_t_size(std::size_t , false_)
0275 { return true; }
0276
0277 template<bool dummy>
0278 static bool check_offset_t_size(std::size_t size, true_)
0279 { return size == std::size_t(offset_t(size)); }
0280
0281
0282 template<bool dummy, class DeviceId>
0283 static void create_device(DeviceAbstraction &dev, const DeviceId & id, std::size_t size, const permissions &perm, false_ )
0284 {
0285 DeviceAbstraction tmp(create_only, id, read_write, size, perm);
0286 tmp.swap(dev);
0287 }
0288
0289 template<bool dummy, class DeviceId>
0290 static void create_device(DeviceAbstraction &dev, const DeviceId & id, std::size_t, const permissions &perm, true_ )
0291 {
0292 DeviceAbstraction tmp(create_only, id, read_write, perm);
0293 tmp.swap(dev);
0294 }
0295
0296 template <class DeviceId>
0297 static bool do_create_else_open(DeviceAbstraction &dev, const DeviceId & id, std::size_t size, const permissions &perm)
0298 {
0299
0300
0301
0302
0303
0304
0305
0306
0307
0308 spin_wait swait;
0309 unsigned tries = 0;
0310 while(1){
0311 BOOST_INTERPROCESS_TRY{
0312 create_device<FileBased>(dev, id, size, perm, file_like_t());
0313 return true;
0314 }
0315 BOOST_INTERPROCESS_CATCH(interprocess_exception &ex){
0316 #ifndef BOOST_NO_EXCEPTIONS
0317 if(ex.get_error_code() != already_exists_error){
0318 BOOST_INTERPROCESS_RETHROW
0319 }
0320 else if (++tries == MaxCreateOrOpenTries) {
0321
0322
0323
0324 throw interprocess_exception(error_info(corrupted_error));
0325 }
0326 else{
0327 BOOST_INTERPROCESS_TRY{
0328 DeviceAbstraction tmp(open_only, id, read_write);
0329 dev.swap(tmp);
0330 return false;
0331 }
0332 BOOST_INTERPROCESS_CATCH(interprocess_exception &e){
0333 if(e.get_error_code() != not_found_error){
0334 BOOST_INTERPROCESS_RETHROW
0335 }
0336 }
0337 BOOST_INTERPROCESS_CATCH(...){
0338 BOOST_INTERPROCESS_RETHROW
0339 } BOOST_INTERPROCESS_CATCH_END
0340 }
0341 #endif
0342 }
0343 BOOST_INTERPROCESS_CATCH(...){
0344 BOOST_INTERPROCESS_RETHROW
0345 } BOOST_INTERPROCESS_CATCH_END
0346 swait.yield();
0347 }
0348 return false;
0349 }
0350
0351 template <class ConstructFunc>
0352 static void do_map_after_create
0353 (DeviceAbstraction &dev, mapped_region &final_region,
0354 std::size_t size, const void *addr, ConstructFunc construct_func)
0355 {
0356 BOOST_INTERPROCESS_TRY{
0357
0358 truncate_device<FileBased>(dev, static_cast<offset_t>(size), file_like_t());
0359
0360
0361 mapped_region region(dev, read_write, 0, 0, addr);
0362 boost::uint32_t *patomic_word = 0;
0363 patomic_word = static_cast<boost::uint32_t*>(region.get_address());
0364 boost::uint32_t previous = atomic_cas32(patomic_word, InitializingSegment, UninitializedSegment);
0365
0366 if(previous == UninitializedSegment){
0367 BOOST_INTERPROCESS_TRY{
0368 construct_func( static_cast<char*>(region.get_address()) + ManagedOpenOrCreateUserOffset
0369 , size - ManagedOpenOrCreateUserOffset, true);
0370
0371 final_region.swap(region);
0372 }
0373 BOOST_INTERPROCESS_CATCH(...){
0374 atomic_write32(patomic_word, CorruptedSegment);
0375 BOOST_INTERPROCESS_RETHROW
0376 } BOOST_INTERPROCESS_CATCH_END
0377 atomic_write32(patomic_word, InitializedSegment);
0378 }
0379 else{
0380 atomic_write32(patomic_word, CorruptedSegment);
0381 throw interprocess_exception(error_info(corrupted_error));
0382 }
0383 }
0384 BOOST_INTERPROCESS_CATCH(...){
0385 BOOST_INTERPROCESS_TRY{
0386 truncate_device<FileBased>(dev, 1u, file_like_t());
0387 }
0388 BOOST_INTERPROCESS_CATCH(...){
0389 }
0390 BOOST_INTERPROCESS_CATCH_END
0391 BOOST_INTERPROCESS_RETHROW
0392 }
0393 BOOST_INTERPROCESS_CATCH_END
0394 }
0395
0396 template <class ConstructFunc>
0397 static void do_map_after_open
0398 ( DeviceAbstraction &dev, mapped_region &final_region
0399 , const void *addr, ConstructFunc construct_func
0400 , bool ronly, bool cow)
0401 {
0402 const usduration TimeoutSec(usduration_from_seconds(MaxInitializeTimeSec));
0403
0404 if(FileBased){
0405 offset_t filesize = 0;
0406 spin_wait swait;
0407
0408
0409
0410 ustime ustime_start = microsec_clock<ustime>::universal_time();
0411
0412 while(1){
0413 if(!get_file_size(file_handle_from_mapping_handle(dev.get_mapping_handle()), filesize)){
0414 error_info err = system_error_code();
0415 throw interprocess_exception(err);
0416 }
0417 if (filesize != 0)
0418 break;
0419 else {
0420
0421
0422 const usduration elapsed(microsec_clock<ustime>::universal_time() - ustime_start);
0423 if (elapsed > TimeoutSec){
0424 throw interprocess_exception(error_info(corrupted_error));
0425 }
0426 swait.yield();
0427 }
0428 }
0429
0430 if(filesize == 1){
0431 throw interprocess_exception(error_info(corrupted_error));
0432 }
0433 }
0434
0435 mapped_region region(dev, ronly ? read_only : (cow ? copy_on_write : read_write), 0, 0, addr);
0436
0437 boost::uint32_t *patomic_word = static_cast<boost::uint32_t*>(region.get_address());
0438 boost::uint32_t value = atomic_read32(patomic_word);
0439
0440 if (value != InitializedSegment){
0441 ustime ustime_start = microsec_clock<ustime>::universal_time();
0442 spin_wait swait;
0443 while ((value = atomic_read32(patomic_word)) != InitializedSegment){
0444 if(value == CorruptedSegment){
0445 throw interprocess_exception(error_info(corrupted_error));
0446 }
0447
0448
0449 const usduration elapsed(microsec_clock<ustime>::universal_time() - ustime_start);
0450 if (elapsed > TimeoutSec){
0451 throw interprocess_exception(error_info(corrupted_error));
0452 }
0453 swait.yield();
0454 }
0455
0456 {
0457 mapped_region null_map;
0458 region.swap(null_map);
0459 }
0460 mapped_region final_size_map(dev, ronly ? read_only : (cow ? copy_on_write : read_write), 0, 0, addr);
0461 final_size_map.swap(region);
0462 }
0463 construct_func( static_cast<char*>(region.get_address()) + ManagedOpenOrCreateUserOffset
0464 , region.get_size() - ManagedOpenOrCreateUserOffset
0465 , false);
0466
0467 final_region.swap(region);
0468 }
0469
0470 template <class DeviceId, class ConstructFunc> inline
0471 void priv_open_or_create
0472 (create_enum_t type,
0473 const DeviceId & id,
0474 std::size_t size,
0475 mode_t mode, const void *addr,
0476 const permissions &perm,
0477 ConstructFunc construct_func)
0478 {
0479 if(type != DoOpen){
0480
0481 const std::size_t func_min_size = construct_func.get_min_size();
0482 if( (std::size_t(-1) - ManagedOpenOrCreateUserOffset) < func_min_size ||
0483 size < (func_min_size + ManagedOpenOrCreateUserOffset) ){
0484 throw interprocess_exception(error_info(size_error));
0485 }
0486
0487 if (!check_offset_t_size<FileBased>(size, file_like_t())){
0488 throw interprocess_exception(error_info(size_error));
0489 }
0490 }
0491
0492
0493 DeviceAbstraction dev;
0494 (void)mode;
0495 bool created = false;
0496 bool ronly = false;
0497 bool cow = false;
0498 if(type == DoOpen){
0499 DeviceAbstraction tmp(open_only, id, mode == read_write ? read_write : read_only);
0500 tmp.swap(dev);
0501 ronly = mode == read_only;
0502 cow = mode == copy_on_write;
0503 }
0504 else if(type == DoCreate){
0505 create_device<FileBased>(dev, id, size, perm, file_like_t());
0506 created = true;
0507 }
0508 else {
0509 created = this->do_create_else_open(dev, id, size, perm);
0510 }
0511
0512 if(created){
0513 this->do_map_after_create(dev, m_mapped_region, size, addr, construct_func);
0514 }
0515 else{
0516 this->do_map_after_open(dev, m_mapped_region, addr, construct_func, ronly, cow);
0517 }
0518
0519 if(StoreDevice){
0520 this->DevHolder::get_device() = boost::move(dev);
0521 }
0522 }
0523
0524 template <class ConstructFunc> inline
0525 void priv_map_anonymous
0526 (std::size_t size,
0527 void *addr,
0528 ConstructFunc construct_func)
0529 {
0530 mapped_region region = anonymous_shared_memory(size, addr);
0531
0532 boost::uint32_t *patomic_word = 0;
0533 patomic_word = static_cast<boost::uint32_t*>(region.get_address());
0534 boost::uint32_t previous = atomic_cas32(patomic_word, InitializingSegment, UninitializedSegment);
0535
0536 if(previous == UninitializedSegment){
0537 BOOST_INTERPROCESS_TRY{
0538 construct_func( static_cast<char*>(region.get_address()) + ManagedOpenOrCreateUserOffset
0539 , size - ManagedOpenOrCreateUserOffset, true);
0540
0541 m_mapped_region.swap(region);
0542 }
0543 BOOST_INTERPROCESS_CATCH(...){
0544 atomic_write32(patomic_word, CorruptedSegment);
0545 BOOST_INTERPROCESS_RETHROW
0546 } BOOST_INTERPROCESS_CATCH_END
0547 atomic_write32(patomic_word, InitializedSegment);
0548 }
0549 else{
0550 atomic_write32(patomic_word, CorruptedSegment);
0551 throw interprocess_exception(error_info(corrupted_error));
0552 }
0553 }
0554
0555 friend void swap(managed_open_or_create_impl &left, managed_open_or_create_impl &right)
0556 {
0557 left.swap(right);
0558 }
0559
0560 private:
0561 friend class interprocess_tester;
0562 void dont_close_on_destruction()
0563 { interprocess_tester::dont_close_on_destruction(m_mapped_region); }
0564
0565 mapped_region m_mapped_region;
0566 };
0567
0568 }
0569
0570 }
0571 }
0572
0573 #include <boost/interprocess/detail/config_end.hpp>
0574
0575 #endif