Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:38:26

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/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    //Non-copyable
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    //These are templatized to allow explicit instantiations
0253    template<bool dummy>
0254    static void truncate_device(DeviceAbstraction &, offset_t, false_)
0255    {} //Empty
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; } //Empty
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    //These are templatized to allow explicit instantiations
0271    template<bool dummy, class DeviceId>
0272    static void create_device(DeviceAbstraction &dev, const DeviceId & id, std::size_t size, const permissions &perm, false_ /*file_like*/)
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_ /*file_like*/)
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       //This loop is very ugly, but brute force is sometimes better
0289       //than diplomacy. In POSIX file-based resources we can' know if we
0290       //effectively created the file or not (there is no ERROR_ALREADY_EXISTS equivalent),
0291       //so we try to create exclusively and fallback to open if already exists, with
0292       //some retries if opening also fails because the file does not exist
0293       //(there is a race, the creator just removed the file after creating it).
0294       //
0295       //We'll put a maximum retry limit just to avoid possible deadlocks, we don't
0296       //want to support pathological use cases.
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                //File existing when trying to create, but non-existing when
0311                //trying to open, and tried MaxCreateOrOpenTries times. Something fishy
0312                //is happening here and we can't solve it
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   //#ifndef BOOST_NO_EXCEPTIONS
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          //If this throws, we are lost
0347          truncate_device<FileBased>(dev, static_cast<offset_t>(size), file_like_t());
0348 
0349          //If the following throws, we will truncate the file to 1
0350          mapped_region region(dev, read_write, 0, 0, addr);
0351          boost::uint32_t *patomic_word = 0;  //avoid gcc warning
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                //All ok, just move resources to the external mapped region
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          //If a file device was used, the creator might be truncating the device, so wait
0398          //until the file size is enough to map the initial word
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                //More than MaxZeroTruncateTimeSec seconds waiting to the creator
0410                //to minimally increase the size of the file: something bad has happened
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          //The creator detected an error creating the file and signalled it with size 1
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             //More than MaxZeroTruncateTimeSec seconds waiting to the creator
0437             //to minimally increase the size of the file: something bad has happened
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          //The size of the file might have grown while Uninitialized -> Initializing, so remap
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       //All ok, just move resources to the external mapped region
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          //Check if the requested size is enough to build the managed metadata
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          //Check size can be represented by offset_t (used by truncate)
0476          if (!check_offset_t_size<FileBased>(size, file_like_t())){
0477            throw interprocess_exception(error_info(size_error));
0478          }
0479       }
0480 
0481       //Now create the device (file, shm file, etc.)
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 { //DoOpenOrCreate
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 }  //namespace ipcdetail {
0527 
0528 }  //namespace interprocess {
0529 }  //namespace boost {
0530 
0531 #include <boost/interprocess/detail/config_end.hpp>
0532 
0533 #endif   //#ifndef BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_IMPL