1 //////////////////////////////////////////////////////////////////////////////
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)
7 // See http://www.boost.org/libs/interprocess for documentation.
9 //////////////////////////////////////////////////////////////////////////////
11 #ifndef BOOST_INTERPROCESS_SEGMENT_MANAGER_HPP
12 #define BOOST_INTERPROCESS_SEGMENT_MANAGER_HPP
18 #include <boost/interprocess/detail/config_begin.hpp>
19 #include <boost/interprocess/detail/workaround.hpp>
21 #include <boost/detail/no_exceptions_support.hpp>
22 #include <boost/interprocess/detail/type_traits.hpp>
24 #include <boost/interprocess/detail/transform_iterator.hpp>
26 #include <boost/interprocess/detail/mpl.hpp>
27 #include <boost/interprocess/detail/segment_manager_helper.hpp>
28 #include <boost/interprocess/detail/named_proxy.hpp>
29 #include <boost/interprocess/detail/utilities.hpp>
30 #include <boost/interprocess/offset_ptr.hpp>
31 #include <boost/interprocess/indexes/iset_index.hpp>
32 #include <boost/interprocess/exceptions.hpp>
33 #include <boost/interprocess/allocators/allocator.hpp>
34 #include <boost/interprocess/smart_ptr/deleter.hpp>
35 #include <boost/move/utility_core.hpp>
36 #include <boost/interprocess/sync/scoped_lock.hpp>
37 #include <cstddef> //std::size_t
38 #include <string> //char_traits
39 #include <new> //std::nothrow
40 #include <utility> //std::pair
41 #include <boost/assert.hpp>
42 #ifndef BOOST_NO_EXCEPTIONS
47 //!Describes the object placed in a memory segment that provides
48 //!named object allocation capabilities for single-segment and
49 //!multi-segment allocations.
52 namespace interprocess{
54 //!This object is the public base class of segment manager.
55 //!This class only depends on the memory allocation algorithm
56 //!and implements all the allocation features not related
57 //!to named or unique objects.
59 //!Storing a reference to segment_manager forces
60 //!the holder class to be dependent on index types and character types.
61 //!When such dependence is not desirable and only anonymous and raw
62 //!allocations are needed, segment_manager_base is the correct answer.
63 template<class MemoryAlgorithm>
64 class segment_manager_base
65 : private MemoryAlgorithm
68 typedef segment_manager_base<MemoryAlgorithm> segment_manager_base_type;
69 typedef typename MemoryAlgorithm::void_pointer void_pointer;
70 typedef typename MemoryAlgorithm::mutex_family mutex_family;
71 typedef MemoryAlgorithm memory_algorithm;
73 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
75 //Experimental. Don't use
76 typedef typename MemoryAlgorithm::multiallocation_chain multiallocation_chain;
77 typedef typename MemoryAlgorithm::difference_type difference_type;
78 typedef typename MemoryAlgorithm::size_type size_type;
80 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
82 //!This constant indicates the payload size
83 //!associated with each allocation of the memory algorithm
84 static const size_type PayloadPerAllocation = MemoryAlgorithm::PayloadPerAllocation;
86 //!Constructor of the segment_manager_base
88 //!"size" is the size of the memory segment where
89 //!the basic segment manager is being constructed.
91 //!"reserved_bytes" is the number of bytes
92 //!after the end of the memory algorithm object itself
93 //!that the memory algorithm will exclude from
97 segment_manager_base(size_type sz, size_type reserved_bytes)
98 : MemoryAlgorithm(sz, reserved_bytes)
100 BOOST_ASSERT((sizeof(segment_manager_base<MemoryAlgorithm>) == sizeof(MemoryAlgorithm)));
103 //!Returns the size of the memory
105 size_type get_size() const
106 { return MemoryAlgorithm::get_size(); }
108 //!Returns the number of free bytes of the memory
110 size_type get_free_memory() const
111 { return MemoryAlgorithm::get_free_memory(); }
113 //!Obtains the minimum size needed by
114 //!the segment manager
115 static size_type get_min_size (size_type size)
116 { return MemoryAlgorithm::get_min_size(size); }
118 //!Allocates nbytes bytes. This function is only used in
119 //!single-segment management. Never throws
120 void * allocate (size_type nbytes, std::nothrow_t)
121 { return MemoryAlgorithm::allocate(nbytes); }
123 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
125 //Experimental. Dont' use.
126 //!Allocates n_elements of elem_bytes bytes.
127 //!Throws bad_alloc on failure. chain.size() is not increased on failure.
128 void allocate_many(size_type elem_bytes, size_type n_elements, multiallocation_chain &chain)
130 size_type prev_size = chain.size();
131 MemoryAlgorithm::allocate_many(elem_bytes, n_elements, chain);
132 if(!elem_bytes || chain.size() == prev_size){
137 //!Allocates n_elements, each one of element_lengths[i]*sizeof_element bytes.
138 //!Throws bad_alloc on failure. chain.size() is not increased on failure.
139 void allocate_many(const size_type *element_lengths, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain)
141 size_type prev_size = chain.size();
142 MemoryAlgorithm::allocate_many(element_lengths, n_elements, sizeof_element, chain);
143 if(!sizeof_element || chain.size() == prev_size){
148 //!Allocates n_elements of elem_bytes bytes.
149 //!Non-throwing version. chain.size() is not increased on failure.
150 void allocate_many(std::nothrow_t, size_type elem_bytes, size_type n_elements, multiallocation_chain &chain)
151 { MemoryAlgorithm::allocate_many(elem_bytes, n_elements, chain); }
153 //!Allocates n_elements, each one of
154 //!element_lengths[i]*sizeof_element bytes.
155 //!Non-throwing version. chain.size() is not increased on failure.
156 void allocate_many(std::nothrow_t, const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain)
157 { MemoryAlgorithm::allocate_many(elem_sizes, n_elements, sizeof_element, chain); }
159 //!Deallocates all elements contained in chain.
161 void deallocate_many(multiallocation_chain &chain)
162 { MemoryAlgorithm::deallocate_many(chain); }
164 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
166 //!Allocates nbytes bytes. Throws boost::interprocess::bad_alloc
168 void * allocate(size_type nbytes)
170 void * ret = MemoryAlgorithm::allocate(nbytes);
176 //!Allocates nbytes bytes. This function is only used in
177 //!single-segment management. Never throws
178 void * allocate_aligned (size_type nbytes, size_type alignment, std::nothrow_t)
179 { return MemoryAlgorithm::allocate_aligned(nbytes, alignment); }
181 //!Allocates nbytes bytes. This function is only used in
182 //!single-segment management. Throws bad_alloc when fails
183 void * allocate_aligned(size_type nbytes, size_type alignment)
185 void * ret = MemoryAlgorithm::allocate_aligned(nbytes, alignment);
191 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
195 allocation_command (boost::interprocess::allocation_type command, size_type limit_size,
196 size_type preferred_size,size_type &received_size,
199 std::pair<T *, bool> ret = MemoryAlgorithm::allocation_command
200 ( command | boost::interprocess::nothrow_allocation, limit_size, preferred_size, received_size
202 if(!(command & boost::interprocess::nothrow_allocation) && !ret.first)
207 std::pair<void *, bool>
208 raw_allocation_command (boost::interprocess::allocation_type command, size_type limit_objects,
209 size_type preferred_objects,size_type &received_objects,
210 void *reuse_ptr = 0, size_type sizeof_object = 1)
212 std::pair<void *, bool> ret = MemoryAlgorithm::raw_allocation_command
213 ( command | boost::interprocess::nothrow_allocation, limit_objects, preferred_objects, received_objects
214 , reuse_ptr, sizeof_object);
215 if(!(command & boost::interprocess::nothrow_allocation) && !ret.first)
220 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
222 //!Deallocates the bytes allocated with allocate/allocate_many()
224 void deallocate (void *addr)
225 { MemoryAlgorithm::deallocate(addr); }
227 //!Increases managed memory in extra_size bytes more. This only works
228 //!with single-segment management.
229 void grow(size_type extra_size)
230 { MemoryAlgorithm::grow(extra_size); }
232 //!Decreases managed memory to the minimum. This only works
233 //!with single-segment management.
235 { MemoryAlgorithm::shrink_to_fit(); }
237 //!Returns the result of "all_memory_deallocated()" function
238 //!of the used memory algorithm
239 bool all_memory_deallocated()
240 { return MemoryAlgorithm::all_memory_deallocated(); }
242 //!Returns the result of "check_sanity()" function
243 //!of the used memory algorithm
245 { return MemoryAlgorithm::check_sanity(); }
247 //!Writes to zero free memory (memory not yet allocated)
248 //!of the memory algorithm
249 void zero_free_memory()
250 { MemoryAlgorithm::zero_free_memory(); }
252 //!Returns the size of the buffer previously allocated pointed by ptr
253 size_type size(const void *ptr) const
254 { return MemoryAlgorithm::size(ptr); }
256 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
258 void * prot_anonymous_construct
259 (size_type num, bool dothrow, ipcdetail::in_place_interface &table)
261 typedef ipcdetail::block_header<size_type> block_header_t;
262 block_header_t block_info ( size_type(table.size*num)
263 , size_type(table.alignment)
269 void *ptr_struct = this->allocate(block_info.total_size(), std::nothrow_t());
271 //Check if there is enough memory
281 //Build scoped ptr to avoid leaks with constructor exception
282 ipcdetail::mem_algo_deallocator<MemoryAlgorithm> mem(ptr_struct, *this);
284 //Now construct the header
285 block_header_t * hdr = new(ptr_struct) block_header_t(block_info);
286 void *ptr = 0; //avoid gcc warning
289 //Now call constructors
290 ipcdetail::array_construct(ptr, num, table);
292 //All constructors successful, we don't want erase memory
297 //!Calls the destructor and makes an anonymous deallocate
298 void prot_anonymous_destroy(const void *object, ipcdetail::in_place_interface &table)
301 //Get control data from associated with this object
302 typedef ipcdetail::block_header<size_type> block_header_t;
303 block_header_t *ctrl_data = block_header_t::block_header_from_value(object, table.size, table.alignment);
305 //-------------------------------
306 //scoped_lock<rmutex> guard(m_header);
307 //-------------------------------
309 if(ctrl_data->alloc_type() != anonymous_type){
310 //This is not an anonymous object, the pointer is wrong!
314 //Call destructors and free memory
315 //Build scoped ptr to avoid leaks with destructor exception
316 std::size_t destroyed = 0;
317 table.destroy_n(const_cast<void*>(object), ctrl_data->m_value_bytes/table.size, destroyed);
318 this->deallocate(ctrl_data);
320 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
323 //!This object is placed in the beginning of memory segment and
324 //!implements the allocation (named or anonymous) of portions
325 //!of the segment. This object contains two indexes that
326 //!maintain an association between a name and a portion of the segment.
328 //!The first index contains the mappings for normal named objects using the
329 //!char type specified in the template parameter.
331 //!The second index contains the association for unique instances. The key will
332 //!be the const char * returned from type_info.name() function for the unique
333 //!type to be constructed.
335 //!segment_manager<CharType, MemoryAlgorithm, IndexType> inherits publicly
336 //!from segment_manager_base<MemoryAlgorithm> and inherits from it
337 //!many public functions related to anonymous object and raw memory allocation.
338 //!See segment_manager_base reference to know about those functions.
339 template<class CharType
340 ,class MemoryAlgorithm
341 ,template<class IndexConfig> class IndexType>
342 class segment_manager
343 : public segment_manager_base<MemoryAlgorithm>
345 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
348 segment_manager(const segment_manager &);
349 segment_manager &operator=(const segment_manager &);
350 typedef segment_manager_base<MemoryAlgorithm> segment_manager_base_t;
351 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
354 typedef MemoryAlgorithm memory_algorithm;
355 typedef typename segment_manager_base_t::void_pointer void_pointer;
356 typedef typename segment_manager_base_t::size_type size_type;
357 typedef typename segment_manager_base_t::difference_type difference_type;
358 typedef CharType char_type;
360 typedef segment_manager_base<MemoryAlgorithm> segment_manager_base_type;
362 static const size_type PayloadPerAllocation = segment_manager_base_t::PayloadPerAllocation;
364 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
366 typedef ipcdetail::block_header<size_type> block_header_t;
367 typedef ipcdetail::index_config<CharType, MemoryAlgorithm> index_config_named;
368 typedef ipcdetail::index_config<char, MemoryAlgorithm> index_config_unique;
369 typedef IndexType<index_config_named> index_type;
370 typedef ipcdetail::bool_<is_intrusive_index<index_type>::value > is_intrusive_t;
371 typedef ipcdetail::bool_<is_node_index<index_type>::value> is_node_index_t;
374 typedef IndexType<index_config_named> named_index_t;
375 typedef IndexType<index_config_unique> unique_index_t;
376 typedef ipcdetail::char_ptr_holder<CharType> char_ptr_holder_t;
377 typedef ipcdetail::segment_manager_iterator_transform
378 <typename named_index_t::const_iterator
379 ,is_intrusive_index<index_type>::value> named_transform;
381 typedef ipcdetail::segment_manager_iterator_transform
382 <typename unique_index_t::const_iterator
383 ,is_intrusive_index<index_type>::value> unique_transform;
384 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
386 typedef typename segment_manager_base_t::mutex_family mutex_family;
388 typedef transform_iterator
389 <typename named_index_t::const_iterator, named_transform> const_named_iterator;
390 typedef transform_iterator
391 <typename unique_index_t::const_iterator, unique_transform> const_unique_iterator;
393 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
395 //!Constructor proxy object definition helper class
397 struct construct_proxy
399 typedef ipcdetail::named_proxy<segment_manager, T, false> type;
402 //!Constructor proxy object definition helper class
404 struct construct_iter_proxy
406 typedef ipcdetail::named_proxy<segment_manager, T, true> type;
409 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
411 //!Constructor of the segment manager
412 //!"size" is the size of the memory segment where
413 //!the segment manager is being constructed.
415 explicit segment_manager(size_type segment_size)
416 : segment_manager_base_t(segment_size, priv_get_reserved_bytes())
417 , m_header(static_cast<segment_manager_base_t*>(get_this_pointer()))
419 (void) anonymous_instance; (void) unique_instance;
420 //Check EBO is applied, it's required
421 const void * const this_addr = this;
422 const void *const segm_addr = static_cast<segment_manager_base_t*>(this);
423 (void)this_addr; (void)segm_addr;
424 BOOST_ASSERT( this_addr == segm_addr);
427 //!Tries to find a previous named/unique allocation. Returns the address
428 //!and the object count. On failure the first member of the
429 //!returned pair is 0.
431 std::pair<T*, size_type> find (char_ptr_holder_t name)
432 { return this->priv_find_impl<T>(name, true); }
434 //!Tries to find a previous named/unique allocation. Returns the address
435 //!and the object count. On failure the first member of the
436 //!returned pair is 0. This search is not mutex-protected!
437 //!Use it only inside atomic_func() calls, where the internal mutex
438 //!is guaranteed to be locked.
440 std::pair<T*, size_type> find_no_lock (char_ptr_holder_t name)
441 { return this->priv_find_impl<T>(name, false); }
443 //!Returns throwing "construct" proxy
446 typename construct_proxy<T>::type
447 construct(char_ptr_holder_t name)
448 { return typename construct_proxy<T>::type (this, name, false, true); }
450 //!Returns throwing "search or construct" proxy
453 typename construct_proxy<T>::type find_or_construct(char_ptr_holder_t name)
454 { return typename construct_proxy<T>::type (this, name, true, true); }
456 //!Returns no throwing "construct" proxy
459 typename construct_proxy<T>::type
460 construct(char_ptr_holder_t name, std::nothrow_t)
461 { return typename construct_proxy<T>::type (this, name, false, false); }
463 //!Returns no throwing "search or construct"
466 typename construct_proxy<T>::type
467 find_or_construct(char_ptr_holder_t name, std::nothrow_t)
468 { return typename construct_proxy<T>::type (this, name, true, false); }
470 //!Returns throwing "construct from iterators" proxy object
472 typename construct_iter_proxy<T>::type
473 construct_it(char_ptr_holder_t name)
474 { return typename construct_iter_proxy<T>::type (this, name, false, true); }
476 //!Returns throwing "search or construct from iterators"
479 typename construct_iter_proxy<T>::type
480 find_or_construct_it(char_ptr_holder_t name)
481 { return typename construct_iter_proxy<T>::type (this, name, true, true); }
483 //!Returns no throwing "construct from iterators"
486 typename construct_iter_proxy<T>::type
487 construct_it(char_ptr_holder_t name, std::nothrow_t)
488 { return typename construct_iter_proxy<T>::type (this, name, false, false); }
490 //!Returns no throwing "search or construct from iterators"
493 typename construct_iter_proxy<T>::type
494 find_or_construct_it(char_ptr_holder_t name, std::nothrow_t)
495 { return typename construct_iter_proxy<T>::type (this, name, true, false); }
497 //!Calls object function blocking recursive interprocess_mutex and guarantees that
498 //!no new named_alloc or destroy will be executed by any process while
499 //!executing the object function call
500 template <class Func>
501 void atomic_func(Func &f)
502 { scoped_lock<rmutex> guard(m_header); f(); }
504 //!Tries to calls a functor guaranteeing that no new construction, search or
505 //!destruction will be executed by any process while executing the object
506 //!function call. If the atomic function can't be immediatelly executed
507 //!because the internal mutex is already locked, returns false.
508 //!If the functor throws, this function throws.
509 template <class Func>
510 bool try_atomic_func(Func &f)
512 scoped_lock<rmutex> guard(m_header, try_to_lock);
522 //!Destroys a previously created named/unique instance.
523 //!Returns false if the object was not present.
525 bool destroy(char_ptr_holder_t name)
527 BOOST_ASSERT(!name.is_anonymous());
528 ipcdetail::placement_destroy<T> dtor;
530 if(name.is_unique()){
531 return this->priv_generic_named_destroy<char>
532 ( typeid(T).name(), m_header.m_unique_index , dtor, is_intrusive_t());
535 return this->priv_generic_named_destroy<CharType>
536 ( name.get(), m_header.m_named_index, dtor, is_intrusive_t());
540 //!Destroys an anonymous, unique or named object
543 void destroy_ptr(const T *p)
545 //If T is void transform it to char
546 typedef typename ipcdetail::char_if_void<T>::type data_t;
547 ipcdetail::placement_destroy<data_t> dtor;
548 priv_destroy_ptr(p, dtor);
551 //!Returns the name of an object created with construct/find_or_construct
552 //!functions. Does not throw
554 static const CharType *get_instance_name(const T *ptr)
555 { return priv_get_instance_name(block_header_t::block_header_from_value(ptr)); }
557 //!Returns the length of an object created with construct/find_or_construct
558 //!functions. Does not throw.
560 static size_type get_instance_length(const T *ptr)
561 { return priv_get_instance_length(block_header_t::block_header_from_value(ptr), sizeof(T)); }
563 //!Returns is the the name of an object created with construct/find_or_construct
564 //!functions. Does not throw
566 static instance_type get_instance_type(const T *ptr)
567 { return priv_get_instance_type(block_header_t::block_header_from_value(ptr)); }
569 //!Preallocates needed index resources to optimize the
570 //!creation of "num" named objects in the managed memory segment.
571 //!Can throw boost::interprocess::bad_alloc if there is no enough memory.
572 void reserve_named_objects(size_type num)
574 //-------------------------------
575 scoped_lock<rmutex> guard(m_header);
576 //-------------------------------
577 m_header.m_named_index.reserve(num);
580 //!Preallocates needed index resources to optimize the
581 //!creation of "num" unique objects in the managed memory segment.
582 //!Can throw boost::interprocess::bad_alloc if there is no enough memory.
583 void reserve_unique_objects(size_type num)
585 //-------------------------------
586 scoped_lock<rmutex> guard(m_header);
587 //-------------------------------
588 m_header.m_unique_index.reserve(num);
591 //!Calls shrink_to_fit in both named and unique object indexes
592 //!to try to free unused memory from those indexes.
593 void shrink_to_fit_indexes()
595 //-------------------------------
596 scoped_lock<rmutex> guard(m_header);
597 //-------------------------------
598 m_header.m_named_index.shrink_to_fit();
599 m_header.m_unique_index.shrink_to_fit();
602 //!Returns the number of named objects stored in
604 size_type get_num_named_objects()
606 //-------------------------------
607 scoped_lock<rmutex> guard(m_header);
608 //-------------------------------
609 return m_header.m_named_index.size();
612 //!Returns the number of unique objects stored in
614 size_type get_num_unique_objects()
616 //-------------------------------
617 scoped_lock<rmutex> guard(m_header);
618 //-------------------------------
619 return m_header.m_unique_index.size();
622 //!Obtains the minimum size needed by the
624 static size_type get_min_size()
625 { return segment_manager_base_t::get_min_size(priv_get_reserved_bytes()); }
627 //!Returns a constant iterator to the beginning of the information about
628 //!the named allocations performed in this segment manager
629 const_named_iterator named_begin() const
631 return make_transform_iterator
632 (m_header.m_named_index.begin(), named_transform());
635 //!Returns a constant iterator to the end of the information about
636 //!the named allocations performed in this segment manager
637 const_named_iterator named_end() const
639 return make_transform_iterator
640 (m_header.m_named_index.end(), named_transform());
643 //!Returns a constant iterator to the beginning of the information about
644 //!the unique allocations performed in this segment manager
645 const_unique_iterator unique_begin() const
647 return make_transform_iterator
648 (m_header.m_unique_index.begin(), unique_transform());
651 //!Returns a constant iterator to the end of the information about
652 //!the unique allocations performed in this segment manager
653 const_unique_iterator unique_end() const
655 return make_transform_iterator
656 (m_header.m_unique_index.end(), unique_transform());
659 //!This is the default allocator to allocate types T
660 //!from this managed segment
664 typedef boost::interprocess::allocator<T, segment_manager> type;
667 //!Returns an instance of the default allocator for type T
668 //!initialized that allocates memory from this segment manager.
670 typename allocator<T>::type
672 { return typename allocator<T>::type(this); }
674 //!This is the default deleter to delete types T
675 //!from this managed segment.
679 typedef boost::interprocess::deleter<T, segment_manager> type;
682 //!Returns an instance of the default deleter for type T
683 //!that will delete an object constructed in this segment manager.
685 typename deleter<T>::type
687 { return typename deleter<T>::type(this); }
689 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
691 //!Generic named/anonymous new function. Offers all the possibilities,
692 //!such as throwing, search before creating, and the constructor is
693 //!encapsulated in an object function.
695 T *generic_construct(const CharType *name,
699 ipcdetail::in_place_interface &table)
701 return static_cast<T*>
702 (priv_generic_construct(name, num, try2find, dothrow, table));
706 //!Tries to find a previous named allocation. Returns the address
707 //!and the object count. On failure the first member of the
708 //!returned pair is 0.
710 std::pair<T*, size_type> priv_find_impl (const CharType* name, bool lock)
712 //The name can't be null, no anonymous object can be found by name
713 BOOST_ASSERT(name != 0);
714 ipcdetail::placement_destroy<T> table;
718 if(name == reinterpret_cast<const CharType*>(-1)){
719 ret = priv_generic_find<char> (typeid(T).name(), m_header.m_unique_index, table, sz, is_intrusive_t(), lock);
722 ret = priv_generic_find<CharType> (name, m_header.m_named_index, table, sz, is_intrusive_t(), lock);
724 return std::pair<T*, size_type>(static_cast<T*>(ret), sz);
727 //!Tries to find a previous unique allocation. Returns the address
728 //!and the object count. On failure the first member of the
729 //!returned pair is 0.
731 std::pair<T*, size_type> priv_find__impl (const ipcdetail::unique_instance_t* name, bool lock)
733 ipcdetail::placement_destroy<T> table;
735 void *ret = priv_generic_find<char>(name, m_header.m_unique_index, table, size, is_intrusive_t(), lock);
736 return std::pair<T*, size_type>(static_cast<T*>(ret), size);
739 void *priv_generic_construct
740 (const CharType *name, size_type num, bool try2find, bool dothrow, ipcdetail::in_place_interface &table)
743 //Security overflow check
744 if(num > ((std::size_t)-1)/table.size){
751 ret = this->prot_anonymous_construct(num, dothrow, table);
753 else if(name == reinterpret_cast<const CharType*>(-1)){
754 ret = this->priv_generic_named_construct<char>
755 (unique_type, table.type_name, num, try2find, dothrow, table, m_header.m_unique_index, is_intrusive_t());
758 ret = this->priv_generic_named_construct<CharType>
759 (named_type, name, num, try2find, dothrow, table, m_header.m_named_index, is_intrusive_t());
764 void priv_destroy_ptr(const void *ptr, ipcdetail::in_place_interface &dtor)
766 block_header_t *ctrl_data = block_header_t::block_header_from_value(ptr, dtor.size, dtor.alignment);
767 switch(ctrl_data->alloc_type()){
769 this->prot_anonymous_destroy(ptr, dtor);
773 this->priv_generic_named_destroy<CharType>
774 (ctrl_data, m_header.m_named_index, dtor, is_node_index_t());
778 this->priv_generic_named_destroy<char>
779 (ctrl_data, m_header.m_unique_index, dtor, is_node_index_t());
783 //This type is unknown, bad pointer passed to this function!
789 //!Returns the name of an object created with construct/find_or_construct
790 //!functions. Does not throw
791 static const CharType *priv_get_instance_name(block_header_t *ctrl_data)
793 boost::interprocess::allocation_type type = ctrl_data->alloc_type();
794 if(type == anonymous_type){
795 BOOST_ASSERT((type == anonymous_type && ctrl_data->m_num_char == 0) ||
796 (type == unique_type && ctrl_data->m_num_char != 0) );
799 CharType *name = static_cast<CharType*>(ctrl_data->template name<CharType>());
802 BOOST_ASSERT(ctrl_data->sizeof_char() == sizeof(CharType));
803 BOOST_ASSERT(ctrl_data->m_num_char == std::char_traits<CharType>::length(name));
807 static size_type priv_get_instance_length(block_header_t *ctrl_data, size_type sizeofvalue)
810 BOOST_ASSERT((ctrl_data->value_bytes() %sizeofvalue) == 0);
811 return ctrl_data->value_bytes()/sizeofvalue;
814 //!Returns is the the name of an object created with construct/find_or_construct
815 //!functions. Does not throw
816 static instance_type priv_get_instance_type(block_header_t *ctrl_data)
819 BOOST_ASSERT((instance_type)ctrl_data->alloc_type() < max_allocation_type);
820 return (instance_type)ctrl_data->alloc_type();
823 static size_type priv_get_reserved_bytes()
825 //Get the number of bytes until the end of (*this)
826 //beginning in the end of the segment_manager_base_t base.
827 return sizeof(segment_manager) - sizeof(segment_manager_base_t);
830 template <class CharT>
831 void *priv_generic_find
833 IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
834 ipcdetail::in_place_interface &table,
835 size_type &length, ipcdetail::true_ is_intrusive, bool use_lock)
838 typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type;
839 typedef typename index_type::iterator index_it;
841 //-------------------------------
842 scoped_lock<rmutex> guard(priv_get_lock(use_lock));
843 //-------------------------------
845 ipcdetail::intrusive_compare_key<CharT> key
846 (name, std::char_traits<CharT>::length(name));
847 index_it it = index.find(key);
849 //Initialize return values
853 //If found, assign values
854 if(it != index.end()){
856 block_header_t *ctrl_data = it->get_block_header();
859 BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0);
860 BOOST_ASSERT(ctrl_data->sizeof_char() == sizeof(CharT));
861 ret_ptr = ctrl_data->value();
862 length = ctrl_data->m_value_bytes/table.size;
867 template <class CharT>
868 void *priv_generic_find
870 IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
871 ipcdetail::in_place_interface &table,
872 size_type &length, ipcdetail::false_ is_intrusive, bool use_lock)
875 typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type;
876 typedef typename index_type::key_type key_type;
877 typedef typename index_type::iterator index_it;
879 //-------------------------------
880 scoped_lock<rmutex> guard(priv_get_lock(use_lock));
881 //-------------------------------
883 index_it it = index.find(key_type(name, std::char_traits<CharT>::length(name)));
885 //Initialize return values
889 //If found, assign values
890 if(it != index.end()){
892 block_header_t *ctrl_data = reinterpret_cast<block_header_t*>
893 (ipcdetail::to_raw_pointer(it->second.m_ptr));
896 BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0);
897 BOOST_ASSERT(ctrl_data->sizeof_char() == sizeof(CharT));
898 ret_ptr = ctrl_data->value();
899 length = ctrl_data->m_value_bytes/table.size;
904 template <class CharT>
905 bool priv_generic_named_destroy
906 (block_header_t *block_header,
907 IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
908 ipcdetail::in_place_interface &table, ipcdetail::true_ is_node_index)
911 typedef typename IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> >::iterator index_it;
913 index_it *ihdr = block_header_t::template to_first_header<index_it>(block_header);
914 return this->priv_generic_named_destroy_impl<CharT>(*ihdr, index, table);
917 template <class CharT>
918 bool priv_generic_named_destroy
919 (block_header_t *block_header,
920 IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
921 ipcdetail::in_place_interface &table,
922 ipcdetail::false_ is_node_index)
925 CharT *name = static_cast<CharT*>(block_header->template name<CharT>());
926 return this->priv_generic_named_destroy<CharT>(name, index, table, is_intrusive_t());
929 template <class CharT>
930 bool priv_generic_named_destroy(const CharT *name,
931 IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
932 ipcdetail::in_place_interface &table, ipcdetail::true_ is_intrusive_index)
934 (void)is_intrusive_index;
935 typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type;
936 typedef typename index_type::iterator index_it;
937 typedef typename index_type::value_type intrusive_value_type;
939 //-------------------------------
940 scoped_lock<rmutex> guard(m_header);
941 //-------------------------------
943 ipcdetail::intrusive_compare_key<CharT> key
944 (name, std::char_traits<CharT>::length(name));
945 index_it it = index.find(key);
947 //If not found, return false
948 if(it == index.end()){
949 //This name is not present in the index, wrong pointer or name!
954 block_header_t *ctrl_data = it->get_block_header();
955 intrusive_value_type *iv = intrusive_value_type::get_intrusive_value_type(ctrl_data);
957 void *values = ctrl_data->value();
958 std::size_t num = ctrl_data->m_value_bytes/table.size;
961 BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0);
962 BOOST_ASSERT(sizeof(CharT) == ctrl_data->sizeof_char());
964 //Erase node from index
967 //Destroy the headers
968 ctrl_data->~block_header_t();
969 iv->~intrusive_value_type();
971 //Call destructors and free memory
972 std::size_t destroyed;
973 table.destroy_n(values, num, destroyed);
974 this->deallocate(memory);
978 template <class CharT>
979 bool priv_generic_named_destroy(const CharT *name,
980 IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
981 ipcdetail::in_place_interface &table,
982 ipcdetail::false_ is_intrusive_index)
984 (void)is_intrusive_index;
985 typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type;
986 typedef typename index_type::iterator index_it;
987 typedef typename index_type::key_type key_type;
989 //-------------------------------
990 scoped_lock<rmutex> guard(m_header);
991 //-------------------------------
992 //Try to find the name in the index
993 index_it it = index.find(key_type (name,
994 std::char_traits<CharT>::length(name)));
996 //If not found, return false
997 if(it == index.end()){
998 //This name is not present in the index, wrong pointer or name!
1002 return this->priv_generic_named_destroy_impl<CharT>(it, index, table);
1005 template <class CharT>
1006 bool priv_generic_named_destroy_impl
1007 (const typename IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> >::iterator &it,
1008 IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
1009 ipcdetail::in_place_interface &table)
1011 typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type;
1012 typedef typename index_type::iterator index_it;
1014 //Get allocation parameters
1015 block_header_t *ctrl_data = reinterpret_cast<block_header_t*>
1016 (ipcdetail::to_raw_pointer(it->second.m_ptr));
1017 char *stored_name = static_cast<char*>(static_cast<void*>(const_cast<CharT*>(it->first.name())));
1020 //Check if the distance between the name pointer and the memory pointer
1021 //is correct (this can detect incorrect type in destruction)
1022 std::size_t num = ctrl_data->m_value_bytes/table.size;
1023 void *values = ctrl_data->value();
1026 BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0);
1027 BOOST_ASSERT(static_cast<void*>(stored_name) == static_cast<void*>(ctrl_data->template name<CharT>()));
1028 BOOST_ASSERT(sizeof(CharT) == ctrl_data->sizeof_char());
1030 //Erase node from index
1033 //Destroy the header
1034 ctrl_data->~block_header_t();
1037 if(is_node_index_t::value){
1038 index_it *ihdr = block_header_t::template
1039 to_first_header<index_it>(ctrl_data);
1047 //Call destructors and free memory
1048 std::size_t destroyed;
1049 table.destroy_n(values, num, destroyed);
1050 this->deallocate(memory);
1054 template<class CharT>
1055 void * priv_generic_named_construct
1056 (unsigned char type, const CharT *name, size_type num, bool try2find,
1057 bool dothrow, ipcdetail::in_place_interface &table,
1058 IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index, ipcdetail::true_ is_intrusive)
1061 std::size_t namelen = std::char_traits<CharT>::length(name);
1063 block_header_t block_info ( size_type(table.size*num)
1064 , size_type(table.alignment)
1069 typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type;
1070 typedef typename index_type::iterator index_it;
1071 typedef std::pair<index_it, bool> index_ib;
1073 //-------------------------------
1074 scoped_lock<rmutex> guard(m_header);
1075 //-------------------------------
1076 //Insert the node. This can throw.
1077 //First, we want to know if the key is already present before
1078 //we allocate any memory, and if the key is not present, we
1079 //want to allocate all memory in a single buffer that will
1080 //contain the name and the user buffer.
1082 //Since equal_range(key) + insert(hint, value) approach is
1083 //quite inefficient in container implementations
1084 //(they re-test if the position is correct), I've chosen
1085 //to insert the node, do an ugly un-const cast and modify
1086 //the key (which is a smart pointer) to an equivalent one
1087 index_ib insert_ret;
1089 typename index_type::insert_commit_data commit_data;
1090 typedef typename index_type::value_type intrusive_value_type;
1093 ipcdetail::intrusive_compare_key<CharT> key(name, namelen);
1094 insert_ret = index.insert_check(key, commit_data);
1104 index_it it = insert_ret.first;
1106 //If found and this is find or construct, return data
1108 if(!insert_ret.second){
1110 return it->get_block_header()->value();
1113 throw interprocess_exception(already_exists_error);
1120 //Allocates buffer for name + data, this can throw (it hurts)
1123 //Check if there is enough memory
1125 buffer_ptr = this->allocate
1126 (block_info.template total_size_with_header<intrusive_value_type>());
1129 buffer_ptr = this->allocate
1130 (block_info.template total_size_with_header<intrusive_value_type>(), std::nothrow_t());
1135 //Now construct the intrusive hook plus the header
1136 intrusive_value_type * intrusive_hdr = new(buffer_ptr) intrusive_value_type();
1137 block_header_t * hdr = new(intrusive_hdr->get_block_header())block_header_t(block_info);
1138 void *ptr = 0; //avoid gcc warning
1141 //Copy name to memory segment and insert data
1142 CharT *name_ptr = static_cast<CharT *>(hdr->template name<CharT>());
1143 std::char_traits<CharT>::copy(name_ptr, name, namelen+1);
1146 //Now commit the insertion using previous context data
1147 it = index.insert_commit(*intrusive_hdr, commit_data);
1157 //Avoid constructions if constructor is trivial
1158 //Build scoped ptr to avoid leaks with constructor exception
1159 ipcdetail::mem_algo_deallocator<segment_manager_base_type> mem
1160 (buffer_ptr, *static_cast<segment_manager_base_type*>(this));
1162 //Initialize the node value_eraser to erase inserted node
1163 //if something goes wrong. This will be executed *before*
1164 //the memory allocation as the intrusive value is built in that
1166 value_eraser<index_type> v_eraser(index, it);
1168 //Construct array, this can throw
1169 ipcdetail::array_construct(ptr, num, table);
1171 //Release rollbacks since construction was successful
1177 //!Generic named new function for
1179 template<class CharT>
1180 void * priv_generic_named_construct
1181 (unsigned char type, const CharT *name, size_type num, bool try2find, bool dothrow,
1182 ipcdetail::in_place_interface &table,
1183 IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index, ipcdetail::false_ is_intrusive)
1186 std::size_t namelen = std::char_traits<CharT>::length(name);
1188 block_header_t block_info ( size_type(table.size*num)
1189 , size_type(table.alignment)
1194 typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type;
1195 typedef typename index_type::key_type key_type;
1196 typedef typename index_type::mapped_type mapped_type;
1197 typedef typename index_type::value_type value_type;
1198 typedef typename index_type::iterator index_it;
1199 typedef std::pair<index_it, bool> index_ib;
1201 //-------------------------------
1202 scoped_lock<rmutex> guard(m_header);
1203 //-------------------------------
1204 //Insert the node. This can throw.
1205 //First, we want to know if the key is already present before
1206 //we allocate any memory, and if the key is not present, we
1207 //want to allocate all memory in a single buffer that will
1208 //contain the name and the user buffer.
1210 //Since equal_range(key) + insert(hint, value) approach is
1211 //quite inefficient in container implementations
1212 //(they re-test if the position is correct), I've chosen
1213 //to insert the node, do an ugly un-const cast and modify
1214 //the key (which is a smart pointer) to an equivalent one
1215 index_ib insert_ret;
1217 insert_ret = index.insert(value_type(key_type (name, namelen), mapped_type(0)));
1227 index_it it = insert_ret.first;
1229 //If found and this is find or construct, return data
1231 if(!insert_ret.second){
1233 block_header_t *hdr = static_cast<block_header_t*>
1234 (ipcdetail::to_raw_pointer(it->second.m_ptr));
1235 return hdr->value();
1239 //Initialize the node value_eraser to erase inserted node
1240 //if something goes wrong
1241 value_eraser<index_type> v_eraser(index, it);
1243 //Allocates buffer for name + data, this can throw (it hurts)
1245 block_header_t * hdr;
1247 //Allocate and construct the headers
1248 if(is_node_index_t::value){
1249 size_type total_size = block_info.template total_size_with_header<index_it>();
1251 buffer_ptr = this->allocate(total_size);
1254 buffer_ptr = this->allocate(total_size, std::nothrow_t());
1258 index_it *idr = new(buffer_ptr) index_it(it);
1259 hdr = block_header_t::template from_first_header<index_it>(idr);
1263 buffer_ptr = this->allocate(block_info.total_size());
1266 buffer_ptr = this->allocate(block_info.total_size(), std::nothrow_t());
1270 hdr = static_cast<block_header_t*>(buffer_ptr);
1273 hdr = new(hdr)block_header_t(block_info);
1274 void *ptr = 0; //avoid gcc warning
1277 //Copy name to memory segment and insert data
1278 CharT *name_ptr = static_cast<CharT *>(hdr->template name<CharT>());
1279 std::char_traits<CharT>::copy(name_ptr, name, namelen+1);
1281 //Do the ugly cast, please mama, forgive me!
1282 //This new key points to an identical string, so it must have the
1283 //same position than the overwritten key according to the predicate
1284 const_cast<key_type &>(it->first).name(name_ptr);
1285 it->second.m_ptr = hdr;
1287 //Build scoped ptr to avoid leaks with constructor exception
1288 ipcdetail::mem_algo_deallocator<segment_manager_base_type> mem
1289 (buffer_ptr, *static_cast<segment_manager_base_type*>(this));
1291 //Construct array, this can throw
1292 ipcdetail::array_construct(ptr, num, table);
1294 //All constructors successful, we don't want to release memory
1297 //Release node v_eraser since construction was successful
1303 //!Returns the this pointer
1304 segment_manager *get_this_pointer()
1307 typedef typename MemoryAlgorithm::mutex_family::recursive_mutex_type rmutex;
1309 scoped_lock<rmutex> priv_get_lock(bool use_lock)
1311 scoped_lock<rmutex> local(m_header, defer_lock);
1315 return scoped_lock<rmutex>(boost::move(local));
1318 //!This struct includes needed data and derives from
1319 //!rmutex to allow EBO when using null interprocess_mutex
1323 named_index_t m_named_index;
1324 unique_index_t m_unique_index;
1326 header_t(segment_manager_base_t *segment_mngr_base)
1327 : m_named_index (segment_mngr_base)
1328 , m_unique_index(segment_mngr_base)
1332 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
1336 }} //namespace boost { namespace interprocess
1338 #include <boost/interprocess/detail/config_end.hpp>
1340 #endif //#ifndef BOOST_INTERPROCESS_SEGMENT_MANAGER_HPP