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