managed_open_or_create_impl.hpp

来自「Boost provides free peer-reviewed portab」· HPP 代码 · 共 458 行

HPP
458
字号
////////////////////////////////////////////////////////////////////////////////// (C) Copyright Ion Gaztanaga 2006. Distributed under the Boost// Software License, Version 1.0. (See accompanying file// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)//// See http://www.boost.org/libs/interprocess for documentation.////////////////////////////////////////////////////////////////////////////////#ifndef BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_IMPL#define BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_IMPL#include <boost/interprocess/detail/os_thread_functions.hpp>#include <boost/interprocess/detail/os_file_functions.hpp>#include <boost/interprocess/creation_tags.hpp>#include <boost/interprocess/mapped_region.hpp>#include <boost/interprocess/detail/utilities.hpp>#include <boost/interprocess/detail/type_traits.hpp>#include <boost/interprocess/detail/atomic.hpp>#include <boost/interprocess/detail/interprocess_tester.hpp>#include <boost/interprocess/creation_tags.hpp>#include <boost/interprocess/detail/mpl.hpp>#include <boost/interprocess/detail/move.hpp>#include <boost/cstdint.hpp>namespace boost {namespace interprocess {/// @condnamespace detail{ class interprocess_tester; }/// @endcondnamespace detail {template<class DeviceAbstraction, bool FileBased = true>class managed_open_or_create_impl{   //Non-copyable   managed_open_or_create_impl(const managed_open_or_create_impl &);   managed_open_or_create_impl &operator=(const managed_open_or_create_impl &);   enum   {        UninitializedSegment,        InitializingSegment,        InitializedSegment,      CorruptedSegment   };   public:   static const std::size_t      ManagedOpenOrCreateUserOffset =          detail::ct_rounded_size            < sizeof(boost::uint32_t)            , detail::alignment_of<detail::max_align>::value>::value;   managed_open_or_create_impl()   {}   managed_open_or_create_impl(create_only_t,                  const char *name,                 std::size_t size,                 mode_t mode = read_write,                 const void *addr = 0)   {      m_name = name;      priv_open_or_create         ( detail::DoCreate         , size         , mode         , addr         , null_mapped_region_function());   }   managed_open_or_create_impl(open_only_t,                  const char *name,                 mode_t mode = read_write,                 const void *addr = 0)   {      m_name = name;      priv_open_or_create         ( detail::DoOpen         , 0         , mode         , addr         , null_mapped_region_function());   }   managed_open_or_create_impl(open_or_create_t,                  const char *name,                 std::size_t size,                 mode_t mode = read_write,                 const void *addr = 0)   {      m_name = name;      priv_open_or_create         ( detail::DoOpenOrCreate         , size         , mode         , addr         , null_mapped_region_function());   }   template <class ConstructFunc>   managed_open_or_create_impl(create_only_t,                  const char *name,                 std::size_t size,                 mode_t mode,                 const void *addr,                 const ConstructFunc &construct_func)   {      m_name = name;      priv_open_or_create         (detail::DoCreate         , size         , mode         , addr         , construct_func);   }   template <class ConstructFunc>   managed_open_or_create_impl(open_only_t,                  const char *name,                 mode_t mode,                 const void *addr,                 const ConstructFunc &construct_func)   {      m_name = name;      priv_open_or_create         ( detail::DoOpen         , 0         , mode         , addr         , construct_func);   }   template <class ConstructFunc>   managed_open_or_create_impl(open_or_create_t,                  const char *name,                 std::size_t size,                 mode_t mode,                 const void *addr,                 const ConstructFunc &construct_func)   {      m_name = name;      priv_open_or_create         ( detail::DoOpenOrCreate         , size         , mode         , addr         , construct_func);   }   #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE   managed_open_or_create_impl(detail::moved_object<managed_open_or_create_impl> moved)   {  this->swap(moved.get());   }   #else   managed_open_or_create_impl(managed_open_or_create_impl &&moved)   {  this->swap(moved);   }   #endif   //!Move assignment. If *this owns a memory mapped region, it will be   //!destroyed and it will take ownership of "other"'s memory mapped region.   #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE   managed_open_or_create_impl &operator=(detail::moved_object<managed_open_or_create_impl> moved)   {        managed_open_or_create_impl tmp(moved);      this->swap(tmp);      return *this;     }   #else   managed_open_or_create_impl &operator=(managed_open_or_create_impl &&moved)   {        managed_open_or_create_impl tmp(detail::move_impl(moved));      this->swap(tmp);      return *this;     }   #endif   ~managed_open_or_create_impl()   {}   std::size_t get_user_size()  const   {  return m_mapped_region.get_size() - ManagedOpenOrCreateUserOffset; }   void *get_user_address()  const   {  return static_cast<char*>(m_mapped_region.get_address()) + ManagedOpenOrCreateUserOffset;  }   std::size_t get_real_size()  const   {  return m_mapped_region.get_size(); }   void *get_real_address()  const   {  return m_mapped_region.get_address();  }   void swap(managed_open_or_create_impl &other)   {      this->m_name.swap(other.m_name);      this->m_mapped_region.swap(other.m_mapped_region);   }   const char *get_name() const   {  return m_name.c_str();  }   bool flush()   {  return m_mapped_region.flush();  }   const mapped_region &get_mapped_region() const   {  return m_mapped_region;  }   private:   //These are templatized to allow explicit instantiations   template<bool dummy>   static void write_whole_device(DeviceAbstraction &, std::size_t, detail::false_)   {} //Empty   template<bool dummy>   static void write_whole_device(DeviceAbstraction &dev, std::size_t size, detail::true_)   {      file_handle_t hnd = detail::file_handle_from_mapping_handle(dev.get_mapping_handle());      if(size <= ManagedOpenOrCreateUserOffset){         throw interprocess_exception(error_info(system_error_code()));      }      size -= ManagedOpenOrCreateUserOffset;      if(!detail::set_file_pointer(hnd, ManagedOpenOrCreateUserOffset, file_begin)){         throw interprocess_exception(error_info(system_error_code()));      }      //We will write zeros in the file      for(std::size_t remaining = size, write_size = 0         ;remaining > 0         ;remaining -= write_size){         const std::size_t DataSize = 512;         static char data [DataSize];         write_size = DataSize < remaining ? DataSize : remaining;         if(!detail::write_file(hnd, data, write_size)){            error_info err = system_error_code();            throw interprocess_exception(err);         }      }   }   //These are templatized to allow explicit instantiations   template<bool dummy>   static void truncate_device(DeviceAbstraction &, std::size_t, detail::false_)   {} //Empty   template<bool dummy>   static void truncate_device(DeviceAbstraction &dev, std::size_t size, detail::true_)   {  dev.truncate(size);  }   //These are templatized to allow explicit instantiations   template<bool dummy>   static void create_device(DeviceAbstraction &dev, const char *name, std::size_t size, detail::false_)   {      DeviceAbstraction tmp(create_only, name, read_write, size);      tmp.swap(dev);   }   template<bool dummy>   static void create_device(DeviceAbstraction &dev, const char *name, std::size_t, detail::true_)   {      DeviceAbstraction tmp(create_only, name, read_write);      tmp.swap(dev);   }   template <class ConstructFunc> inline    void priv_open_or_create      (detail::create_enum_t type, std::size_t size,       mode_t mode, const void *addr,       ConstructFunc construct_func)   {      typedef detail::bool_<FileBased> file_like_t;      (void)mode;      error_info err;      bool created = false;      bool ronly   = false;      bool cow     = false;      DeviceAbstraction dev;      if(type != detail::DoOpen && size < ManagedOpenOrCreateUserOffset){         throw interprocess_exception(error_info(size_error));      }      if(type == detail::DoOpen && mode == read_write){         DeviceAbstraction tmp(open_only, m_name.c_str(), read_write);         tmp.swap(dev);         created = false;      }      else if(type == detail::DoOpen && mode == read_only){         DeviceAbstraction tmp(open_only, m_name.c_str(), read_only);         tmp.swap(dev);         created = false;         ronly   = true;      }      else if(type == detail::DoOpen && mode == copy_on_write){         DeviceAbstraction tmp(open_only, m_name.c_str(), read_only);         tmp.swap(dev);         created = false;         cow     = true;      }      else if(type == detail::DoCreate){         create_device<FileBased>(dev, m_name.c_str(), size, file_like_t());         created = true;      }      else if(type == detail::DoOpenOrCreate){         //This loop is very ugly, but brute force is sometimes better         //than diplomacy. If someone knows how to open or create a         //file and know if we have really created it or just open it         //drop me a e-mail!         bool completed = false;         while(!completed){            try{               create_device<FileBased>(dev, m_name.c_str(), size, file_like_t());               created     = true;               completed   = true;            }            catch(interprocess_exception &ex){               if(ex.get_error_code() != already_exists_error){                  throw;               }               else{                  try{                     DeviceAbstraction tmp(open_only, m_name.c_str(), read_write);                     dev.swap(tmp);                     created     = false;                     completed   = true;                  }                  catch(interprocess_exception &ex){                     if(ex.get_error_code() != not_found_error){                        throw;                     }                  }               }            }            detail::thread_yield();         }      }      if(created){         try{            //If this throws, we are lost            truncate_device<FileBased>(dev, size, file_like_t());            //If the following throws, we will truncate the file to 1            mapped_region        region(dev, read_write, 0, 0, addr);            boost::uint32_t *patomic_word = 0;  //avoid gcc warning            patomic_word = static_cast<boost::uint32_t*>(region.get_address());            boost::uint32_t previous = detail::atomic_cas32(patomic_word, InitializingSegment, UninitializedSegment);            if(previous == UninitializedSegment){               try{                  write_whole_device<FileBased>(dev, size, file_like_t());                  construct_func(static_cast<char*>(region.get_address()) + ManagedOpenOrCreateUserOffset, size - ManagedOpenOrCreateUserOffset, true);                  //All ok, just move resources to the external mapped region                  m_mapped_region.swap(region);               }               catch(...){                  detail::atomic_write32(patomic_word, CorruptedSegment);                  throw;               }               detail::atomic_write32(patomic_word, InitializedSegment);            }            else if(previous == InitializingSegment || previous == InitializedSegment){               throw interprocess_exception(error_info(already_exists_error));            }            else{               throw interprocess_exception(error_info(corrupted_error));            }         }         catch(...){            try{               truncate_device<FileBased>(dev, 1u, file_like_t());            }            catch(...){            }            throw;         }      }      else{         if(FileBased){            offset_t filesize = 0;            while(filesize == 0){               if(!detail::get_file_size(detail::file_handle_from_mapping_handle(dev.get_mapping_handle()), filesize)){                  throw interprocess_exception(error_info(system_error_code()));               }               detail::thread_yield();            }            if(filesize == 1){               throw interprocess_exception(error_info(corrupted_error));            }         }         mapped_region  region(dev, ronly ? read_only : (cow ? copy_on_write : read_write), 0, 0, addr);         boost::uint32_t *patomic_word = static_cast<boost::uint32_t*>(region.get_address());         boost::uint32_t value = detail::atomic_read32(patomic_word);         while(value == InitializingSegment || value == UninitializedSegment){            detail::thread_yield();            value = detail::atomic_read32(patomic_word);         }         if(value != InitializedSegment)            throw interprocess_exception(error_info(corrupted_error));         construct_func( static_cast<char*>(region.get_address()) + ManagedOpenOrCreateUserOffset                        , region.get_size() - ManagedOpenOrCreateUserOffset                        , false);         //All ok, just move resources to the external mapped region         m_mapped_region.swap(region);      }   }   private:   friend class detail::interprocess_tester;   void dont_close_on_destruction()   {  detail::interprocess_tester::dont_close_on_destruction(m_mapped_region);  }   mapped_region     m_mapped_region;   std::string       m_name;};template<class DeviceAbstraction>inline void swap(managed_open_or_create_impl<DeviceAbstraction> &x                ,managed_open_or_create_impl<DeviceAbstraction> &y){  x.swap(y);  }}  //namespace detail {///@cond//!Trait class to detect if a type is//!movabletemplate<class DeviceAbstraction>struct is_movable<detail::managed_open_or_create_impl<DeviceAbstraction> >{   enum {  value = true };};///@endcond}  //namespace interprocess {}  //namespace boost {#endif   //#ifndef BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_IMPL

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?