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_BASE_HPP
12 #define BOOST_INTERPROCESS_SEGMENT_MANAGER_BASE_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 // interprocess
26 #include <boost/interprocess/exceptions.hpp>
27 // interprocess/detail
28 #include <boost/interprocess/detail/type_traits.hpp>
29 #include <boost/interprocess/detail/utilities.hpp>
30 #include <boost/interprocess/detail/in_place_interface.hpp>
31 // container/detail
32 #include <boost/container/detail/type_traits.hpp> //alignment_of
33 #include <boost/container/detail/minimal_char_traits_header.hpp>
34 // intrusive
35 #include <boost/intrusive/pointer_traits.hpp>
36 // move/detail
37 #include <boost/move/detail/type_traits.hpp> //make_unsigned
38 // other boost
39 #include <boost/assert.hpp>   //BOOST_ASSERT
40 #include <boost/core/no_exceptions_support.hpp>
41 // std
42 #include <cstddef>   //std::size_t
43 
44 //!\file
45 //!Describes the object placed in a memory segment that provides
46 //!named object allocation capabilities.
47 
48 namespace boost{
49 namespace interprocess{
50 
51 template<class MemoryManager>
52 class segment_manager_base;
53 
54 //!An integer that describes the type of the
55 //!instance constructed in memory
56 enum instance_type {   anonymous_type, named_type, unique_type, max_allocation_type };
57 
58 namespace ipcdetail{
59 
60 template<class MemoryAlgorithm>
61 class mem_algo_deallocator
62 {
63    void *            m_ptr;
64    MemoryAlgorithm & m_algo;
65 
66    public:
mem_algo_deallocator(void * ptr,MemoryAlgorithm & algo)67    mem_algo_deallocator(void *ptr, MemoryAlgorithm &algo)
68       :  m_ptr(ptr), m_algo(algo)
69    {}
70 
release()71    void release()
72    {  m_ptr = 0;  }
73 
~mem_algo_deallocator()74    ~mem_algo_deallocator()
75    {  if(m_ptr) m_algo.deallocate(m_ptr);  }
76 };
77 
78 template<class size_type>
79 struct block_header
80 {
81    size_type      m_value_bytes;
82    unsigned short m_num_char;
83    unsigned char  m_value_alignment;
84    unsigned char  m_alloc_type_sizeof_char;
85 
block_headerboost::interprocess::ipcdetail::block_header86    block_header(size_type val_bytes
87                ,size_type val_alignment
88                ,unsigned char al_type
89                ,std::size_t szof_char
90                ,std::size_t num_char
91                )
92       :  m_value_bytes(val_bytes)
93       ,  m_num_char((unsigned short)num_char)
94       ,  m_value_alignment((unsigned char)val_alignment)
95       ,  m_alloc_type_sizeof_char( (al_type << 5u) | ((unsigned char)szof_char & 0x1F) )
96    {};
97 
98    template<class T>
operator =boost::interprocess::ipcdetail::block_header99    block_header &operator= (const T& )
100    {  return *this;  }
101 
total_sizeboost::interprocess::ipcdetail::block_header102    size_type total_size() const
103    {
104       if(alloc_type() != anonymous_type){
105          return name_offset() + (m_num_char+1)*sizeof_char();
106       }
107       else{
108          return this->value_offset() + m_value_bytes;
109       }
110    }
111 
value_bytesboost::interprocess::ipcdetail::block_header112    size_type value_bytes() const
113    {  return m_value_bytes;   }
114 
115    template<class Header>
total_size_with_headerboost::interprocess::ipcdetail::block_header116    size_type total_size_with_header() const
117    {
118       return get_rounded_size
119                ( size_type(sizeof(Header))
120             , size_type(::boost::container::dtl::alignment_of<block_header<size_type> >::value))
121            + total_size();
122    }
123 
alloc_typeboost::interprocess::ipcdetail::block_header124    unsigned char alloc_type() const
125    {  return (m_alloc_type_sizeof_char >> 5u)&(unsigned char)0x7;  }
126 
sizeof_charboost::interprocess::ipcdetail::block_header127    unsigned char sizeof_char() const
128    {  return m_alloc_type_sizeof_char & (unsigned char)0x1F;  }
129 
130    template<class CharType>
nameboost::interprocess::ipcdetail::block_header131    CharType *name() const
132    {
133       return const_cast<CharType*>(reinterpret_cast<const CharType*>
134          (reinterpret_cast<const char*>(this) + name_offset()));
135    }
136 
name_lengthboost::interprocess::ipcdetail::block_header137    unsigned short name_length() const
138    {  return m_num_char;   }
139 
name_offsetboost::interprocess::ipcdetail::block_header140    size_type name_offset() const
141    {
142       return this->value_offset() + get_rounded_size(size_type(m_value_bytes), size_type(sizeof_char()));
143    }
144 
valueboost::interprocess::ipcdetail::block_header145    void *value() const
146    {
147       return const_cast<char*>((reinterpret_cast<const char*>(this) + this->value_offset()));
148    }
149 
value_offsetboost::interprocess::ipcdetail::block_header150    size_type value_offset() const
151    {
152       return get_rounded_size(size_type(sizeof(block_header<size_type>)), size_type(m_value_alignment));
153    }
154 
155    template<class CharType>
less_compboost::interprocess::ipcdetail::block_header156    bool less_comp(const block_header<size_type> &b) const
157    {
158       return m_num_char < b.m_num_char ||
159              (m_num_char < b.m_num_char &&
160               std::char_traits<CharType>::compare(name<CharType>(), b.name<CharType>(), m_num_char) < 0);
161    }
162 
163    template<class CharType>
equal_compboost::interprocess::ipcdetail::block_header164    bool equal_comp(const block_header<size_type> &b) const
165    {
166       return m_num_char == b.m_num_char &&
167              std::char_traits<CharType>::compare(name<CharType>(), b.name<CharType>(), m_num_char) == 0;
168    }
169 
170    template<class T>
block_header_from_valueboost::interprocess::ipcdetail::block_header171    static block_header<size_type> *block_header_from_value(T *value)
172    {  return block_header_from_value(value, sizeof(T), ::boost::container::dtl::alignment_of<T>::value);  }
173 
block_header_from_valueboost::interprocess::ipcdetail::block_header174    static block_header<size_type> *block_header_from_value(const void *value, std::size_t sz, std::size_t algn)
175    {
176       block_header * hdr =
177          const_cast<block_header*>
178             (reinterpret_cast<const block_header*>(reinterpret_cast<const char*>(value) -
179                get_rounded_size(sizeof(block_header), algn)));
180       (void)sz;
181       //Some sanity checks
182       BOOST_ASSERT(hdr->m_value_alignment == algn);
183       BOOST_ASSERT(hdr->m_value_bytes % sz == 0);
184       return hdr;
185    }
186 
187    template<class Header>
from_first_headerboost::interprocess::ipcdetail::block_header188    static block_header<size_type> *from_first_header(Header *header)
189    {
190       block_header<size_type> * hdr =
191          reinterpret_cast<block_header<size_type>*>(reinterpret_cast<char*>(header) +
192        get_rounded_size( size_type(sizeof(Header))
193                        , size_type(::boost::container::dtl::alignment_of<block_header<size_type> >::value)));
194       //Some sanity checks
195       return hdr;
196    }
197 
198    template<class Header>
to_first_headerboost::interprocess::ipcdetail::block_header199    static Header *to_first_header(block_header<size_type> *bheader)
200    {
201       Header * hdr =
202          reinterpret_cast<Header*>(reinterpret_cast<char*>(bheader) -
203        get_rounded_size( size_type(sizeof(Header))
204                        , size_type(::boost::container::dtl::alignment_of<block_header<size_type> >::value)));
205       //Some sanity checks
206       return hdr;
207    }
208 };
209 
array_construct(void * mem,std::size_t num,in_place_interface & table)210 inline void array_construct(void *mem, std::size_t num, in_place_interface &table)
211 {
212    //Try constructors
213    std::size_t constructed = 0;
214    BOOST_TRY{
215       table.construct_n(mem, num, constructed);
216    }
217    //If there is an exception call destructors and erase index node
218    BOOST_CATCH(...){
219       std::size_t destroyed = 0;
220       table.destroy_n(mem, constructed, destroyed);
221       BOOST_RETHROW
222    }
223    BOOST_CATCH_END
224 }
225 
226 template<class CharT>
227 struct intrusive_compare_key
228 {
229    typedef CharT char_type;
230 
intrusive_compare_keyboost::interprocess::ipcdetail::intrusive_compare_key231    intrusive_compare_key(const CharT *str, std::size_t len)
232       :  mp_str(str), m_len(len)
233    {}
234 
235    const CharT *  mp_str;
236    std::size_t    m_len;
237 };
238 
239 //!This struct indicates an anonymous object creation
240 //!allocation
241 template<instance_type type>
242 class instance_t
243 {
instance_t()244    instance_t(){}
245 };
246 
247 template<class T>
248 struct char_if_void
249 {
250    typedef T type;
251 };
252 
253 template<>
254 struct char_if_void<void>
255 {
256    typedef char type;
257 };
258 
259 typedef instance_t<anonymous_type>  anonymous_instance_t;
260 typedef instance_t<unique_type>     unique_instance_t;
261 
262 
263 template<class Hook, class CharType, class SizeType>
264 struct intrusive_value_type_impl
265    :  public Hook
266 {
267    private:
268    //Non-copyable
269    intrusive_value_type_impl(const intrusive_value_type_impl &);
270    intrusive_value_type_impl& operator=(const intrusive_value_type_impl &);
271 
272    public:
273    typedef CharType char_type;
274    typedef SizeType size_type;
275 
intrusive_value_type_implboost::interprocess::ipcdetail::intrusive_value_type_impl276    intrusive_value_type_impl(){}
277 
278    enum  {  BlockHdrAlignment = ::boost::container::dtl::alignment_of<block_header<size_type> >::value  };
279 
get_block_headerboost::interprocess::ipcdetail::intrusive_value_type_impl280    block_header<size_type> *get_block_header() const
281    {
282       return const_cast<block_header<size_type>*>
283          (reinterpret_cast<const block_header<size_type> *>(reinterpret_cast<const char*>(this) +
284             get_rounded_size(size_type(sizeof(*this)), size_type(BlockHdrAlignment))));
285    }
286 
operator <boost::interprocess::ipcdetail::intrusive_value_type_impl287    bool operator <(const intrusive_value_type_impl<Hook, CharType, SizeType> & other) const
288    {  return (this->get_block_header())->template less_comp<CharType>(*other.get_block_header());  }
289 
operator ==boost::interprocess::ipcdetail::intrusive_value_type_impl290    bool operator ==(const intrusive_value_type_impl<Hook, CharType, SizeType> & other) const
291    {  return (this->get_block_header())->template equal_comp<CharType>(*other.get_block_header());  }
292 
get_intrusive_value_typeboost::interprocess::ipcdetail::intrusive_value_type_impl293    static intrusive_value_type_impl *get_intrusive_value_type(block_header<size_type> *hdr)
294    {
295       return reinterpret_cast<intrusive_value_type_impl *>(reinterpret_cast<char*>(hdr) -
296          get_rounded_size(size_type(sizeof(intrusive_value_type_impl)), size_type(BlockHdrAlignment)));
297    }
298 
nameboost::interprocess::ipcdetail::intrusive_value_type_impl299    CharType *name() const
300    {  return get_block_header()->template name<CharType>(); }
301 
name_lengthboost::interprocess::ipcdetail::intrusive_value_type_impl302    unsigned short name_length() const
303    {  return get_block_header()->name_length(); }
304 
valueboost::interprocess::ipcdetail::intrusive_value_type_impl305    void *value() const
306    {  return get_block_header()->value(); }
307 };
308 
309 template<class CharType>
310 class char_ptr_holder
311 {
312    public:
char_ptr_holder(const CharType * name)313    char_ptr_holder(const CharType *name)
314       : m_name(name)
315    {}
316 
char_ptr_holder(const anonymous_instance_t *)317    char_ptr_holder(const anonymous_instance_t *)
318       : m_name(static_cast<CharType*>(0))
319    {}
320 
char_ptr_holder(const unique_instance_t *)321    char_ptr_holder(const unique_instance_t *)
322       : m_name(reinterpret_cast<CharType*>(-1))
323    {}
324 
operator const CharType*()325    operator const CharType *()
326    {  return m_name;  }
327 
get() const328    const CharType *get() const
329    {  return m_name;  }
330 
is_unique() const331    bool is_unique() const
332    {  return m_name == reinterpret_cast<CharType*>(-1);  }
333 
is_anonymous() const334    bool is_anonymous() const
335    {  return m_name == static_cast<CharType*>(0);  }
336 
337    private:
338    const CharType *m_name;
339 };
340 
341 //!The key of the the named allocation information index. Stores an offset pointer
342 //!to a null terminated string and the length of the string to speed up sorting
343 template<class CharT, class VoidPointer>
344 struct index_key
345 {
346    typedef typename boost::intrusive::
347       pointer_traits<VoidPointer>::template
348          rebind_pointer<const CharT>::type               const_char_ptr_t;
349    typedef CharT                                         char_type;
350    typedef typename boost::intrusive::pointer_traits<const_char_ptr_t>::difference_type difference_type;
351    typedef typename boost::move_detail::make_unsigned<difference_type>::type size_type;
352 
353    private:
354    //Offset pointer to the object's name
355    const_char_ptr_t  mp_str;
356    //Length of the name buffer (null NOT included)
357    size_type         m_len;
358    public:
359 
360    //!Constructor of the key
index_keyboost::interprocess::ipcdetail::index_key361    index_key (const char_type *nm, size_type length)
362       : mp_str(nm), m_len(length)
363    {}
364 
365    //!Less than function for index ordering
operator <boost::interprocess::ipcdetail::index_key366    bool operator < (const index_key & right) const
367    {
368       return (m_len < right.m_len) ||
369                (m_len == right.m_len &&
370                 std::char_traits<char_type>::compare
371                   (to_raw_pointer(mp_str),to_raw_pointer(right.mp_str), m_len) < 0);
372    }
373 
374    //!Equal to function for index ordering
operator ==boost::interprocess::ipcdetail::index_key375    bool operator == (const index_key & right) const
376    {
377       return   m_len == right.m_len &&
378                std::char_traits<char_type>::compare
379                   (to_raw_pointer(mp_str), to_raw_pointer(right.mp_str), m_len) == 0;
380    }
381 
nameboost::interprocess::ipcdetail::index_key382    void name(const CharT *nm)
383    {  mp_str = nm; }
384 
name_lengthboost::interprocess::ipcdetail::index_key385    void name_length(size_type len)
386    {  m_len = len; }
387 
nameboost::interprocess::ipcdetail::index_key388    const CharT *name() const
389    {  return to_raw_pointer(mp_str); }
390 
name_lengthboost::interprocess::ipcdetail::index_key391    size_type name_length() const
392    {  return m_len; }
393 };
394 
395 //!The index_data stores a pointer to a buffer and the element count needed
396 //!to know how many destructors must be called when calling destroy
397 template<class VoidPointer>
398 struct index_data
399 {
400    typedef VoidPointer void_pointer;
401    void_pointer    m_ptr;
index_databoost::interprocess::ipcdetail::index_data402    explicit index_data(void *ptr) : m_ptr(ptr){}
403 
valueboost::interprocess::ipcdetail::index_data404    void *value() const
405    {  return static_cast<void*>(to_raw_pointer(m_ptr));  }
406 };
407 
408 template<class MemoryAlgorithm>
409 struct segment_manager_base_type
410 {  typedef segment_manager_base<MemoryAlgorithm> type;   };
411 
412 template<class CharT, class MemoryAlgorithm>
413 struct index_config
414 {
415    typedef typename MemoryAlgorithm::void_pointer        void_pointer;
416    typedef CharT                                         char_type;
417    typedef index_key<CharT, void_pointer>        key_type;
418    typedef index_data<void_pointer>              mapped_type;
419    typedef typename segment_manager_base_type
420       <MemoryAlgorithm>::type                            segment_manager_base;
421 
422    template<class HeaderBase>
423    struct intrusive_value_type
424    {  typedef intrusive_value_type_impl<HeaderBase, CharT, typename segment_manager_base::size_type>  type; };
425 
426    typedef intrusive_compare_key<CharT>            intrusive_compare_key_type;
427 };
428 
429 template<class Iterator, bool intrusive>
430 class segment_manager_iterator_value_adaptor
431 {
432    typedef typename Iterator::value_type        iterator_val_t;
433    typedef typename iterator_val_t::char_type   char_type;
434 
435    public:
segment_manager_iterator_value_adaptor(const typename Iterator::value_type & val)436    segment_manager_iterator_value_adaptor(const typename Iterator::value_type &val)
437       :  m_val(&val)
438    {}
439 
name() const440    const char_type *name() const
441    {  return m_val->name(); }
442 
name_length() const443    unsigned short name_length() const
444    {  return m_val->name_length(); }
445 
value() const446    const void *value() const
447    {  return m_val->value(); }
448 
449    const typename Iterator::value_type *m_val;
450 };
451 
452 
453 template<class Iterator>
454 class segment_manager_iterator_value_adaptor<Iterator, false>
455 {
456    typedef typename Iterator::value_type        iterator_val_t;
457    typedef typename iterator_val_t::first_type  first_type;
458    typedef typename iterator_val_t::second_type second_type;
459    typedef typename first_type::char_type       char_type;
460    typedef typename first_type::size_type       size_type;
461 
462    public:
segment_manager_iterator_value_adaptor(const typename Iterator::value_type & val)463    segment_manager_iterator_value_adaptor(const typename Iterator::value_type &val)
464       :  m_val(&val)
465    {}
466 
name() const467    const char_type *name() const
468    {  return m_val->first.name(); }
469 
name_length() const470    size_type name_length() const
471    {  return m_val->first.name_length(); }
472 
value() const473    const void *value() const
474    {
475       return reinterpret_cast<block_header<size_type>*>
476          (to_raw_pointer(m_val->second.m_ptr))->value();
477    }
478 
479    const typename Iterator::value_type *m_val;
480 };
481 
482 template<class Iterator, bool intrusive>
483 struct segment_manager_iterator_transform
484 {
485    typedef segment_manager_iterator_value_adaptor<Iterator, intrusive> result_type;
486 
operator ()boost::interprocess::ipcdetail::segment_manager_iterator_transform487    template <class T> result_type operator()(const T &arg) const
488    {  return result_type(arg); }
489 };
490 
491 }  //namespace ipcdetail {
492 
493 //These pointers are the ones the user will use to
494 //indicate previous allocation types
495 static const ipcdetail::anonymous_instance_t   * anonymous_instance = 0;
496 static const ipcdetail::unique_instance_t      * unique_instance = 0;
497 
498 namespace ipcdetail_really_deep_namespace {
499 
500 //Otherwise, gcc issues a warning of previously defined
501 //anonymous_instance and unique_instance
502 struct dummy
503 {
dummyboost::interprocess::ipcdetail_really_deep_namespace::dummy504    dummy()
505    {
506       (void)anonymous_instance;
507       (void)unique_instance;
508    }
509 };
510 
511 }  //detail_really_deep_namespace
512 
513 }} //namespace boost { namespace interprocess
514 
515 #include <boost/interprocess/detail/config_end.hpp>
516 
517 #endif //#ifndef BOOST_INTERPROCESS_SEGMENT_MANAGER_BASE_HPP
518 
519