segment_manager.hpp 51 KB

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