segment_manager.hpp 51 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359
  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_SEGMENT_MANAGER_HPP
  11. #define BOOST_INTERPROCESS_SEGMENT_MANAGER_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/core/no_exceptions_support.hpp>
  22. #include <boost/interprocess/detail/type_traits.hpp>
  23. #include <boost/interprocess/detail/transform_iterator.hpp>
  24. #include <boost/interprocess/detail/mpl.hpp>
  25. #include <boost/interprocess/detail/nothrow.hpp>
  26. #include <boost/interprocess/detail/segment_manager_helper.hpp>
  27. #include <boost/interprocess/detail/named_proxy.hpp>
  28. #include <boost/interprocess/detail/utilities.hpp>
  29. #include <boost/interprocess/offset_ptr.hpp>
  30. #include <boost/interprocess/indexes/iset_index.hpp>
  31. #include <boost/interprocess/exceptions.hpp>
  32. #include <boost/interprocess/allocators/allocator.hpp>
  33. #include <boost/interprocess/smart_ptr/deleter.hpp>
  34. #include <boost/move/utility_core.hpp>
  35. #include <boost/interprocess/sync/scoped_lock.hpp>
  36. // container/detail
  37. #include <boost/container/detail/minimal_char_traits_header.hpp>
  38. #include <boost/container/detail/placement_new.hpp>
  39. // std
  40. #include <cstddef> //std::size_t
  41. #include <boost/intrusive/detail/minimal_pair_header.hpp>
  42. #include <boost/assert.hpp>
  43. #ifndef BOOST_NO_EXCEPTIONS
  44. #include <exception>
  45. #endif
  46. //!\file
  47. //!Describes the object placed in a memory segment that provides
  48. //!named object allocation capabilities for single-segment and
  49. //!multi-segment allocations.
  50. namespace boost{
  51. namespace interprocess{
  52. //!This object is the public base class of segment manager.
  53. //!This class only depends on the memory allocation algorithm
  54. //!and implements all the allocation features not related
  55. //!to named or unique objects.
  56. //!
  57. //!Storing a reference to segment_manager forces
  58. //!the holder class to be dependent on index types and character types.
  59. //!When such dependence is not desirable and only anonymous and raw
  60. //!allocations are needed, segment_manager_base is the correct answer.
  61. template<class MemoryAlgorithm>
  62. class segment_manager_base
  63. : private MemoryAlgorithm
  64. {
  65. public:
  66. typedef segment_manager_base<MemoryAlgorithm> segment_manager_base_type;
  67. typedef typename MemoryAlgorithm::void_pointer void_pointer;
  68. typedef typename MemoryAlgorithm::mutex_family mutex_family;
  69. typedef MemoryAlgorithm memory_algorithm;
  70. #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
  71. //Experimental. Don't use
  72. typedef typename MemoryAlgorithm::multiallocation_chain multiallocation_chain;
  73. typedef typename MemoryAlgorithm::difference_type difference_type;
  74. typedef typename MemoryAlgorithm::size_type size_type;
  75. #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
  76. //!This constant indicates the payload size
  77. //!associated with each allocation of the memory algorithm
  78. static const size_type PayloadPerAllocation = MemoryAlgorithm::PayloadPerAllocation;
  79. //!Constructor of the segment_manager_base
  80. //!
  81. //!"size" is the size of the memory segment where
  82. //!the basic segment manager is being constructed.
  83. //!
  84. //!"reserved_bytes" is the number of bytes
  85. //!after the end of the memory algorithm object itself
  86. //!that the memory algorithm will exclude from
  87. //!dynamic allocation
  88. //!
  89. //!Can throw
  90. segment_manager_base(size_type sz, size_type reserved_bytes)
  91. : MemoryAlgorithm(sz, reserved_bytes)
  92. {
  93. BOOST_ASSERT((sizeof(segment_manager_base<MemoryAlgorithm>) == sizeof(MemoryAlgorithm)));
  94. }
  95. //!Returns the size of the memory
  96. //!segment
  97. size_type get_size() const
  98. { return MemoryAlgorithm::get_size(); }
  99. //!Returns the number of free bytes of the memory
  100. //!segment
  101. size_type get_free_memory() const
  102. { return MemoryAlgorithm::get_free_memory(); }
  103. //!Obtains the minimum size needed by
  104. //!the segment manager
  105. static size_type get_min_size (size_type size)
  106. { return MemoryAlgorithm::get_min_size(size); }
  107. //!Allocates nbytes bytes. This function is only used in
  108. //!single-segment management. Never throws
  109. void * allocate (size_type nbytes, const std::nothrow_t &)
  110. { return MemoryAlgorithm::allocate(nbytes); }
  111. //!Returns a reference to the internal memory algorithm.
  112. //!This function is useful for custom memory algorithms that
  113. //!need additional configuration options after construction. Never throws.
  114. //!This function should be only used by advanced users.
  115. MemoryAlgorithm &get_memory_algorithm()
  116. { return static_cast<MemoryAlgorithm&>(*this); }
  117. //!Returns a const reference to the internal memory algorithm.
  118. //!This function is useful for custom memory algorithms that
  119. //!need additional configuration options after construction. Never throws.
  120. //!This function should be only used by advanced users.
  121. const MemoryAlgorithm &get_memory_algorithm() const
  122. { return static_cast<const MemoryAlgorithm&>(*this); }
  123. #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
  124. //Experimental. Dont' use.
  125. //!Allocates n_elements of elem_bytes bytes.
  126. //!Throws bad_alloc on failure. chain.size() is not increased on failure.
  127. void allocate_many(size_type elem_bytes, size_type n_elements, multiallocation_chain &chain)
  128. {
  129. size_type prev_size = chain.size();
  130. MemoryAlgorithm::allocate_many(elem_bytes, n_elements, chain);
  131. if(!elem_bytes || chain.size() == prev_size){
  132. throw bad_alloc();
  133. }
  134. }
  135. //!Allocates n_elements, each one of element_lengths[i]*sizeof_element bytes.
  136. //!Throws bad_alloc on failure. chain.size() is not increased on failure.
  137. void allocate_many(const size_type *element_lengths, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain)
  138. {
  139. size_type prev_size = chain.size();
  140. MemoryAlgorithm::allocate_many(element_lengths, n_elements, sizeof_element, chain);
  141. if(!sizeof_element || chain.size() == prev_size){
  142. throw bad_alloc();
  143. }
  144. }
  145. //!Allocates n_elements of elem_bytes bytes.
  146. //!Non-throwing version. chain.size() is not increased on failure.
  147. void allocate_many(const std::nothrow_t &, size_type elem_bytes, size_type n_elements, multiallocation_chain &chain)
  148. { MemoryAlgorithm::allocate_many(elem_bytes, n_elements, chain); }
  149. //!Allocates n_elements, each one of
  150. //!element_lengths[i]*sizeof_element bytes.
  151. //!Non-throwing version. chain.size() is not increased on failure.
  152. void allocate_many(const std::nothrow_t &, const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain)
  153. { MemoryAlgorithm::allocate_many(elem_sizes, n_elements, sizeof_element, chain); }
  154. //!Deallocates all elements contained in chain.
  155. //!Never throws.
  156. void deallocate_many(multiallocation_chain &chain)
  157. { MemoryAlgorithm::deallocate_many(chain); }
  158. #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
  159. //!Allocates nbytes bytes. Throws boost::interprocess::bad_alloc
  160. //!on failure
  161. void * allocate(size_type nbytes)
  162. {
  163. void * ret = MemoryAlgorithm::allocate(nbytes);
  164. if(!ret)
  165. throw bad_alloc();
  166. return ret;
  167. }
  168. //!Allocates nbytes bytes. This function is only used in
  169. //!single-segment management. Never throws
  170. void * allocate_aligned (size_type nbytes, size_type alignment, const std::nothrow_t &)
  171. { return MemoryAlgorithm::allocate_aligned(nbytes, alignment); }
  172. //!Allocates nbytes bytes. This function is only used in
  173. //!single-segment management. Throws bad_alloc when fails
  174. void * allocate_aligned(size_type nbytes, size_type alignment)
  175. {
  176. void * ret = MemoryAlgorithm::allocate_aligned(nbytes, alignment);
  177. if(!ret)
  178. throw bad_alloc();
  179. return ret;
  180. }
  181. #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
  182. template<class T>
  183. T *allocation_command (boost::interprocess::allocation_type command, size_type limit_size,
  184. size_type &prefer_in_recvd_out_size, T *&reuse)
  185. {
  186. T *ret = MemoryAlgorithm::allocation_command
  187. (command | boost::interprocess::nothrow_allocation, limit_size, prefer_in_recvd_out_size, reuse);
  188. if(!(command & boost::interprocess::nothrow_allocation) && !ret)
  189. throw bad_alloc();
  190. return ret;
  191. }
  192. void *raw_allocation_command (boost::interprocess::allocation_type command, size_type limit_objects,
  193. size_type &prefer_in_recvd_out_size, void *&reuse, size_type sizeof_object = 1)
  194. {
  195. void *ret = MemoryAlgorithm::raw_allocation_command
  196. ( command | boost::interprocess::nothrow_allocation, limit_objects,
  197. prefer_in_recvd_out_size, reuse, sizeof_object);
  198. if(!(command & boost::interprocess::nothrow_allocation) && !ret)
  199. throw bad_alloc();
  200. return ret;
  201. }
  202. #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
  203. //!Deallocates the bytes allocated with allocate/allocate_many()
  204. //!pointed by addr
  205. void deallocate (void *addr)
  206. { MemoryAlgorithm::deallocate(addr); }
  207. //!Increases managed memory in extra_size bytes more. This only works
  208. //!with single-segment management.
  209. void grow(size_type extra_size)
  210. { MemoryAlgorithm::grow(extra_size); }
  211. //!Decreases managed memory to the minimum. This only works
  212. //!with single-segment management.
  213. void shrink_to_fit()
  214. { MemoryAlgorithm::shrink_to_fit(); }
  215. //!Returns the result of "all_memory_deallocated()" function
  216. //!of the used memory algorithm
  217. bool all_memory_deallocated()
  218. { return MemoryAlgorithm::all_memory_deallocated(); }
  219. //!Returns the result of "check_sanity()" function
  220. //!of the used memory algorithm
  221. bool check_sanity()
  222. { return MemoryAlgorithm::check_sanity(); }
  223. //!Writes to zero free memory (memory not yet allocated)
  224. //!of the memory algorithm
  225. void zero_free_memory()
  226. { MemoryAlgorithm::zero_free_memory(); }
  227. //!Returns the size of the buffer previously allocated pointed by ptr
  228. size_type size(const void *ptr) const
  229. { return MemoryAlgorithm::size(ptr); }
  230. #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
  231. protected:
  232. void * prot_anonymous_construct
  233. (size_type num, bool dothrow, ipcdetail::in_place_interface &table)
  234. {
  235. typedef ipcdetail::block_header<size_type> block_header_t;
  236. block_header_t block_info ( size_type(table.size*num)
  237. , size_type(table.alignment)
  238. , anonymous_type
  239. , 1
  240. , 0);
  241. //Allocate memory
  242. void *ptr_struct = this->allocate(block_info.total_size(), nothrow<>::get());
  243. //Check if there is enough memory
  244. if(!ptr_struct){
  245. if(dothrow){
  246. throw bad_alloc();
  247. }
  248. else{
  249. return 0;
  250. }
  251. }
  252. //Build scoped ptr to avoid leaks with constructor exception
  253. ipcdetail::mem_algo_deallocator<MemoryAlgorithm> mem(ptr_struct, *this);
  254. //Now construct the header
  255. block_header_t * hdr = ::new(ptr_struct, boost_container_new_t()) block_header_t(block_info);
  256. void *ptr = 0; //avoid gcc warning
  257. ptr = hdr->value();
  258. //Now call constructors
  259. ipcdetail::array_construct(ptr, num, table);
  260. //All constructors successful, we don't want erase memory
  261. mem.release();
  262. return ptr;
  263. }
  264. //!Calls the destructor and makes an anonymous deallocate
  265. void prot_anonymous_destroy(const void *object, ipcdetail::in_place_interface &table)
  266. {
  267. //Get control data from associated with this object
  268. typedef ipcdetail::block_header<size_type> block_header_t;
  269. block_header_t *ctrl_data = block_header_t::block_header_from_value(object, table.size, table.alignment);
  270. //-------------------------------
  271. //scoped_lock<rmutex> guard(m_header);
  272. //-------------------------------
  273. if(ctrl_data->alloc_type() != anonymous_type){
  274. //This is not an anonymous object, the pointer is wrong!
  275. BOOST_ASSERT(0);
  276. }
  277. //Call destructors and free memory
  278. //Build scoped ptr to avoid leaks with destructor exception
  279. std::size_t destroyed = 0;
  280. table.destroy_n(const_cast<void*>(object), ctrl_data->m_value_bytes/table.size, destroyed);
  281. this->deallocate(ctrl_data);
  282. }
  283. #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
  284. };
  285. //!This object is placed in the beginning of memory segment and
  286. //!implements the allocation (named or anonymous) of portions
  287. //!of the segment. This object contains two indexes that
  288. //!maintain an association between a name and a portion of the segment.
  289. //!
  290. //!The first index contains the mappings for normal named objects using the
  291. //!char type specified in the template parameter.
  292. //!
  293. //!The second index contains the association for unique instances. The key will
  294. //!be the const char * returned from type_info.name() function for the unique
  295. //!type to be constructed.
  296. //!
  297. //!segment_manager<CharType, MemoryAlgorithm, IndexType> inherits publicly
  298. //!from segment_manager_base<MemoryAlgorithm> and inherits from it
  299. //!many public functions related to anonymous object and raw memory allocation.
  300. //!See segment_manager_base reference to know about those functions.
  301. template<class CharType
  302. ,class MemoryAlgorithm
  303. ,template<class IndexConfig> class IndexType>
  304. class segment_manager
  305. : public segment_manager_base<MemoryAlgorithm>
  306. {
  307. #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
  308. //Non-copyable
  309. segment_manager();
  310. segment_manager(const segment_manager &);
  311. segment_manager &operator=(const segment_manager &);
  312. typedef segment_manager_base<MemoryAlgorithm> segment_manager_base_t;
  313. #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
  314. public:
  315. typedef MemoryAlgorithm memory_algorithm;
  316. typedef typename segment_manager_base_t::void_pointer void_pointer;
  317. typedef typename segment_manager_base_t::size_type size_type;
  318. typedef typename segment_manager_base_t::difference_type difference_type;
  319. typedef CharType char_type;
  320. typedef segment_manager_base<MemoryAlgorithm> segment_manager_base_type;
  321. static const size_type PayloadPerAllocation = segment_manager_base_t::PayloadPerAllocation;
  322. #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
  323. private:
  324. typedef ipcdetail::block_header<size_type> block_header_t;
  325. typedef ipcdetail::index_config<CharType, MemoryAlgorithm> index_config_named;
  326. typedef ipcdetail::index_config<char, MemoryAlgorithm> index_config_unique;
  327. typedef IndexType<index_config_named> index_type;
  328. typedef ipcdetail::bool_<is_intrusive_index<index_type>::value > is_intrusive_t;
  329. typedef ipcdetail::bool_<is_node_index<index_type>::value> is_node_index_t;
  330. public:
  331. typedef IndexType<index_config_named> named_index_t;
  332. typedef IndexType<index_config_unique> unique_index_t;
  333. typedef ipcdetail::char_ptr_holder<CharType> char_ptr_holder_t;
  334. typedef ipcdetail::segment_manager_iterator_transform
  335. <typename named_index_t::const_iterator
  336. ,is_intrusive_index<index_type>::value> named_transform;
  337. typedef ipcdetail::segment_manager_iterator_transform
  338. <typename unique_index_t::const_iterator
  339. ,is_intrusive_index<index_type>::value> unique_transform;
  340. #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
  341. typedef typename segment_manager_base_t::mutex_family mutex_family;
  342. typedef transform_iterator
  343. <typename named_index_t::const_iterator, named_transform> const_named_iterator;
  344. typedef transform_iterator
  345. <typename unique_index_t::const_iterator, unique_transform> const_unique_iterator;
  346. #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
  347. //!Constructor proxy object definition helper class
  348. template<class T>
  349. struct construct_proxy
  350. {
  351. typedef ipcdetail::named_proxy<segment_manager, T, false> type;
  352. };
  353. //!Constructor proxy object definition helper class
  354. template<class T>
  355. struct construct_iter_proxy
  356. {
  357. typedef ipcdetail::named_proxy<segment_manager, T, true> type;
  358. };
  359. #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
  360. //!Constructor of the segment manager
  361. //!"size" is the size of the memory segment where
  362. //!the segment manager is being constructed.
  363. //!Can throw
  364. explicit segment_manager(size_type segment_size)
  365. : segment_manager_base_t(segment_size, priv_get_reserved_bytes())
  366. , m_header(static_cast<segment_manager_base_t*>(get_this_pointer()))
  367. {
  368. (void) anonymous_instance; (void) unique_instance;
  369. //Check EBO is applied, it's required
  370. const void * const this_addr = this;
  371. const void *const segm_addr = static_cast<segment_manager_base_t*>(this);
  372. (void)this_addr; (void)segm_addr;
  373. BOOST_ASSERT( this_addr == segm_addr);
  374. const std::size_t void_ptr_alignment = boost::move_detail::alignment_of<void_pointer>::value; (void)void_ptr_alignment;
  375. BOOST_ASSERT((0 == (std::size_t)this_addr % boost::move_detail::alignment_of<segment_manager>::value));
  376. }
  377. //!Tries to find a previous named/unique allocation. Returns the address
  378. //!and the object count. On failure the first member of the
  379. //!returned pair is 0.
  380. template <class T>
  381. std::pair<T*, size_type> find (char_ptr_holder_t name)
  382. { return this->priv_find_impl<T>(name, true); }
  383. //!Tries to find a previous named/unique allocation. Returns the address
  384. //!and the object count. On failure the first member of the
  385. //!returned pair is 0. This search is not mutex-protected!
  386. //!Use it only inside atomic_func() calls, where the internal mutex
  387. //!is guaranteed to be locked.
  388. template <class T>
  389. std::pair<T*, size_type> find_no_lock (char_ptr_holder_t name)
  390. { return this->priv_find_impl<T>(name, false); }
  391. //!Returns throwing "construct" proxy
  392. //!object
  393. template <class T>
  394. typename construct_proxy<T>::type
  395. construct(char_ptr_holder_t name)
  396. { return typename construct_proxy<T>::type (this, name, false, true); }
  397. //!Returns throwing "search or construct" proxy
  398. //!object
  399. template <class T>
  400. typename construct_proxy<T>::type find_or_construct(char_ptr_holder_t name)
  401. { return typename construct_proxy<T>::type (this, name, true, true); }
  402. //!Returns no throwing "construct" proxy
  403. //!object
  404. template <class T>
  405. typename construct_proxy<T>::type
  406. construct(char_ptr_holder_t name, const std::nothrow_t &)
  407. { return typename construct_proxy<T>::type (this, name, false, false); }
  408. //!Returns no throwing "search or construct"
  409. //!proxy object
  410. template <class T>
  411. typename construct_proxy<T>::type
  412. find_or_construct(char_ptr_holder_t name, const std::nothrow_t &)
  413. { return typename construct_proxy<T>::type (this, name, true, false); }
  414. //!Returns throwing "construct from iterators" proxy object
  415. template <class T>
  416. typename construct_iter_proxy<T>::type
  417. construct_it(char_ptr_holder_t name)
  418. { return typename construct_iter_proxy<T>::type (this, name, false, true); }
  419. //!Returns throwing "search or construct from iterators"
  420. //!proxy object
  421. template <class T>
  422. typename construct_iter_proxy<T>::type
  423. find_or_construct_it(char_ptr_holder_t name)
  424. { return typename construct_iter_proxy<T>::type (this, name, true, true); }
  425. //!Returns no throwing "construct from iterators"
  426. //!proxy object
  427. template <class T>
  428. typename construct_iter_proxy<T>::type
  429. construct_it(char_ptr_holder_t name, const std::nothrow_t &)
  430. { return typename construct_iter_proxy<T>::type (this, name, false, false); }
  431. //!Returns no throwing "search or construct from iterators"
  432. //!proxy object
  433. template <class T>
  434. typename construct_iter_proxy<T>::type
  435. find_or_construct_it(char_ptr_holder_t name, const std::nothrow_t &)
  436. { return typename construct_iter_proxy<T>::type (this, name, true, false); }
  437. //!Calls object function blocking recursive interprocess_mutex and guarantees that
  438. //!no new named_alloc or destroy will be executed by any process while
  439. //!executing the object function call
  440. template <class Func>
  441. void atomic_func(Func &f)
  442. { scoped_lock<rmutex> guard(m_header); f(); }
  443. //!Tries to calls a functor guaranteeing that no new construction, search or
  444. //!destruction will be executed by any process while executing the object
  445. //!function call. If the atomic function can't be immediatelly executed
  446. //!because the internal mutex is already locked, returns false.
  447. //!If the functor throws, this function throws.
  448. template <class Func>
  449. bool try_atomic_func(Func &f)
  450. {
  451. scoped_lock<rmutex> guard(m_header, try_to_lock);
  452. if(guard){
  453. f();
  454. return true;
  455. }
  456. else{
  457. return false;
  458. }
  459. }
  460. //!Destroys a previously created named/unique instance.
  461. //!Returns false if the object was not present.
  462. template <class T>
  463. bool destroy(char_ptr_holder_t name)
  464. {
  465. BOOST_ASSERT(!name.is_anonymous());
  466. ipcdetail::placement_destroy<T> dtor;
  467. if(name.is_unique()){
  468. return this->priv_generic_named_destroy<char>
  469. ( typeid(T).name(), m_header.m_unique_index , dtor, is_intrusive_t());
  470. }
  471. else{
  472. return this->priv_generic_named_destroy<CharType>
  473. ( name.get(), m_header.m_named_index, dtor, is_intrusive_t());
  474. }
  475. }
  476. //!Destroys an anonymous, unique or named object
  477. //!using its address
  478. template <class T>
  479. void destroy_ptr(const T *p)
  480. {
  481. //If T is void transform it to char
  482. typedef typename ipcdetail::char_if_void<T>::type data_t;
  483. ipcdetail::placement_destroy<data_t> dtor;
  484. priv_destroy_ptr(p, dtor);
  485. }
  486. //!Returns the name of an object created with construct/find_or_construct
  487. //!functions. Does not throw
  488. template<class T>
  489. static const CharType *get_instance_name(const T *ptr)
  490. { return priv_get_instance_name(block_header_t::block_header_from_value(ptr)); }
  491. //!Returns the length of an object created with construct/find_or_construct
  492. //!functions. Does not throw.
  493. template<class T>
  494. static size_type get_instance_length(const T *ptr)
  495. { return priv_get_instance_length(block_header_t::block_header_from_value(ptr), sizeof(T)); }
  496. //!Returns is the the name of an object created with construct/find_or_construct
  497. //!functions. Does not throw
  498. template<class T>
  499. static instance_type get_instance_type(const T *ptr)
  500. { return priv_get_instance_type(block_header_t::block_header_from_value(ptr)); }
  501. //!Preallocates needed index resources to optimize the
  502. //!creation of "num" named objects in the managed memory segment.
  503. //!Can throw boost::interprocess::bad_alloc if there is no enough memory.
  504. void reserve_named_objects(size_type num)
  505. {
  506. //-------------------------------
  507. scoped_lock<rmutex> guard(m_header);
  508. //-------------------------------
  509. m_header.m_named_index.reserve(num);
  510. }
  511. //!Preallocates needed index resources to optimize the
  512. //!creation of "num" unique objects in the managed memory segment.
  513. //!Can throw boost::interprocess::bad_alloc if there is no enough memory.
  514. void reserve_unique_objects(size_type num)
  515. {
  516. //-------------------------------
  517. scoped_lock<rmutex> guard(m_header);
  518. //-------------------------------
  519. m_header.m_unique_index.reserve(num);
  520. }
  521. //!Calls shrink_to_fit in both named and unique object indexes
  522. //!to try to free unused memory from those indexes.
  523. void shrink_to_fit_indexes()
  524. {
  525. //-------------------------------
  526. scoped_lock<rmutex> guard(m_header);
  527. //-------------------------------
  528. m_header.m_named_index.shrink_to_fit();
  529. m_header.m_unique_index.shrink_to_fit();
  530. }
  531. //!Returns the number of named objects stored in
  532. //!the segment.
  533. size_type get_num_named_objects()
  534. {
  535. //-------------------------------
  536. scoped_lock<rmutex> guard(m_header);
  537. //-------------------------------
  538. return m_header.m_named_index.size();
  539. }
  540. //!Returns the number of unique objects stored in
  541. //!the segment.
  542. size_type get_num_unique_objects()
  543. {
  544. //-------------------------------
  545. scoped_lock<rmutex> guard(m_header);
  546. //-------------------------------
  547. return m_header.m_unique_index.size();
  548. }
  549. //!Obtains the minimum size needed by the
  550. //!segment manager
  551. static size_type get_min_size()
  552. { return segment_manager_base_t::get_min_size(priv_get_reserved_bytes()); }
  553. //!Returns a constant iterator to the beginning of the information about
  554. //!the named allocations performed in this segment manager
  555. const_named_iterator named_begin() const
  556. {
  557. return (make_transform_iterator)
  558. (m_header.m_named_index.begin(), named_transform());
  559. }
  560. //!Returns a constant iterator to the end of the information about
  561. //!the named allocations performed in this segment manager
  562. const_named_iterator named_end() const
  563. {
  564. return (make_transform_iterator)
  565. (m_header.m_named_index.end(), named_transform());
  566. }
  567. //!Returns a constant iterator to the beginning of the information about
  568. //!the unique allocations performed in this segment manager
  569. const_unique_iterator unique_begin() const
  570. {
  571. return (make_transform_iterator)
  572. (m_header.m_unique_index.begin(), unique_transform());
  573. }
  574. //!Returns a constant iterator to the end of the information about
  575. //!the unique allocations performed in this segment manager
  576. const_unique_iterator unique_end() const
  577. {
  578. return (make_transform_iterator)
  579. (m_header.m_unique_index.end(), unique_transform());
  580. }
  581. //!This is the default allocator to allocate types T
  582. //!from this managed segment
  583. template<class T>
  584. struct allocator
  585. {
  586. typedef boost::interprocess::allocator<T, segment_manager> type;
  587. };
  588. //!Returns an instance of the default allocator for type T
  589. //!initialized that allocates memory from this segment manager.
  590. template<class T>
  591. typename allocator<T>::type
  592. get_allocator()
  593. { return typename allocator<T>::type(this); }
  594. //!This is the default deleter to delete types T
  595. //!from this managed segment.
  596. template<class T>
  597. struct deleter
  598. {
  599. typedef boost::interprocess::deleter<T, segment_manager> type;
  600. };
  601. //!Returns an instance of the default deleter for type T
  602. //!that will delete an object constructed in this segment manager.
  603. template<class T>
  604. typename deleter<T>::type
  605. get_deleter()
  606. { return typename deleter<T>::type(this); }
  607. #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
  608. //!Generic named/anonymous new function. Offers all the possibilities,
  609. //!such as throwing, search before creating, and the constructor is
  610. //!encapsulated in an object function.
  611. template<class T>
  612. T *generic_construct(const CharType *name,
  613. size_type num,
  614. bool try2find,
  615. bool dothrow,
  616. ipcdetail::in_place_interface &table)
  617. {
  618. return static_cast<T*>
  619. (priv_generic_construct(name, num, try2find, dothrow, table));
  620. }
  621. private:
  622. //!Tries to find a previous named allocation. Returns the address
  623. //!and the object count. On failure the first member of the
  624. //!returned pair is 0.
  625. template <class T>
  626. std::pair<T*, size_type> priv_find_impl (const CharType* name, bool lock)
  627. {
  628. //The name can't be null, no anonymous object can be found by name
  629. BOOST_ASSERT(name != 0);
  630. ipcdetail::placement_destroy<T> table;
  631. size_type sz;
  632. void *ret;
  633. if(name == reinterpret_cast<const CharType*>(-1)){
  634. ret = priv_generic_find<char> (typeid(T).name(), m_header.m_unique_index, table, sz, is_intrusive_t(), lock);
  635. }
  636. else{
  637. ret = priv_generic_find<CharType> (name, m_header.m_named_index, table, sz, is_intrusive_t(), lock);
  638. }
  639. return std::pair<T*, size_type>(static_cast<T*>(ret), sz);
  640. }
  641. //!Tries to find a previous unique allocation. Returns the address
  642. //!and the object count. On failure the first member of the
  643. //!returned pair is 0.
  644. template <class T>
  645. std::pair<T*, size_type> priv_find_impl (const ipcdetail::unique_instance_t* name, bool lock)
  646. {
  647. ipcdetail::placement_destroy<T> table;
  648. size_type size;
  649. void *ret = priv_generic_find<char>(name, m_header.m_unique_index, table, size, is_intrusive_t(), lock);
  650. return std::pair<T*, size_type>(static_cast<T*>(ret), size);
  651. }
  652. void *priv_generic_construct
  653. (const CharType *name, size_type num, bool try2find, bool dothrow, ipcdetail::in_place_interface &table)
  654. {
  655. void *ret;
  656. //Security overflow check
  657. if(num > ((std::size_t)-1)/table.size){
  658. if(dothrow)
  659. throw bad_alloc();
  660. else
  661. return 0;
  662. }
  663. if(name == 0){
  664. ret = this->prot_anonymous_construct(num, dothrow, table);
  665. }
  666. else if(name == reinterpret_cast<const CharType*>(-1)){
  667. ret = this->priv_generic_named_construct<char>
  668. (unique_type, table.type_name, num, try2find, dothrow, table, m_header.m_unique_index, is_intrusive_t());
  669. }
  670. else{
  671. ret = this->priv_generic_named_construct<CharType>
  672. (named_type, name, num, try2find, dothrow, table, m_header.m_named_index, is_intrusive_t());
  673. }
  674. return ret;
  675. }
  676. void priv_destroy_ptr(const void *ptr, ipcdetail::in_place_interface &dtor)
  677. {
  678. block_header_t *ctrl_data = block_header_t::block_header_from_value(ptr, dtor.size, dtor.alignment);
  679. switch(ctrl_data->alloc_type()){
  680. case anonymous_type:
  681. this->prot_anonymous_destroy(ptr, dtor);
  682. break;
  683. case named_type:
  684. this->priv_generic_named_destroy<CharType>
  685. (ctrl_data, m_header.m_named_index, dtor, is_node_index_t());
  686. break;
  687. case unique_type:
  688. this->priv_generic_named_destroy<char>
  689. (ctrl_data, m_header.m_unique_index, dtor, is_node_index_t());
  690. break;
  691. default:
  692. //This type is unknown, bad pointer passed to this function!
  693. BOOST_ASSERT(0);
  694. break;
  695. }
  696. }
  697. //!Returns the name of an object created with construct/find_or_construct
  698. //!functions. Does not throw
  699. static const CharType *priv_get_instance_name(block_header_t *ctrl_data)
  700. {
  701. boost::interprocess::allocation_type type = ctrl_data->alloc_type();
  702. if(type == anonymous_type){
  703. BOOST_ASSERT((type == anonymous_type && ctrl_data->m_num_char == 0) ||
  704. (type == unique_type && ctrl_data->m_num_char != 0) );
  705. return 0;
  706. }
  707. CharType *name = static_cast<CharType*>(ctrl_data->template name<CharType>());
  708. //Sanity checks
  709. BOOST_ASSERT(ctrl_data->sizeof_char() == sizeof(CharType));
  710. BOOST_ASSERT(ctrl_data->m_num_char == std::char_traits<CharType>::length(name));
  711. return name;
  712. }
  713. static size_type priv_get_instance_length(block_header_t *ctrl_data, size_type sizeofvalue)
  714. {
  715. //Get header
  716. BOOST_ASSERT((ctrl_data->value_bytes() %sizeofvalue) == 0);
  717. return ctrl_data->value_bytes()/sizeofvalue;
  718. }
  719. //!Returns is the the name of an object created with construct/find_or_construct
  720. //!functions. Does not throw
  721. static instance_type priv_get_instance_type(block_header_t *ctrl_data)
  722. {
  723. //Get header
  724. BOOST_ASSERT((instance_type)ctrl_data->alloc_type() < max_allocation_type);
  725. return (instance_type)ctrl_data->alloc_type();
  726. }
  727. static size_type priv_get_reserved_bytes()
  728. {
  729. //Get the number of bytes until the end of (*this)
  730. //beginning in the end of the segment_manager_base_t base.
  731. return sizeof(segment_manager) - sizeof(segment_manager_base_t);
  732. }
  733. template <class CharT>
  734. void *priv_generic_find
  735. (const CharT* name,
  736. IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
  737. ipcdetail::in_place_interface &table,
  738. size_type &length, ipcdetail::true_ is_intrusive, bool use_lock)
  739. {
  740. (void)is_intrusive;
  741. typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type_t;
  742. typedef typename index_type_t::iterator index_it;
  743. //-------------------------------
  744. scoped_lock<rmutex> guard(priv_get_lock(use_lock));
  745. //-------------------------------
  746. //Find name in index
  747. ipcdetail::intrusive_compare_key<CharT> key
  748. (name, std::char_traits<CharT>::length(name));
  749. index_it it = index.find(key);
  750. //Initialize return values
  751. void *ret_ptr = 0;
  752. length = 0;
  753. //If found, assign values
  754. if(it != index.end()){
  755. //Get header
  756. block_header_t *ctrl_data = it->get_block_header();
  757. //Sanity check
  758. BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0);
  759. BOOST_ASSERT(ctrl_data->sizeof_char() == sizeof(CharT));
  760. ret_ptr = ctrl_data->value();
  761. length = ctrl_data->m_value_bytes/table.size;
  762. }
  763. return ret_ptr;
  764. }
  765. template <class CharT>
  766. void *priv_generic_find
  767. (const CharT* name,
  768. IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
  769. ipcdetail::in_place_interface &table,
  770. size_type &length, ipcdetail::false_ is_intrusive, bool use_lock)
  771. {
  772. (void)is_intrusive;
  773. typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type;
  774. typedef typename index_type::key_type key_type;
  775. typedef typename index_type::iterator index_it;
  776. //-------------------------------
  777. scoped_lock<rmutex> guard(priv_get_lock(use_lock));
  778. //-------------------------------
  779. //Find name in index
  780. index_it it = index.find(key_type(name, std::char_traits<CharT>::length(name)));
  781. //Initialize return values
  782. void *ret_ptr = 0;
  783. length = 0;
  784. //If found, assign values
  785. if(it != index.end()){
  786. //Get header
  787. block_header_t *ctrl_data = reinterpret_cast<block_header_t*>
  788. (ipcdetail::to_raw_pointer(it->second.m_ptr));
  789. //Sanity check
  790. BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0);
  791. BOOST_ASSERT(ctrl_data->sizeof_char() == sizeof(CharT));
  792. ret_ptr = ctrl_data->value();
  793. length = ctrl_data->m_value_bytes/table.size;
  794. }
  795. return ret_ptr;
  796. }
  797. template <class CharT>
  798. bool priv_generic_named_destroy
  799. (block_header_t *block_header,
  800. IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
  801. ipcdetail::in_place_interface &table, ipcdetail::true_ is_node_index)
  802. {
  803. (void)is_node_index;
  804. typedef typename IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> >::iterator index_it;
  805. index_it *ihdr = block_header_t::template to_first_header<index_it>(block_header);
  806. return this->priv_generic_named_destroy_impl<CharT>(*ihdr, index, table);
  807. }
  808. template <class CharT>
  809. bool priv_generic_named_destroy
  810. (block_header_t *block_header,
  811. IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
  812. ipcdetail::in_place_interface &table,
  813. ipcdetail::false_ is_node_index)
  814. {
  815. (void)is_node_index;
  816. CharT *name = static_cast<CharT*>(block_header->template name<CharT>());
  817. return this->priv_generic_named_destroy<CharT>(name, index, table, is_intrusive_t());
  818. }
  819. template <class CharT>
  820. bool priv_generic_named_destroy(const CharT *name,
  821. IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
  822. ipcdetail::in_place_interface &table, ipcdetail::true_ is_intrusive_index)
  823. {
  824. (void)is_intrusive_index;
  825. typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type_t;
  826. typedef typename index_type_t::iterator index_it;
  827. typedef typename index_type_t::value_type intrusive_value_type;
  828. //-------------------------------
  829. scoped_lock<rmutex> guard(m_header);
  830. //-------------------------------
  831. //Find name in index
  832. ipcdetail::intrusive_compare_key<CharT> key
  833. (name, std::char_traits<CharT>::length(name));
  834. index_it it = index.find(key);
  835. //If not found, return false
  836. if(it == index.end()){
  837. //This name is not present in the index, wrong pointer or name!
  838. //BOOST_ASSERT(0);
  839. return false;
  840. }
  841. block_header_t *ctrl_data = it->get_block_header();
  842. intrusive_value_type *iv = intrusive_value_type::get_intrusive_value_type(ctrl_data);
  843. void *memory = iv;
  844. void *values = ctrl_data->value();
  845. std::size_t num = ctrl_data->m_value_bytes/table.size;
  846. //Sanity check
  847. BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0);
  848. BOOST_ASSERT(sizeof(CharT) == ctrl_data->sizeof_char());
  849. //Erase node from index
  850. index.erase(it);
  851. //Destroy the headers
  852. ctrl_data->~block_header_t();
  853. iv->~intrusive_value_type();
  854. //Call destructors and free memory
  855. std::size_t destroyed;
  856. table.destroy_n(values, num, destroyed);
  857. this->deallocate(memory);
  858. return true;
  859. }
  860. template <class CharT>
  861. bool priv_generic_named_destroy(const CharT *name,
  862. IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
  863. ipcdetail::in_place_interface &table,
  864. ipcdetail::false_ is_intrusive_index)
  865. {
  866. (void)is_intrusive_index;
  867. typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type;
  868. typedef typename index_type::iterator index_it;
  869. typedef typename index_type::key_type key_type;
  870. //-------------------------------
  871. scoped_lock<rmutex> guard(m_header);
  872. //-------------------------------
  873. //Try to find the name in the index
  874. index_it it = index.find(key_type (name,
  875. std::char_traits<CharT>::length(name)));
  876. //If not found, return false
  877. if(it == index.end()){
  878. //This name is not present in the index, wrong pointer or name!
  879. //BOOST_ASSERT(0);
  880. return false;
  881. }
  882. return this->priv_generic_named_destroy_impl<CharT>(it, index, table);
  883. }
  884. template <class CharT>
  885. bool priv_generic_named_destroy_impl
  886. (const typename IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> >::iterator &it,
  887. IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
  888. ipcdetail::in_place_interface &table)
  889. {
  890. typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type;
  891. typedef typename index_type::iterator index_it;
  892. //Get allocation parameters
  893. block_header_t *ctrl_data = reinterpret_cast<block_header_t*>
  894. (ipcdetail::to_raw_pointer(it->second.m_ptr));
  895. char *stored_name = static_cast<char*>(static_cast<void*>(const_cast<CharT*>(it->first.name())));
  896. (void)stored_name;
  897. //Check if the distance between the name pointer and the memory pointer
  898. //is correct (this can detect incorrect type in destruction)
  899. std::size_t num = ctrl_data->m_value_bytes/table.size;
  900. void *values = ctrl_data->value();
  901. //Sanity check
  902. BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0);
  903. BOOST_ASSERT(static_cast<void*>(stored_name) == static_cast<void*>(ctrl_data->template name<CharT>()));
  904. BOOST_ASSERT(sizeof(CharT) == ctrl_data->sizeof_char());
  905. //Erase node from index
  906. index.erase(it);
  907. //Destroy the header
  908. ctrl_data->~block_header_t();
  909. void *memory;
  910. if(is_node_index_t::value){
  911. index_it *ihdr = block_header_t::template
  912. to_first_header<index_it>(ctrl_data);
  913. ihdr->~index_it();
  914. memory = ihdr;
  915. }
  916. else{
  917. memory = ctrl_data;
  918. }
  919. //Call destructors and free memory
  920. std::size_t destroyed;
  921. table.destroy_n(values, num, destroyed);
  922. this->deallocate(memory);
  923. return true;
  924. }
  925. template<class CharT>
  926. void * priv_generic_named_construct
  927. (unsigned char type, const CharT *name, size_type num, bool try2find,
  928. bool dothrow, ipcdetail::in_place_interface &table,
  929. IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index, ipcdetail::true_ is_intrusive)
  930. {
  931. (void)is_intrusive;
  932. std::size_t namelen = std::char_traits<CharT>::length(name);
  933. block_header_t block_info ( size_type(table.size*num)
  934. , size_type(table.alignment)
  935. , type
  936. , sizeof(CharT)
  937. , namelen);
  938. typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type_t;
  939. typedef typename index_type_t::iterator index_it;
  940. typedef std::pair<index_it, bool> index_ib;
  941. //-------------------------------
  942. scoped_lock<rmutex> guard(m_header);
  943. //-------------------------------
  944. //Insert the node. This can throw.
  945. //First, we want to know if the key is already present before
  946. //we allocate any memory, and if the key is not present, we
  947. //want to allocate all memory in a single buffer that will
  948. //contain the name and the user buffer.
  949. //
  950. //Since equal_range(key) + insert(hint, value) approach is
  951. //quite inefficient in container implementations
  952. //(they re-test if the position is correct), I've chosen
  953. //to insert the node, do an ugly un-const cast and modify
  954. //the key (which is a smart pointer) to an equivalent one
  955. index_ib insert_ret;
  956. typename index_type_t::insert_commit_data commit_data;
  957. typedef typename index_type_t::value_type intrusive_value_type;
  958. BOOST_TRY{
  959. ipcdetail::intrusive_compare_key<CharT> key(name, namelen);
  960. insert_ret = index.insert_check(key, commit_data);
  961. }
  962. //Ignore exceptions
  963. BOOST_CATCH(...){
  964. if(dothrow)
  965. BOOST_RETHROW
  966. return 0;
  967. }
  968. BOOST_CATCH_END
  969. index_it it = insert_ret.first;
  970. //If found and this is find or construct, return data
  971. //else return null
  972. if(!insert_ret.second){
  973. if(try2find){
  974. return it->get_block_header()->value();
  975. }
  976. if(dothrow){
  977. throw interprocess_exception(already_exists_error);
  978. }
  979. else{
  980. return 0;
  981. }
  982. }
  983. //Allocates buffer for name + data, this can throw (it hurts)
  984. void *buffer_ptr;
  985. //Check if there is enough memory
  986. if(dothrow){
  987. buffer_ptr = this->allocate
  988. (block_info.template total_size_with_header<intrusive_value_type>());
  989. }
  990. else{
  991. buffer_ptr = this->allocate
  992. (block_info.template total_size_with_header<intrusive_value_type>(), nothrow<>::get());
  993. if(!buffer_ptr)
  994. return 0;
  995. }
  996. //Now construct the intrusive hook plus the header
  997. intrusive_value_type * intrusive_hdr = ::new(buffer_ptr, boost_container_new_t()) intrusive_value_type();
  998. block_header_t * hdr = ::new(intrusive_hdr->get_block_header(), boost_container_new_t())block_header_t(block_info);
  999. void *ptr = 0; //avoid gcc warning
  1000. ptr = hdr->value();
  1001. //Copy name to memory segment and insert data
  1002. CharT *name_ptr = static_cast<CharT *>(hdr->template name<CharT>());
  1003. std::char_traits<CharT>::copy(name_ptr, name, namelen+1);
  1004. BOOST_TRY{
  1005. //Now commit the insertion using previous context data
  1006. it = index.insert_commit(*intrusive_hdr, commit_data);
  1007. }
  1008. //Ignore exceptions
  1009. BOOST_CATCH(...){
  1010. if(dothrow)
  1011. BOOST_RETHROW
  1012. return 0;
  1013. }
  1014. BOOST_CATCH_END
  1015. //Avoid constructions if constructor is trivial
  1016. //Build scoped ptr to avoid leaks with constructor exception
  1017. ipcdetail::mem_algo_deallocator<segment_manager_base_type> mem
  1018. (buffer_ptr, *static_cast<segment_manager_base_type*>(this));
  1019. //Initialize the node value_eraser to erase inserted node
  1020. //if something goes wrong. This will be executed *before*
  1021. //the memory allocation as the intrusive value is built in that
  1022. //memory
  1023. value_eraser<index_type_t> v_eraser(index, it);
  1024. //Construct array, this can throw
  1025. ipcdetail::array_construct(ptr, num, table);
  1026. //Release rollbacks since construction was successful
  1027. v_eraser.release();
  1028. mem.release();
  1029. return ptr;
  1030. }
  1031. //!Generic named new function for
  1032. //!named functions
  1033. template<class CharT>
  1034. void * priv_generic_named_construct
  1035. (unsigned char type, const CharT *name, size_type num, bool try2find, bool dothrow,
  1036. ipcdetail::in_place_interface &table,
  1037. IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index, ipcdetail::false_ is_intrusive)
  1038. {
  1039. (void)is_intrusive;
  1040. std::size_t namelen = std::char_traits<CharT>::length(name);
  1041. block_header_t block_info ( size_type(table.size*num)
  1042. , size_type(table.alignment)
  1043. , type
  1044. , sizeof(CharT)
  1045. , namelen);
  1046. typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type_t;
  1047. typedef typename index_type_t::key_type key_type;
  1048. typedef typename index_type_t::mapped_type mapped_type;
  1049. typedef typename index_type_t::value_type value_type;
  1050. typedef typename index_type_t::iterator index_it;
  1051. typedef std::pair<index_it, bool> index_ib;
  1052. //-------------------------------
  1053. scoped_lock<rmutex> guard(m_header);
  1054. //-------------------------------
  1055. //Insert the node. This can throw.
  1056. //First, we want to know if the key is already present before
  1057. //we allocate any memory, and if the key is not present, we
  1058. //want to allocate all memory in a single buffer that will
  1059. //contain the name and the user buffer.
  1060. //
  1061. //Since equal_range(key) + insert(hint, value) approach is
  1062. //quite inefficient in container implementations
  1063. //(they re-test if the position is correct), I've chosen
  1064. //to insert the node, do an ugly un-const cast and modify
  1065. //the key (which is a smart pointer) to an equivalent one
  1066. index_ib insert_ret;
  1067. BOOST_TRY{
  1068. insert_ret = index.insert(value_type(key_type (name, namelen), mapped_type(0)));
  1069. }
  1070. //Ignore exceptions
  1071. BOOST_CATCH(...){
  1072. if(dothrow)
  1073. BOOST_RETHROW;
  1074. return 0;
  1075. }
  1076. BOOST_CATCH_END
  1077. index_it it = insert_ret.first;
  1078. //If found and this is find or construct, return data
  1079. //else return null
  1080. if(!insert_ret.second){
  1081. if(try2find){
  1082. block_header_t *hdr = static_cast<block_header_t*>
  1083. (ipcdetail::to_raw_pointer(it->second.m_ptr));
  1084. return hdr->value();
  1085. }
  1086. return 0;
  1087. }
  1088. //Initialize the node value_eraser to erase inserted node
  1089. //if something goes wrong
  1090. value_eraser<index_type_t> v_eraser(index, it);
  1091. //Allocates buffer for name + data, this can throw (it hurts)
  1092. void *buffer_ptr;
  1093. block_header_t * hdr;
  1094. //Allocate and construct the headers
  1095. if(is_node_index_t::value){
  1096. size_type total_size = block_info.template total_size_with_header<index_it>();
  1097. if(dothrow){
  1098. buffer_ptr = this->allocate(total_size);
  1099. }
  1100. else{
  1101. buffer_ptr = this->allocate(total_size, nothrow<>::get());
  1102. if(!buffer_ptr)
  1103. return 0;
  1104. }
  1105. index_it *idr = ::new(buffer_ptr, boost_container_new_t()) index_it(it);
  1106. hdr = block_header_t::template from_first_header<index_it>(idr);
  1107. }
  1108. else{
  1109. if(dothrow){
  1110. buffer_ptr = this->allocate(block_info.total_size());
  1111. }
  1112. else{
  1113. buffer_ptr = this->allocate(block_info.total_size(), nothrow<>::get());
  1114. if(!buffer_ptr)
  1115. return 0;
  1116. }
  1117. hdr = static_cast<block_header_t*>(buffer_ptr);
  1118. }
  1119. hdr = ::new(hdr, boost_container_new_t())block_header_t(block_info);
  1120. void *ptr = 0; //avoid gcc warning
  1121. ptr = hdr->value();
  1122. //Copy name to memory segment and insert data
  1123. CharT *name_ptr = static_cast<CharT *>(hdr->template name<CharT>());
  1124. std::char_traits<CharT>::copy(name_ptr, name, namelen+1);
  1125. //Do the ugly cast, please mama, forgive me!
  1126. //This new key points to an identical string, so it must have the
  1127. //same position than the overwritten key according to the predicate
  1128. const_cast<key_type &>(it->first).name(name_ptr);
  1129. it->second.m_ptr = hdr;
  1130. //Build scoped ptr to avoid leaks with constructor exception
  1131. ipcdetail::mem_algo_deallocator<segment_manager_base_type> mem
  1132. (buffer_ptr, *static_cast<segment_manager_base_type*>(this));
  1133. //Construct array, this can throw
  1134. ipcdetail::array_construct(ptr, num, table);
  1135. //All constructors successful, we don't want to release memory
  1136. mem.release();
  1137. //Release node v_eraser since construction was successful
  1138. v_eraser.release();
  1139. return ptr;
  1140. }
  1141. private:
  1142. //!Returns the this pointer
  1143. segment_manager *get_this_pointer()
  1144. { return this; }
  1145. typedef typename MemoryAlgorithm::mutex_family::recursive_mutex_type rmutex;
  1146. scoped_lock<rmutex> priv_get_lock(bool use_lock)
  1147. {
  1148. scoped_lock<rmutex> local(m_header, defer_lock);
  1149. if(use_lock){
  1150. local.lock();
  1151. }
  1152. return scoped_lock<rmutex>(boost::move(local));
  1153. }
  1154. //!This struct includes needed data and derives from
  1155. //!rmutex to allow EBO when using null interprocess_mutex
  1156. struct header_t
  1157. : public rmutex
  1158. {
  1159. named_index_t m_named_index;
  1160. unique_index_t m_unique_index;
  1161. header_t(segment_manager_base_t *segment_mngr_base)
  1162. : m_named_index (segment_mngr_base)
  1163. , m_unique_index(segment_mngr_base)
  1164. {}
  1165. } m_header;
  1166. #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
  1167. };
  1168. }} //namespace boost { namespace interprocess
  1169. #include <boost/interprocess/detail/config_end.hpp>
  1170. #endif //#ifndef BOOST_INTERPROCESS_SEGMENT_MANAGER_HPP