Chris@16: ////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost Chris@16: // Software License, Version 1.0. (See accompanying file Chris@16: // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: // Chris@16: // See http://www.boost.org/libs/interprocess for documentation. Chris@16: // Chris@16: ////////////////////////////////////////////////////////////////////////////// Chris@16: Chris@16: #ifndef BOOST_INTERPROCESS_SHARED_MEMORY_OBJECT_HPP Chris@16: #define BOOST_INTERPROCESS_SHARED_MEMORY_OBJECT_HPP Chris@16: Chris@101: #ifndef BOOST_CONFIG_HPP Chris@101: # include Chris@101: #endif Chris@101: # Chris@101: #if defined(BOOST_HAS_PRAGMA_ONCE) Chris@101: # pragma once Chris@101: #endif Chris@101: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@101: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@101: #include Chris@16: #include Chris@101: #include Chris@16: #include Chris@16: #include Chris@16: Chris@101: #if defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS) Chris@16: # include //O_CREAT, O_*... Chris@16: # include //shm_xxx Chris@16: # include //ftruncate, close Chris@16: # include //mode_t, S_IRWXG, S_IRWXO, S_IRWXU, Chris@16: # if defined(BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY) Chris@16: # if defined(__FreeBSD__) Chris@16: # include Chris@16: # endif Chris@16: # endif Chris@16: #else Chris@16: // Chris@16: #endif Chris@16: Chris@16: //!\file Chris@16: //!Describes a shared memory object management class. Chris@16: Chris@16: namespace boost { Chris@16: namespace interprocess { Chris@16: Chris@16: //!A class that wraps a shared memory mapping that can be used to Chris@16: //!create mapped regions from the mapped files Chris@16: class shared_memory_object Chris@16: { Chris@101: #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) Chris@16: //Non-copyable and non-assignable Chris@16: BOOST_MOVABLE_BUT_NOT_COPYABLE(shared_memory_object) Chris@101: #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED Chris@16: Chris@16: public: Chris@16: //!Default constructor. Represents an empty shared_memory_object. Chris@16: shared_memory_object(); Chris@16: Chris@16: //!Creates a shared memory object with name "name" and mode "mode", with the access mode "mode" Chris@16: //!If the file previously exists, throws an error.*/ Chris@16: shared_memory_object(create_only_t, const char *name, mode_t mode, const permissions &perm = permissions()) Chris@16: { this->priv_open_or_create(ipcdetail::DoCreate, name, mode, perm); } Chris@16: Chris@16: //!Tries to create a shared memory object with name "name" and mode "mode", with the Chris@16: //!access mode "mode". If the file previously exists, it tries to open it with mode "mode". Chris@16: //!Otherwise throws an error. Chris@16: shared_memory_object(open_or_create_t, const char *name, mode_t mode, const permissions &perm = permissions()) Chris@16: { this->priv_open_or_create(ipcdetail::DoOpenOrCreate, name, mode, perm); } Chris@16: Chris@16: //!Tries to open a shared memory object with name "name", with the access mode "mode". Chris@16: //!If the file does not previously exist, it throws an error. Chris@16: shared_memory_object(open_only_t, const char *name, mode_t mode) Chris@16: { this->priv_open_or_create(ipcdetail::DoOpen, name, mode, permissions()); } Chris@16: Chris@16: //!Moves the ownership of "moved"'s shared memory object to *this. Chris@16: //!After the call, "moved" does not represent any shared memory object. Chris@16: //!Does not throw Chris@16: shared_memory_object(BOOST_RV_REF(shared_memory_object) moved) Chris@16: : m_handle(file_handle_t(ipcdetail::invalid_file())) Chris@16: , m_mode(read_only) Chris@16: { this->swap(moved); } Chris@16: Chris@16: //!Moves the ownership of "moved"'s shared memory to *this. Chris@16: //!After the call, "moved" does not represent any shared memory. Chris@16: //!Does not throw Chris@16: shared_memory_object &operator=(BOOST_RV_REF(shared_memory_object) moved) Chris@16: { Chris@16: shared_memory_object tmp(boost::move(moved)); Chris@16: this->swap(tmp); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: //!Swaps the shared_memory_objects. Does not throw Chris@16: void swap(shared_memory_object &moved); Chris@16: Chris@16: //!Erases a shared memory object from the system. Chris@16: //!Returns false on error. Never throws Chris@16: static bool remove(const char *name); Chris@16: Chris@16: //!Sets the size of the shared memory mapping Chris@16: void truncate(offset_t length); Chris@16: Chris@16: //!Destroys *this and indicates that the calling process is finished using Chris@16: //!the resource. All mapped regions are still Chris@16: //!valid after destruction. The destructor function will deallocate Chris@16: //!any system resources allocated by the system for use by this process for Chris@16: //!this resource. The resource can still be opened again calling Chris@16: //!the open constructor overload. To erase the resource from the system Chris@16: //!use remove(). Chris@16: ~shared_memory_object(); Chris@16: Chris@16: //!Returns the name of the shared memory object. Chris@16: const char *get_name() const; Chris@16: Chris@16: //!Returns true if the size of the shared memory object Chris@16: //!can be obtained and writes the size in the passed reference Chris@16: bool get_size(offset_t &size) const; Chris@16: Chris@16: //!Returns access mode Chris@16: mode_t get_mode() const; Chris@16: Chris@16: //!Returns mapping handle. Never throws. Chris@16: mapping_handle_t get_mapping_handle() const; Chris@16: Chris@101: #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) Chris@16: private: Chris@16: Chris@16: //!Closes a previously opened file mapping. Never throws. Chris@16: void priv_close(); Chris@16: Chris@101: //!Opens or creates a shared memory object. Chris@16: bool priv_open_or_create(ipcdetail::create_enum_t type, const char *filename, mode_t mode, const permissions &perm); Chris@16: Chris@16: file_handle_t m_handle; Chris@16: mode_t m_mode; Chris@16: std::string m_filename; Chris@101: #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED Chris@16: }; Chris@16: Chris@101: #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) Chris@16: Chris@16: inline shared_memory_object::shared_memory_object() Chris@16: : m_handle(file_handle_t(ipcdetail::invalid_file())) Chris@16: , m_mode(read_only) Chris@16: {} Chris@16: Chris@16: inline shared_memory_object::~shared_memory_object() Chris@16: { this->priv_close(); } Chris@16: Chris@16: Chris@16: inline const char *shared_memory_object::get_name() const Chris@16: { return m_filename.c_str(); } Chris@16: Chris@16: inline bool shared_memory_object::get_size(offset_t &size) const Chris@16: { return ipcdetail::get_file_size((file_handle_t)m_handle, size); } Chris@16: Chris@16: inline void shared_memory_object::swap(shared_memory_object &other) Chris@16: { Chris@101: boost::adl_move_swap(m_handle, other.m_handle); Chris@101: boost::adl_move_swap(m_mode, other.m_mode); Chris@16: m_filename.swap(other.m_filename); Chris@16: } Chris@16: Chris@16: inline mapping_handle_t shared_memory_object::get_mapping_handle() const Chris@16: { Chris@16: return ipcdetail::mapping_handle_from_file_handle(m_handle); Chris@16: } Chris@16: Chris@16: inline mode_t shared_memory_object::get_mode() const Chris@16: { return m_mode; } Chris@16: Chris@16: #if !defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS) Chris@16: Chris@16: inline bool shared_memory_object::priv_open_or_create Chris@16: (ipcdetail::create_enum_t type, const char *filename, mode_t mode, const permissions &perm) Chris@16: { Chris@16: m_filename = filename; Chris@16: std::string shmfile; Chris@101: ipcdetail::create_shared_dir_cleaning_old_and_get_filepath(filename, shmfile); Chris@16: Chris@16: //Set accesses Chris@16: if (mode != read_write && mode != read_only){ Chris@16: error_info err = other_error; Chris@16: throw interprocess_exception(err); Chris@16: } Chris@16: Chris@16: switch(type){ Chris@16: case ipcdetail::DoOpen: Chris@16: m_handle = ipcdetail::open_existing_file(shmfile.c_str(), mode, true); Chris@16: break; Chris@16: case ipcdetail::DoCreate: Chris@16: m_handle = ipcdetail::create_new_file(shmfile.c_str(), mode, perm, true); Chris@16: break; Chris@16: case ipcdetail::DoOpenOrCreate: Chris@16: m_handle = ipcdetail::create_or_open_file(shmfile.c_str(), mode, perm, true); Chris@16: break; Chris@16: default: Chris@16: { Chris@16: error_info err = other_error; Chris@16: throw interprocess_exception(err); Chris@16: } Chris@16: } Chris@16: Chris@16: //Check for error Chris@16: if(m_handle == ipcdetail::invalid_file()){ Chris@16: error_info err = system_error_code(); Chris@16: this->priv_close(); Chris@16: throw interprocess_exception(err); Chris@16: } Chris@16: Chris@16: m_mode = mode; Chris@16: return true; Chris@16: } Chris@16: Chris@16: inline bool shared_memory_object::remove(const char *filename) Chris@16: { Chris@16: try{ Chris@16: //Make sure a temporary path is created for shared memory Chris@16: std::string shmfile; Chris@101: ipcdetail::shared_filepath(filename, shmfile); Chris@16: return ipcdetail::delete_file(shmfile.c_str()); Chris@16: } Chris@16: catch(...){ Chris@16: return false; Chris@16: } Chris@16: } Chris@16: Chris@16: inline void shared_memory_object::truncate(offset_t length) Chris@16: { Chris@16: if(!ipcdetail::truncate_file(m_handle, length)){ Chris@16: error_info err = system_error_code(); Chris@16: throw interprocess_exception(err); Chris@16: } Chris@16: } Chris@16: Chris@16: inline void shared_memory_object::priv_close() Chris@16: { Chris@16: if(m_handle != ipcdetail::invalid_file()){ Chris@16: ipcdetail::close_file(m_handle); Chris@16: m_handle = ipcdetail::invalid_file(); Chris@16: } Chris@16: } Chris@16: Chris@16: #else //!defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS) Chris@16: Chris@16: namespace shared_memory_object_detail { Chris@16: Chris@16: #ifdef BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY Chris@16: Chris@16: #if defined(__FreeBSD__) Chris@16: Chris@16: inline bool use_filesystem_based_posix() Chris@16: { Chris@16: int jailed = 0; Chris@16: std::size_t len = sizeof(jailed); Chris@16: ::sysctlbyname("security.jail.jailed", &jailed, &len, NULL, 0); Chris@16: return jailed != 0; Chris@16: } Chris@16: Chris@16: #else Chris@16: #error "Not supported platform for BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY" Chris@16: #endif Chris@16: Chris@16: #endif Chris@16: Chris@16: } //shared_memory_object_detail Chris@16: Chris@16: inline bool shared_memory_object::priv_open_or_create Chris@16: (ipcdetail::create_enum_t type, Chris@16: const char *filename, Chris@16: mode_t mode, const permissions &perm) Chris@16: { Chris@16: #if defined(BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SHARED_MEMORY) Chris@16: const bool add_leading_slash = false; Chris@16: #elif defined(BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY) Chris@16: const bool add_leading_slash = !shared_memory_object_detail::use_filesystem_based_posix(); Chris@16: #else Chris@16: const bool add_leading_slash = true; Chris@16: #endif Chris@16: if(add_leading_slash){ Chris@16: ipcdetail::add_leading_slash(filename, m_filename); Chris@16: } Chris@16: else{ Chris@101: ipcdetail::create_shared_dir_cleaning_old_and_get_filepath(filename, m_filename); Chris@16: } Chris@16: Chris@16: //Create new mapping Chris@16: int oflag = 0; Chris@16: if(mode == read_only){ Chris@16: oflag |= O_RDONLY; Chris@16: } Chris@16: else if(mode == read_write){ Chris@16: oflag |= O_RDWR; Chris@16: } Chris@16: else{ Chris@16: error_info err(mode_error); Chris@16: throw interprocess_exception(err); Chris@16: } Chris@16: int unix_perm = perm.get_permissions(); Chris@16: Chris@16: switch(type){ Chris@16: case ipcdetail::DoOpen: Chris@16: { Chris@16: //No oflag addition Chris@16: m_handle = shm_open(m_filename.c_str(), oflag, unix_perm); Chris@16: } Chris@16: break; Chris@16: case ipcdetail::DoCreate: Chris@16: { Chris@16: oflag |= (O_CREAT | O_EXCL); Chris@16: m_handle = shm_open(m_filename.c_str(), oflag, unix_perm); Chris@16: if(m_handle >= 0){ Chris@16: ::fchmod(m_handle, unix_perm); Chris@16: } Chris@16: } Chris@16: break; Chris@16: case ipcdetail::DoOpenOrCreate: Chris@16: { Chris@16: //We need a create/open loop to change permissions correctly using fchmod, since Chris@16: //with "O_CREAT" only we don't know if we've created or opened the shm. Chris@16: while(1){ Chris@16: //Try to create shared memory Chris@16: m_handle = shm_open(m_filename.c_str(), oflag | (O_CREAT | O_EXCL), unix_perm); Chris@16: //If successful change real permissions Chris@16: if(m_handle >= 0){ Chris@16: ::fchmod(m_handle, unix_perm); Chris@16: } Chris@16: //If already exists, try to open Chris@16: else if(errno == EEXIST){ Chris@16: m_handle = shm_open(m_filename.c_str(), oflag, unix_perm); Chris@16: //If open fails and errno tells the file does not exist Chris@16: //(shm was removed between creation and opening tries), just retry Chris@16: if(m_handle < 0 && errno == ENOENT){ Chris@16: continue; Chris@16: } Chris@16: } Chris@16: //Exit retries Chris@16: break; Chris@16: } Chris@16: } Chris@16: break; Chris@16: default: Chris@16: { Chris@16: error_info err = other_error; Chris@16: throw interprocess_exception(err); Chris@16: } Chris@16: } Chris@16: Chris@16: //Check for error Chris@16: if(m_handle < 0){ Chris@16: error_info err = errno; Chris@16: this->priv_close(); Chris@16: throw interprocess_exception(err); Chris@16: } Chris@16: Chris@16: m_filename = filename; Chris@16: m_mode = mode; Chris@16: return true; Chris@16: } Chris@16: Chris@16: inline bool shared_memory_object::remove(const char *filename) Chris@16: { Chris@16: try{ Chris@101: std::string filepath; Chris@16: #if defined(BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SHARED_MEMORY) Chris@16: const bool add_leading_slash = false; Chris@16: #elif defined(BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY) Chris@16: const bool add_leading_slash = !shared_memory_object_detail::use_filesystem_based_posix(); Chris@16: #else Chris@16: const bool add_leading_slash = true; Chris@16: #endif Chris@16: if(add_leading_slash){ Chris@101: ipcdetail::add_leading_slash(filename, filepath); Chris@16: } Chris@16: else{ Chris@101: ipcdetail::shared_filepath(filename, filepath); Chris@16: } Chris@101: return 0 == shm_unlink(filepath.c_str()); Chris@16: } Chris@16: catch(...){ Chris@16: return false; Chris@16: } Chris@16: } Chris@16: Chris@16: inline void shared_memory_object::truncate(offset_t length) Chris@16: { Chris@16: if(0 != ftruncate(m_handle, length)){ Chris@16: error_info err(system_error_code()); Chris@16: throw interprocess_exception(err); Chris@16: } Chris@16: } Chris@16: Chris@16: inline void shared_memory_object::priv_close() Chris@16: { Chris@16: if(m_handle != -1){ Chris@16: ::close(m_handle); Chris@16: m_handle = -1; Chris@16: } Chris@16: } Chris@16: Chris@16: #endif Chris@16: Chris@16: //!A class that stores the name of a shared memory Chris@16: //!and calls shared_memory_object::remove(name) in its destructor Chris@16: //!Useful to remove temporary shared memory objects in the presence Chris@16: //!of exceptions Chris@16: class remove_shared_memory_on_destroy Chris@16: { Chris@16: const char * m_name; Chris@16: public: Chris@16: remove_shared_memory_on_destroy(const char *name) Chris@16: : m_name(name) Chris@16: {} Chris@16: Chris@16: ~remove_shared_memory_on_destroy() Chris@16: { shared_memory_object::remove(m_name); } Chris@16: }; Chris@16: Chris@101: #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED Chris@101: Chris@16: } //namespace interprocess { Chris@16: } //namespace boost { Chris@16: Chris@16: #include Chris@16: Chris@16: #endif //BOOST_INTERPROCESS_SHARED_MEMORY_OBJECT_HPP