Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-15 08:36:44

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