managed_multi_shared_memory.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  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_MANAGED_MULTI_SHARED_MEMORY_HPP
  11. #define BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_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/detail/managed_memory_impl.hpp>
  22. #include <boost/interprocess/creation_tags.hpp>
  23. #include <boost/core/no_exceptions_support.hpp>
  24. #include <boost/interprocess/detail/multi_segment_services.hpp>
  25. #include <boost/interprocess/detail/utilities.hpp>
  26. #include <boost/interprocess/shared_memory_object.hpp>
  27. #include <boost/interprocess/containers/list.hpp>//list
  28. #include <boost/interprocess/mapped_region.hpp> //mapped_region
  29. #include <boost/interprocess/shared_memory_object.hpp>
  30. #include <boost/interprocess/permissions.hpp>
  31. #include <boost/interprocess/detail/managed_open_or_create_impl.hpp> //managed_open_or_create_impl
  32. #include <boost/interprocess/containers/string.hpp>
  33. #include <boost/interprocess/streams/vectorstream.hpp>
  34. #include <boost/intrusive/detail/minimal_pair_header.hpp>
  35. #include <string> //string
  36. #include <new> //bad_alloc
  37. #include <ostream>//std::ends
  38. #include <boost/assert.hpp>
  39. //These includes needed to fulfill default template parameters of
  40. //predeclarations in interprocess_fwd.hpp
  41. #include <boost/interprocess/mem_algo/rbtree_best_fit.hpp>
  42. #include <boost/interprocess/sync/mutex_family.hpp>
  43. //!\file
  44. //!Describes a named shared memory object allocation user class.
  45. namespace boost {
  46. namespace interprocess {
  47. //TODO: We must somehow obtain the permissions of the first segment
  48. //to apply them to subsequent segments
  49. //-Use GetSecurityInfo?
  50. //-Change everything to use only a shared memory object expanded via truncate()?
  51. //!A basic shared memory named object creation class. Initializes the
  52. //!shared memory segment. Inherits all basic functionality from
  53. //!basic_managed_memory_impl<CharType, MemoryAlgorithm, IndexType>
  54. template
  55. <
  56. class CharType,
  57. class MemoryAlgorithm,
  58. template<class IndexConfig> class IndexType
  59. >
  60. class basic_managed_multi_shared_memory
  61. : public ipcdetail::basic_managed_memory_impl
  62. <CharType, MemoryAlgorithm, IndexType>
  63. {
  64. typedef basic_managed_multi_shared_memory
  65. <CharType, MemoryAlgorithm, IndexType> self_t;
  66. typedef ipcdetail::basic_managed_memory_impl
  67. <CharType, MemoryAlgorithm, IndexType> base_t;
  68. typedef typename MemoryAlgorithm::void_pointer void_pointer;
  69. typedef typename ipcdetail::
  70. managed_open_or_create_impl<shared_memory_object, MemoryAlgorithm::Alignment, true, false> managed_impl;
  71. typedef typename void_pointer::segment_group_id segment_group_id;
  72. typedef typename base_t::size_type size_type;
  73. ////////////////////////////////////////////////////////////////////////
  74. //
  75. // Some internal helper structs/functors
  76. //
  77. ////////////////////////////////////////////////////////////////////////
  78. //!This class defines an operator() that creates a shared memory
  79. //!of the requested size. The rest of the parameters are
  80. //!passed in the constructor. The class a template parameter
  81. //!to be used with create_from_file/create_from_istream functions
  82. //!of basic_named_object classes
  83. // class segment_creator
  84. // {
  85. // public:
  86. // segment_creator(shared_memory &shmem,
  87. // const char *mem_name,
  88. // const void *addr)
  89. // : m_shmem(shmem), m_mem_name(mem_name), m_addr(addr){}
  90. //
  91. // void *operator()(size_type size)
  92. // {
  93. // if(!m_shmem.create(m_mem_name, size, m_addr))
  94. // return 0;
  95. // return m_shmem.get_address();
  96. // }
  97. // private:
  98. // shared_memory &m_shmem;
  99. // const char *m_mem_name;
  100. // const void *m_addr;
  101. // };
  102. class group_services
  103. : public multi_segment_services
  104. {
  105. public:
  106. typedef std::pair<void *, size_type> result_type;
  107. typedef basic_managed_multi_shared_memory frontend_t;
  108. typedef typename
  109. basic_managed_multi_shared_memory::void_pointer void_pointer;
  110. typedef typename void_pointer::segment_group_id segment_group_id;
  111. group_services(frontend_t *const frontend)
  112. : mp_frontend(frontend), m_group(0), m_min_segment_size(0){}
  113. virtual std::pair<void *, size_type> create_new_segment(size_type alloc_size)
  114. { (void)alloc_size;
  115. /*
  116. //We should allocate an extra byte so that the
  117. //[base_addr + alloc_size] byte belongs to this segment
  118. alloc_size += 1;
  119. //If requested size is less than minimum, update that
  120. alloc_size = (m_min_segment_size > alloc_size) ?
  121. m_min_segment_size : alloc_size;
  122. if(mp_frontend->priv_new_segment(create_open_func::DoCreate,
  123. alloc_size, 0, permissions())){
  124. typename shmem_list_t::value_type &m_impl = *mp_frontend->m_shmem_list.rbegin();
  125. return result_type(m_impl.get_real_address(), m_impl.get_real_size()-1);
  126. }*/
  127. return result_type(static_cast<void *>(0), 0);
  128. }
  129. virtual bool update_segments ()
  130. { return true; }
  131. virtual ~group_services(){}
  132. void set_group(segment_group_id group)
  133. { m_group = group; }
  134. segment_group_id get_group() const
  135. { return m_group; }
  136. void set_min_segment_size(size_type min_segment_size)
  137. { m_min_segment_size = min_segment_size; }
  138. size_type get_min_segment_size() const
  139. { return m_min_segment_size; }
  140. private:
  141. frontend_t * const mp_frontend;
  142. segment_group_id m_group;
  143. size_type m_min_segment_size;
  144. };
  145. //!Functor to execute atomically when opening or creating a shared memory
  146. //!segment.
  147. struct create_open_func
  148. {
  149. enum type_t { DoCreate, DoOpen, DoOpenOrCreate };
  150. typedef typename
  151. basic_managed_multi_shared_memory::void_pointer void_pointer;
  152. create_open_func(self_t * const frontend,
  153. type_t type, size_type segment_number)
  154. : mp_frontend(frontend), m_type(type), m_segment_number(segment_number){}
  155. bool operator()(void *addr, size_type size, bool created) const
  156. {
  157. if(((m_type == DoOpen) && created) ||
  158. ((m_type == DoCreate) && !created))
  159. return false;
  160. segment_group_id group = mp_frontend->m_group_services.get_group();
  161. bool mapped = false;
  162. bool impl_done = false;
  163. //Associate this newly created segment as the
  164. //segment id = 0 of this group
  165. void_pointer::insert_mapping
  166. ( group
  167. , static_cast<char*>(addr) - managed_impl::ManagedOpenOrCreateUserOffset
  168. , size + managed_impl::ManagedOpenOrCreateUserOffset);
  169. //Check if this is the master segment
  170. if(!m_segment_number){
  171. //Create or open the Interprocess machinery
  172. if((impl_done = created ?
  173. mp_frontend->create_impl(addr, size) : mp_frontend->open_impl(addr, size))){
  174. return true;
  175. }
  176. }
  177. else{
  178. return true;
  179. }
  180. //This is the cleanup part
  181. //---------------
  182. if(impl_done){
  183. mp_frontend->close_impl();
  184. }
  185. if(mapped){
  186. bool ret = void_pointer::erase_last_mapping(group);
  187. BOOST_ASSERT(ret);(void)ret;
  188. }
  189. return false;
  190. }
  191. static std::size_t get_min_size()
  192. {
  193. const size_type sz = self_t::segment_manager::get_min_size();
  194. if(sz > std::size_t(-1)){
  195. //The minimum size is not representable by std::size_t
  196. BOOST_ASSERT(false);
  197. return std::size_t(-1);
  198. }
  199. else{
  200. return static_cast<std::size_t>(sz);
  201. }
  202. }
  203. self_t * const mp_frontend;
  204. type_t m_type;
  205. size_type m_segment_number;
  206. };
  207. //!Functor to execute atomically when closing a shared memory segment.
  208. struct close_func
  209. {
  210. typedef typename
  211. basic_managed_multi_shared_memory::void_pointer void_pointer;
  212. close_func(self_t * const frontend)
  213. : mp_frontend(frontend){}
  214. void operator()(const mapped_region &region, bool last) const
  215. {
  216. if(last) mp_frontend->destroy_impl();
  217. else mp_frontend->close_impl();
  218. }
  219. self_t * const mp_frontend;
  220. };
  221. //Friend declarations
  222. friend struct basic_managed_multi_shared_memory::create_open_func;
  223. friend struct basic_managed_multi_shared_memory::close_func;
  224. friend class basic_managed_multi_shared_memory::group_services;
  225. typedef list<managed_impl> shmem_list_t;
  226. basic_managed_multi_shared_memory *get_this_pointer()
  227. { return this; }
  228. public:
  229. basic_managed_multi_shared_memory(create_only_t,
  230. const char *name,
  231. size_type size,
  232. const permissions &perm = permissions())
  233. : m_group_services(get_this_pointer())
  234. {
  235. priv_open_or_create(create_open_func::DoCreate,name, size, perm);
  236. }
  237. basic_managed_multi_shared_memory(open_or_create_t,
  238. const char *name,
  239. size_type size,
  240. const permissions &perm = permissions())
  241. : m_group_services(get_this_pointer())
  242. {
  243. priv_open_or_create(create_open_func::DoOpenOrCreate, name, size, perm);
  244. }
  245. basic_managed_multi_shared_memory(open_only_t, const char *name)
  246. : m_group_services(get_this_pointer())
  247. {
  248. priv_open_or_create(create_open_func::DoOpen, name, 0, permissions());
  249. }
  250. ~basic_managed_multi_shared_memory()
  251. { this->priv_close(); }
  252. private:
  253. bool priv_open_or_create(typename create_open_func::type_t type,
  254. const char *name,
  255. size_type size,
  256. const permissions &perm)
  257. {
  258. if(!m_shmem_list.empty())
  259. return false;
  260. typename void_pointer::segment_group_id group = 0;
  261. BOOST_TRY{
  262. m_root_name = name;
  263. //Insert multi segment services and get a group identifier
  264. group = void_pointer::new_segment_group(&m_group_services);
  265. size = void_pointer::round_size(size);
  266. m_group_services.set_group(group);
  267. m_group_services.set_min_segment_size(size);
  268. if(group){
  269. if(this->priv_new_segment(type, size, 0, perm)){
  270. return true;
  271. }
  272. }
  273. }
  274. BOOST_CATCH(const std::bad_alloc&){
  275. }
  276. BOOST_CATCH_END
  277. if(group){
  278. void_pointer::delete_group(group);
  279. }
  280. return false;
  281. }
  282. bool priv_new_segment(typename create_open_func::type_t type,
  283. size_type size,
  284. const void *addr,
  285. const permissions &perm)
  286. {
  287. BOOST_TRY{
  288. //Get the number of groups of this multi_segment group
  289. size_type segment_id = m_shmem_list.size();
  290. //Format the name of the shared memory: append segment number.
  291. boost::interprocess::basic_ovectorstream<boost::interprocess::string> formatter;
  292. //Pre-reserve string size
  293. size_type str_size = m_root_name.length()+10;
  294. if(formatter.vector().size() < str_size){
  295. //This can throw.
  296. formatter.reserve(str_size);
  297. }
  298. //Format segment's name
  299. formatter << m_root_name
  300. << static_cast<unsigned int>(segment_id) << std::ends;
  301. //This functor will be executed when constructing
  302. create_open_func func(this, type, segment_id);
  303. const char *name = formatter.vector().c_str();
  304. //This can throw.
  305. managed_impl mshm;
  306. switch(type){
  307. case create_open_func::DoCreate:
  308. {
  309. managed_impl shm(create_only, name, size, read_write, addr, func, perm);
  310. mshm = boost::move(shm);
  311. }
  312. break;
  313. case create_open_func::DoOpen:
  314. {
  315. managed_impl shm(open_only, name,read_write, addr, func);
  316. mshm = boost::move(shm);
  317. }
  318. break;
  319. case create_open_func::DoOpenOrCreate:
  320. {
  321. managed_impl shm(open_or_create, name, size, read_write, addr, func, perm);
  322. mshm = boost::move(shm);
  323. }
  324. break;
  325. default:
  326. return false;
  327. break;
  328. }
  329. //This can throw.
  330. m_shmem_list.push_back(boost::move(mshm));
  331. return true;
  332. }
  333. BOOST_CATCH(const std::bad_alloc&){
  334. }
  335. BOOST_CATCH_END
  336. return false;
  337. }
  338. //!Frees resources. Never throws.
  339. void priv_close()
  340. {
  341. if(!m_shmem_list.empty()){
  342. bool ret;
  343. //Obtain group identifier
  344. segment_group_id group = m_group_services.get_group();
  345. //Erase main segment and its resources
  346. //typename shmem_list_t::iterator itbeg = m_shmem_list.begin(),
  347. // itend = m_shmem_list.end(),
  348. // it = itbeg;
  349. //(*itbeg)->close_with_func(close_func(this));
  350. //Delete group. All mappings are erased too.
  351. ret = void_pointer::delete_group(group);
  352. (void)ret;
  353. BOOST_ASSERT(ret);
  354. m_shmem_list.clear();
  355. }
  356. }
  357. private:
  358. shmem_list_t m_shmem_list;
  359. group_services m_group_services;
  360. std::string m_root_name;
  361. };
  362. typedef basic_managed_multi_shared_memory
  363. < char
  364. , rbtree_best_fit<mutex_family, intersegment_ptr<void> >
  365. , iset_index>
  366. managed_multi_shared_memory;
  367. } //namespace interprocess {
  368. } //namespace boost {
  369. #include <boost/interprocess/detail/config_end.hpp>
  370. #endif //BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_HPP