shared_memory_object.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
  4. // Software License, Version 1.0. (See accompanying file
  5. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. // See http://www.boost.org/libs/interprocess for documentation.
  8. //
  9. //////////////////////////////////////////////////////////////////////////////
  10. #ifndef BOOST_INTERPROCESS_SHARED_MEMORY_OBJECT_HPP
  11. #define BOOST_INTERPROCESS_SHARED_MEMORY_OBJECT_HPP
  12. #ifndef BOOST_CONFIG_HPP
  13. # include <boost/config.hpp>
  14. #endif
  15. #
  16. #if defined(BOOST_HAS_PRAGMA_ONCE)
  17. # pragma once
  18. #endif
  19. #include <boost/interprocess/detail/config_begin.hpp>
  20. #include <boost/interprocess/detail/workaround.hpp>
  21. #include <boost/interprocess/creation_tags.hpp>
  22. #include <boost/interprocess/exceptions.hpp>
  23. #include <boost/move/utility_core.hpp>
  24. #include <boost/interprocess/interprocess_fwd.hpp>
  25. #include <boost/interprocess/exceptions.hpp>
  26. #include <boost/interprocess/detail/os_file_functions.hpp>
  27. #include <boost/interprocess/detail/shared_dir_helpers.hpp>
  28. #include <boost/interprocess/permissions.hpp>
  29. #include <boost/move/adl_move_swap.hpp>
  30. #include <cstddef>
  31. #include <string>
  32. #if defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS)
  33. # include <fcntl.h> //O_CREAT, O_*...
  34. # include <sys/mman.h> //shm_xxx
  35. # include <unistd.h> //ftruncate, close
  36. # include <sys/stat.h> //mode_t, S_IRWXG, S_IRWXO, S_IRWXU,
  37. # if defined(BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY)
  38. # if defined(__FreeBSD__)
  39. # include <sys/sysctl.h>
  40. # endif
  41. # endif
  42. #else
  43. //
  44. #endif
  45. //!\file
  46. //!Describes a shared memory object management class.
  47. namespace boost {
  48. namespace interprocess {
  49. //!A class that wraps a shared memory mapping that can be used to
  50. //!create mapped regions from the mapped files
  51. class shared_memory_object
  52. {
  53. #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
  54. //Non-copyable and non-assignable
  55. BOOST_MOVABLE_BUT_NOT_COPYABLE(shared_memory_object)
  56. #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
  57. public:
  58. //!Default constructor. Represents an empty shared_memory_object.
  59. shared_memory_object();
  60. //!Creates a shared memory object with name "name" and mode "mode", with the access mode "mode"
  61. //!If the file previously exists, throws an error.*/
  62. shared_memory_object(create_only_t, const char *name, mode_t mode, const permissions &perm = permissions())
  63. { this->priv_open_or_create(ipcdetail::DoCreate, name, mode, perm); }
  64. //!Tries to create a shared memory object with name "name" and mode "mode", with the
  65. //!access mode "mode". If the file previously exists, it tries to open it with mode "mode".
  66. //!Otherwise throws an error.
  67. shared_memory_object(open_or_create_t, const char *name, mode_t mode, const permissions &perm = permissions())
  68. { this->priv_open_or_create(ipcdetail::DoOpenOrCreate, name, mode, perm); }
  69. //!Tries to open a shared memory object with name "name", with the access mode "mode".
  70. //!If the file does not previously exist, it throws an error.
  71. shared_memory_object(open_only_t, const char *name, mode_t mode)
  72. { this->priv_open_or_create(ipcdetail::DoOpen, name, mode, permissions()); }
  73. //!Moves the ownership of "moved"'s shared memory object to *this.
  74. //!After the call, "moved" does not represent any shared memory object.
  75. //!Does not throw
  76. shared_memory_object(BOOST_RV_REF(shared_memory_object) moved)
  77. : m_handle(file_handle_t(ipcdetail::invalid_file()))
  78. , m_mode(read_only)
  79. { this->swap(moved); }
  80. //!Moves the ownership of "moved"'s shared memory to *this.
  81. //!After the call, "moved" does not represent any shared memory.
  82. //!Does not throw
  83. shared_memory_object &operator=(BOOST_RV_REF(shared_memory_object) moved)
  84. {
  85. shared_memory_object tmp(boost::move(moved));
  86. this->swap(tmp);
  87. return *this;
  88. }
  89. //!Swaps the shared_memory_objects. Does not throw
  90. void swap(shared_memory_object &moved);
  91. //!Erases a shared memory object from the system.
  92. //!Returns false on error. Never throws
  93. static bool remove(const char *name);
  94. //!Sets the size of the shared memory mapping
  95. void truncate(offset_t length);
  96. //!Destroys *this and indicates that the calling process is finished using
  97. //!the resource. All mapped regions are still
  98. //!valid after destruction. The destructor function will deallocate
  99. //!any system resources allocated by the system for use by this process for
  100. //!this resource. The resource can still be opened again calling
  101. //!the open constructor overload. To erase the resource from the system
  102. //!use remove().
  103. ~shared_memory_object();
  104. //!Returns the name of the shared memory object.
  105. const char *get_name() const;
  106. //!Returns true if the size of the shared memory object
  107. //!can be obtained and writes the size in the passed reference
  108. bool get_size(offset_t &size) const;
  109. //!Returns access mode
  110. mode_t get_mode() const;
  111. //!Returns mapping handle. Never throws.
  112. mapping_handle_t get_mapping_handle() const;
  113. #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
  114. private:
  115. //!Closes a previously opened file mapping. Never throws.
  116. void priv_close();
  117. //!Opens or creates a shared memory object.
  118. bool priv_open_or_create(ipcdetail::create_enum_t type, const char *filename, mode_t mode, const permissions &perm);
  119. file_handle_t m_handle;
  120. mode_t m_mode;
  121. std::string m_filename;
  122. #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
  123. };
  124. #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
  125. inline shared_memory_object::shared_memory_object()
  126. : m_handle(file_handle_t(ipcdetail::invalid_file()))
  127. , m_mode(read_only)
  128. {}
  129. inline shared_memory_object::~shared_memory_object()
  130. { this->priv_close(); }
  131. inline const char *shared_memory_object::get_name() const
  132. { return m_filename.c_str(); }
  133. inline bool shared_memory_object::get_size(offset_t &size) const
  134. { return ipcdetail::get_file_size((file_handle_t)m_handle, size); }
  135. inline void shared_memory_object::swap(shared_memory_object &other)
  136. {
  137. boost::adl_move_swap(m_handle, other.m_handle);
  138. boost::adl_move_swap(m_mode, other.m_mode);
  139. m_filename.swap(other.m_filename);
  140. }
  141. inline mapping_handle_t shared_memory_object::get_mapping_handle() const
  142. {
  143. return ipcdetail::mapping_handle_from_file_handle(m_handle);
  144. }
  145. inline mode_t shared_memory_object::get_mode() const
  146. { return m_mode; }
  147. #if !defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS)
  148. inline bool shared_memory_object::priv_open_or_create
  149. (ipcdetail::create_enum_t type, const char *filename, mode_t mode, const permissions &perm)
  150. {
  151. m_filename = filename;
  152. std::string shmfile;
  153. ipcdetail::create_shared_dir_cleaning_old_and_get_filepath(filename, shmfile);
  154. //Set accesses
  155. if (mode != read_write && mode != read_only){
  156. error_info err = other_error;
  157. throw interprocess_exception(err);
  158. }
  159. switch(type){
  160. case ipcdetail::DoOpen:
  161. m_handle = ipcdetail::open_existing_file(shmfile.c_str(), mode, true);
  162. break;
  163. case ipcdetail::DoCreate:
  164. m_handle = ipcdetail::create_new_file(shmfile.c_str(), mode, perm, true);
  165. break;
  166. case ipcdetail::DoOpenOrCreate:
  167. m_handle = ipcdetail::create_or_open_file(shmfile.c_str(), mode, perm, true);
  168. break;
  169. default:
  170. {
  171. error_info err = other_error;
  172. throw interprocess_exception(err);
  173. }
  174. }
  175. //Check for error
  176. if(m_handle == ipcdetail::invalid_file()){
  177. error_info err = system_error_code();
  178. this->priv_close();
  179. throw interprocess_exception(err);
  180. }
  181. m_mode = mode;
  182. return true;
  183. }
  184. inline bool shared_memory_object::remove(const char *filename)
  185. {
  186. try{
  187. //Make sure a temporary path is created for shared memory
  188. std::string shmfile;
  189. ipcdetail::shared_filepath(filename, shmfile);
  190. return ipcdetail::delete_file(shmfile.c_str());
  191. }
  192. catch(...){
  193. return false;
  194. }
  195. }
  196. inline void shared_memory_object::truncate(offset_t length)
  197. {
  198. if(!ipcdetail::truncate_file(m_handle, length)){
  199. error_info err = system_error_code();
  200. throw interprocess_exception(err);
  201. }
  202. }
  203. inline void shared_memory_object::priv_close()
  204. {
  205. if(m_handle != ipcdetail::invalid_file()){
  206. ipcdetail::close_file(m_handle);
  207. m_handle = ipcdetail::invalid_file();
  208. }
  209. }
  210. #else //!defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS)
  211. namespace shared_memory_object_detail {
  212. #ifdef BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY
  213. #if defined(__FreeBSD__)
  214. inline bool use_filesystem_based_posix()
  215. {
  216. int jailed = 0;
  217. std::size_t len = sizeof(jailed);
  218. ::sysctlbyname("security.jail.jailed", &jailed, &len, NULL, 0);
  219. return jailed != 0;
  220. }
  221. #else
  222. #error "Not supported platform for BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY"
  223. #endif
  224. #endif
  225. } //shared_memory_object_detail
  226. inline bool shared_memory_object::priv_open_or_create
  227. (ipcdetail::create_enum_t type,
  228. const char *filename,
  229. mode_t mode, const permissions &perm)
  230. {
  231. #if defined(BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SHARED_MEMORY)
  232. const bool add_leading_slash = false;
  233. #elif defined(BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY)
  234. const bool add_leading_slash = !shared_memory_object_detail::use_filesystem_based_posix();
  235. #else
  236. const bool add_leading_slash = true;
  237. #endif
  238. if(add_leading_slash){
  239. ipcdetail::add_leading_slash(filename, m_filename);
  240. }
  241. else{
  242. ipcdetail::create_shared_dir_cleaning_old_and_get_filepath(filename, m_filename);
  243. }
  244. //Create new mapping
  245. int oflag = 0;
  246. if(mode == read_only){
  247. oflag |= O_RDONLY;
  248. }
  249. else if(mode == read_write){
  250. oflag |= O_RDWR;
  251. }
  252. else{
  253. error_info err(mode_error);
  254. throw interprocess_exception(err);
  255. }
  256. int unix_perm = perm.get_permissions();
  257. switch(type){
  258. case ipcdetail::DoOpen:
  259. {
  260. //No oflag addition
  261. m_handle = shm_open(m_filename.c_str(), oflag, unix_perm);
  262. }
  263. break;
  264. case ipcdetail::DoCreate:
  265. {
  266. oflag |= (O_CREAT | O_EXCL);
  267. m_handle = shm_open(m_filename.c_str(), oflag, unix_perm);
  268. if(m_handle >= 0){
  269. ::fchmod(m_handle, unix_perm);
  270. }
  271. }
  272. break;
  273. case ipcdetail::DoOpenOrCreate:
  274. {
  275. //We need a create/open loop to change permissions correctly using fchmod, since
  276. //with "O_CREAT" only we don't know if we've created or opened the shm.
  277. while(1){
  278. //Try to create shared memory
  279. m_handle = shm_open(m_filename.c_str(), oflag | (O_CREAT | O_EXCL), unix_perm);
  280. //If successful change real permissions
  281. if(m_handle >= 0){
  282. ::fchmod(m_handle, unix_perm);
  283. }
  284. //If already exists, try to open
  285. else if(errno == EEXIST){
  286. m_handle = shm_open(m_filename.c_str(), oflag, unix_perm);
  287. //If open fails and errno tells the file does not exist
  288. //(shm was removed between creation and opening tries), just retry
  289. if(m_handle < 0 && errno == ENOENT){
  290. continue;
  291. }
  292. }
  293. //Exit retries
  294. break;
  295. }
  296. }
  297. break;
  298. default:
  299. {
  300. error_info err = other_error;
  301. throw interprocess_exception(err);
  302. }
  303. }
  304. //Check for error
  305. if(m_handle < 0){
  306. error_info err = errno;
  307. this->priv_close();
  308. throw interprocess_exception(err);
  309. }
  310. m_filename = filename;
  311. m_mode = mode;
  312. return true;
  313. }
  314. inline bool shared_memory_object::remove(const char *filename)
  315. {
  316. try{
  317. std::string filepath;
  318. #if defined(BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SHARED_MEMORY)
  319. const bool add_leading_slash = false;
  320. #elif defined(BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY)
  321. const bool add_leading_slash = !shared_memory_object_detail::use_filesystem_based_posix();
  322. #else
  323. const bool add_leading_slash = true;
  324. #endif
  325. if(add_leading_slash){
  326. ipcdetail::add_leading_slash(filename, filepath);
  327. }
  328. else{
  329. ipcdetail::shared_filepath(filename, filepath);
  330. }
  331. return 0 == shm_unlink(filepath.c_str());
  332. }
  333. catch(...){
  334. return false;
  335. }
  336. }
  337. inline void shared_memory_object::truncate(offset_t length)
  338. {
  339. if(0 != ftruncate(m_handle, length)){
  340. error_info err(system_error_code());
  341. throw interprocess_exception(err);
  342. }
  343. }
  344. inline void shared_memory_object::priv_close()
  345. {
  346. if(m_handle != -1){
  347. ::close(m_handle);
  348. m_handle = -1;
  349. }
  350. }
  351. #endif
  352. //!A class that stores the name of a shared memory
  353. //!and calls shared_memory_object::remove(name) in its destructor
  354. //!Useful to remove temporary shared memory objects in the presence
  355. //!of exceptions
  356. class remove_shared_memory_on_destroy
  357. {
  358. const char * m_name;
  359. public:
  360. remove_shared_memory_on_destroy(const char *name)
  361. : m_name(name)
  362. {}
  363. ~remove_shared_memory_on_destroy()
  364. { shared_memory_object::remove(m_name); }
  365. };
  366. #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
  367. } //namespace interprocess {
  368. } //namespace boost {
  369. #include <boost/interprocess/detail/config_end.hpp>
  370. #endif //BOOST_INTERPROCESS_SHARED_MEMORY_OBJECT_HPP