segment_manager.hpp 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366
  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 ipcdetail::index_key<CharT, void_pointer> index_key_t;
  738. typedef typename index_type::iterator index_it;
  739. //-------------------------------
  740. scoped_lock<rmutex> guard(priv_get_lock(use_lock));
  741. //-------------------------------
  742. //Find name in index
  743. ipcdetail::intrusive_compare_key<CharT> key
  744. (name, std::char_traits<CharT>::length(name));
  745. index_it it = index.find(key);
  746. //Initialize return values
  747. void *ret_ptr = 0;
  748. length = 0;
  749. //If found, assign values
  750. if(it != index.end()){
  751. //Get header
  752. block_header_t *ctrl_data = it->get_block_header();
  753. //Sanity check
  754. BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0);
  755. BOOST_ASSERT(ctrl_data->sizeof_char() == sizeof(CharT));
  756. ret_ptr = ctrl_data->value();
  757. length = ctrl_data->m_value_bytes/table.size;
  758. }
  759. return ret_ptr;
  760. }
  761. template <class CharT>
  762. void *priv_generic_find
  763. (const CharT* name,
  764. IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
  765. ipcdetail::in_place_interface &table,
  766. size_type &length,
  767. ipcdetail::false_ is_intrusive,
  768. bool use_lock)
  769. {
  770. (void)is_intrusive;
  771. typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type;
  772. typedef typename index_type::key_type key_type;
  773. typedef typename index_type::iterator index_it;
  774. //-------------------------------
  775. scoped_lock<rmutex> guard(priv_get_lock(use_lock));
  776. //-------------------------------
  777. //Find name in index
  778. index_it it = index.find(key_type(name, std::char_traits<CharT>::length(name)));
  779. //Initialize return values
  780. void *ret_ptr = 0;
  781. length = 0;
  782. //If found, assign values
  783. if(it != index.end()){
  784. //Get header
  785. block_header_t *ctrl_data = reinterpret_cast<block_header_t*>
  786. (ipcdetail::to_raw_pointer(it->second.m_ptr));
  787. //Sanity check
  788. BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0);
  789. BOOST_ASSERT(ctrl_data->sizeof_char() == sizeof(CharT));
  790. ret_ptr = ctrl_data->value();
  791. length = ctrl_data->m_value_bytes/table.size;
  792. }
  793. return ret_ptr;
  794. }
  795. template <class CharT>
  796. bool priv_generic_named_destroy
  797. (block_header_t *block_header,
  798. IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
  799. ipcdetail::in_place_interface &table,
  800. ipcdetail::true_ is_node_index)
  801. {
  802. (void)is_node_index;
  803. typedef typename IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> >::iterator index_it;
  804. index_it *ihdr = block_header_t::template to_first_header<index_it>(block_header);
  805. return this->priv_generic_named_destroy_impl<CharT>(*ihdr, index, table);
  806. }
  807. template <class CharT>
  808. bool priv_generic_named_destroy
  809. (block_header_t *block_header,
  810. IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
  811. ipcdetail::in_place_interface &table,
  812. ipcdetail::false_ is_node_index)
  813. {
  814. (void)is_node_index;
  815. CharT *name = static_cast<CharT*>(block_header->template name<CharT>());
  816. return this->priv_generic_named_destroy<CharT>(name, index, table, is_intrusive_t());
  817. }
  818. template <class CharT>
  819. bool priv_generic_named_destroy(const CharT *name,
  820. IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
  821. ipcdetail::in_place_interface &table,
  822. ipcdetail::true_ is_intrusive_index)
  823. {
  824. (void)is_intrusive_index;
  825. typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type;
  826. typedef ipcdetail::index_key<CharT, void_pointer> index_key_t;
  827. typedef typename index_type::iterator index_it;
  828. typedef typename index_type::value_type intrusive_value_type;
  829. //-------------------------------
  830. scoped_lock<rmutex> guard(m_header);
  831. //-------------------------------
  832. //Find name in index
  833. ipcdetail::intrusive_compare_key<CharT> key
  834. (name, std::char_traits<CharT>::length(name));
  835. index_it it = index.find(key);
  836. //If not found, return false
  837. if(it == index.end()){
  838. //This name is not present in the index, wrong pointer or name!
  839. //BOOST_ASSERT(0);
  840. return false;
  841. }
  842. block_header_t *ctrl_data = it->get_block_header();
  843. intrusive_value_type *iv = intrusive_value_type::get_intrusive_value_type(ctrl_data);
  844. void *memory = iv;
  845. void *values = ctrl_data->value();
  846. std::size_t num = ctrl_data->m_value_bytes/table.size;
  847. //Sanity check
  848. BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0);
  849. BOOST_ASSERT(sizeof(CharT) == ctrl_data->sizeof_char());
  850. //Erase node from index
  851. index.erase(it);
  852. //Destroy the headers
  853. ctrl_data->~block_header_t();
  854. iv->~intrusive_value_type();
  855. //Call destructors and free memory
  856. std::size_t destroyed;
  857. table.destroy_n(values, num, destroyed);
  858. this->deallocate(memory);
  859. return true;
  860. }
  861. template <class CharT>
  862. bool priv_generic_named_destroy(const CharT *name,
  863. IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
  864. ipcdetail::in_place_interface &table,
  865. ipcdetail::false_ is_intrusive_index)
  866. {
  867. (void)is_intrusive_index;
  868. typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type;
  869. typedef typename index_type::iterator index_it;
  870. typedef typename index_type::key_type key_type;
  871. //-------------------------------
  872. scoped_lock<rmutex> guard(m_header);
  873. //-------------------------------
  874. //Try to find the name in the index
  875. index_it it = index.find(key_type (name,
  876. std::char_traits<CharT>::length(name)));
  877. //If not found, return false
  878. if(it == index.end()){
  879. //This name is not present in the index, wrong pointer or name!
  880. //BOOST_ASSERT(0);
  881. return false;
  882. }
  883. return this->priv_generic_named_destroy_impl<CharT>(it, index, table);
  884. }
  885. template <class CharT>
  886. bool priv_generic_named_destroy_impl
  887. (const typename IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> >::iterator &it,
  888. IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
  889. ipcdetail::in_place_interface &table)
  890. {
  891. typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type;
  892. typedef typename index_type::iterator index_it;
  893. //Get allocation parameters
  894. block_header_t *ctrl_data = reinterpret_cast<block_header_t*>
  895. (ipcdetail::to_raw_pointer(it->second.m_ptr));
  896. char *stored_name = static_cast<char*>(static_cast<void*>(const_cast<CharT*>(it->first.name())));
  897. (void)stored_name;
  898. //Check if the distance between the name pointer and the memory pointer
  899. //is correct (this can detect incorrect type in destruction)
  900. std::size_t num = ctrl_data->m_value_bytes/table.size;
  901. void *values = ctrl_data->value();
  902. //Sanity check
  903. BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0);
  904. BOOST_ASSERT(static_cast<void*>(stored_name) == static_cast<void*>(ctrl_data->template name<CharT>()));
  905. BOOST_ASSERT(sizeof(CharT) == ctrl_data->sizeof_char());
  906. //Erase node from index
  907. index.erase(it);
  908. //Destroy the header
  909. ctrl_data->~block_header_t();
  910. void *memory;
  911. if(is_node_index_t::value){
  912. index_it *ihdr = block_header_t::template
  913. to_first_header<index_it>(ctrl_data);
  914. ihdr->~index_it();
  915. memory = ihdr;
  916. }
  917. else{
  918. memory = ctrl_data;
  919. }
  920. //Call destructors and free memory
  921. std::size_t destroyed;
  922. table.destroy_n(values, num, destroyed);
  923. this->deallocate(memory);
  924. return true;
  925. }
  926. template<class CharT>
  927. void * priv_generic_named_construct(unsigned char type,
  928. const CharT *name,
  929. size_type num,
  930. bool try2find,
  931. bool dothrow,
  932. ipcdetail::in_place_interface &table,
  933. IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
  934. ipcdetail::true_ is_intrusive)
  935. {
  936. (void)is_intrusive;
  937. std::size_t namelen = std::char_traits<CharT>::length(name);
  938. block_header_t block_info ( size_type(table.size*num)
  939. , size_type(table.alignment)
  940. , type
  941. , sizeof(CharT)
  942. , namelen);
  943. typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type;
  944. typedef typename index_type::iterator index_it;
  945. typedef std::pair<index_it, bool> index_ib;
  946. //-------------------------------
  947. scoped_lock<rmutex> guard(m_header);
  948. //-------------------------------
  949. //Insert the node. This can throw.
  950. //First, we want to know if the key is already present before
  951. //we allocate any memory, and if the key is not present, we
  952. //want to allocate all memory in a single buffer that will
  953. //contain the name and the user buffer.
  954. //
  955. //Since equal_range(key) + insert(hint, value) approach is
  956. //quite inefficient in container implementations
  957. //(they re-test if the position is correct), I've chosen
  958. //to insert the node, do an ugly un-const cast and modify
  959. //the key (which is a smart pointer) to an equivalent one
  960. index_ib insert_ret;
  961. typename index_type::insert_commit_data commit_data;
  962. typedef typename index_type::value_type intrusive_value_type;
  963. BOOST_TRY{
  964. ipcdetail::intrusive_compare_key<CharT> key(name, namelen);
  965. insert_ret = index.insert_check(key, commit_data);
  966. }
  967. //Ignore exceptions
  968. BOOST_CATCH(...){
  969. if(dothrow)
  970. BOOST_RETHROW
  971. return 0;
  972. }
  973. BOOST_CATCH_END
  974. index_it it = insert_ret.first;
  975. //If found and this is find or construct, return data
  976. //else return null
  977. if(!insert_ret.second){
  978. if(try2find){
  979. return it->get_block_header()->value();
  980. }
  981. if(dothrow){
  982. throw interprocess_exception(already_exists_error);
  983. }
  984. else{
  985. return 0;
  986. }
  987. }
  988. //Allocates buffer for name + data, this can throw (it hurts)
  989. void *buffer_ptr;
  990. //Check if there is enough memory
  991. if(dothrow){
  992. buffer_ptr = this->allocate
  993. (block_info.template total_size_with_header<intrusive_value_type>());
  994. }
  995. else{
  996. buffer_ptr = this->allocate
  997. (block_info.template total_size_with_header<intrusive_value_type>(), std::nothrow_t());
  998. if(!buffer_ptr)
  999. return 0;
  1000. }
  1001. //Now construct the intrusive hook plus the header
  1002. intrusive_value_type * intrusive_hdr = new(buffer_ptr) intrusive_value_type();
  1003. block_header_t * hdr = new(intrusive_hdr->get_block_header())block_header_t(block_info);
  1004. void *ptr = 0; //avoid gcc warning
  1005. ptr = hdr->value();
  1006. //Copy name to memory segment and insert data
  1007. CharT *name_ptr = static_cast<CharT *>(hdr->template name<CharT>());
  1008. std::char_traits<CharT>::copy(name_ptr, name, namelen+1);
  1009. BOOST_TRY{
  1010. //Now commit the insertion using previous context data
  1011. it = index.insert_commit(*intrusive_hdr, commit_data);
  1012. }
  1013. //Ignore exceptions
  1014. BOOST_CATCH(...){
  1015. if(dothrow)
  1016. BOOST_RETHROW
  1017. return 0;
  1018. }
  1019. BOOST_CATCH_END
  1020. //Avoid constructions if constructor is trivial
  1021. //Build scoped ptr to avoid leaks with constructor exception
  1022. ipcdetail::mem_algo_deallocator<segment_manager_base_type> mem
  1023. (buffer_ptr, *static_cast<segment_manager_base_type*>(this));
  1024. //Initialize the node value_eraser to erase inserted node
  1025. //if something goes wrong. This will be executed *before*
  1026. //the memory allocation as the intrusive value is built in that
  1027. //memory
  1028. value_eraser<index_type> v_eraser(index, it);
  1029. //Construct array, this can throw
  1030. ipcdetail::array_construct(ptr, num, table);
  1031. //Release rollbacks since construction was successful
  1032. v_eraser.release();
  1033. mem.release();
  1034. return ptr;
  1035. }
  1036. //!Generic named new function for
  1037. //!named functions
  1038. template<class CharT>
  1039. void * priv_generic_named_construct(unsigned char type,
  1040. const CharT *name,
  1041. size_type num,
  1042. bool try2find,
  1043. bool dothrow,
  1044. ipcdetail::in_place_interface &table,
  1045. IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
  1046. ipcdetail::false_ is_intrusive)
  1047. {
  1048. (void)is_intrusive;
  1049. std::size_t namelen = std::char_traits<CharT>::length(name);
  1050. block_header_t block_info ( size_type(table.size*num)
  1051. , size_type(table.alignment)
  1052. , type
  1053. , sizeof(CharT)
  1054. , namelen);
  1055. typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type;
  1056. typedef typename index_type::key_type key_type;
  1057. typedef typename index_type::mapped_type mapped_type;
  1058. typedef typename index_type::value_type value_type;
  1059. typedef typename index_type::iterator index_it;
  1060. typedef std::pair<index_it, bool> index_ib;
  1061. //-------------------------------
  1062. scoped_lock<rmutex> guard(m_header);
  1063. //-------------------------------
  1064. //Insert the node. This can throw.
  1065. //First, we want to know if the key is already present before
  1066. //we allocate any memory, and if the key is not present, we
  1067. //want to allocate all memory in a single buffer that will
  1068. //contain the name and the user buffer.
  1069. //
  1070. //Since equal_range(key) + insert(hint, value) approach is
  1071. //quite inefficient in container implementations
  1072. //(they re-test if the position is correct), I've chosen
  1073. //to insert the node, do an ugly un-const cast and modify
  1074. //the key (which is a smart pointer) to an equivalent one
  1075. index_ib insert_ret;
  1076. BOOST_TRY{
  1077. insert_ret = index.insert(value_type(key_type (name, namelen), mapped_type(0)));
  1078. }
  1079. //Ignore exceptions
  1080. BOOST_CATCH(...){
  1081. if(dothrow)
  1082. BOOST_RETHROW;
  1083. return 0;
  1084. }
  1085. BOOST_CATCH_END
  1086. index_it it = insert_ret.first;
  1087. //If found and this is find or construct, return data
  1088. //else return null
  1089. if(!insert_ret.second){
  1090. if(try2find){
  1091. block_header_t *hdr = static_cast<block_header_t*>
  1092. (ipcdetail::to_raw_pointer(it->second.m_ptr));
  1093. return hdr->value();
  1094. }
  1095. return 0;
  1096. }
  1097. //Initialize the node value_eraser to erase inserted node
  1098. //if something goes wrong
  1099. value_eraser<index_type> v_eraser(index, it);
  1100. //Allocates buffer for name + data, this can throw (it hurts)
  1101. void *buffer_ptr;
  1102. block_header_t * hdr;
  1103. //Allocate and construct the headers
  1104. if(is_node_index_t::value){
  1105. size_type total_size = block_info.template total_size_with_header<index_it>();
  1106. if(dothrow){
  1107. buffer_ptr = this->allocate(total_size);
  1108. }
  1109. else{
  1110. buffer_ptr = this->allocate(total_size, std::nothrow_t());
  1111. if(!buffer_ptr)
  1112. return 0;
  1113. }
  1114. index_it *idr = new(buffer_ptr) index_it(it);
  1115. hdr = block_header_t::template from_first_header<index_it>(idr);
  1116. }
  1117. else{
  1118. if(dothrow){
  1119. buffer_ptr = this->allocate(block_info.total_size());
  1120. }
  1121. else{
  1122. buffer_ptr = this->allocate(block_info.total_size(), std::nothrow_t());
  1123. if(!buffer_ptr)
  1124. return 0;
  1125. }
  1126. hdr = static_cast<block_header_t*>(buffer_ptr);
  1127. }
  1128. hdr = new(hdr)block_header_t(block_info);
  1129. void *ptr = 0; //avoid gcc warning
  1130. ptr = hdr->value();
  1131. //Copy name to memory segment and insert data
  1132. CharT *name_ptr = static_cast<CharT *>(hdr->template name<CharT>());
  1133. std::char_traits<CharT>::copy(name_ptr, name, namelen+1);
  1134. //Do the ugly cast, please mama, forgive me!
  1135. //This new key points to an identical string, so it must have the
  1136. //same position than the overwritten key according to the predicate
  1137. const_cast<key_type &>(it->first).name(name_ptr);
  1138. it->second.m_ptr = hdr;
  1139. //Build scoped ptr to avoid leaks with constructor exception
  1140. ipcdetail::mem_algo_deallocator<segment_manager_base_type> mem
  1141. (buffer_ptr, *static_cast<segment_manager_base_type*>(this));
  1142. //Construct array, this can throw
  1143. ipcdetail::array_construct(ptr, num, table);
  1144. //All constructors successful, we don't want to release memory
  1145. mem.release();
  1146. //Release node v_eraser since construction was successful
  1147. v_eraser.release();
  1148. return ptr;
  1149. }
  1150. private:
  1151. //!Returns the this pointer
  1152. segment_manager *get_this_pointer()
  1153. { return this; }
  1154. typedef typename MemoryAlgorithm::mutex_family::recursive_mutex_type rmutex;
  1155. scoped_lock<rmutex> priv_get_lock(bool use_lock)
  1156. {
  1157. scoped_lock<rmutex> local(m_header, defer_lock);
  1158. if(use_lock){
  1159. local.lock();
  1160. }
  1161. return scoped_lock<rmutex>(boost::move(local));
  1162. }
  1163. //!This struct includes needed data and derives from
  1164. //!rmutex to allow EBO when using null interprocess_mutex
  1165. struct header_t
  1166. : public rmutex
  1167. {
  1168. named_index_t m_named_index;
  1169. unique_index_t m_unique_index;
  1170. header_t(Base *restricted_segment_mngr)
  1171. : m_named_index (restricted_segment_mngr)
  1172. , m_unique_index(restricted_segment_mngr)
  1173. {}
  1174. } m_header;
  1175. /// @endcond
  1176. };
  1177. }} //namespace boost { namespace interprocess
  1178. #include <boost/interprocess/detail/config_end.hpp>
  1179. #endif //#ifndef BOOST_INTERPROCESS_SEGMENT_MANAGER_HPP