segment_manager.hpp 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357
  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. #include <typeinfo>
  47. //!\file
  48. //!Describes the object placed in a memory segment that provides
  49. //!named object allocation capabilities for single-segment and
  50. //!multi-segment allocations.
  51. namespace boost{
  52. namespace interprocess{
  53. //!This object is the public base class of segment manager.
  54. //!This class only depends on the memory allocation algorithm
  55. //!and implements all the allocation features not related
  56. //!to named or unique objects.
  57. //!
  58. //!Storing a reference to segment_manager forces
  59. //!the holder class to be dependent on index types and character types.
  60. //!When such dependence is not desirable and only anonymous and raw
  61. //!allocations are needed, segment_manager_base is the correct answer.
  62. template<class MemoryAlgorithm>
  63. class segment_manager_base
  64. : private MemoryAlgorithm
  65. {
  66. public:
  67. typedef segment_manager_base<MemoryAlgorithm> segment_manager_base_type;
  68. typedef typename MemoryAlgorithm::void_pointer void_pointer;
  69. typedef typename MemoryAlgorithm::mutex_family mutex_family;
  70. typedef MemoryAlgorithm memory_algorithm;
  71. #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
  72. //Experimental. Don't use
  73. typedef typename MemoryAlgorithm::multiallocation_chain multiallocation_chain;
  74. typedef typename MemoryAlgorithm::difference_type difference_type;
  75. typedef typename MemoryAlgorithm::size_type size_type;
  76. #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
  77. //!This constant indicates the payload size
  78. //!associated with each allocation of the memory algorithm
  79. static const size_type PayloadPerAllocation = MemoryAlgorithm::PayloadPerAllocation;
  80. //!Constructor of the segment_manager_base
  81. //!
  82. //!"size" is the size of the memory segment where
  83. //!the basic segment manager is being constructed.
  84. //!
  85. //!"reserved_bytes" is the number of bytes
  86. //!after the end of the memory algorithm object itself
  87. //!that the memory algorithm will exclude from
  88. //!dynamic allocation
  89. //!
  90. //!Can throw
  91. segment_manager_base(size_type sz, size_type reserved_bytes)
  92. : MemoryAlgorithm(sz, reserved_bytes)
  93. {
  94. BOOST_ASSERT((sizeof(segment_manager_base<MemoryAlgorithm>) == sizeof(MemoryAlgorithm)));
  95. }
  96. //!Returns the size of the memory
  97. //!segment
  98. size_type get_size() const
  99. { return MemoryAlgorithm::get_size(); }
  100. //!Returns the number of free bytes of the memory
  101. //!segment
  102. size_type get_free_memory() const
  103. { return MemoryAlgorithm::get_free_memory(); }
  104. //!Obtains the minimum size needed by
  105. //!the segment manager
  106. static size_type get_min_size (size_type size)
  107. { return MemoryAlgorithm::get_min_size(size); }
  108. //!Allocates nbytes bytes. This function is only used in
  109. //!single-segment management. Never throws
  110. void * allocate (size_type nbytes, const std::nothrow_t &)
  111. { return MemoryAlgorithm::allocate(nbytes); }
  112. //!Returns a reference to the internal memory algorithm.
  113. //!This function is useful for custom memory algorithms that
  114. //!need additional configuration options after construction. Never throws.
  115. //!This function should be only used by advanced users.
  116. MemoryAlgorithm &get_memory_algorithm()
  117. { return static_cast<MemoryAlgorithm&>(*this); }
  118. //!Returns a const reference to the internal memory algorithm.
  119. //!This function is useful for custom memory algorithms that
  120. //!need additional configuration options after construction. Never throws.
  121. //!This function should be only used by advanced users.
  122. const MemoryAlgorithm &get_memory_algorithm() const
  123. { return static_cast<const MemoryAlgorithm&>(*this); }
  124. #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
  125. //Experimental. Dont' use.
  126. //!Allocates n_elements of elem_bytes bytes.
  127. //!Throws bad_alloc on failure. chain.size() is not increased on failure.
  128. void allocate_many(size_type elem_bytes, size_type n_elements, multiallocation_chain &chain)
  129. {
  130. size_type prev_size = chain.size();
  131. MemoryAlgorithm::allocate_many(elem_bytes, n_elements, chain);
  132. if(!elem_bytes || chain.size() == prev_size){
  133. throw bad_alloc();
  134. }
  135. }
  136. //!Allocates n_elements, each one of element_lengths[i]*sizeof_element bytes.
  137. //!Throws bad_alloc on failure. chain.size() is not increased on failure.
  138. void allocate_many(const size_type *element_lengths, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain)
  139. {
  140. size_type prev_size = chain.size();
  141. MemoryAlgorithm::allocate_many(element_lengths, n_elements, sizeof_element, chain);
  142. if(!sizeof_element || chain.size() == prev_size){
  143. throw bad_alloc();
  144. }
  145. }
  146. //!Allocates n_elements of elem_bytes bytes.
  147. //!Non-throwing version. chain.size() is not increased on failure.
  148. void allocate_many(const std::nothrow_t &, size_type elem_bytes, size_type n_elements, multiallocation_chain &chain)
  149. { MemoryAlgorithm::allocate_many(elem_bytes, n_elements, chain); }
  150. //!Allocates n_elements, each one of
  151. //!element_lengths[i]*sizeof_element bytes.
  152. //!Non-throwing version. chain.size() is not increased on failure.
  153. void allocate_many(const std::nothrow_t &, const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain)
  154. { MemoryAlgorithm::allocate_many(elem_sizes, n_elements, sizeof_element, chain); }
  155. //!Deallocates all elements contained in chain.
  156. //!Never throws.
  157. void deallocate_many(multiallocation_chain &chain)
  158. { MemoryAlgorithm::deallocate_many(chain); }
  159. #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
  160. //!Allocates nbytes bytes. Throws boost::interprocess::bad_alloc
  161. //!on failure
  162. void * allocate(size_type nbytes)
  163. {
  164. void * ret = MemoryAlgorithm::allocate(nbytes);
  165. if(!ret)
  166. throw bad_alloc();
  167. return ret;
  168. }
  169. //!Allocates nbytes bytes. This function is only used in
  170. //!single-segment management. Never throws
  171. void * allocate_aligned (size_type nbytes, size_type alignment, const std::nothrow_t &)
  172. { return MemoryAlgorithm::allocate_aligned(nbytes, alignment); }
  173. //!Allocates nbytes bytes. This function is only used in
  174. //!single-segment management. Throws bad_alloc when fails
  175. void * allocate_aligned(size_type nbytes, size_type alignment)
  176. {
  177. void * ret = MemoryAlgorithm::allocate_aligned(nbytes, alignment);
  178. if(!ret)
  179. throw bad_alloc();
  180. return ret;
  181. }
  182. #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
  183. template<class T>
  184. T *allocation_command (boost::interprocess::allocation_type command, size_type limit_size,
  185. size_type &prefer_in_recvd_out_size, T *&reuse)
  186. {
  187. T *ret = MemoryAlgorithm::allocation_command
  188. (command | boost::interprocess::nothrow_allocation, limit_size, prefer_in_recvd_out_size, reuse);
  189. if(!(command & boost::interprocess::nothrow_allocation) && !ret)
  190. throw bad_alloc();
  191. return ret;
  192. }
  193. void *raw_allocation_command (boost::interprocess::allocation_type command, size_type limit_objects,
  194. size_type &prefer_in_recvd_out_size, void *&reuse, size_type sizeof_object = 1)
  195. {
  196. void *ret = MemoryAlgorithm::raw_allocation_command
  197. ( command | boost::interprocess::nothrow_allocation, limit_objects,
  198. prefer_in_recvd_out_size, reuse, sizeof_object);
  199. if(!(command & boost::interprocess::nothrow_allocation) && !ret)
  200. throw bad_alloc();
  201. return ret;
  202. }
  203. #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
  204. //!Deallocates the bytes allocated with allocate/allocate_many()
  205. //!pointed by addr
  206. void deallocate (void *addr)
  207. { MemoryAlgorithm::deallocate(addr); }
  208. //!Increases managed memory in extra_size bytes more. This only works
  209. //!with single-segment management.
  210. void grow(size_type extra_size)
  211. { MemoryAlgorithm::grow(extra_size); }
  212. //!Decreases managed memory to the minimum. This only works
  213. //!with single-segment management.
  214. void shrink_to_fit()
  215. { MemoryAlgorithm::shrink_to_fit(); }
  216. //!Returns the result of "all_memory_deallocated()" function
  217. //!of the used memory algorithm
  218. bool all_memory_deallocated()
  219. { return MemoryAlgorithm::all_memory_deallocated(); }
  220. //!Returns the result of "check_sanity()" function
  221. //!of the used memory algorithm
  222. bool check_sanity()
  223. { return MemoryAlgorithm::check_sanity(); }
  224. //!Writes to zero free memory (memory not yet allocated)
  225. //!of the memory algorithm
  226. void zero_free_memory()
  227. { MemoryAlgorithm::zero_free_memory(); }
  228. //!Returns the size of the buffer previously allocated pointed by ptr
  229. size_type size(const void *ptr) const
  230. { return MemoryAlgorithm::size(ptr); }
  231. #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
  232. protected:
  233. void * prot_anonymous_construct
  234. (size_type num, bool dothrow, ipcdetail::in_place_interface &table)
  235. {
  236. typedef ipcdetail::block_header<size_type> block_header_t;
  237. block_header_t block_info ( size_type(table.size*num)
  238. , size_type(table.alignment)
  239. , anonymous_type
  240. , 1
  241. , 0);
  242. //Allocate memory
  243. void *ptr_struct = this->allocate(block_info.total_size(), nothrow<>::get());
  244. //Check if there is enough memory
  245. if(!ptr_struct){
  246. if(dothrow){
  247. throw bad_alloc();
  248. }
  249. else{
  250. return 0;
  251. }
  252. }
  253. //Build scoped ptr to avoid leaks with constructor exception
  254. ipcdetail::mem_algo_deallocator<MemoryAlgorithm> mem(ptr_struct, *this);
  255. //Now construct the header
  256. block_header_t * hdr = ::new(ptr_struct, boost_container_new_t()) block_header_t(block_info);
  257. void *ptr = 0; //avoid gcc warning
  258. ptr = hdr->value();
  259. //Now call constructors
  260. table.construct_n(ptr, num);
  261. //All constructors successful, we don't want erase memory
  262. mem.release();
  263. return ptr;
  264. }
  265. //!Calls the destructor and makes an anonymous deallocate
  266. void prot_anonymous_destroy(const void *object, ipcdetail::in_place_interface &table)
  267. {
  268. //Get control data from associated with this object
  269. typedef ipcdetail::block_header<size_type> block_header_t;
  270. block_header_t *ctrl_data = block_header_t::block_header_from_value(object, table.size, table.alignment);
  271. //-------------------------------
  272. //scoped_lock<rmutex> guard(m_header);
  273. //-------------------------------
  274. if(ctrl_data->alloc_type() != anonymous_type){
  275. //This is not an anonymous object, the pointer is wrong!
  276. BOOST_ASSERT(0);
  277. }
  278. //Call destructors and free memory
  279. //Build scoped ptr to avoid leaks with destructor exception
  280. table.destroy_n(const_cast<void*>(object), ctrl_data->m_value_bytes/table.size);
  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> > char_aware_index_type;
  774. typedef typename char_aware_index_type::key_type key_type;
  775. typedef typename char_aware_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. table.destroy_n(values, num);
  856. this->deallocate(memory);
  857. return true;
  858. }
  859. template <class CharT>
  860. bool priv_generic_named_destroy(const CharT *name,
  861. IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
  862. ipcdetail::in_place_interface &table,
  863. ipcdetail::false_ is_intrusive_index)
  864. {
  865. (void)is_intrusive_index;
  866. typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > char_aware_index_type;
  867. typedef typename char_aware_index_type::iterator index_it;
  868. typedef typename char_aware_index_type::key_type key_type;
  869. //-------------------------------
  870. scoped_lock<rmutex> guard(m_header);
  871. //-------------------------------
  872. //Try to find the name in the index
  873. index_it it = index.find(key_type (name,
  874. std::char_traits<CharT>::length(name)));
  875. //If not found, return false
  876. if(it == index.end()){
  877. //This name is not present in the index, wrong pointer or name!
  878. //BOOST_ASSERT(0);
  879. return false;
  880. }
  881. return this->priv_generic_named_destroy_impl<CharT>(it, index, table);
  882. }
  883. template <class CharT>
  884. bool priv_generic_named_destroy_impl
  885. (const typename IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> >::iterator &it,
  886. IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
  887. ipcdetail::in_place_interface &table)
  888. {
  889. typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > char_aware_index_type;
  890. typedef typename char_aware_index_type::iterator index_it;
  891. //Get allocation parameters
  892. block_header_t *ctrl_data = reinterpret_cast<block_header_t*>
  893. (ipcdetail::to_raw_pointer(it->second.m_ptr));
  894. char *stored_name = static_cast<char*>(static_cast<void*>(const_cast<CharT*>(it->first.name())));
  895. (void)stored_name;
  896. //Check if the distance between the name pointer and the memory pointer
  897. //is correct (this can detect incorrect type in destruction)
  898. std::size_t num = ctrl_data->m_value_bytes/table.size;
  899. void *values = ctrl_data->value();
  900. //Sanity check
  901. BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0);
  902. BOOST_ASSERT(static_cast<void*>(stored_name) == static_cast<void*>(ctrl_data->template name<CharT>()));
  903. BOOST_ASSERT(sizeof(CharT) == ctrl_data->sizeof_char());
  904. //Erase node from index
  905. index.erase(it);
  906. //Destroy the header
  907. ctrl_data->~block_header_t();
  908. void *memory;
  909. if(is_node_index_t::value){
  910. index_it *ihdr = block_header_t::template
  911. to_first_header<index_it>(ctrl_data);
  912. ihdr->~index_it();
  913. memory = ihdr;
  914. }
  915. else{
  916. memory = ctrl_data;
  917. }
  918. //Call destructors and free memory
  919. table.destroy_n(values, num);
  920. this->deallocate(memory);
  921. return true;
  922. }
  923. template<class CharT>
  924. void * priv_generic_named_construct
  925. (unsigned char type, const CharT *name, size_type num, bool try2find,
  926. bool dothrow, ipcdetail::in_place_interface &table,
  927. IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index, ipcdetail::true_ is_intrusive)
  928. {
  929. (void)is_intrusive;
  930. std::size_t namelen = std::char_traits<CharT>::length(name);
  931. block_header_t block_info ( size_type(table.size*num)
  932. , size_type(table.alignment)
  933. , type
  934. , sizeof(CharT)
  935. , namelen);
  936. typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type_t;
  937. typedef typename index_type_t::iterator index_it;
  938. typedef std::pair<index_it, bool> index_ib;
  939. //-------------------------------
  940. scoped_lock<rmutex> guard(m_header);
  941. //-------------------------------
  942. //Insert the node. This can throw.
  943. //First, we want to know if the key is already present before
  944. //we allocate any memory, and if the key is not present, we
  945. //want to allocate all memory in a single buffer that will
  946. //contain the name and the user buffer.
  947. //
  948. //Since equal_range(key) + insert(hint, value) approach is
  949. //quite inefficient in container implementations
  950. //(they re-test if the position is correct), I've chosen
  951. //to insert the node, do an ugly un-const cast and modify
  952. //the key (which is a smart pointer) to an equivalent one
  953. index_ib insert_ret;
  954. typename index_type_t::insert_commit_data commit_data;
  955. typedef typename index_type_t::value_type intrusive_value_type;
  956. BOOST_TRY{
  957. ipcdetail::intrusive_compare_key<CharT> key(name, namelen);
  958. insert_ret = index.insert_check(key, commit_data);
  959. }
  960. //Ignore exceptions
  961. BOOST_CATCH(...){
  962. if(dothrow)
  963. BOOST_RETHROW
  964. return 0;
  965. }
  966. BOOST_CATCH_END
  967. index_it it = insert_ret.first;
  968. //If found and this is find or construct, return data
  969. //else return null
  970. if(!insert_ret.second){
  971. if(try2find){
  972. return it->get_block_header()->value();
  973. }
  974. if(dothrow){
  975. throw interprocess_exception(already_exists_error);
  976. }
  977. else{
  978. return 0;
  979. }
  980. }
  981. //Allocates buffer for name + data, this can throw (it hurts)
  982. void *buffer_ptr;
  983. //Check if there is enough memory
  984. if(dothrow){
  985. buffer_ptr = this->allocate
  986. (block_info.template total_size_with_header<intrusive_value_type>());
  987. }
  988. else{
  989. buffer_ptr = this->allocate
  990. (block_info.template total_size_with_header<intrusive_value_type>(), nothrow<>::get());
  991. if(!buffer_ptr)
  992. return 0;
  993. }
  994. //Now construct the intrusive hook plus the header
  995. intrusive_value_type * intrusive_hdr = ::new(buffer_ptr, boost_container_new_t()) intrusive_value_type();
  996. block_header_t * hdr = ::new(intrusive_hdr->get_block_header(), boost_container_new_t())block_header_t(block_info);
  997. void *ptr = 0; //avoid gcc warning
  998. ptr = hdr->value();
  999. //Copy name to memory segment and insert data
  1000. CharT *name_ptr = static_cast<CharT *>(hdr->template name<CharT>());
  1001. std::char_traits<CharT>::copy(name_ptr, name, namelen+1);
  1002. BOOST_TRY{
  1003. //Now commit the insertion using previous context data
  1004. it = index.insert_commit(*intrusive_hdr, commit_data);
  1005. }
  1006. //Ignore exceptions
  1007. BOOST_CATCH(...){
  1008. if(dothrow)
  1009. BOOST_RETHROW
  1010. return 0;
  1011. }
  1012. BOOST_CATCH_END
  1013. //Avoid constructions if constructor is trivial
  1014. //Build scoped ptr to avoid leaks with constructor exception
  1015. ipcdetail::mem_algo_deallocator<segment_manager_base_type> mem
  1016. (buffer_ptr, *static_cast<segment_manager_base_type*>(this));
  1017. //Initialize the node value_eraser to erase inserted node
  1018. //if something goes wrong. This will be executed *before*
  1019. //the memory allocation as the intrusive value is built in that
  1020. //memory
  1021. value_eraser<index_type_t> v_eraser(index, it);
  1022. //Construct array, this can throw
  1023. table.construct_n(ptr, num);
  1024. //Release rollbacks since construction was successful
  1025. v_eraser.release();
  1026. mem.release();
  1027. return ptr;
  1028. }
  1029. //!Generic named new function for
  1030. //!named functions
  1031. template<class CharT>
  1032. void * priv_generic_named_construct
  1033. (unsigned char type, const CharT *name, size_type num, bool try2find, bool dothrow,
  1034. ipcdetail::in_place_interface &table,
  1035. IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index, ipcdetail::false_ is_intrusive)
  1036. {
  1037. (void)is_intrusive;
  1038. std::size_t namelen = std::char_traits<CharT>::length(name);
  1039. block_header_t block_info ( size_type(table.size*num)
  1040. , size_type(table.alignment)
  1041. , type
  1042. , sizeof(CharT)
  1043. , namelen);
  1044. typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type_t;
  1045. typedef typename index_type_t::key_type key_type;
  1046. typedef typename index_type_t::mapped_type mapped_type;
  1047. typedef typename index_type_t::value_type value_type;
  1048. typedef typename index_type_t::iterator index_it;
  1049. typedef std::pair<index_it, bool> index_ib;
  1050. //-------------------------------
  1051. scoped_lock<rmutex> guard(m_header);
  1052. //-------------------------------
  1053. //Insert the node. This can throw.
  1054. //First, we want to know if the key is already present before
  1055. //we allocate any memory, and if the key is not present, we
  1056. //want to allocate all memory in a single buffer that will
  1057. //contain the name and the user buffer.
  1058. //
  1059. //Since equal_range(key) + insert(hint, value) approach is
  1060. //quite inefficient in container implementations
  1061. //(they re-test if the position is correct), I've chosen
  1062. //to insert the node, do an ugly un-const cast and modify
  1063. //the key (which is a smart pointer) to an equivalent one
  1064. index_ib insert_ret;
  1065. BOOST_TRY{
  1066. insert_ret = index.insert(value_type(key_type (name, namelen), mapped_type(0)));
  1067. }
  1068. //Ignore exceptions
  1069. BOOST_CATCH(...){
  1070. if(dothrow)
  1071. BOOST_RETHROW;
  1072. return 0;
  1073. }
  1074. BOOST_CATCH_END
  1075. index_it it = insert_ret.first;
  1076. //If found and this is find or construct, return data
  1077. //else return null
  1078. if(!insert_ret.second){
  1079. if(try2find){
  1080. block_header_t *hdr = static_cast<block_header_t*>
  1081. (ipcdetail::to_raw_pointer(it->second.m_ptr));
  1082. return hdr->value();
  1083. }
  1084. return 0;
  1085. }
  1086. //Initialize the node value_eraser to erase inserted node
  1087. //if something goes wrong
  1088. value_eraser<index_type_t> v_eraser(index, it);
  1089. //Allocates buffer for name + data, this can throw (it hurts)
  1090. void *buffer_ptr;
  1091. block_header_t * hdr;
  1092. //Allocate and construct the headers
  1093. if(is_node_index_t::value){
  1094. size_type total_size = block_info.template total_size_with_header<index_it>();
  1095. if(dothrow){
  1096. buffer_ptr = this->allocate(total_size);
  1097. }
  1098. else{
  1099. buffer_ptr = this->allocate(total_size, nothrow<>::get());
  1100. if(!buffer_ptr)
  1101. return 0;
  1102. }
  1103. index_it *idr = ::new(buffer_ptr, boost_container_new_t()) index_it(it);
  1104. hdr = block_header_t::template from_first_header<index_it>(idr);
  1105. }
  1106. else{
  1107. if(dothrow){
  1108. buffer_ptr = this->allocate(block_info.total_size());
  1109. }
  1110. else{
  1111. buffer_ptr = this->allocate(block_info.total_size(), nothrow<>::get());
  1112. if(!buffer_ptr)
  1113. return 0;
  1114. }
  1115. hdr = static_cast<block_header_t*>(buffer_ptr);
  1116. }
  1117. hdr = ::new(hdr, boost_container_new_t())block_header_t(block_info);
  1118. void *ptr = 0; //avoid gcc warning
  1119. ptr = hdr->value();
  1120. //Copy name to memory segment and insert data
  1121. CharT *name_ptr = static_cast<CharT *>(hdr->template name<CharT>());
  1122. std::char_traits<CharT>::copy(name_ptr, name, namelen+1);
  1123. //Do the ugly cast, please mama, forgive me!
  1124. //This new key points to an identical string, so it must have the
  1125. //same position than the overwritten key according to the predicate
  1126. const_cast<key_type &>(it->first).name(name_ptr);
  1127. it->second.m_ptr = hdr;
  1128. //Build scoped ptr to avoid leaks with constructor exception
  1129. ipcdetail::mem_algo_deallocator<segment_manager_base_type> mem
  1130. (buffer_ptr, *static_cast<segment_manager_base_type*>(this));
  1131. //Construct array, this can throw
  1132. table.construct_n(ptr, num);
  1133. //All constructors successful, we don't want to release memory
  1134. mem.release();
  1135. //Release node v_eraser since construction was successful
  1136. v_eraser.release();
  1137. return ptr;
  1138. }
  1139. private:
  1140. //!Returns the this pointer
  1141. segment_manager *get_this_pointer()
  1142. { return this; }
  1143. typedef typename MemoryAlgorithm::mutex_family::recursive_mutex_type rmutex;
  1144. scoped_lock<rmutex> priv_get_lock(bool use_lock)
  1145. {
  1146. scoped_lock<rmutex> local(m_header, defer_lock);
  1147. if(use_lock){
  1148. local.lock();
  1149. }
  1150. return scoped_lock<rmutex>(boost::move(local));
  1151. }
  1152. //!This struct includes needed data and derives from
  1153. //!rmutex to allow EBO when using null interprocess_mutex
  1154. struct header_t
  1155. : public rmutex
  1156. {
  1157. named_index_t m_named_index;
  1158. unique_index_t m_unique_index;
  1159. header_t(segment_manager_base_t *segment_mngr_base)
  1160. : m_named_index (segment_mngr_base)
  1161. , m_unique_index(segment_mngr_base)
  1162. {}
  1163. } m_header;
  1164. #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
  1165. };
  1166. }} //namespace boost { namespace interprocess
  1167. #include <boost/interprocess/detail/config_end.hpp>
  1168. #endif //#ifndef BOOST_INTERPROCESS_SEGMENT_MANAGER_HPP