segment_manager.hpp 50 KB

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