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