shared_memory_object.hpp 13 KB

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