/Src/Dependencies/Boost/boost/interprocess/detail/xsi_shared_memory_device.hpp

http://hadesmem.googlecode.com/ · C++ Header · 392 lines · 286 code · 63 blank · 43 comment · 46 complexity · 242a4bf50171c00ba94cbe312e992aa6 MD5 · raw file

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // (C) Copyright Ion Gaztanaga 2009-2010. 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_XSI_SHARED_MEMORY_DEVICE_HPP
  11. #define BOOST_INTERPROCESS_XSI_SHARED_MEMORY_DEVICE_HPP
  12. #include <boost/interprocess/detail/config_begin.hpp>
  13. #include <boost/interprocess/detail/workaround.hpp>
  14. #include <boost/detail/workaround.hpp>
  15. #if defined(BOOST_INTERPROCESS_WINDOWS)
  16. #error "This header can't be used in Windows operating systems"
  17. #endif
  18. #include <boost/interprocess/creation_tags.hpp>
  19. #include <boost/interprocess/exceptions.hpp>
  20. #include <boost/interprocess/detail/utilities.hpp>
  21. #include <boost/interprocess/detail/os_file_functions.hpp>
  22. #include <boost/interprocess/detail/tmp_dir_helpers.hpp>
  23. #include <boost/interprocess/interprocess_fwd.hpp>
  24. #include <boost/interprocess/exceptions.hpp>
  25. #include <boost/interprocess/xsi_shared_memory.hpp>
  26. #include <boost/interprocess/sync/xsi/xsi_named_mutex.hpp>
  27. #include <boost/interprocess/mapped_region.hpp>
  28. #include <boost/interprocess/sync/scoped_lock.hpp>
  29. #include <cstddef>
  30. #include <boost/cstdint.hpp>
  31. #include <string>
  32. #include <cstring>
  33. //!\file
  34. //!Describes a class representing a native xsi shared memory.
  35. namespace boost {
  36. namespace interprocess {
  37. class xsi_shared_memory_device
  38. {
  39. /// @cond
  40. BOOST_INTERPROCESS_MOVABLE_BUT_NOT_COPYABLE(xsi_shared_memory_file_wrapper)
  41. /// @endcond
  42. public:
  43. xsi_shared_memory_device();
  44. xsi_shared_memory_device(create_only_t, const char *name, mode_t mode, std::size_t size)
  45. { this->priv_open_or_create_name_only(detail::DoCreate, name, mode, size); }
  46. xsi_shared_memory_device(open_or_create_t, const char *name, mode_t mode, std::size_t size)
  47. { this->priv_open_or_create_name_only(detail::DoOpenOrCreate, name, mode, size); }
  48. xsi_shared_memory_device(open_only_t, const char *name, mode_t mode)
  49. { this->priv_open_or_create_name_only(detail::DoOpen, name, mode, 0); }
  50. xsi_shared_memory_device(create_only_t, const char *filepath, boost::uint8_t id, mode_t mode, std::size_t size)
  51. { this->priv_open_or_create_name_id(detail::DoCreate, name, id, mode, size); }
  52. xsi_shared_memory_device(open_or_create_t, const char *filepath, boost::uint8_t id, mode_t mode, std::size_t size)
  53. { this->priv_open_or_create_name_id(detail::DoOpenOrCreate, id, name, mode, size); }
  54. xsi_shared_memory_device(open_only_t, const char *filepath, boost::uint8_t id, mode_t mode)
  55. { this->priv_open_or_create_name_id(detail::DoOpen, name, id, mode, 0); }
  56. xsi_shared_memory_device(BOOST_INTERPROCESS_RV_REF(xsi_shared_memory_device) moved)
  57. { this->swap(moved); }
  58. xsi_shared_memory_device &operator=(BOOST_INTERPROCESS_RV_REF(xsi_shared_memory_device) moved)
  59. {
  60. xsi_shared_memory_device tmp(boost::interprocess::move(moved));
  61. this->swap(tmp);
  62. return *this;
  63. }
  64. //!Swaps two xsi_shared_memory_device. Does not throw
  65. void swap(xsi_shared_memory_device &other);
  66. //!Destroys *this. The shared memory won't be destroyed, just
  67. //!this connection to it. Use remove() to destroy the shared memory.
  68. ~xsi_shared_memory_device();
  69. //!Returns the name of the
  70. //!shared memory.
  71. const char *get_name() const;
  72. //!Returns the shared memory ID that
  73. //!identifies the shared memory
  74. int get_shmid() const;
  75. //!Returns access
  76. //!permissions
  77. mode_t get_mode() const;
  78. //!Returns the mapping handle.
  79. //!Never throws
  80. mapping_handle_t get_mapping_handle() const;
  81. //!Erases a XSI shared memory object identified by shmname
  82. //!from the system.
  83. //!Returns false on error. Never throws
  84. static bool remove(const char *shmname);
  85. //!Erases the XSI shared memory object identified by shmid
  86. //!from the system.
  87. //!Returns false on error. Never throws
  88. static bool remove(int shmid);
  89. /// @cond
  90. private:
  91. template<int Dummy>
  92. struct info_constants_t
  93. {
  94. static const std::size_t MaxName = 32;
  95. static const std::size_t FirstID = 2;
  96. static const std::size_t LastID = 256;
  97. static const std::size_t NumID = LastID - FirstID;
  98. };
  99. struct info_t
  100. {
  101. struct names_t
  102. {
  103. char buf[info_constants_t<0>::MaxName];
  104. } names[info_constants_t<0>::NumID];
  105. };
  106. static void priv_obtain_index(mapped_region &m, xsi_named_mutex &m, std::string &path);
  107. static bool priv_remove_dead_memory(info_t *info, const char *path);
  108. bool priv_open_or_create_name_only( detail::create_enum_t type
  109. , const char *shmname
  110. , mode_t mode
  111. , std::size_t size);
  112. bool priv_open_or_create_name_id( detail::create_enum_t type
  113. , const char *shmname
  114. , boost::uint8_t id
  115. , mode_t mode
  116. , std::size_t size);
  117. xsi_shared_memory m_shm;
  118. mode_t m_mode;
  119. std::string m_name;
  120. /// @endcond
  121. };
  122. template<int Dummy>
  123. const std::size_t xsi_shared_memory_device::info_constants_t<Dummy>::MaxName;
  124. template<int Dummy>
  125. const std::size_t xsi_shared_memory_device::info_constants_t<Dummy>::FirstID;
  126. template<int Dummy>
  127. const std::size_t xsi_shared_memory_device::info_constants_t<Dummy>::LastID;
  128. template<int Dummy>
  129. const std::size_t xsi_shared_memory_device::info_constants_t<Dummy>::NumID;
  130. /// @cond
  131. inline xsi_shared_memory_device::xsi_shared_memory_device()
  132. : m_shm(), m_mode(invalid_mode), m_name()
  133. {}
  134. inline xsi_shared_memory_device::~xsi_shared_memory_device()
  135. {}
  136. inline const char *xsi_shared_memory_device::get_name() const
  137. { return m_name.c_str(); }
  138. inline void xsi_shared_memory_device::swap(xsi_shared_memory_device &other)
  139. {
  140. m_shm.swap(other.m_shm);
  141. std::swap(m_mode, other.m_mode);
  142. m_name.swap(other.m_name);
  143. }
  144. inline mapping_handle_t xsi_shared_memory_device::get_mapping_handle() const
  145. { return m_shm.get_mapping_handle(); }
  146. inline mode_t xsi_shared_memory_device::get_mode() const
  147. { return m_mode; }
  148. inline int xsi_shared_memory::get_shmid() const
  149. { return m_shm.get_shmid(); }
  150. inline void xsi_shared_memory_device::priv_obtain_index
  151. (mapped_region &reg, xsi_named_mutex &mut, std::string &path)
  152. {
  153. const char *const filename = "xsi_shm_emulation_file";
  154. permissions p;
  155. p.set_unrestricted();
  156. std::string xsi_shm_emulation_file_path;
  157. detail::create_tmp_and_clean_old_and_get_filename(filename, xsi_shm_emulation_file_path);
  158. detail::create_or_open_file(xsi_shm_emulation_file_path.c_str(), read_write, p);
  159. const std::size_t MemSize = sizeof(info_t);
  160. xsi_shared_memory index_shm(open_or_create, xsi_shm_emulation_file_path.c_str(), 1, MemSize, 0666);
  161. mapped_region r(index_shm, read_write, 0, MemSize, 0);
  162. xsi_named_mutex m(open_or_create, xsi_shm_emulation_file_path.c_str(), 2, 0666);
  163. reg = boost::interprocess::move(r);
  164. mut = boost::interprocess::move(m);
  165. path.swap(xsi_shm_emulation_file_path);
  166. }
  167. inline bool xsi_shared_memory_device::priv_remove_dead_memory
  168. (xsi_shared_memory_device::info_t *info, const char *path)
  169. {
  170. bool removed = false;
  171. for(std::size_t i = 0; i != info_constants_t<0>::NumID; ++i){
  172. if(info->names[i].buf[0]){
  173. try{
  174. xsi_shared_memory temp( open_only, path, i+info_constants_t<0>::FirstID, 0600);
  175. }
  176. catch(interprocess_exception &e){
  177. if(e.get_error_code() == not_found_error){
  178. std::memset(info->names[i].buf, 0, info_constants_t<0>::MaxName);
  179. removed = true;
  180. }
  181. }
  182. }
  183. }
  184. return removed;
  185. }
  186. inline bool xsi_shared_memory_device::priv_open_or_create_name_id
  187. (detail::create_enum_t type, const char *filepath, mode_t mode, std::size_t size)
  188. {
  189. //Set accesses
  190. if (mode != read_write && mode != read_only){
  191. error_info err = other_error;
  192. throw interprocess_exception(err);
  193. }
  194. int perm = (mode == read_only) ? (0444) : (0666);
  195. if(type == detail::DoOpen){
  196. if(!found){
  197. error_info err = not_found_error;
  198. throw interprocess_exception(err);
  199. }
  200. xsi_shared_memory temp(open_only, filepath, id, perm);
  201. m_shm = boost::interprocess::move(temp);
  202. }
  203. else if(type == detail::DoCreate){
  204. //Try to reuse slot
  205. xsi_shared_memory temp(create_only, filepath, id, size, perm);
  206. std::strcpy(info->names[target_entry].buf, shmname);
  207. m_shm = boost::interprocess::move(temp);
  208. }
  209. else{ // if(type == detail::DoOpenOrCreate){
  210. xsi_shared_memory temp(open_or_create, filepath, id, size, perm);
  211. m_shm = boost::interprocess::move(temp);
  212. }
  213. m_mode = mode;
  214. m_name.clear();
  215. return true;
  216. }
  217. inline bool xsi_shared_memory_device::priv_open_or_create_name_only
  218. (detail::create_enum_t type, const char *shmname, mode_t mode, std::size_t size)
  219. {
  220. //Set accesses
  221. if (mode != read_write && mode != read_only){
  222. error_info err = other_error;
  223. throw interprocess_exception(err);
  224. }
  225. if (std::strlen(shmname) >= (info_constants_t<0>::MaxName)){
  226. error_info err = other_error;
  227. throw interprocess_exception(err);
  228. }
  229. {
  230. //Obtain index and index lock
  231. mapped_region region;
  232. xsi_named_mutex mut;
  233. std::string xsi_shm_emulation_file_path;
  234. priv_obtain_index(region, mut, xsi_shm_emulation_file_path);
  235. info_t *info = static_cast<info_t *>(region.get_address());
  236. scoped_lock<xsi_named_mutex> lock(mut);
  237. //Find the correct entry or the first empty index
  238. bool found = false;
  239. int target_entry = -1;
  240. int tries = 2;
  241. while(tries--){
  242. for(std::size_t i = 0; i != info_constants_t<0>::NumID; ++i){
  243. if(target_entry < 0 && !info->names[i].buf[0]){
  244. target_entry = static_cast<int>(i);
  245. }
  246. else if(0 == std::strcmp(info->names[i].buf, shmname)){
  247. found = true;
  248. target_entry = static_cast<int>(i);
  249. break;
  250. }
  251. }
  252. if(target_entry < 0){
  253. if(!tries || !priv_remove_dead_memory(info, xsi_shm_emulation_file_path.c_str())){
  254. error_info err = out_of_resource_error;
  255. throw interprocess_exception(err);
  256. }
  257. }
  258. }
  259. //Now handle the result
  260. int perm = (mode == read_only) ? (0444) : (0666);
  261. if(type == detail::DoOpen){
  262. if(!found){
  263. error_info err = not_found_error;
  264. throw interprocess_exception(err);
  265. }
  266. xsi_shared_memory temp( open_only, xsi_shm_emulation_file_path.c_str()
  267. , target_entry+info_constants_t<0>::FirstID, perm);
  268. m_shm = boost::interprocess::move(temp);
  269. }
  270. else{
  271. if(type == detail::DoCreate){
  272. //Try to reuse slot
  273. xsi_shared_memory temp( create_only, xsi_shm_emulation_file_path.c_str()
  274. , target_entry+info_constants_t<0>::FirstID, size, perm);
  275. std::strcpy(info->names[target_entry].buf, shmname);
  276. m_shm = boost::interprocess::move(temp);
  277. }
  278. else{ // if(type == detail::DoOpenOrCreate){
  279. xsi_shared_memory temp( open_or_create, xsi_shm_emulation_file_path.c_str()
  280. , target_entry+info_constants_t<0>::FirstID, size, perm);
  281. if(!found){
  282. std::memset(info->names[target_entry].buf, 0, info_constants_t<0>::MaxName);
  283. std::strcpy(info->names[target_entry].buf, shmname);
  284. }
  285. m_shm = boost::interprocess::move(temp);
  286. }
  287. }
  288. }
  289. m_mode = mode;
  290. m_name = shmname;
  291. return true;
  292. }
  293. inline bool xsi_shared_memory_device::remove(const char *shmname)
  294. {
  295. try{
  296. //Obtain index and index lockss
  297. mapped_region region;
  298. xsi_named_mutex mut;
  299. std::string xsi_shm_emulation_file_path;
  300. priv_obtain_index(region, mut, xsi_shm_emulation_file_path);
  301. scoped_lock<xsi_named_mutex> lock(mut);
  302. info_t *info = static_cast<info_t *>(region.get_address());
  303. //Now check and remove
  304. bool removed = false;
  305. for(std::size_t i = 0; i != info_constants_t<0>::NumID; ++i){
  306. if(0 == std::strcmp(info->names[i].buf, name)){
  307. xsi_shared_memory temp( open_only, xsi_shm_emulation_file_path.c_str()
  308. , i+info_constants_t<0>::FirstID);
  309. if(!xsi_shared_memory::remove(temp.get_shmid()) && (system_error_code() != invalid_argument)){
  310. return false;
  311. }
  312. std::memset(info->names[i].buf, 0, info_constants_t<0>::MaxName);
  313. removed = true;
  314. break;
  315. }
  316. }
  317. return removed;
  318. }
  319. catch(...){
  320. return false;
  321. }
  322. }
  323. inline bool xsi_shared_memory_device::remove(int shmid)
  324. { return xsi_shared_memory::remove(shmid); }
  325. ///@endcond
  326. } //namespace interprocess {
  327. } //namespace boost {
  328. #include <boost/interprocess/detail/config_end.hpp>
  329. #endif //BOOST_INTERPROCESS_XSI_SHARED_MEMORY_DEVICE_HPP