segment_manager.hpp 49 KB

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