]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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: | |
67 | mem_algo_deallocator(void *ptr, MemoryAlgorithm &algo) | |
68 | : m_ptr(ptr), m_algo(algo) | |
69 | {} | |
70 | ||
71 | void release() | |
72 | { m_ptr = 0; } | |
73 | ||
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 | ||
86 | 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> | |
99 | block_header &operator= (const T& ) | |
100 | { return *this; } | |
101 | ||
102 | 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 | ||
112 | size_type value_bytes() const | |
113 | { return m_value_bytes; } | |
114 | ||
115 | template<class Header> | |
116 | size_type total_size_with_header() const | |
117 | { | |
118 | return get_rounded_size | |
119 | ( size_type(sizeof(Header)) | |
120 | , size_type(::boost::container::container_detail::alignment_of<block_header<size_type> >::value)) | |
121 | + total_size(); | |
122 | } | |
123 | ||
124 | unsigned char alloc_type() const | |
125 | { return (m_alloc_type_sizeof_char >> 5u)&(unsigned char)0x7; } | |
126 | ||
127 | unsigned char sizeof_char() const | |
128 | { return m_alloc_type_sizeof_char & (unsigned char)0x1F; } | |
129 | ||
130 | template<class CharType> | |
131 | CharType *name() const | |
132 | { | |
133 | return const_cast<CharType*>(reinterpret_cast<const CharType*> | |
134 | (reinterpret_cast<const char*>(this) + name_offset())); | |
135 | } | |
136 | ||
137 | unsigned short name_length() const | |
138 | { return m_num_char; } | |
139 | ||
140 | 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 | ||
145 | void *value() const | |
146 | { | |
147 | return const_cast<char*>((reinterpret_cast<const char*>(this) + this->value_offset())); | |
148 | } | |
149 | ||
150 | 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> | |
156 | 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> | |
164 | 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> | |
171 | static block_header<size_type> *block_header_from_value(T *value) | |
172 | { return block_header_from_value(value, sizeof(T), ::boost::container::container_detail::alignment_of<T>::value); } | |
173 | ||
174 | 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> | |
188 | 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::container_detail::alignment_of<block_header<size_type> >::value))); | |
194 | //Some sanity checks | |
195 | return hdr; | |
196 | } | |
197 | ||
198 | template<class Header> | |
199 | 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::container_detail::alignment_of<block_header<size_type> >::value))); | |
205 | //Some sanity checks | |
206 | return hdr; | |
207 | } | |
208 | }; | |
209 | ||
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 | ||
231 | 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 | { | |
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 | ||
276 | intrusive_value_type_impl(){} | |
277 | ||
278 | enum { BlockHdrAlignment = ::boost::container::container_detail::alignment_of<block_header<size_type> >::value }; | |
279 | ||
280 | 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 | ||
287 | 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 | ||
290 | 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 | ||
293 | 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 | ||
299 | CharType *name() const | |
300 | { return get_block_header()->template name<CharType>(); } | |
301 | ||
302 | unsigned short name_length() const | |
303 | { return get_block_header()->name_length(); } | |
304 | ||
305 | void *value() const | |
306 | { return get_block_header()->value(); } | |
307 | }; | |
308 | ||
309 | template<class CharType> | |
310 | class char_ptr_holder | |
311 | { | |
312 | public: | |
313 | char_ptr_holder(const CharType *name) | |
314 | : m_name(name) | |
315 | {} | |
316 | ||
317 | char_ptr_holder(const anonymous_instance_t *) | |
318 | : m_name(static_cast<CharType*>(0)) | |
319 | {} | |
320 | ||
321 | char_ptr_holder(const unique_instance_t *) | |
322 | : m_name(reinterpret_cast<CharType*>(-1)) | |
323 | {} | |
324 | ||
325 | operator const CharType *() | |
326 | { return m_name; } | |
327 | ||
328 | const CharType *get() const | |
329 | { return m_name; } | |
330 | ||
331 | bool is_unique() const | |
332 | { return m_name == reinterpret_cast<CharType*>(-1); } | |
333 | ||
334 | 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 | |
361 | 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 | |
366 | 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 | |
375 | 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 | ||
382 | void name(const CharT *nm) | |
383 | { mp_str = nm; } | |
384 | ||
385 | void name_length(size_type len) | |
386 | { m_len = len; } | |
387 | ||
388 | const CharT *name() const | |
389 | { return to_raw_pointer(mp_str); } | |
390 | ||
391 | 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; | |
402 | explicit index_data(void *ptr) : m_ptr(ptr){} | |
403 | ||
404 | 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: | |
436 | segment_manager_iterator_value_adaptor(const typename Iterator::value_type &val) | |
437 | : m_val(&val) | |
438 | {} | |
439 | ||
440 | const char_type *name() const | |
441 | { return m_val->name(); } | |
442 | ||
443 | unsigned short name_length() const | |
444 | { return m_val->name_length(); } | |
445 | ||
446 | 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: | |
463 | segment_manager_iterator_value_adaptor(const typename Iterator::value_type &val) | |
464 | : m_val(&val) | |
465 | {} | |
466 | ||
467 | const char_type *name() const | |
468 | { return m_val->first.name(); } | |
469 | ||
470 | size_type name_length() const | |
471 | { return m_val->first.name_length(); } | |
472 | ||
473 | 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 | ||
487 | 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 | { | |
504 | 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 |