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