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