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