Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-20 08:50:14

0001 //////////////////////////////////////////////////////////////////////////////
0002 //
0003 // (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost
0004 // Software License, Version 1.0. (See accompanying file
0005 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 // See http://www.boost.org/libs/interprocess for documentation.
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    //Non-copyable
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    //These are templatized to allow explicit instantiations
0264    template<bool dummy>
0265    static void truncate_device(DeviceAbstraction &, offset_t, false_)
0266    {} //Empty
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; } //Empty
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    //These are templatized to allow explicit instantiations
0282    template<bool dummy, class DeviceId>
0283    static void create_device(DeviceAbstraction &dev, const DeviceId & id, std::size_t size, const permissions &perm, false_ /*file_like*/)
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_ /*file_like*/)
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       //This loop is very ugly, but brute force is sometimes better
0300       //than diplomacy. In POSIX file-based resources we can' know if we
0301       //effectively created the file or not (there is no ERROR_ALREADY_EXISTS equivalent),
0302       //so we try to create exclusively and fallback to open if already exists, with
0303       //some retries if opening also fails because the file does not exist
0304       //(there is a race, the creator just removed the file after creating it).
0305       //
0306       //We'll put a maximum retry limit just to avoid possible deadlocks, we don't
0307       //want to support pathological use cases.
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                //File existing when trying to create, but non-existing when
0322                //trying to open, and tried MaxCreateOrOpenTries times. Something fishy
0323                //is happening here and we can't solve it
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   //#ifndef BOOST_NO_EXCEPTIONS
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          //If this throws, we are lost
0358          truncate_device<FileBased>(dev, static_cast<offset_t>(size), file_like_t());
0359 
0360          //If the following throws, we will truncate the file to 1
0361          mapped_region region(dev, read_write, 0, 0, addr);
0362          boost::uint32_t *patomic_word = 0;  //avoid gcc warning
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                //All ok, just move resources to the external mapped region
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          //If a file device was used, the creator might be truncating the device, so wait
0409          //until the file size is enough to map the initial word
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                //More than MaxZeroTruncateTimeSec seconds waiting to the creator
0421                //to minimally increase the size of the file: something bad has happened
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          //The creator detected an error creating the file and signalled it with size 1
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             //More than MaxZeroTruncateTimeSec seconds waiting to the creator
0448             //to minimally increase the size of the file: something bad has happened
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          //The size of the file might have grown while Uninitialized -> Initializing, so remap
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       //All ok, just move resources to the external mapped region
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          //Check if the requested size is enough to build the managed metadata
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          //Check size can be represented by offset_t (used by truncate)
0487          if (!check_offset_t_size<FileBased>(size, file_like_t())){
0488            throw interprocess_exception(error_info(size_error));
0489          }
0490       }
0491 
0492       //Now create the device (file, shm file, etc.)
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 { //DoOpenOrCreate
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;  //avoid gcc warning
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             //All ok, just move resources to the external mapped region
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 }  //namespace ipcdetail {
0569 
0570 }  //namespace interprocess {
0571 }  //namespace boost {
0572 
0573 #include <boost/interprocess/detail/config_end.hpp>
0574 
0575 #endif   //#ifndef BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_IMPL