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

http://hadesmem.googlecode.com/ · C++ Header · 456 lines · 370 code · 64 blank · 22 comment · 49 complexity · 2699ace7a9fa65bfdc674b5843cd0ece MD5 · raw file

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