1 //////////////////////////////////////////////////////////////////////////////
3 // (C) Copyright Ion Gaztanaga 2005-2009. 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
14 #if (defined _MSC_VER) && (_MSC_VER >= 1200)
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/interprocess/detail/move.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;
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;
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 size, size_type reserved_bytes)
98 : MemoryAlgorithm(size, 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); }
125 //Experimental. Dont' use.
126 //!Allocates n_elements of
127 //!elem_size bytes. Throws bad_alloc on failure.
128 multiallocation_chain allocate_many(size_type elem_bytes, size_type num_elements)
130 multiallocation_chain mem(MemoryAlgorithm::allocate_many(elem_bytes, num_elements));
131 if(mem.empty()) throw bad_alloc();
132 return boost::interprocess::move(mem);
135 //!Allocates n_elements, each one of
136 //!element_lenghts[i]*sizeof_element bytes. Throws bad_alloc on failure.
137 multiallocation_chain allocate_many
138 (const size_type *element_lenghts, size_type n_elements, size_type sizeof_element = 1)
140 multiallocation_chain mem(MemoryAlgorithm::allocate_many(element_lenghts, n_elements, sizeof_element));
141 if(mem.empty()) throw bad_alloc();
142 return boost::interprocess::move(mem);
145 //!Allocates n_elements of
146 //!elem_size bytes. Returns a default constructed iterator on failure.
147 multiallocation_chain allocate_many
148 (size_type elem_bytes, size_type num_elements, std::nothrow_t)
149 { return MemoryAlgorithm::allocate_many(elem_bytes, num_elements); }
151 //!Allocates n_elements, each one of
152 //!element_lenghts[i]*sizeof_element bytes.
153 //!Returns a default constructed iterator on failure.
154 multiallocation_chain allocate_many
155 (const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, std::nothrow_t)
156 { return MemoryAlgorithm::allocate_many(elem_sizes, n_elements, sizeof_element); }
158 //!Deallocates elements pointed by the
159 //!multiallocation iterator range.
160 void deallocate_many(multiallocation_chain chain)
161 { MemoryAlgorithm::deallocate_many(boost::interprocess::move(chain)); }
165 //!Allocates nbytes bytes. Throws boost::interprocess::bad_alloc
167 void * allocate(size_type nbytes)
169 void * ret = MemoryAlgorithm::allocate(nbytes);
175 //!Allocates nbytes bytes. This function is only used in
176 //!single-segment management. Never throws
177 void * allocate_aligned (size_type nbytes, size_type alignment, std::nothrow_t)
178 { return MemoryAlgorithm::allocate_aligned(nbytes, alignment); }
180 //!Allocates nbytes bytes. This function is only used in
181 //!single-segment management. Throws bad_alloc when fails
182 void * allocate_aligned(size_type nbytes, size_type alignment)
184 void * ret = MemoryAlgorithm::allocate_aligned(nbytes, alignment);
192 allocation_command (boost::interprocess::allocation_type command, size_type limit_size,
193 size_type preferred_size,size_type &received_size,
196 std::pair<T *, bool> ret = MemoryAlgorithm::allocation_command
197 ( command | boost::interprocess::nothrow_allocation, limit_size, preferred_size, received_size
199 if(!(command & boost::interprocess::nothrow_allocation) && !ret.first)
204 std::pair<void *, bool>
205 raw_allocation_command (boost::interprocess::allocation_type command, size_type limit_objects,
206 size_type preferred_objects,size_type &received_objects,
207 void *reuse_ptr = 0, size_type sizeof_object = 1)
209 std::pair<void *, bool> ret = MemoryAlgorithm::raw_allocation_command
210 ( command | boost::interprocess::nothrow_allocation, limit_objects, preferred_objects, received_objects
211 , reuse_ptr, sizeof_object);
212 if(!(command & boost::interprocess::nothrow_allocation) && !ret.first)
217 //!Deallocates the bytes allocated with allocate/allocate_many()
219 void deallocate (void *addr)
220 { MemoryAlgorithm::deallocate(addr); }
222 //!Increases managed memory in extra_size bytes more. This only works
223 //!with single-segment management.
224 void grow(size_type extra_size)
225 { MemoryAlgorithm::grow(extra_size); }
227 //!Decreases managed memory to the minimum. This only works
228 //!with single-segment management.
230 { MemoryAlgorithm::shrink_to_fit(); }
232 //!Returns the result of "all_memory_deallocated()" function
233 //!of the used memory algorithm
234 bool all_memory_deallocated()
235 { return MemoryAlgorithm::all_memory_deallocated(); }
237 //!Returns the result of "check_sanity()" function
238 //!of the used memory algorithm
240 { return MemoryAlgorithm::check_sanity(); }
242 //!Writes to zero free memory (memory not yet allocated)
243 //!of the memory algorithm
244 void zero_free_memory()
245 { MemoryAlgorithm::zero_free_memory(); }
247 //!Returns the size of the buffer previously allocated pointed by ptr
248 size_type size(const void *ptr) const
249 { return MemoryAlgorithm::size(ptr); }
253 void * prot_anonymous_construct
254 (size_type num, bool dothrow, ipcdetail::in_place_interface &table)
256 typedef ipcdetail::block_header<size_type> block_header_t;
257 block_header_t block_info ( size_type(table.size*num)
258 , size_type(table.alignment)
264 void *ptr_struct = this->allocate(block_info.total_size(), std::nothrow_t());
266 //Check if there is enough memory
276 //Build scoped ptr to avoid leaks with constructor exception
277 ipcdetail::mem_algo_deallocator<MemoryAlgorithm> mem(ptr_struct, *this);
279 //Now construct the header
280 block_header_t * hdr = new(ptr_struct) block_header_t(block_info);
281 void *ptr = 0; //avoid gcc warning
284 //Now call constructors
285 ipcdetail::array_construct(ptr, num, table);
287 //All constructors successful, we don't want erase memory
292 //!Calls the destructor and makes an anonymous deallocate
293 void prot_anonymous_destroy(const void *object, ipcdetail::in_place_interface &table)
296 //Get control data from associated with this object
297 typedef ipcdetail::block_header<size_type> block_header_t;
298 block_header_t *ctrl_data = block_header_t::block_header_from_value(object, table.size, table.alignment);
300 //-------------------------------
301 //scoped_lock<rmutex> guard(m_header);
302 //-------------------------------
304 if(ctrl_data->alloc_type() != anonymous_type){
305 //This is not an anonymous object, the pointer is wrong!
309 //Call destructors and free memory
310 //Build scoped ptr to avoid leaks with destructor exception
311 std::size_t destroyed = 0;
312 table.destroy_n(const_cast<void*>(object), ctrl_data->m_value_bytes/table.size, destroyed);
313 this->deallocate(ctrl_data);
318 //!This object is placed in the beginning of memory segment and
319 //!implements the allocation (named or anonymous) of portions
320 //!of the segment. This object contains two indexes that
321 //!maintain an association between a name and a portion of the segment.
323 //!The first index contains the mappings for normal named objects using the
324 //!char type specified in the template parameter.
326 //!The second index contains the association for unique instances. The key will
327 //!be the const char * returned from type_info.name() function for the unique
328 //!type to be constructed.
330 //!segment_manager<CharType, MemoryAlgorithm, IndexType> inherits publicly
331 //!from segment_manager_base<MemoryAlgorithm> and inherits from it
332 //!many public functions related to anonymous object and raw memory allocation.
333 //!See segment_manager_base reference to know about those functions.
334 template<class CharType
335 ,class MemoryAlgorithm
336 ,template<class IndexConfig> class IndexType>
337 class segment_manager
338 : public segment_manager_base<MemoryAlgorithm>
343 segment_manager(const segment_manager &);
344 segment_manager &operator=(const segment_manager &);
345 typedef segment_manager_base<MemoryAlgorithm> Base;
349 typedef MemoryAlgorithm memory_algorithm;
350 typedef typename Base::void_pointer void_pointer;
351 typedef typename Base::size_type size_type;
352 typedef typename Base::difference_type difference_type;
353 typedef CharType char_type;
355 typedef segment_manager_base<MemoryAlgorithm> segment_manager_base_type;
357 static const size_type PayloadPerAllocation = Base::PayloadPerAllocation;
361 typedef ipcdetail::block_header<size_type> block_header_t;
362 typedef ipcdetail::index_config<CharType, MemoryAlgorithm> index_config_named;
363 typedef ipcdetail::index_config<char, MemoryAlgorithm> index_config_unique;
364 typedef IndexType<index_config_named> index_type;
365 typedef ipcdetail::bool_<is_intrusive_index<index_type>::value > is_intrusive_t;
366 typedef ipcdetail::bool_<is_node_index<index_type>::value> is_node_index_t;
369 typedef IndexType<index_config_named> named_index_t;
370 typedef IndexType<index_config_unique> unique_index_t;
371 typedef ipcdetail::char_ptr_holder<CharType> char_ptr_holder_t;
372 typedef ipcdetail::segment_manager_iterator_transform
373 <typename named_index_t::const_iterator
374 ,is_intrusive_index<index_type>::value> named_transform;
376 typedef ipcdetail::segment_manager_iterator_transform
377 <typename unique_index_t::const_iterator
378 ,is_intrusive_index<index_type>::value> unique_transform;
381 typedef typename Base::mutex_family mutex_family;
383 typedef transform_iterator
384 <typename named_index_t::const_iterator, named_transform> const_named_iterator;
385 typedef transform_iterator
386 <typename unique_index_t::const_iterator, unique_transform> const_unique_iterator;
390 //!Constructor proxy object definition helper class
392 struct construct_proxy
394 typedef ipcdetail::named_proxy<segment_manager, T, false> type;
397 //!Constructor proxy object definition helper class
399 struct construct_iter_proxy
401 typedef ipcdetail::named_proxy<segment_manager, T, true> type;
406 //!Constructor of the segment manager
407 //!"size" is the size of the memory segment where
408 //!the segment manager is being constructed.
410 segment_manager(size_type size)
411 : Base(size, priv_get_reserved_bytes())
412 , m_header(static_cast<Base*>(get_this_pointer()))
414 (void) anonymous_instance; (void) unique_instance;
415 BOOST_ASSERT(static_cast<const void*>(this) == static_cast<const void*>(static_cast<Base*>(this)));
418 //!Tries to find a previous named allocation. Returns the address
419 //!and the object count. On failure the first member of the
420 //!returned pair is 0.
422 std::pair<T*, size_type> find (const CharType* name)
423 { return this->priv_find_impl<T>(name, true); }
425 //!Tries to find a previous unique allocation. Returns the address
426 //!and the object count. On failure the first member of the
427 //!returned pair is 0.
429 std::pair<T*, size_type> find (const ipcdetail::unique_instance_t* name)
430 { return this->priv_find_impl<T>(name, true); }
432 //!Tries to find a previous named allocation. Returns the address
433 //!and the object count. On failure the first member of the
434 //!returned pair is 0. This search is not mutex-protected!
436 std::pair<T*, size_type> find_no_lock (const CharType* name)
437 { return this->priv_find_impl<T>(name, false); }
439 //!Tries to find a previous unique allocation. Returns the address
440 //!and the object count. On failure the first member of the
441 //!returned pair is 0. This search is not mutex-protected!
443 std::pair<T*, size_type> find_no_lock (const ipcdetail::unique_instance_t* name)
444 { return this->priv_find_impl<T>(name, false); }
446 //!Returns throwing "construct" proxy
449 typename construct_proxy<T>::type
450 construct(char_ptr_holder_t name)
451 { return typename construct_proxy<T>::type (this, name, false, true); }
453 //!Returns throwing "search or construct" proxy
456 typename construct_proxy<T>::type find_or_construct(char_ptr_holder_t name)
457 { return typename construct_proxy<T>::type (this, name, true, true); }
459 //!Returns no throwing "construct" proxy
462 typename construct_proxy<T>::type
463 construct(char_ptr_holder_t name, std::nothrow_t)
464 { return typename construct_proxy<T>::type (this, name, false, false); }
466 //!Returns no throwing "search or construct"
469 typename construct_proxy<T>::type
470 find_or_construct(char_ptr_holder_t name, std::nothrow_t)
471 { return typename construct_proxy<T>::type (this, name, true, false); }
473 //!Returns throwing "construct from iterators" proxy object
475 typename construct_iter_proxy<T>::type
476 construct_it(char_ptr_holder_t name)
477 { return typename construct_iter_proxy<T>::type (this, name, false, true); }
479 //!Returns throwing "search or construct from iterators"
482 typename construct_iter_proxy<T>::type
483 find_or_construct_it(char_ptr_holder_t name)
484 { return typename construct_iter_proxy<T>::type (this, name, true, true); }
486 //!Returns no throwing "construct from iterators"
489 typename construct_iter_proxy<T>::type
490 construct_it(char_ptr_holder_t name, std::nothrow_t)
491 { return typename construct_iter_proxy<T>::type (this, name, false, false); }
493 //!Returns no throwing "search or construct from iterators"
496 typename construct_iter_proxy<T>::type
497 find_or_construct_it(char_ptr_holder_t name, std::nothrow_t)
498 { return typename construct_iter_proxy<T>::type (this, name, true, false); }
500 //!Calls object function blocking recursive interprocess_mutex and guarantees that
501 //!no new named_alloc or destroy will be executed by any process while
502 //!executing the object function call*/
503 template <class Func>
504 void atomic_func(Func &f)
505 { scoped_lock<rmutex> guard(m_header); f(); }
507 //!Tries to calls a functor guaranteeing that no new construction, search or
508 //!destruction will be executed by any process while executing the object
509 //!function call. If the atomic function can't be immediatelly executed
510 //!because the internal mutex is already locked, returns false.
511 //!If the functor throws, this function throws.
512 template <class Func>
513 bool try_atomic_func(Func &f)
515 scoped_lock<rmutex> guard(m_header, try_to_lock);
525 //!Destroys a previously created unique instance.
526 //!Returns false if the object was not present.
528 bool destroy(const ipcdetail::unique_instance_t *)
530 ipcdetail::placement_destroy<T> dtor;
531 return this->priv_generic_named_destroy<char>
532 (typeid(T).name(), m_header.m_unique_index, dtor, is_intrusive_t());
535 //!Destroys the named object with
536 //!the given name. Returns false if that object can't be found.
538 bool destroy(const CharType *name)
540 ipcdetail::placement_destroy<T> dtor;
541 return this->priv_generic_named_destroy<CharType>
542 (name, m_header.m_named_index, dtor, is_intrusive_t());
545 //!Destroys an anonymous, unique or named object
546 //!using it's address
548 void destroy_ptr(const T *p)
550 //If T is void transform it to char
551 typedef typename ipcdetail::char_if_void<T>::type data_t;
552 ipcdetail::placement_destroy<data_t> dtor;
553 priv_destroy_ptr(p, dtor);
556 //!Returns the name of an object created with construct/find_or_construct
557 //!functions. Does not throw
559 static const CharType *get_instance_name(const T *ptr)
560 { return priv_get_instance_name(block_header_t::block_header_from_value(ptr)); }
562 //!Returns the length of an object created with construct/find_or_construct
563 //!functions. Does not throw.
565 static size_type get_instance_length(const T *ptr)
566 { return priv_get_instance_length(block_header_t::block_header_from_value(ptr), sizeof(T)); }
568 //!Returns is the the name of an object created with construct/find_or_construct
569 //!functions. Does not throw
571 static instance_type get_instance_type(const T *ptr)
572 { return priv_get_instance_type(block_header_t::block_header_from_value(ptr)); }
574 //!Preallocates needed index resources to optimize the
575 //!creation of "num" named objects in the managed memory segment.
576 //!Can throw boost::interprocess::bad_alloc if there is no enough memory.
577 void reserve_named_objects(size_type num)
579 //-------------------------------
580 scoped_lock<rmutex> guard(m_header);
581 //-------------------------------
582 m_header.m_named_index.reserve(num);
585 //!Preallocates needed index resources to optimize the
586 //!creation of "num" unique objects in the managed memory segment.
587 //!Can throw boost::interprocess::bad_alloc if there is no enough memory.
588 void reserve_unique_objects(size_type num)
590 //-------------------------------
591 scoped_lock<rmutex> guard(m_header);
592 //-------------------------------
593 m_header.m_unique_index.reserve(num);
596 //!Calls shrink_to_fit in both named and unique object indexes
597 //!to try to free unused memory from those indexes.
598 void shrink_to_fit_indexes()
600 //-------------------------------
601 scoped_lock<rmutex> guard(m_header);
602 //-------------------------------
603 m_header.m_named_index.shrink_to_fit();
604 m_header.m_unique_index.shrink_to_fit();
607 //!Returns the number of named objects stored in
609 size_type get_num_named_objects()
611 //-------------------------------
612 scoped_lock<rmutex> guard(m_header);
613 //-------------------------------
614 return m_header.m_named_index.size();
617 //!Returns the number of unique objects stored in
619 size_type get_num_unique_objects()
621 //-------------------------------
622 scoped_lock<rmutex> guard(m_header);
623 //-------------------------------
624 return m_header.m_unique_index.size();
627 //!Obtains the minimum size needed by the
629 static size_type get_min_size()
630 { return Base::get_min_size(priv_get_reserved_bytes()); }
632 //!Returns a constant iterator to the beginning of the information about
633 //!the named allocations performed in this segment manager
634 const_named_iterator named_begin() const
636 return make_transform_iterator
637 (m_header.m_named_index.begin(), named_transform());
640 //!Returns a constant iterator to the end of the information about
641 //!the named allocations performed in this segment manager
642 const_named_iterator named_end() const
644 return make_transform_iterator
645 (m_header.m_named_index.end(), named_transform());
648 //!Returns a constant iterator to the beginning of the information about
649 //!the unique allocations performed in this segment manager
650 const_unique_iterator unique_begin() const
652 return make_transform_iterator
653 (m_header.m_unique_index.begin(), unique_transform());
656 //!Returns a constant iterator to the end of the information about
657 //!the unique allocations performed in this segment manager
658 const_unique_iterator unique_end() const
660 return make_transform_iterator
661 (m_header.m_unique_index.end(), unique_transform());
664 //!This is the default allocator to allocate types T
665 //!from this managed segment
669 typedef boost::interprocess::allocator<T, segment_manager> type;
672 //!Returns an instance of the default allocator for type T
673 //!initialized that allocates memory from this segment manager.
675 typename allocator<T>::type
677 { return typename allocator<T>::type(this); }
679 //!This is the default deleter to delete types T
680 //!from this managed segment.
684 typedef boost::interprocess::deleter<T, segment_manager> type;
687 //!Returns an instance of the default allocator for type T
688 //!initialized that allocates memory from this segment manager.
690 typename deleter<T>::type
692 { return typename deleter<T>::type(this); }
696 //!Generic named/anonymous new function. Offers all the possibilities,
697 //!such as throwing, search before creating, and the constructor is
698 //!encapsulated in an object function.
700 T *generic_construct(const CharType *name,
704 ipcdetail::in_place_interface &table)
706 return static_cast<T*>
707 (priv_generic_construct(name, num, try2find, dothrow, table));
711 //!Tries to find a previous named allocation. Returns the address
712 //!and the object count. On failure the first member of the
713 //!returned pair is 0.
715 std::pair<T*, size_type> priv_find_impl (const CharType* name, bool lock)
717 //The name can't be null, no anonymous object can be found by name
718 BOOST_ASSERT(name != 0);
719 ipcdetail::placement_destroy<T> table;
723 if(name == reinterpret_cast<const CharType*>(-1)){
724 ret = priv_generic_find<char> (typeid(T).name(), m_header.m_unique_index, table, size, is_intrusive_t(), lock);
727 ret = priv_generic_find<CharType> (name, m_header.m_named_index, table, size, is_intrusive_t(), lock);
729 return std::pair<T*, size_type>(static_cast<T*>(ret), size);
732 //!Tries to find a previous unique allocation. Returns the address
733 //!and the object count. On failure the first member of the
734 //!returned pair is 0.
736 std::pair<T*, size_type> priv_find__impl (const ipcdetail::unique_instance_t* name, bool lock)
738 ipcdetail::placement_destroy<T> table;
740 void *ret = priv_generic_find<char>(name, m_header.m_unique_index, table, size, is_intrusive_t(), lock);
741 return std::pair<T*, size_type>(static_cast<T*>(ret), size);
744 void *priv_generic_construct(const CharType *name,
748 ipcdetail::in_place_interface &table)
751 //Security overflow check
752 if(num > ((std::size_t)-1)/table.size){
759 ret = this->prot_anonymous_construct(num, dothrow, table);
761 else if(name == reinterpret_cast<const CharType*>(-1)){
762 ret = this->priv_generic_named_construct<char>
763 (unique_type, table.type_name, num, try2find, dothrow, table, m_header.m_unique_index, is_intrusive_t());
766 ret = this->priv_generic_named_construct<CharType>
767 (named_type, name, num, try2find, dothrow, table, m_header.m_named_index, is_intrusive_t());
772 void priv_destroy_ptr(const void *ptr, ipcdetail::in_place_interface &dtor)
774 block_header_t *ctrl_data = block_header_t::block_header_from_value(ptr, dtor.size, dtor.alignment);
775 switch(ctrl_data->alloc_type()){
777 this->prot_anonymous_destroy(ptr, dtor);
781 this->priv_generic_named_destroy<CharType>
782 (ctrl_data, m_header.m_named_index, dtor, is_node_index_t());
786 this->priv_generic_named_destroy<char>
787 (ctrl_data, m_header.m_unique_index, dtor, is_node_index_t());
791 //This type is unknown, bad pointer passed to this function!
797 //!Returns the name of an object created with construct/find_or_construct
798 //!functions. Does not throw
799 static const CharType *priv_get_instance_name(block_header_t *ctrl_data)
801 boost::interprocess::allocation_type type = ctrl_data->alloc_type();
802 if(type != named_type){
803 BOOST_ASSERT((type == anonymous_type && ctrl_data->m_num_char == 0) ||
804 (type == unique_type && ctrl_data->m_num_char != 0) );
807 CharType *name = static_cast<CharType*>(ctrl_data->template name<CharType>());
810 BOOST_ASSERT(ctrl_data->sizeof_char() == sizeof(CharType));
811 BOOST_ASSERT(ctrl_data->m_num_char == std::char_traits<CharType>::length(name));
815 static size_type priv_get_instance_length(block_header_t *ctrl_data, size_type sizeofvalue)
818 BOOST_ASSERT((ctrl_data->value_bytes() %sizeofvalue) == 0);
819 return ctrl_data->value_bytes()/sizeofvalue;
822 //!Returns is the the name of an object created with construct/find_or_construct
823 //!functions. Does not throw
824 static instance_type priv_get_instance_type(block_header_t *ctrl_data)
827 BOOST_ASSERT((instance_type)ctrl_data->alloc_type() < max_allocation_type);
828 return (instance_type)ctrl_data->alloc_type();
831 static size_type priv_get_reserved_bytes()
833 //Get the number of bytes until the end of (*this)
834 //beginning in the end of the Base base.
835 return sizeof(segment_manager) - sizeof(Base);
838 template <class CharT>
839 void *priv_generic_find
841 IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
842 ipcdetail::in_place_interface &table,
844 ipcdetail::true_ is_intrusive,
848 typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type;
849 typedef ipcdetail::index_key<CharT, void_pointer> index_key_t;
850 typedef typename index_type::iterator index_it;
852 //-------------------------------
853 scoped_lock<rmutex> guard(priv_get_lock(use_lock));
854 //-------------------------------
856 ipcdetail::intrusive_compare_key<CharT> key
857 (name, std::char_traits<CharT>::length(name));
858 index_it it = index.find(key);
860 //Initialize return values
864 //If found, assign values
865 if(it != index.end()){
867 block_header_t *ctrl_data = it->get_block_header();
870 BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0);
871 BOOST_ASSERT(ctrl_data->sizeof_char() == sizeof(CharT));
872 ret_ptr = ctrl_data->value();
873 length = ctrl_data->m_value_bytes/table.size;
878 template <class CharT>
879 void *priv_generic_find
881 IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
882 ipcdetail::in_place_interface &table,
884 ipcdetail::false_ is_intrusive,
888 typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type;
889 typedef typename index_type::key_type key_type;
890 typedef typename index_type::iterator index_it;
892 //-------------------------------
893 scoped_lock<rmutex> guard(priv_get_lock(use_lock));
894 //-------------------------------
896 index_it it = index.find(key_type(name, std::char_traits<CharT>::length(name)));
898 //Initialize return values
902 //If found, assign values
903 if(it != index.end()){
905 block_header_t *ctrl_data = reinterpret_cast<block_header_t*>
906 (ipcdetail::get_pointer(it->second.m_ptr));
909 BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0);
910 BOOST_ASSERT(ctrl_data->sizeof_char() == sizeof(CharT));
911 ret_ptr = ctrl_data->value();
912 length = ctrl_data->m_value_bytes/table.size;
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::true_ is_node_index)
925 typedef typename IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> >::iterator index_it;
927 index_it *ihdr = block_header_t::template to_first_header<index_it>(block_header);
928 return this->priv_generic_named_destroy_impl<CharT>(*ihdr, index, table);
931 template <class CharT>
932 bool priv_generic_named_destroy
933 (block_header_t *block_header,
934 IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
935 ipcdetail::in_place_interface &table,
936 ipcdetail::false_ is_node_index)
939 CharT *name = static_cast<CharT*>(block_header->template name<CharT>());
940 return this->priv_generic_named_destroy<CharT>(name, index, table, is_intrusive_t());
943 template <class CharT>
944 bool priv_generic_named_destroy(const CharT *name,
945 IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
946 ipcdetail::in_place_interface &table,
947 ipcdetail::true_ is_intrusive_index)
949 (void)is_intrusive_index;
950 typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type;
951 typedef ipcdetail::index_key<CharT, void_pointer> index_key_t;
952 typedef typename index_type::iterator index_it;
953 typedef typename index_type::value_type intrusive_value_type;
955 //-------------------------------
956 scoped_lock<rmutex> guard(m_header);
957 //-------------------------------
959 ipcdetail::intrusive_compare_key<CharT> key
960 (name, std::char_traits<CharT>::length(name));
961 index_it it = index.find(key);
963 //If not found, return false
964 if(it == index.end()){
965 //This name is not present in the index, wrong pointer or name!
970 block_header_t *ctrl_data = it->get_block_header();
971 intrusive_value_type *iv = intrusive_value_type::get_intrusive_value_type(ctrl_data);
973 void *values = ctrl_data->value();
974 std::size_t num = ctrl_data->m_value_bytes/table.size;
977 BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0);
978 BOOST_ASSERT(sizeof(CharT) == ctrl_data->sizeof_char());
980 //Erase node from index
983 //Destroy the headers
984 ctrl_data->~block_header_t();
985 iv->~intrusive_value_type();
987 //Call destructors and free memory
988 std::size_t destroyed;
989 table.destroy_n(values, num, destroyed);
990 this->deallocate(memory);
994 template <class CharT>
995 bool priv_generic_named_destroy(const CharT *name,
996 IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
997 ipcdetail::in_place_interface &table,
998 ipcdetail::false_ is_intrusive_index)
1000 (void)is_intrusive_index;
1001 typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type;
1002 typedef typename index_type::iterator index_it;
1003 typedef typename index_type::key_type key_type;
1005 //-------------------------------
1006 scoped_lock<rmutex> guard(m_header);
1007 //-------------------------------
1008 //Try to find the name in the index
1009 index_it it = index.find(key_type (name,
1010 std::char_traits<CharT>::length(name)));
1012 //If not found, return false
1013 if(it == index.end()){
1014 //This name is not present in the index, wrong pointer or name!
1018 return this->priv_generic_named_destroy_impl<CharT>(it, index, table);
1021 template <class CharT>
1022 bool priv_generic_named_destroy_impl
1023 (const typename IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> >::iterator &it,
1024 IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
1025 ipcdetail::in_place_interface &table)
1027 typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type;
1028 typedef typename index_type::iterator index_it;
1030 //Get allocation parameters
1031 block_header_t *ctrl_data = reinterpret_cast<block_header_t*>
1032 (ipcdetail::get_pointer(it->second.m_ptr));
1033 char *stored_name = static_cast<char*>(static_cast<void*>(const_cast<CharT*>(it->first.name())));
1036 //Check if the distance between the name pointer and the memory pointer
1037 //is correct (this can detect incorrect type in destruction)
1038 std::size_t num = ctrl_data->m_value_bytes/table.size;
1039 void *values = ctrl_data->value();
1042 BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0);
1043 BOOST_ASSERT(static_cast<void*>(stored_name) == static_cast<void*>(ctrl_data->template name<CharT>()));
1044 BOOST_ASSERT(sizeof(CharT) == ctrl_data->sizeof_char());
1046 //Erase node from index
1049 //Destroy the header
1050 ctrl_data->~block_header_t();
1053 if(is_node_index_t::value){
1054 index_it *ihdr = block_header_t::template
1055 to_first_header<index_it>(ctrl_data);
1063 //Call destructors and free memory
1064 std::size_t destroyed;
1065 table.destroy_n(values, num, destroyed);
1066 this->deallocate(memory);
1070 template<class CharT>
1071 void * priv_generic_named_construct(unsigned char type,
1076 ipcdetail::in_place_interface &table,
1077 IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
1078 ipcdetail::true_ is_intrusive)
1081 std::size_t namelen = std::char_traits<CharT>::length(name);
1083 block_header_t block_info ( size_type(table.size*num)
1084 , size_type(table.alignment)
1089 typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type;
1090 typedef typename index_type::iterator index_it;
1091 typedef std::pair<index_it, bool> index_ib;
1093 //-------------------------------
1094 scoped_lock<rmutex> guard(m_header);
1095 //-------------------------------
1096 //Insert the node. This can throw.
1097 //First, we want to know if the key is already present before
1098 //we allocate any memory, and if the key is not present, we
1099 //want to allocate all memory in a single buffer that will
1100 //contain the name and the user buffer.
1102 //Since equal_range(key) + insert(hint, value) approach is
1103 //quite inefficient in container implementations
1104 //(they re-test if the position is correct), I've chosen
1105 //to insert the node, do an ugly un-const cast and modify
1106 //the key (which is a smart pointer) to an equivalent one
1107 index_ib insert_ret;
1109 typename index_type::insert_commit_data commit_data;
1110 typedef typename index_type::value_type intrusive_value_type;
1113 ipcdetail::intrusive_compare_key<CharT> key(name, namelen);
1114 insert_ret = index.insert_check(key, commit_data);
1124 index_it it = insert_ret.first;
1126 //If found and this is find or construct, return data
1128 if(!insert_ret.second){
1130 return it->get_block_header()->value();
1133 throw interprocess_exception(already_exists_error);
1140 //Allocates buffer for name + data, this can throw (it hurts)
1143 //Check if there is enough memory
1145 buffer_ptr = this->allocate
1146 (block_info.template total_size_with_header<intrusive_value_type>());
1149 buffer_ptr = this->allocate
1150 (block_info.template total_size_with_header<intrusive_value_type>(), std::nothrow_t());
1155 //Now construct the intrusive hook plus the header
1156 intrusive_value_type * intrusive_hdr = new(buffer_ptr) intrusive_value_type();
1157 block_header_t * hdr = new(intrusive_hdr->get_block_header())block_header_t(block_info);
1158 void *ptr = 0; //avoid gcc warning
1161 //Copy name to memory segment and insert data
1162 CharT *name_ptr = static_cast<CharT *>(hdr->template name<CharT>());
1163 std::char_traits<CharT>::copy(name_ptr, name, namelen+1);
1166 //Now commit the insertion using previous context data
1167 it = index.insert_commit(*intrusive_hdr, commit_data);
1177 //Avoid constructions if constructor is trivial
1178 //Build scoped ptr to avoid leaks with constructor exception
1179 ipcdetail::mem_algo_deallocator<segment_manager_base_type> mem
1180 (buffer_ptr, *static_cast<segment_manager_base_type*>(this));
1182 //Initialize the node value_eraser to erase inserted node
1183 //if something goes wrong. This will be executed *before*
1184 //the memory allocation as the intrusive value is built in that
1186 value_eraser<index_type> v_eraser(index, it);
1188 //Construct array, this can throw
1189 ipcdetail::array_construct(ptr, num, table);
1191 //Release rollbacks since construction was successful
1197 //!Generic named new function for
1199 template<class CharT>
1200 void * priv_generic_named_construct(unsigned char type,
1205 ipcdetail::in_place_interface &table,
1206 IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
1207 ipcdetail::false_ is_intrusive)
1210 std::size_t namelen = std::char_traits<CharT>::length(name);
1212 block_header_t block_info ( size_type(table.size*num)
1213 , size_type(table.alignment)
1218 typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type;
1219 typedef typename index_type::key_type key_type;
1220 typedef typename index_type::mapped_type mapped_type;
1221 typedef typename index_type::value_type value_type;
1222 typedef typename index_type::iterator index_it;
1223 typedef std::pair<index_it, bool> index_ib;
1225 //-------------------------------
1226 scoped_lock<rmutex> guard(m_header);
1227 //-------------------------------
1228 //Insert the node. This can throw.
1229 //First, we want to know if the key is already present before
1230 //we allocate any memory, and if the key is not present, we
1231 //want to allocate all memory in a single buffer that will
1232 //contain the name and the user buffer.
1234 //Since equal_range(key) + insert(hint, value) approach is
1235 //quite inefficient in container implementations
1236 //(they re-test if the position is correct), I've chosen
1237 //to insert the node, do an ugly un-const cast and modify
1238 //the key (which is a smart pointer) to an equivalent one
1239 index_ib insert_ret;
1241 insert_ret = index.insert(value_type(key_type (name, namelen), mapped_type(0)));
1251 index_it it = insert_ret.first;
1253 //If found and this is find or construct, return data
1255 if(!insert_ret.second){
1257 block_header_t *hdr = static_cast<block_header_t*>
1258 (ipcdetail::get_pointer(it->second.m_ptr));
1259 return hdr->value();
1263 //Initialize the node value_eraser to erase inserted node
1264 //if something goes wrong
1265 value_eraser<index_type> v_eraser(index, it);
1267 //Allocates buffer for name + data, this can throw (it hurts)
1269 block_header_t * hdr;
1271 //Allocate and construct the headers
1272 if(is_node_index_t::value){
1273 size_type total_size = block_info.template total_size_with_header<index_it>();
1275 buffer_ptr = this->allocate(total_size);
1278 buffer_ptr = this->allocate(total_size, std::nothrow_t());
1282 index_it *idr = new(buffer_ptr) index_it(it);
1283 hdr = block_header_t::template from_first_header<index_it>(idr);
1287 buffer_ptr = this->allocate(block_info.total_size());
1290 buffer_ptr = this->allocate(block_info.total_size(), std::nothrow_t());
1294 hdr = static_cast<block_header_t*>(buffer_ptr);
1297 hdr = new(hdr)block_header_t(block_info);
1298 void *ptr = 0; //avoid gcc warning
1301 //Copy name to memory segment and insert data
1302 CharT *name_ptr = static_cast<CharT *>(hdr->template name<CharT>());
1303 std::char_traits<CharT>::copy(name_ptr, name, namelen+1);
1305 //Do the ugly cast, please mama, forgive me!
1306 //This new key points to an identical string, so it must have the
1307 //same position than the overwritten key according to the predicate
1308 const_cast<key_type &>(it->first).name(name_ptr);
1309 it->second.m_ptr = hdr;
1311 //Build scoped ptr to avoid leaks with constructor exception
1312 ipcdetail::mem_algo_deallocator<segment_manager_base_type> mem
1313 (buffer_ptr, *static_cast<segment_manager_base_type*>(this));
1315 //Construct array, this can throw
1316 ipcdetail::array_construct(ptr, num, table);
1318 //All constructors successful, we don't want to release memory
1321 //Release node v_eraser since construction was successful
1327 //!Returns the this pointer
1328 segment_manager *get_this_pointer()
1331 typedef typename MemoryAlgorithm::mutex_family::recursive_mutex_type rmutex;
1333 scoped_lock<rmutex> priv_get_lock(bool use_lock)
1335 scoped_lock<rmutex> local(m_header, defer_lock);
1339 return scoped_lock<rmutex>(boost::interprocess::move(local));
1342 //!This struct includes needed data and derives from
1343 //!rmutex to allow EBO when using null interprocess_mutex
1347 named_index_t m_named_index;
1348 unique_index_t m_unique_index;
1350 header_t(Base *restricted_segment_mngr)
1351 : m_named_index (restricted_segment_mngr)
1352 , m_unique_index(restricted_segment_mngr)
1360 }} //namespace boost { namespace interprocess
1362 #include <boost/interprocess/detail/config_end.hpp>
1364 #endif //#ifndef BOOST_INTERPROCESS_SEGMENT_MANAGER_HPP