1 //////////////////////////////////////////////////////////////////////////////
3 // (C) Copyright Ion Gaztanaga 2005-2008. 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 #ifndef BOOST_NO_EXCEPTIONS
46 //!Describes the object placed in a memory segment that provides
47 //!named object allocation capabilities for single-segment and
48 //!multi-segment allocations.
51 namespace interprocess
{
53 //!This object is the public base class of segment manager.
54 //!This class only depends on the memory allocation algorithm
55 //!and implements all the allocation features not related
56 //!to named or unique objects.
58 //!Storing a reference to segment_manager forces
59 //!the holder class to be dependent on index types and character types.
60 //!When such dependence is not desirable and only anonymous and raw
61 //!allocations are needed, segment_manager_base is the correct answer.
62 template<class MemoryAlgorithm
>
63 class segment_manager_base
64 : private MemoryAlgorithm
67 typedef segment_manager_base
<MemoryAlgorithm
> segment_manager_base_type
;
68 typedef typename
MemoryAlgorithm::void_pointer void_pointer
;
69 typedef typename
MemoryAlgorithm::mutex_family mutex_family
;
70 typedef MemoryAlgorithm memory_algorithm
;
74 //Experimental. Don't use
75 typedef typename
MemoryAlgorithm::multiallocation_chain multiallocation_chain
;
79 //!This constant indicates the payload size
80 //!associated with each allocation of the memory algorithm
81 static const std::size_t PayloadPerAllocation
= MemoryAlgorithm::PayloadPerAllocation
;
83 //!Constructor of the segment_manager_base
85 //!"size" is the size of the memory segment where
86 //!the basic segment manager is being constructed.
88 //!"reserved_bytes" is the number of bytes
89 //!after the end of the memory algorithm object itself
90 //!that the memory algorithm will exclude from
94 segment_manager_base(std::size_t size
, std::size_t reserved_bytes
)
95 : MemoryAlgorithm(size
, reserved_bytes
)
97 assert((sizeof(segment_manager_base
<MemoryAlgorithm
>) == sizeof(MemoryAlgorithm
)));
100 //!Returns the size of the memory
102 std::size_t get_size() const
103 { return MemoryAlgorithm::get_size(); }
105 //!Returns the number of free bytes of the memory
107 std::size_t get_free_memory() const
108 { return MemoryAlgorithm::get_free_memory(); }
110 //!Obtains the minimum size needed by
111 //!the segment manager
112 static std::size_t get_min_size (std::size_t size
)
113 { return MemoryAlgorithm::get_min_size(size
); }
115 //!Allocates nbytes bytes. This function is only used in
116 //!single-segment management. Never throws
117 void * allocate (std::size_t nbytes
, std::nothrow_t
)
118 { return MemoryAlgorithm::allocate(nbytes
); }
122 //Experimental. Dont' use.
123 //!Allocates n_elements of
124 //!elem_size bytes. Throws bad_alloc on failure.
125 multiallocation_chain
allocate_many(std::size_t elem_bytes
, std::size_t num_elements
)
127 multiallocation_chain
mem(MemoryAlgorithm::allocate_many(elem_bytes
, num_elements
));
128 if(mem
.empty()) throw bad_alloc();
129 return boost::interprocess::move(mem
);
132 //!Allocates n_elements, each one of
133 //!element_lenghts[i]*sizeof_element bytes. Throws bad_alloc on failure.
134 multiallocation_chain allocate_many
135 (const std::size_t *element_lenghts
, std::size_t n_elements
, std::size_t sizeof_element
= 1)
137 multiallocation_chain
mem(MemoryAlgorithm::allocate_many(element_lenghts
, n_elements
, sizeof_element
));
138 if(mem
.empty()) throw bad_alloc();
139 return boost::interprocess::move(mem
);
142 //!Allocates n_elements of
143 //!elem_size bytes. Returns a default constructed iterator on failure.
144 multiallocation_chain allocate_many
145 (std::size_t elem_bytes
, std::size_t num_elements
, std::nothrow_t
)
146 { return MemoryAlgorithm::allocate_many(elem_bytes
, num_elements
); }
148 //!Allocates n_elements, each one of
149 //!element_lenghts[i]*sizeof_element bytes.
150 //!Returns a default constructed iterator on failure.
151 multiallocation_chain allocate_many
152 (const std::size_t *elem_sizes
, std::size_t n_elements
, std::size_t sizeof_element
, std::nothrow_t
)
153 { return MemoryAlgorithm::allocate_many(elem_sizes
, n_elements
, sizeof_element
); }
155 //!Deallocates elements pointed by the
156 //!multiallocation iterator range.
157 void deallocate_many(multiallocation_chain chain
)
158 { MemoryAlgorithm::deallocate_many(boost::interprocess::move(chain
)); }
162 //!Allocates nbytes bytes. Throws boost::interprocess::bad_alloc
164 void * allocate(std::size_t nbytes
)
166 void * ret
= MemoryAlgorithm::allocate(nbytes
);
172 //!Allocates nbytes bytes. This function is only used in
173 //!single-segment management. Never throws
174 void * allocate_aligned (std::size_t nbytes
, std::size_t alignment
, std::nothrow_t
)
175 { return MemoryAlgorithm::allocate_aligned(nbytes
, alignment
); }
177 //!Allocates nbytes bytes. This function is only used in
178 //!single-segment management. Throws bad_alloc when fails
179 void * allocate_aligned(std::size_t nbytes
, std::size_t alignment
)
181 void * ret
= MemoryAlgorithm::allocate_aligned(nbytes
, alignment
);
189 allocation_command (boost::interprocess::allocation_type command
, std::size_t limit_size
,
190 std::size_t preferred_size
,std::size_t &received_size
,
193 std::pair
<T
*, bool> ret
= MemoryAlgorithm::allocation_command
194 ( command
| boost::interprocess::nothrow_allocation
, limit_size
, preferred_size
, received_size
196 if(!(command
& boost::interprocess::nothrow_allocation
) && !ret
.first
)
201 std::pair
<void *, bool>
202 raw_allocation_command (boost::interprocess::allocation_type command
, std::size_t limit_objects
,
203 std::size_t preferred_objects
,std::size_t &received_objects
,
204 void *reuse_ptr
= 0, std::size_t sizeof_object
= 1)
206 std::pair
<void *, bool> ret
= MemoryAlgorithm::raw_allocation_command
207 ( command
| boost::interprocess::nothrow_allocation
, limit_objects
, preferred_objects
, received_objects
208 , reuse_ptr
, sizeof_object
);
209 if(!(command
& boost::interprocess::nothrow_allocation
) && !ret
.first
)
214 //!Deallocates the bytes allocated with allocate/allocate_many()
216 void deallocate (void *addr
)
217 { MemoryAlgorithm::deallocate(addr
); }
219 //!Increases managed memory in extra_size bytes more. This only works
220 //!with single-segment management.
221 void grow(std::size_t extra_size
)
222 { MemoryAlgorithm::grow(extra_size
); }
224 //!Decreases managed memory to the minimum. This only works
225 //!with single-segment management.
227 { MemoryAlgorithm::shrink_to_fit(); }
229 //!Returns the result of "all_memory_deallocated()" function
230 //!of the used memory algorithm
231 bool all_memory_deallocated()
232 { return MemoryAlgorithm::all_memory_deallocated(); }
234 //!Returns the result of "check_sanity()" function
235 //!of the used memory algorithm
237 { return MemoryAlgorithm::check_sanity(); }
239 //!Writes to zero free memory (memory not yet allocated)
240 //!of the memory algorithm
241 void zero_free_memory()
242 { MemoryAlgorithm::zero_free_memory(); }
244 //!Returns the size of the buffer previously allocated pointed by ptr
245 std::size_t size(const void *ptr
) const
246 { return MemoryAlgorithm::size(ptr
); }
250 void * prot_anonymous_construct
251 (std::size_t num
, bool dothrow
, detail::in_place_interface
&table
)
253 typedef detail::block_header block_header_t
;
254 block_header_t
block_info ( table
.size
*num
261 void *ptr_struct
= this->allocate(block_info
.total_size(), std::nothrow_t());
263 //Check if there is enough memory
273 //Build scoped ptr to avoid leaks with constructor exception
274 detail::mem_algo_deallocator
<MemoryAlgorithm
> mem(ptr_struct
, *this);
276 //Now construct the header
277 block_header_t
* hdr
= new(ptr_struct
) block_header_t(block_info
);
278 void *ptr
= 0; //avoid gcc warning
281 //Now call constructors
282 detail::array_construct(ptr
, num
, table
);
284 //All constructors successful, we don't want erase memory
289 //!Calls the destructor and makes an anonymous deallocate
290 void prot_anonymous_destroy(const void *object
, detail::in_place_interface
&table
)
293 //Get control data from associated with this object
294 typedef detail::block_header block_header_t
;
295 block_header_t
*ctrl_data
= block_header_t::block_header_from_value(object
, table
.size
, table
.alignment
);
297 //-------------------------------
298 //scoped_lock<rmutex> guard(m_header);
299 //-------------------------------
301 if(ctrl_data
->alloc_type() != anonymous_type
){
302 //This is not an anonymous object, the pointer is wrong!
306 //Call destructors and free memory
307 //Build scoped ptr to avoid leaks with destructor exception
308 std::size_t destroyed
= 0;
309 table
.destroy_n(const_cast<void*>(object
), ctrl_data
->m_value_bytes
/table
.size
, destroyed
);
310 this->deallocate(ctrl_data
);
315 //!This object is placed in the beginning of memory segment and
316 //!implements the allocation (named or anonymous) of portions
317 //!of the segment. This object contains two indexes that
318 //!maintain an association between a name and a portion of the segment.
320 //!The first index contains the mappings for normal named objects using the
321 //!char type specified in the template parameter.
323 //!The second index contains the association for unique instances. The key will
324 //!be the const char * returned from type_info.name() function for the unique
325 //!type to be constructed.
327 //!segment_manager<CharType, MemoryAlgorithm, IndexType> inherits publicly
328 //!from segment_manager_base<MemoryAlgorithm> and inherits from it
329 //!many public functions related to anonymous object and raw memory allocation.
330 //!See segment_manager_base reference to know about those functions.
331 template<class CharType
332 ,class MemoryAlgorithm
333 ,template<class IndexConfig
> class IndexType
>
334 class segment_manager
335 : public segment_manager_base
<MemoryAlgorithm
>
340 segment_manager(const segment_manager
&);
341 segment_manager
&operator=(const segment_manager
&);
342 typedef segment_manager_base
<MemoryAlgorithm
> Base
;
343 typedef detail::block_header block_header_t
;
347 typedef MemoryAlgorithm memory_algorithm
;
348 typedef typename
Base::void_pointer void_pointer
;
349 typedef CharType char_type
;
351 typedef segment_manager_base
<MemoryAlgorithm
> segment_manager_base_type
;
353 static const std::size_t PayloadPerAllocation
= Base::PayloadPerAllocation
;
357 typedef detail::index_config
<CharType
, MemoryAlgorithm
> index_config_named
;
358 typedef detail::index_config
<char, MemoryAlgorithm
> index_config_unique
;
359 typedef IndexType
<index_config_named
> index_type
;
360 typedef detail::bool_
<is_intrusive_index
<index_type
>::value
> is_intrusive_t
;
361 typedef detail::bool_
<is_node_index
<index_type
>::value
> is_node_index_t
;
364 typedef IndexType
<index_config_named
> named_index_t
;
365 typedef IndexType
<index_config_unique
> unique_index_t
;
366 typedef detail::char_ptr_holder
<CharType
> char_ptr_holder_t
;
367 typedef detail::segment_manager_iterator_transform
368 <typename
named_index_t::const_iterator
369 ,is_intrusive_index
<index_type
>::value
> named_transform
;
371 typedef detail::segment_manager_iterator_transform
372 <typename
unique_index_t::const_iterator
373 ,is_intrusive_index
<index_type
>::value
> unique_transform
;
376 typedef typename
Base::mutex_family mutex_family
;
378 typedef transform_iterator
379 <typename
named_index_t::const_iterator
, named_transform
> const_named_iterator
;
380 typedef transform_iterator
381 <typename
unique_index_t::const_iterator
, unique_transform
> const_unique_iterator
;
385 //!Constructor proxy object definition helper class
387 struct construct_proxy
389 typedef detail::named_proxy
<segment_manager
, T
, false> type
;
392 //!Constructor proxy object definition helper class
394 struct construct_iter_proxy
396 typedef detail::named_proxy
<segment_manager
, T
, true> type
;
401 //!Constructor of the segment manager
402 //!"size" is the size of the memory segment where
403 //!the segment manager is being constructed.
405 segment_manager(std::size_t size
)
406 : Base(size
, priv_get_reserved_bytes())
407 , m_header(static_cast<Base
*>(get_this_pointer()))
409 (void) anonymous_instance
; (void) unique_instance
;
410 assert(static_cast<const void*>(this) == static_cast<const void*>(static_cast<Base
*>(this)));
413 //!Tries to find a previous named allocation. Returns the address
414 //!and the object count. On failure the first member of the
415 //!returned pair is 0.
417 std::pair
<T
*, std::size_t> find (const CharType
* name
)
418 { return this->priv_find_impl
<T
>(name
, true); }
420 //!Tries to find a previous unique allocation. Returns the address
421 //!and the object count. On failure the first member of the
422 //!returned pair is 0.
424 std::pair
<T
*, std::size_t> find (const detail::unique_instance_t
* name
)
425 { return this->priv_find_impl
<T
>(name
, true); }
427 //!Tries to find a previous named allocation. Returns the address
428 //!and the object count. On failure the first member of the
429 //!returned pair is 0. This search is not mutex-protected!
431 std::pair
<T
*, std::size_t> find_no_lock (const CharType
* name
)
432 { return this->priv_find_impl
<T
>(name
, false); }
434 //!Tries to find a previous 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!
438 std::pair
<T
*, std::size_t> find_no_lock (const detail::unique_instance_t
* name
)
439 { return this->priv_find_impl
<T
>(name
, false); }
441 //!Returns throwing "construct" proxy
444 typename construct_proxy
<T
>::type
445 construct(char_ptr_holder_t name
)
446 { return typename construct_proxy
<T
>::type (this, name
, false, true); }
448 //!Returns throwing "search or construct" proxy
451 typename construct_proxy
<T
>::type
find_or_construct(char_ptr_holder_t name
)
452 { return typename construct_proxy
<T
>::type (this, name
, true, true); }
454 //!Returns no throwing "construct" proxy
457 typename construct_proxy
<T
>::type
458 construct(char_ptr_holder_t name
, std::nothrow_t
)
459 { return typename construct_proxy
<T
>::type (this, name
, false, false); }
461 //!Returns no throwing "search or construct"
464 typename construct_proxy
<T
>::type
465 find_or_construct(char_ptr_holder_t name
, std::nothrow_t
)
466 { return typename construct_proxy
<T
>::type (this, name
, true, false); }
468 //!Returns throwing "construct from iterators" proxy object
470 typename construct_iter_proxy
<T
>::type
471 construct_it(char_ptr_holder_t name
)
472 { return typename construct_iter_proxy
<T
>::type (this, name
, false, true); }
474 //!Returns throwing "search or construct from iterators"
477 typename construct_iter_proxy
<T
>::type
478 find_or_construct_it(char_ptr_holder_t name
)
479 { return typename construct_iter_proxy
<T
>::type (this, name
, true, true); }
481 //!Returns no throwing "construct from iterators"
484 typename construct_iter_proxy
<T
>::type
485 construct_it(char_ptr_holder_t name
, std::nothrow_t
)
486 { return typename construct_iter_proxy
<T
>::type (this, name
, false, false); }
488 //!Returns no throwing "search or construct from iterators"
491 typename construct_iter_proxy
<T
>::type
492 find_or_construct_it(char_ptr_holder_t name
, std::nothrow_t
)
493 { return typename construct_iter_proxy
<T
>::type (this, name
, true, false); }
495 //!Calls object function blocking recursive interprocess_mutex and guarantees that
496 //!no new named_alloc or destroy will be executed by any process while
497 //!executing the object function call*/
498 template <class Func
>
499 void atomic_func(Func
&f
)
500 { scoped_lock
<rmutex
> guard(m_header
); f(); }
502 //!Destroys a previously created unique instance.
503 //!Returns false if the object was not present.
505 bool destroy(const detail::unique_instance_t
*)
507 detail::placement_destroy
<T
> dtor
;
508 return this->priv_generic_named_destroy
<char>
509 (typeid(T
).name(), m_header
.m_unique_index
, dtor
, is_intrusive_t());
512 //!Destroys the named object with
513 //!the given name. Returns false if that object can't be found.
515 bool destroy(const CharType
*name
)
517 detail::placement_destroy
<T
> dtor
;
518 return this->priv_generic_named_destroy
<CharType
>
519 (name
, m_header
.m_named_index
, dtor
, is_intrusive_t());
522 //!Destroys an anonymous, unique or named object
523 //!using it's address
525 void destroy_ptr(const T
*p
)
527 //If T is void transform it to char
528 typedef typename
detail::char_if_void
<T
>::type data_t
;
529 detail::placement_destroy
<data_t
> dtor
;
530 priv_destroy_ptr(p
, dtor
);
533 //!Returns the name of an object created with construct/find_or_construct
534 //!functions. Does not throw
536 static const CharType
*get_instance_name(const T
*ptr
)
537 { return priv_get_instance_name(block_header_t::block_header_from_value(ptr
)); }
539 //!Returns the length of an object created with construct/find_or_construct
540 //!functions. Does not throw.
542 static std::size_t get_instance_length(const T
*ptr
)
543 { return priv_get_instance_length(block_header_t::block_header_from_value(ptr
), sizeof(T
)); }
545 //!Returns is the the name of an object created with construct/find_or_construct
546 //!functions. Does not throw
548 static instance_type
get_instance_type(const T
*ptr
)
549 { return priv_get_instance_type(block_header_t::block_header_from_value(ptr
)); }
551 //!Preallocates needed index resources to optimize the
552 //!creation of "num" named objects in the managed memory segment.
553 //!Can throw boost::interprocess::bad_alloc if there is no enough memory.
554 void reserve_named_objects(std::size_t num
)
556 //-------------------------------
557 scoped_lock
<rmutex
> guard(m_header
);
558 //-------------------------------
559 m_header
.m_named_index
.reserve(num
);
562 //!Preallocates needed index resources to optimize the
563 //!creation of "num" unique objects in the managed memory segment.
564 //!Can throw boost::interprocess::bad_alloc if there is no enough memory.
565 void reserve_unique_objects(std::size_t num
)
567 //-------------------------------
568 scoped_lock
<rmutex
> guard(m_header
);
569 //-------------------------------
570 m_header
.m_unique_index
.reserve(num
);
573 //!Calls shrink_to_fit in both named and unique object indexes
574 //!to try to free unused memory from those indexes.
575 void shrink_to_fit_indexes()
577 //-------------------------------
578 scoped_lock
<rmutex
> guard(m_header
);
579 //-------------------------------
580 m_header
.m_named_index
.shrink_to_fit();
581 m_header
.m_unique_index
.shrink_to_fit();
584 //!Returns the number of named objects stored in
586 std::size_t get_num_named_objects()
588 //-------------------------------
589 scoped_lock
<rmutex
> guard(m_header
);
590 //-------------------------------
591 return m_header
.m_named_index
.size();
594 //!Returns the number of unique objects stored in
596 std::size_t get_num_unique_objects()
598 //-------------------------------
599 scoped_lock
<rmutex
> guard(m_header
);
600 //-------------------------------
601 return m_header
.m_unique_index
.size();
604 //!Obtains the minimum size needed by the
606 static std::size_t get_min_size()
607 { return Base::get_min_size(priv_get_reserved_bytes()); }
609 //!Returns a constant iterator to the beginning of the information about
610 //!the named allocations performed in this segment manager
611 const_named_iterator
named_begin() const
613 return make_transform_iterator
614 (m_header
.m_named_index
.begin(), named_transform());
617 //!Returns a constant iterator to the end of the information about
618 //!the named allocations performed in this segment manager
619 const_named_iterator
named_end() const
621 return make_transform_iterator
622 (m_header
.m_named_index
.end(), named_transform());
625 //!Returns a constant iterator to the beginning of the information about
626 //!the unique allocations performed in this segment manager
627 const_unique_iterator
unique_begin() const
629 return make_transform_iterator
630 (m_header
.m_unique_index
.begin(), unique_transform());
633 //!Returns a constant iterator to the end of the information about
634 //!the unique allocations performed in this segment manager
635 const_unique_iterator
unique_end() const
637 return make_transform_iterator
638 (m_header
.m_unique_index
.end(), unique_transform());
641 //!This is the default allocator to allocate types T
642 //!from this managed segment
646 typedef boost::interprocess::allocator
<T
, segment_manager
> type
;
649 //!Returns an instance of the default allocator for type T
650 //!initialized that allocates memory from this segment manager.
652 typename allocator
<T
>::type
654 { return typename allocator
<T
>::type(this); }
656 //!This is the default deleter to delete types T
657 //!from this managed segment.
661 typedef boost::interprocess::deleter
<T
, segment_manager
> type
;
664 //!Returns an instance of the default allocator for type T
665 //!initialized that allocates memory from this segment manager.
667 typename deleter
<T
>::type
669 { return typename deleter
<T
>::type(this); }
673 //!Generic named/anonymous new function. Offers all the possibilities,
674 //!such as throwing, search before creating, and the constructor is
675 //!encapsulated in an object function.
677 T
*generic_construct(const CharType
*name
,
681 detail::in_place_interface
&table
)
683 return static_cast<T
*>
684 (priv_generic_construct(name
, num
, try2find
, dothrow
, table
));
688 //!Tries to find a previous named allocation. Returns the address
689 //!and the object count. On failure the first member of the
690 //!returned pair is 0.
692 std::pair
<T
*, std::size_t> priv_find_impl (const CharType
* name
, bool lock
)
694 //The name can't be null, no anonymous object can be found by name
696 detail::placement_destroy
<T
> table
;
700 if(name
== reinterpret_cast<const CharType
*>(-1)){
701 ret
= priv_generic_find
<char> (typeid(T
).name(), m_header
.m_unique_index
, table
, size
, is_intrusive_t(), lock
);
704 ret
= priv_generic_find
<CharType
> (name
, m_header
.m_named_index
, table
, size
, is_intrusive_t(), lock
);
706 return std::pair
<T
*, std::size_t>(static_cast<T
*>(ret
), size
);
709 //!Tries to find a previous unique allocation. Returns the address
710 //!and the object count. On failure the first member of the
711 //!returned pair is 0.
713 std::pair
<T
*, std::size_t> priv_find__impl (const detail::unique_instance_t
* name
, bool lock
)
715 detail::placement_destroy
<T
> table
;
717 void *ret
= priv_generic_find
<char>(name
, m_header
.m_unique_index
, table
, size
, is_intrusive_t(), lock
);
718 return std::pair
<T
*, std::size_t>(static_cast<T
*>(ret
), size
);
721 void *priv_generic_construct(const CharType
*name
,
725 detail::in_place_interface
&table
)
728 //Security overflow check
729 if(num
> ((std::size_t)-1)/table
.size
){
736 ret
= this->prot_anonymous_construct(num
, dothrow
, table
);
738 else if(name
== reinterpret_cast<const CharType
*>(-1)){
739 ret
= this->priv_generic_named_construct
<char>
740 (unique_type
, table
.type_name
, num
, try2find
, dothrow
, table
, m_header
.m_unique_index
, is_intrusive_t());
743 ret
= this->priv_generic_named_construct
<CharType
>
744 (named_type
, name
, num
, try2find
, dothrow
, table
, m_header
.m_named_index
, is_intrusive_t());
749 void priv_destroy_ptr(const void *ptr
, detail::in_place_interface
&dtor
)
751 block_header_t
*ctrl_data
= block_header_t::block_header_from_value(ptr
, dtor
.size
, dtor
.alignment
);
752 switch(ctrl_data
->alloc_type()){
754 this->prot_anonymous_destroy(ptr
, dtor
);
758 this->priv_generic_named_destroy
<CharType
>
759 (ctrl_data
, m_header
.m_named_index
, dtor
, is_node_index_t());
763 this->priv_generic_named_destroy
<char>
764 (ctrl_data
, m_header
.m_unique_index
, dtor
, is_node_index_t());
768 //This type is unknown, bad pointer passed to this function!
774 //!Returns the name of an object created with construct/find_or_construct
775 //!functions. Does not throw
776 static const CharType
*priv_get_instance_name(block_header_t
*ctrl_data
)
778 boost::interprocess::allocation_type type
= ctrl_data
->alloc_type();
779 if(type
!= named_type
){
780 assert((type
== anonymous_type
&& ctrl_data
->m_num_char
== 0) ||
781 (type
== unique_type
&& ctrl_data
->m_num_char
!= 0) );
784 CharType
*name
= static_cast<CharType
*>(ctrl_data
->template name
<CharType
>());
787 assert(ctrl_data
->sizeof_char() == sizeof(CharType
));
788 assert(ctrl_data
->m_num_char
== std::char_traits
<CharType
>::length(name
));
792 static std::size_t priv_get_instance_length(block_header_t
*ctrl_data
, std::size_t sizeofvalue
)
795 assert((ctrl_data
->value_bytes() %sizeofvalue
) == 0);
796 return ctrl_data
->value_bytes()/sizeofvalue
;
799 //!Returns is the the name of an object created with construct/find_or_construct
800 //!functions. Does not throw
801 static instance_type
priv_get_instance_type(block_header_t
*ctrl_data
)
804 assert((instance_type
)ctrl_data
->alloc_type() < max_allocation_type
);
805 return (instance_type
)ctrl_data
->alloc_type();
808 static std::size_t priv_get_reserved_bytes()
810 //Get the number of bytes until the end of (*this)
811 //beginning in the end of the Base base.
812 return sizeof(segment_manager
) - sizeof(Base
);
815 template <class CharT
>
816 void *priv_generic_find
818 IndexType
<detail::index_config
<CharT
, MemoryAlgorithm
> > &index
,
819 detail::in_place_interface
&table
,
821 detail::true_ is_intrusive
,
825 typedef IndexType
<detail::index_config
<CharT
, MemoryAlgorithm
> > index_type
;
826 typedef detail::index_key
<CharT
, void_pointer
> index_key_t
;
827 typedef typename
index_type::iterator index_it
;
829 //-------------------------------
830 scoped_lock
<rmutex
> guard(priv_get_lock(use_lock
));
831 //-------------------------------
833 detail::intrusive_compare_key
<CharT
> key
834 (name
, std::char_traits
<CharT
>::length(name
));
835 index_it it
= index
.find(key
);
837 //Initialize return values
841 //If found, assign values
842 if(it
!= index
.end()){
844 block_header_t
*ctrl_data
= it
->get_block_header();
847 assert((ctrl_data
->m_value_bytes
% table
.size
) == 0);
848 assert(ctrl_data
->sizeof_char() == sizeof(CharT
));
849 ret_ptr
= ctrl_data
->value();
850 length
= ctrl_data
->m_value_bytes
/table
.size
;
855 template <class CharT
>
856 void *priv_generic_find
858 IndexType
<detail::index_config
<CharT
, MemoryAlgorithm
> > &index
,
859 detail::in_place_interface
&table
,
861 detail::false_ is_intrusive
,
865 typedef IndexType
<detail::index_config
<CharT
, MemoryAlgorithm
> > index_type
;
866 typedef typename
index_type::key_type key_type
;
867 typedef typename
index_type::iterator index_it
;
869 //-------------------------------
870 scoped_lock
<rmutex
> guard(priv_get_lock(use_lock
));
871 //-------------------------------
873 index_it it
= index
.find(key_type(name
, std::char_traits
<CharT
>::length(name
)));
875 //Initialize return values
879 //If found, assign values
880 if(it
!= index
.end()){
882 block_header_t
*ctrl_data
= reinterpret_cast<block_header_t
*>
883 (detail::get_pointer(it
->second
.m_ptr
));
886 assert((ctrl_data
->m_value_bytes
% table
.size
) == 0);
887 assert(ctrl_data
->sizeof_char() == sizeof(CharT
));
888 ret_ptr
= ctrl_data
->value();
889 length
= ctrl_data
->m_value_bytes
/table
.size
;
894 template <class CharT
>
895 bool priv_generic_named_destroy
896 (block_header_t
*block_header
,
897 IndexType
<detail::index_config
<CharT
, MemoryAlgorithm
> > &index
,
898 detail::in_place_interface
&table
,
899 detail::true_ is_node_index
)
902 typedef typename IndexType
<detail::index_config
<CharT
, MemoryAlgorithm
> >::iterator index_it
;
904 index_it
*ihdr
= block_header_t::to_first_header
<index_it
>(block_header
);
905 return this->priv_generic_named_destroy_impl
<CharT
>(*ihdr
, index
, table
);
908 template <class CharT
>
909 bool priv_generic_named_destroy
910 (block_header_t
*block_header
,
911 IndexType
<detail::index_config
<CharT
, MemoryAlgorithm
> > &index
,
912 detail::in_place_interface
&table
,
913 detail::false_ is_node_index
)
916 CharT
*name
= static_cast<CharT
*>(block_header
->template name
<CharT
>());
917 return this->priv_generic_named_destroy
<CharT
>(name
, index
, table
, is_intrusive_t());
920 template <class CharT
>
921 bool priv_generic_named_destroy(const CharT
*name
,
922 IndexType
<detail::index_config
<CharT
, MemoryAlgorithm
> > &index
,
923 detail::in_place_interface
&table
,
924 detail::true_ is_intrusive_index
)
926 (void)is_intrusive_index
;
927 typedef IndexType
<detail::index_config
<CharT
, MemoryAlgorithm
> > index_type
;
928 typedef detail::index_key
<CharT
, void_pointer
> index_key_t
;
929 typedef typename
index_type::iterator index_it
;
930 typedef typename
index_type::value_type intrusive_value_type
;
932 //-------------------------------
933 scoped_lock
<rmutex
> guard(m_header
);
934 //-------------------------------
936 detail::intrusive_compare_key
<CharT
> key
937 (name
, std::char_traits
<CharT
>::length(name
));
938 index_it it
= index
.find(key
);
940 //If not found, return false
941 if(it
== index
.end()){
942 //This name is not present in the index, wrong pointer or name!
947 block_header_t
*ctrl_data
= it
->get_block_header();
948 intrusive_value_type
*iv
= intrusive_value_type::get_intrusive_value_type(ctrl_data
);
950 void *values
= ctrl_data
->value();
951 std::size_t num
= ctrl_data
->m_value_bytes
/table
.size
;
954 assert((ctrl_data
->m_value_bytes
% table
.size
) == 0);
955 assert(sizeof(CharT
) == ctrl_data
->sizeof_char());
957 //Erase node from index
960 //Destroy the headers
961 ctrl_data
->~block_header_t();
962 iv
->~intrusive_value_type();
964 //Call destructors and free memory
965 std::size_t destroyed
;
966 table
.destroy_n(values
, num
, destroyed
);
967 this->deallocate(memory
);
971 template <class CharT
>
972 bool priv_generic_named_destroy(const CharT
*name
,
973 IndexType
<detail::index_config
<CharT
, MemoryAlgorithm
> > &index
,
974 detail::in_place_interface
&table
,
975 detail::false_ is_intrusive_index
)
977 (void)is_intrusive_index
;
978 typedef IndexType
<detail::index_config
<CharT
, MemoryAlgorithm
> > index_type
;
979 typedef typename
index_type::iterator index_it
;
980 typedef typename
index_type::key_type key_type
;
982 //-------------------------------
983 scoped_lock
<rmutex
> guard(m_header
);
984 //-------------------------------
985 //Try to find the name in the index
986 index_it it
= index
.find(key_type (name
,
987 std::char_traits
<CharT
>::length(name
)));
989 //If not found, return false
990 if(it
== index
.end()){
991 //This name is not present in the index, wrong pointer or name!
995 return this->priv_generic_named_destroy_impl
<CharT
>(it
, index
, table
);
998 template <class CharT
>
999 bool priv_generic_named_destroy_impl
1000 (const typename IndexType
<detail::index_config
<CharT
, MemoryAlgorithm
> >::iterator
&it
,
1001 IndexType
<detail::index_config
<CharT
, MemoryAlgorithm
> > &index
,
1002 detail::in_place_interface
&table
)
1004 typedef IndexType
<detail::index_config
<CharT
, MemoryAlgorithm
> > index_type
;
1005 typedef typename
index_type::iterator index_it
;
1007 //Get allocation parameters
1008 block_header_t
*ctrl_data
= reinterpret_cast<block_header_t
*>
1009 (detail::get_pointer(it
->second
.m_ptr
));
1010 char *stored_name
= static_cast<char*>(static_cast<void*>(const_cast<CharT
*>(it
->first
.name())));
1013 //Check if the distance between the name pointer and the memory pointer
1014 //is correct (this can detect incorrect type in destruction)
1015 std::size_t num
= ctrl_data
->m_value_bytes
/table
.size
;
1016 void *values
= ctrl_data
->value();
1019 assert((ctrl_data
->m_value_bytes
% table
.size
) == 0);
1020 assert(static_cast<void*>(stored_name
) == static_cast<void*>(ctrl_data
->template name
<CharT
>()));
1021 assert(sizeof(CharT
) == ctrl_data
->sizeof_char());
1023 //Erase node from index
1026 //Destroy the header
1027 ctrl_data
->~block_header_t();
1030 if(is_node_index_t::value
){
1031 index_it
*ihdr
= block_header_t::
1032 to_first_header
<index_it
>(ctrl_data
);
1040 //Call destructors and free memory
1041 std::size_t destroyed
;
1042 table
.destroy_n(values
, num
, destroyed
);
1043 this->deallocate(memory
);
1047 template<class CharT
>
1048 void * priv_generic_named_construct(std::size_t type
,
1053 detail::in_place_interface
&table
,
1054 IndexType
<detail::index_config
<CharT
, MemoryAlgorithm
> > &index
,
1055 detail::true_ is_intrusive
)
1058 std::size_t namelen
= std::char_traits
<CharT
>::length(name
);
1060 block_header_t
block_info ( table
.size
*num
1066 typedef IndexType
<detail::index_config
<CharT
, MemoryAlgorithm
> > index_type
;
1067 typedef typename
index_type::iterator index_it
;
1068 typedef std::pair
<index_it
, bool> index_ib
;
1070 //-------------------------------
1071 scoped_lock
<rmutex
> guard(m_header
);
1072 //-------------------------------
1073 //Insert the node. This can throw.
1074 //First, we want to know if the key is already present before
1075 //we allocate any memory, and if the key is not present, we
1076 //want to allocate all memory in a single buffer that will
1077 //contain the name and the user buffer.
1079 //Since equal_range(key) + insert(hint, value) approach is
1080 //quite inefficient in container implementations
1081 //(they re-test if the position is correct), I've chosen
1082 //to insert the node, do an ugly un-const cast and modify
1083 //the key (which is a smart pointer) to an equivalent one
1084 index_ib insert_ret
;
1086 typename
index_type::insert_commit_data commit_data
;
1087 typedef typename
index_type::value_type intrusive_value_type
;
1090 detail::intrusive_compare_key
<CharT
> key(name
, namelen
);
1091 insert_ret
= index
.insert_check(key
, commit_data
);
1101 index_it it
= insert_ret
.first
;
1103 //If found and this is find or construct, return data
1105 if(!insert_ret
.second
){
1107 return it
->get_block_header()->value();
1110 throw interprocess_exception(already_exists_error
);
1117 //Allocates buffer for name + data, this can throw (it hurts)
1120 //Check if there is enough memory
1122 buffer_ptr
= this->allocate
1123 (block_info
.total_size_with_header
<intrusive_value_type
>());
1126 buffer_ptr
= this->allocate
1127 (block_info
.total_size_with_header
<intrusive_value_type
>(), std::nothrow_t());
1132 //Now construct the intrusive hook plus the header
1133 intrusive_value_type
* intrusive_hdr
= new(buffer_ptr
) intrusive_value_type();
1134 block_header_t
* hdr
= new(intrusive_hdr
->get_block_header())block_header_t(block_info
);
1135 void *ptr
= 0; //avoid gcc warning
1138 //Copy name to memory segment and insert data
1139 CharT
*name_ptr
= static_cast<CharT
*>(hdr
->template name
<CharT
>());
1140 std::char_traits
<CharT
>::copy(name_ptr
, name
, namelen
+1);
1143 //Now commit the insertion using previous context data
1144 it
= index
.insert_commit(*intrusive_hdr
, commit_data
);
1154 //Avoid constructions if constructor is trivial
1155 //Build scoped ptr to avoid leaks with constructor exception
1156 detail::mem_algo_deallocator
<segment_manager_base_type
> mem
1157 (buffer_ptr
, *static_cast<segment_manager_base_type
*>(this));
1159 //Initialize the node value_eraser to erase inserted node
1160 //if something goes wrong. This will be executed *before*
1161 //the memory allocation as the intrusive value is built in that
1163 value_eraser
<index_type
> v_eraser(index
, it
);
1165 //Construct array, this can throw
1166 detail::array_construct(ptr
, num
, table
);
1168 //Release rollbacks since construction was successful
1174 //!Generic named new function for
1176 template<class CharT
>
1177 void * priv_generic_named_construct(std::size_t type
,
1182 detail::in_place_interface
&table
,
1183 IndexType
<detail::index_config
<CharT
, MemoryAlgorithm
> > &index
,
1184 detail::false_ is_intrusive
)
1187 std::size_t namelen
= std::char_traits
<CharT
>::length(name
);
1189 block_header_t
block_info ( table
.size
*num
1195 typedef IndexType
<detail::index_config
<CharT
, MemoryAlgorithm
> > index_type
;
1196 typedef typename
index_type::key_type key_type
;
1197 typedef typename
index_type::mapped_type mapped_type
;
1198 typedef typename
index_type::value_type value_type
;
1199 typedef typename
index_type::iterator index_it
;
1200 typedef std::pair
<index_it
, bool> index_ib
;
1202 //-------------------------------
1203 scoped_lock
<rmutex
> guard(m_header
);
1204 //-------------------------------
1205 //Insert the node. This can throw.
1206 //First, we want to know if the key is already present before
1207 //we allocate any memory, and if the key is not present, we
1208 //want to allocate all memory in a single buffer that will
1209 //contain the name and the user buffer.
1211 //Since equal_range(key) + insert(hint, value) approach is
1212 //quite inefficient in container implementations
1213 //(they re-test if the position is correct), I've chosen
1214 //to insert the node, do an ugly un-const cast and modify
1215 //the key (which is a smart pointer) to an equivalent one
1216 index_ib insert_ret
;
1218 insert_ret
= index
.insert(value_type(key_type (name
, namelen
), mapped_type(0)));
1228 index_it it
= insert_ret
.first
;
1230 //If found and this is find or construct, return data
1232 if(!insert_ret
.second
){
1234 block_header_t
*hdr
= static_cast<block_header_t
*>
1235 (detail::get_pointer(it
->second
.m_ptr
));
1236 return hdr
->value();
1240 //Initialize the node value_eraser to erase inserted node
1241 //if something goes wrong
1242 value_eraser
<index_type
> v_eraser(index
, it
);
1244 //Allocates buffer for name + data, this can throw (it hurts)
1246 block_header_t
* hdr
;
1248 //Allocate and construct the headers
1249 if(is_node_index_t::value
){
1250 std::size_t total_size
= block_info
.total_size_with_header
<index_it
>();
1252 buffer_ptr
= this->allocate(total_size
);
1255 buffer_ptr
= this->allocate(total_size
, std::nothrow_t());
1259 index_it
*idr
= new(buffer_ptr
) index_it(it
);
1260 hdr
= block_header_t::from_first_header
<index_it
>(idr
);
1264 buffer_ptr
= this->allocate(block_info
.total_size());
1267 buffer_ptr
= this->allocate(block_info
.total_size(), std::nothrow_t());
1271 hdr
= static_cast<block_header_t
*>(buffer_ptr
);
1274 hdr
= new(hdr
)block_header_t(block_info
);
1275 void *ptr
= 0; //avoid gcc warning
1278 //Copy name to memory segment and insert data
1279 CharT
*name_ptr
= static_cast<CharT
*>(hdr
->template name
<CharT
>());
1280 std::char_traits
<CharT
>::copy(name_ptr
, name
, namelen
+1);
1282 //Do the ugly cast, please mama, forgive me!
1283 //This new key points to an identical string, so it must have the
1284 //same position than the overwritten key according to the predicate
1285 const_cast<key_type
&>(it
->first
).name(name_ptr
);
1286 it
->second
.m_ptr
= hdr
;
1288 //Build scoped ptr to avoid leaks with constructor exception
1289 detail::mem_algo_deallocator
<segment_manager_base_type
> mem
1290 (buffer_ptr
, *static_cast<segment_manager_base_type
*>(this));
1292 //Construct array, this can throw
1293 detail::array_construct(ptr
, num
, table
);
1295 //All constructors successful, we don't want to release memory
1298 //Release node v_eraser since construction was successful
1304 //!Returns the this pointer
1305 segment_manager
*get_this_pointer()
1308 typedef typename
MemoryAlgorithm::mutex_family::recursive_mutex_type rmutex
;
1310 scoped_lock
<rmutex
> priv_get_lock(bool use_lock
)
1312 scoped_lock
<rmutex
> local(m_header
, defer_lock
);
1316 return scoped_lock
<rmutex
>(boost::interprocess::move(local
));
1319 //!This struct includes needed data and derives from
1320 //!rmutex to allow EBO when using null interprocess_mutex
1324 named_index_t m_named_index
;
1325 unique_index_t m_unique_index
;
1327 header_t(Base
*restricted_segment_mngr
)
1328 : m_named_index (restricted_segment_mngr
)
1329 , m_unique_index(restricted_segment_mngr
)
1337 }} //namespace boost { namespace interprocess
1339 #include <boost/interprocess/detail/config_end.hpp>
1341 #endif //#ifndef BOOST_INTERPROCESS_SEGMENT_MANAGER_HPP