managed_open_or_create_impl.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // (C) Copyright Ion Gaztanaga 2006-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_MANAGED_OPEN_OR_CREATE_IMPL
  11. #define BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_IMPL
  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/os_thread_functions.hpp>
  21. #include <boost/interprocess/detail/os_file_functions.hpp>
  22. #include <boost/interprocess/creation_tags.hpp>
  23. #include <boost/interprocess/mapped_region.hpp>
  24. #include <boost/interprocess/detail/utilities.hpp>
  25. #include <boost/interprocess/detail/type_traits.hpp>
  26. #include <boost/interprocess/detail/atomic.hpp>
  27. #include <boost/interprocess/detail/interprocess_tester.hpp>
  28. #include <boost/interprocess/creation_tags.hpp>
  29. #include <boost/interprocess/detail/mpl.hpp>
  30. #include <boost/interprocess/permissions.hpp>
  31. #include <boost/container/detail/type_traits.hpp> //alignment_of, aligned_storage
  32. #include <boost/interprocess/sync/spin/wait.hpp>
  33. #include <boost/move/move.hpp>
  34. #include <boost/cstdint.hpp>
  35. namespace boost {
  36. namespace interprocess {
  37. #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
  38. namespace ipcdetail{ class interprocess_tester; }
  39. template<class DeviceAbstraction>
  40. struct managed_open_or_create_impl_device_id_t
  41. {
  42. typedef const char *type;
  43. };
  44. #ifdef BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS
  45. class xsi_shared_memory_file_wrapper;
  46. class xsi_key;
  47. template<>
  48. struct managed_open_or_create_impl_device_id_t<xsi_shared_memory_file_wrapper>
  49. {
  50. typedef xsi_key type;
  51. };
  52. #endif //BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS
  53. #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
  54. namespace ipcdetail {
  55. template <bool StoreDevice, class DeviceAbstraction>
  56. class managed_open_or_create_impl_device_holder
  57. {
  58. public:
  59. DeviceAbstraction &get_device()
  60. { static DeviceAbstraction dev; return dev; }
  61. const DeviceAbstraction &get_device() const
  62. { static DeviceAbstraction dev; return dev; }
  63. };
  64. template <class DeviceAbstraction>
  65. class managed_open_or_create_impl_device_holder<true, DeviceAbstraction>
  66. {
  67. public:
  68. DeviceAbstraction &get_device()
  69. { return dev; }
  70. const DeviceAbstraction &get_device() const
  71. { return dev; }
  72. private:
  73. DeviceAbstraction dev;
  74. };
  75. template<class DeviceAbstraction, std::size_t MemAlignment, bool FileBased, bool StoreDevice>
  76. class managed_open_or_create_impl
  77. : public managed_open_or_create_impl_device_holder<StoreDevice, DeviceAbstraction>
  78. {
  79. //Non-copyable
  80. BOOST_MOVABLE_BUT_NOT_COPYABLE(managed_open_or_create_impl)
  81. typedef typename managed_open_or_create_impl_device_id_t<DeviceAbstraction>::type device_id_t;
  82. typedef managed_open_or_create_impl_device_holder<StoreDevice, DeviceAbstraction> DevHolder;
  83. enum
  84. {
  85. UninitializedSegment,
  86. InitializingSegment,
  87. InitializedSegment,
  88. CorruptedSegment
  89. };
  90. public:
  91. static const std::size_t
  92. ManagedOpenOrCreateUserOffset =
  93. ct_rounded_size
  94. < sizeof(boost::uint32_t)
  95. , MemAlignment ? (MemAlignment) :
  96. (::boost::container::dtl::alignment_of
  97. < ::boost::container::dtl::max_align_t >::value)
  98. >::value;
  99. managed_open_or_create_impl()
  100. {}
  101. managed_open_or_create_impl(create_only_t,
  102. const device_id_t & id,
  103. std::size_t size,
  104. mode_t mode,
  105. const void *addr,
  106. const permissions &perm)
  107. {
  108. priv_open_or_create
  109. ( DoCreate
  110. , id
  111. , size
  112. , mode
  113. , addr
  114. , perm
  115. , null_mapped_region_function());
  116. }
  117. managed_open_or_create_impl(open_only_t,
  118. const device_id_t & id,
  119. mode_t mode,
  120. const void *addr)
  121. {
  122. priv_open_or_create
  123. ( DoOpen
  124. , id
  125. , 0
  126. , mode
  127. , addr
  128. , permissions()
  129. , null_mapped_region_function());
  130. }
  131. managed_open_or_create_impl(open_or_create_t,
  132. const device_id_t & id,
  133. std::size_t size,
  134. mode_t mode,
  135. const void *addr,
  136. const permissions &perm)
  137. {
  138. priv_open_or_create
  139. ( DoOpenOrCreate
  140. , id
  141. , size
  142. , mode
  143. , addr
  144. , perm
  145. , null_mapped_region_function());
  146. }
  147. template <class ConstructFunc>
  148. managed_open_or_create_impl(create_only_t,
  149. const device_id_t & id,
  150. std::size_t size,
  151. mode_t mode,
  152. const void *addr,
  153. const ConstructFunc &construct_func,
  154. const permissions &perm)
  155. {
  156. priv_open_or_create
  157. (DoCreate
  158. , id
  159. , size
  160. , mode
  161. , addr
  162. , perm
  163. , construct_func);
  164. }
  165. template <class ConstructFunc>
  166. managed_open_or_create_impl(open_only_t,
  167. const device_id_t & id,
  168. mode_t mode,
  169. const void *addr,
  170. const ConstructFunc &construct_func)
  171. {
  172. priv_open_or_create
  173. ( DoOpen
  174. , id
  175. , 0
  176. , mode
  177. , addr
  178. , permissions()
  179. , construct_func);
  180. }
  181. template <class ConstructFunc>
  182. managed_open_or_create_impl(open_or_create_t,
  183. const device_id_t & id,
  184. std::size_t size,
  185. mode_t mode,
  186. const void *addr,
  187. const ConstructFunc &construct_func,
  188. const permissions &perm)
  189. {
  190. priv_open_or_create
  191. ( DoOpenOrCreate
  192. , id
  193. , size
  194. , mode
  195. , addr
  196. , perm
  197. , construct_func);
  198. }
  199. managed_open_or_create_impl(BOOST_RV_REF(managed_open_or_create_impl) moved)
  200. { this->swap(moved); }
  201. managed_open_or_create_impl &operator=(BOOST_RV_REF(managed_open_or_create_impl) moved)
  202. {
  203. managed_open_or_create_impl tmp(boost::move(moved));
  204. this->swap(tmp);
  205. return *this;
  206. }
  207. ~managed_open_or_create_impl()
  208. {}
  209. std::size_t get_user_size() const
  210. { return m_mapped_region.get_size() - ManagedOpenOrCreateUserOffset; }
  211. void *get_user_address() const
  212. { return static_cast<char*>(m_mapped_region.get_address()) + ManagedOpenOrCreateUserOffset; }
  213. std::size_t get_real_size() const
  214. { return m_mapped_region.get_size(); }
  215. void *get_real_address() const
  216. { return m_mapped_region.get_address(); }
  217. void swap(managed_open_or_create_impl &other)
  218. {
  219. this->m_mapped_region.swap(other.m_mapped_region);
  220. }
  221. bool flush()
  222. { return m_mapped_region.flush(); }
  223. const mapped_region &get_mapped_region() const
  224. { return m_mapped_region; }
  225. DeviceAbstraction &get_device()
  226. { return this->DevHolder::get_device(); }
  227. const DeviceAbstraction &get_device() const
  228. { return this->DevHolder::get_device(); }
  229. private:
  230. //These are templatized to allow explicit instantiations
  231. template<bool dummy>
  232. static void truncate_device(DeviceAbstraction &, offset_t, false_)
  233. {} //Empty
  234. template<bool dummy>
  235. static void truncate_device(DeviceAbstraction &dev, offset_t size, true_)
  236. { dev.truncate(size); }
  237. template<bool dummy>
  238. static bool check_offset_t_size(std::size_t , false_)
  239. { return true; } //Empty
  240. template<bool dummy>
  241. static bool check_offset_t_size(std::size_t size, true_)
  242. { return size == std::size_t(offset_t(size)); }
  243. //These are templatized to allow explicit instantiations
  244. template<bool dummy>
  245. static void create_device(DeviceAbstraction &dev, const device_id_t & id, std::size_t size, const permissions &perm, false_ file_like)
  246. {
  247. (void)file_like;
  248. DeviceAbstraction tmp(create_only, id, read_write, size, perm);
  249. tmp.swap(dev);
  250. }
  251. template<bool dummy>
  252. static void create_device(DeviceAbstraction &dev, const device_id_t & id, std::size_t, const permissions &perm, true_ file_like)
  253. {
  254. (void)file_like;
  255. DeviceAbstraction tmp(create_only, id, read_write, perm);
  256. tmp.swap(dev);
  257. }
  258. template <class ConstructFunc> inline
  259. void priv_open_or_create
  260. (create_enum_t type,
  261. const device_id_t & id,
  262. std::size_t size,
  263. mode_t mode, const void *addr,
  264. const permissions &perm,
  265. ConstructFunc construct_func)
  266. {
  267. typedef bool_<FileBased> file_like_t;
  268. (void)mode;
  269. bool created = false;
  270. bool ronly = false;
  271. bool cow = false;
  272. DeviceAbstraction dev;
  273. if(type != DoOpen){
  274. //Check if the requested size is enough to build the managed metadata
  275. const std::size_t func_min_size = construct_func.get_min_size();
  276. if( (std::size_t(-1) - ManagedOpenOrCreateUserOffset) < func_min_size ||
  277. size < (func_min_size + ManagedOpenOrCreateUserOffset) ){
  278. throw interprocess_exception(error_info(size_error));
  279. }
  280. }
  281. //Check size can be represented by offset_t (used by truncate)
  282. if(type != DoOpen && !check_offset_t_size<FileBased>(size, file_like_t())){
  283. throw interprocess_exception(error_info(size_error));
  284. }
  285. if(type == DoOpen && mode == read_write){
  286. DeviceAbstraction tmp(open_only, id, read_write);
  287. tmp.swap(dev);
  288. created = false;
  289. }
  290. else if(type == DoOpen && mode == read_only){
  291. DeviceAbstraction tmp(open_only, id, read_only);
  292. tmp.swap(dev);
  293. created = false;
  294. ronly = true;
  295. }
  296. else if(type == DoOpen && mode == copy_on_write){
  297. DeviceAbstraction tmp(open_only, id, read_only);
  298. tmp.swap(dev);
  299. created = false;
  300. cow = true;
  301. }
  302. else if(type == DoCreate){
  303. create_device<FileBased>(dev, id, size, perm, file_like_t());
  304. created = true;
  305. }
  306. else if(type == DoOpenOrCreate){
  307. //This loop is very ugly, but brute force is sometimes better
  308. //than diplomacy. If someone knows how to open or create a
  309. //file and know if we have really created it or just open it
  310. //drop me a e-mail!
  311. bool completed = false;
  312. spin_wait swait;
  313. while(!completed){
  314. try{
  315. create_device<FileBased>(dev, id, size, perm, file_like_t());
  316. created = true;
  317. completed = true;
  318. }
  319. catch(interprocess_exception &ex){
  320. if(ex.get_error_code() != already_exists_error){
  321. throw;
  322. }
  323. else{
  324. try{
  325. DeviceAbstraction tmp(open_only, id, read_write);
  326. dev.swap(tmp);
  327. created = false;
  328. completed = true;
  329. }
  330. catch(interprocess_exception &e){
  331. if(e.get_error_code() != not_found_error){
  332. throw;
  333. }
  334. }
  335. catch(...){
  336. throw;
  337. }
  338. }
  339. }
  340. catch(...){
  341. throw;
  342. }
  343. swait.yield();
  344. }
  345. }
  346. if(created){
  347. try{
  348. //If this throws, we are lost
  349. truncate_device<FileBased>(dev, size, file_like_t());
  350. //If the following throws, we will truncate the file to 1
  351. mapped_region region(dev, read_write, 0, 0, addr);
  352. boost::uint32_t *patomic_word = 0; //avoid gcc warning
  353. patomic_word = static_cast<boost::uint32_t*>(region.get_address());
  354. boost::uint32_t previous = atomic_cas32(patomic_word, InitializingSegment, UninitializedSegment);
  355. if(previous == UninitializedSegment){
  356. try{
  357. construct_func( static_cast<char*>(region.get_address()) + ManagedOpenOrCreateUserOffset
  358. , size - ManagedOpenOrCreateUserOffset, true);
  359. //All ok, just move resources to the external mapped region
  360. m_mapped_region.swap(region);
  361. }
  362. catch(...){
  363. atomic_write32(patomic_word, CorruptedSegment);
  364. throw;
  365. }
  366. atomic_write32(patomic_word, InitializedSegment);
  367. }
  368. else if(previous == InitializingSegment || previous == InitializedSegment){
  369. throw interprocess_exception(error_info(already_exists_error));
  370. }
  371. else{
  372. throw interprocess_exception(error_info(corrupted_error));
  373. }
  374. }
  375. catch(...){
  376. try{
  377. truncate_device<FileBased>(dev, 1u, file_like_t());
  378. }
  379. catch(...){
  380. }
  381. throw;
  382. }
  383. }
  384. else{
  385. if(FileBased){
  386. offset_t filesize = 0;
  387. spin_wait swait;
  388. while(filesize == 0){
  389. if(!get_file_size(file_handle_from_mapping_handle(dev.get_mapping_handle()), filesize)){
  390. error_info err = system_error_code();
  391. throw interprocess_exception(err);
  392. }
  393. swait.yield();
  394. }
  395. if(filesize == 1){
  396. throw interprocess_exception(error_info(corrupted_error));
  397. }
  398. }
  399. mapped_region region(dev, ronly ? read_only : (cow ? copy_on_write : read_write), 0, 0, addr);
  400. boost::uint32_t *patomic_word = static_cast<boost::uint32_t*>(region.get_address());
  401. boost::uint32_t value = atomic_read32(patomic_word);
  402. spin_wait swait;
  403. while(value == InitializingSegment || value == UninitializedSegment){
  404. swait.yield();
  405. value = atomic_read32(patomic_word);
  406. }
  407. if(value != InitializedSegment)
  408. throw interprocess_exception(error_info(corrupted_error));
  409. construct_func( static_cast<char*>(region.get_address()) + ManagedOpenOrCreateUserOffset
  410. , region.get_size() - ManagedOpenOrCreateUserOffset
  411. , false);
  412. //All ok, just move resources to the external mapped region
  413. m_mapped_region.swap(region);
  414. }
  415. if(StoreDevice){
  416. this->DevHolder::get_device() = boost::move(dev);
  417. }
  418. }
  419. friend void swap(managed_open_or_create_impl &left, managed_open_or_create_impl &right)
  420. {
  421. left.swap(right);
  422. }
  423. private:
  424. friend class interprocess_tester;
  425. void dont_close_on_destruction()
  426. { interprocess_tester::dont_close_on_destruction(m_mapped_region); }
  427. mapped_region m_mapped_region;
  428. };
  429. } //namespace ipcdetail {
  430. } //namespace interprocess {
  431. } //namespace boost {
  432. #include <boost/interprocess/detail/config_end.hpp>
  433. #endif //#ifndef BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_IMPL