]>
Commit | Line | Data |
---|---|---|
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_INTERSEGMENT_PTR_HPP | |
12 | #define BOOST_INTERPROCESS_INTERSEGMENT_PTR_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 | // interprocess | |
25 | #include <boost/interprocess/interprocess_fwd.hpp> | |
26 | #include <boost/interprocess/sync/scoped_lock.hpp> | |
27 | #include <boost/interprocess/sync/interprocess_mutex.hpp> | |
28 | #include <boost/interprocess/containers/flat_map.hpp> | |
29 | #include <boost/interprocess/containers/vector.hpp> //vector | |
30 | #include <boost/interprocess/containers/set.hpp> //set | |
31 | // interprocess/detail | |
32 | #include <boost/interprocess/detail/multi_segment_services.hpp> | |
33 | #include <boost/interprocess/detail/utilities.hpp> | |
34 | #include <boost/interprocess/detail/math_functions.hpp> | |
35 | #include <boost/interprocess/detail/cast_tags.hpp> | |
36 | #include <boost/interprocess/detail/mpl.hpp> | |
37 | // other boost | |
38 | #include <boost/core/no_exceptions_support.hpp> | |
39 | #include <boost/static_assert.hpp> //BOOST_STATIC_ASSERT | |
40 | #include <boost/integer/static_log2.hpp> | |
41 | #include <boost/assert.hpp> //BOOST_ASSERT | |
42 | // std | |
43 | #include <climits> //CHAR_BIT | |
44 | ||
45 | //!\file | |
46 | //! | |
47 | namespace boost { | |
48 | ||
49 | //Predeclarations | |
50 | template <class T> | |
51 | struct has_trivial_constructor; | |
52 | ||
53 | template <class T> | |
54 | struct has_trivial_destructor; | |
55 | ||
56 | namespace interprocess { | |
57 | ||
58 | template <class T> | |
59 | struct is_multisegment_ptr; | |
60 | ||
61 | struct intersegment_base | |
62 | { | |
63 | typedef intersegment_base self_t; | |
64 | BOOST_STATIC_ASSERT((sizeof(std::size_t) == sizeof(void*))); | |
65 | BOOST_STATIC_ASSERT((sizeof(void*)*CHAR_BIT == 32 || sizeof(void*)*CHAR_BIT == 64)); | |
66 | static const std::size_t size_t_bits = (sizeof(void*)*CHAR_BIT == 32) ? 32 : 64; | |
67 | static const std::size_t ctrl_bits = 2; | |
68 | static const std::size_t align_bits = 12; | |
69 | static const std::size_t align = std::size_t(1) << align_bits; | |
70 | static const std::size_t max_segment_size_bits = size_t_bits - 2; | |
71 | static const std::size_t max_segment_size = std::size_t(1) << max_segment_size_bits; | |
72 | ||
73 | static const std::size_t begin_bits = max_segment_size_bits - align_bits; | |
74 | static const std::size_t pow_size_bits_helper = static_log2<max_segment_size_bits>::value; | |
75 | static const std::size_t pow_size_bits = | |
76 | (max_segment_size_bits == (std::size_t(1) << pow_size_bits_helper)) ? | |
77 | pow_size_bits_helper : pow_size_bits_helper + 1; | |
78 | static const std::size_t frc_size_bits = | |
79 | size_t_bits - ctrl_bits - begin_bits - pow_size_bits; | |
80 | ||
81 | BOOST_STATIC_ASSERT(((size_t_bits - pow_size_bits - frc_size_bits) >= ctrl_bits )); | |
82 | ||
83 | static const std::size_t relative_size_bits = | |
84 | size_t_bits - max_segment_size_bits - ctrl_bits; | |
85 | ||
86 | static const std::size_t is_pointee_outside = 0; | |
87 | static const std::size_t is_in_stack = 1; | |
88 | static const std::size_t is_relative = 2; | |
89 | static const std::size_t is_segmented = 3; | |
90 | static const std::size_t is_max_mode = 4; | |
91 | ||
92 | intersegment_base() | |
93 | { | |
94 | this->set_mode(is_pointee_outside); | |
95 | this->set_null(); | |
96 | } | |
97 | ||
98 | struct relative_addressing | |
99 | { | |
100 | std::size_t ctrl : 2; | |
101 | std::size_t pow : pow_size_bits; | |
102 | std::size_t frc : frc_size_bits; | |
103 | std::size_t beg : begin_bits; | |
104 | std::ptrdiff_t off : sizeof(std::ptrdiff_t)*CHAR_BIT - 2; | |
105 | std::ptrdiff_t bits : 2; | |
106 | }; | |
107 | ||
108 | struct direct_addressing | |
109 | { | |
110 | std::size_t ctrl : 2; | |
111 | std::size_t dummy : sizeof(std::size_t)*CHAR_BIT - 2; | |
112 | void * addr; | |
113 | }; | |
114 | ||
115 | struct segmented_addressing | |
116 | { | |
117 | std::size_t ctrl : 2; | |
118 | std::size_t segment : sizeof(std::size_t)*CHAR_BIT - 2; | |
119 | std::size_t off : sizeof(std::size_t)*CHAR_BIT - 2; | |
120 | std::size_t bits : 2; | |
121 | }; | |
122 | ||
123 | union members_t{ | |
124 | relative_addressing relative; | |
125 | direct_addressing direct; | |
126 | segmented_addressing segmented; | |
127 | } members; | |
128 | ||
129 | BOOST_STATIC_ASSERT(sizeof(members_t) == 2*sizeof(std::size_t)); | |
130 | ||
131 | void *relative_calculate_begin_addr() const | |
132 | { | |
133 | const std::size_t mask = ~(align - 1); | |
134 | std::size_t beg = this->members.relative.beg; | |
135 | return reinterpret_cast<void*>((((std::size_t)this) & mask) - (beg << align_bits)); | |
136 | } | |
137 | ||
138 | void relative_set_begin_from_base(void *addr) | |
139 | { | |
140 | BOOST_ASSERT(addr < static_cast<void*>(this)); | |
141 | std::size_t off = reinterpret_cast<char*>(this) - reinterpret_cast<char*>(addr); | |
142 | members.relative.beg = off >> align_bits; | |
143 | } | |
144 | ||
145 | //!Obtains the address pointed by the | |
146 | //!object | |
147 | std::size_t relative_size() const | |
148 | { | |
149 | std::size_t pow = members.relative.pow; | |
150 | std::size_t size = (std::size_t(1u) << pow); | |
151 | BOOST_ASSERT(pow >= frc_size_bits); | |
152 | size |= members.relative.frc << (pow - frc_size_bits); | |
153 | return size; | |
154 | } | |
155 | ||
156 | static std::size_t calculate_size(std::size_t orig_size, std::size_t &pow, std::size_t &frc) | |
157 | { | |
158 | if(orig_size < align) | |
159 | orig_size = align; | |
160 | orig_size = ipcdetail::get_rounded_size_po2(orig_size, align); | |
161 | pow = ipcdetail::floor_log2(orig_size); | |
162 | std::size_t low_size = (std::size_t(1) << pow); | |
163 | std::size_t diff = orig_size - low_size; | |
164 | BOOST_ASSERT(pow >= frc_size_bits); | |
165 | std::size_t rounded = ipcdetail::get_rounded_size_po2 | |
166 | (diff, (std::size_t)(1u << (pow - frc_size_bits))); | |
167 | if(rounded == low_size){ | |
168 | ++pow; | |
169 | frc = 0; | |
170 | rounded = 0; | |
171 | } | |
172 | else{ | |
173 | frc = rounded >> (pow - frc_size_bits); | |
174 | } | |
175 | BOOST_ASSERT(((frc << (pow - frc_size_bits)) & (align-1))==0); | |
176 | return low_size + rounded; | |
177 | } | |
178 | ||
179 | std::size_t get_mode()const | |
180 | { return members.direct.ctrl; } | |
181 | ||
182 | void set_mode(std::size_t mode) | |
183 | { | |
184 | BOOST_ASSERT(mode < is_max_mode); | |
185 | members.direct.ctrl = mode; | |
186 | } | |
187 | ||
188 | //!Returns true if object represents | |
189 | //!null pointer | |
190 | bool is_null() const | |
191 | { | |
192 | return (this->get_mode() < is_relative) && | |
193 | !members.direct.dummy && | |
194 | !members.direct.addr; | |
195 | } | |
196 | ||
197 | //!Sets the object to represent | |
198 | //!the null pointer | |
199 | void set_null() | |
200 | { | |
201 | if(this->get_mode() >= is_relative){ | |
202 | this->set_mode(is_pointee_outside); | |
203 | } | |
204 | members.direct.dummy = 0; | |
205 | members.direct.addr = 0; | |
206 | } | |
207 | ||
208 | static std::size_t round_size(std::size_t orig_size) | |
209 | { | |
210 | std::size_t pow, frc; | |
211 | return calculate_size(orig_size, pow, frc); | |
212 | } | |
213 | }; | |
214 | ||
215 | ||
216 | ||
217 | //!Configures intersegment_ptr with the capability to address: | |
218 | //!2^(sizeof(std::size_t)*CHAR_BIT/2) segment groups | |
219 | //!2^(sizeof(std::size_t)*CHAR_BIT/2) segments per group. | |
220 | //!2^(sizeof(std::size_t)*CHAR_BIT/2)-1 bytes maximum per segment. | |
221 | //!The mapping is implemented through flat_maps synchronized with mutexes. | |
222 | template <class Mutex> | |
223 | struct flat_map_intersegment | |
224 | : public intersegment_base | |
225 | { | |
226 | typedef flat_map_intersegment<Mutex> self_t; | |
227 | ||
228 | void set_from_pointer(const volatile void *ptr) | |
229 | { this->set_from_pointer(const_cast<const void *>(ptr)); } | |
230 | ||
231 | //!Obtains the address pointed | |
232 | //!by the object | |
233 | void *to_raw_pointer() const | |
234 | { | |
235 | if(is_null()){ | |
236 | return 0; | |
237 | } | |
238 | switch(this->get_mode()){ | |
239 | case is_relative: | |
240 | return const_cast<char*>(reinterpret_cast<const char*>(this)) + members.relative.off; | |
241 | break; | |
242 | case is_segmented: | |
243 | { | |
244 | segment_info_t segment_info; | |
245 | std::size_t offset; | |
246 | void *this_base; | |
247 | get_segment_info_and_offset(this, segment_info, offset, this_base); | |
248 | char *base = static_cast<char*>(segment_info.group->address_of(this->members.segmented.segment)); | |
249 | return base + this->members.segmented.off; | |
250 | } | |
251 | break; | |
252 | case is_in_stack: | |
253 | case is_pointee_outside: | |
254 | return members.direct.addr; | |
255 | break; | |
256 | default: | |
257 | return 0; | |
258 | break; | |
259 | } | |
260 | } | |
261 | ||
262 | //!Calculates the distance between two basic_intersegment_ptr-s. | |
263 | //!This only works with two basic_intersegment_ptr pointing | |
264 | //!to the same segment. Otherwise undefined | |
265 | std::ptrdiff_t diff(const self_t &other) const | |
266 | { return static_cast<char*>(this->to_raw_pointer()) - static_cast<char*>(other.to_raw_pointer()); } | |
267 | ||
268 | //!Returns true if both point to | |
269 | //!the same object | |
270 | bool equal(const self_t &y) const | |
271 | { return this->to_raw_pointer() == y.to_raw_pointer(); } | |
272 | ||
273 | //!Returns true if *this is less than other. | |
274 | //!This only works with two basic_intersegment_ptr pointing | |
275 | //!to the same segment group. Otherwise undefined. Never throws | |
276 | bool less(const self_t &y) const | |
277 | { return this->to_raw_pointer() < y.to_raw_pointer(); } | |
278 | ||
279 | void swap(self_t &other) | |
280 | { | |
281 | void *ptr_this = this->to_raw_pointer(); | |
282 | void *ptr_other = other.to_raw_pointer(); | |
283 | other.set_from_pointer(ptr_this); | |
284 | this->set_from_pointer(ptr_other); | |
285 | } | |
286 | ||
287 | //!Sets the object internals to represent the | |
288 | //!address pointed by ptr | |
289 | void set_from_pointer(const void *ptr) | |
290 | { | |
291 | if(!ptr){ | |
292 | this->set_null(); | |
293 | return; | |
294 | } | |
295 | ||
296 | std::size_t mode = this->get_mode(); | |
297 | if(mode == is_in_stack){ | |
298 | members.direct.addr = const_cast<void*>(ptr); | |
299 | return; | |
300 | } | |
301 | if(mode == is_relative){ | |
302 | char *beg_addr = static_cast<char*>(this->relative_calculate_begin_addr()); | |
303 | std::size_t seg_size = this->relative_size(); | |
304 | if(ptr >= beg_addr && ptr < (beg_addr + seg_size)){ | |
305 | members.relative.off = static_cast<const char*>(ptr) - reinterpret_cast<const char*>(this); | |
306 | return; | |
307 | } | |
308 | } | |
309 | std::size_t ptr_offset; | |
310 | std::size_t this_offset; | |
311 | segment_info_t ptr_info; | |
312 | segment_info_t this_info; | |
313 | void *ptr_base; | |
314 | void *this_base; | |
315 | get_segment_info_and_offset(this, this_info, this_offset, this_base); | |
316 | ||
317 | if(!this_info.group){ | |
318 | this->set_mode(is_in_stack); | |
319 | this->members.direct.addr = const_cast<void*>(ptr); | |
320 | } | |
321 | else{ | |
322 | get_segment_info_and_offset(ptr, ptr_info, ptr_offset, ptr_base); | |
323 | ||
324 | if(ptr_info.group != this_info.group){ | |
325 | this->set_mode(is_pointee_outside); | |
326 | this->members.direct.addr = const_cast<void*>(ptr); | |
327 | } | |
328 | else if(ptr_info.id == this_info.id){ | |
329 | this->set_mode(is_relative); | |
330 | members.relative.off = (static_cast<const char*>(ptr) - reinterpret_cast<const char*>(this)); | |
331 | this->relative_set_begin_from_base(this_base); | |
332 | std::size_t pow, frc; | |
333 | std::size_t s = calculate_size(this_info.size, pow, frc); | |
334 | (void)s; | |
335 | BOOST_ASSERT(this_info.size == s); | |
336 | this->members.relative.pow = pow; | |
337 | this->members.relative.frc = frc; | |
338 | } | |
339 | else{ | |
340 | this->set_mode(is_segmented); | |
341 | this->members.segmented.segment = ptr_info.id; | |
342 | this->members.segmented.off = ptr_offset; | |
343 | } | |
344 | } | |
345 | } | |
346 | ||
347 | //!Sets the object internals to represent the address pointed | |
348 | //!by another flat_map_intersegment | |
349 | void set_from_other(const self_t &other) | |
350 | { | |
351 | this->set_from_pointer(other.to_raw_pointer()); | |
352 | } | |
353 | ||
354 | //!Increments internal | |
355 | //!offset | |
356 | void inc_offset(std::ptrdiff_t bytes) | |
357 | { | |
358 | this->set_from_pointer(static_cast<char*>(this->to_raw_pointer()) + bytes); | |
359 | } | |
360 | ||
361 | //!Decrements internal | |
362 | //!offset | |
363 | void dec_offset(std::ptrdiff_t bytes) | |
364 | { | |
365 | this->set_from_pointer(static_cast<char*>(this->to_raw_pointer()) - bytes); | |
366 | } | |
367 | ||
368 | ////////////////////////////////////// | |
369 | ////////////////////////////////////// | |
370 | ////////////////////////////////////// | |
371 | ||
372 | flat_map_intersegment() | |
373 | : intersegment_base() | |
374 | {} | |
375 | ||
376 | ~flat_map_intersegment() | |
377 | {} | |
378 | ||
379 | private: | |
380 | ||
381 | class segment_group_t | |
382 | { | |
383 | struct segment_data | |
384 | { | |
385 | void *addr; | |
386 | std::size_t size; | |
387 | }; | |
388 | vector<segment_data> m_segments; | |
389 | multi_segment_services &m_ms_services; | |
390 | ||
391 | public: | |
392 | segment_group_t(multi_segment_services &ms_services) | |
393 | : m_ms_services(ms_services) | |
394 | {} | |
395 | ||
396 | void push_back(void *addr, std::size_t size) | |
397 | { | |
398 | segment_data d = { addr, size }; | |
399 | m_segments.push_back(d); | |
400 | } | |
401 | ||
402 | void pop_back() | |
403 | { | |
404 | BOOST_ASSERT(!m_segments.empty()); | |
405 | m_segments.erase(--m_segments.end()); | |
406 | } | |
407 | ||
408 | ||
409 | void *address_of(std::size_t segment_id) | |
410 | { | |
411 | BOOST_ASSERT(segment_id < (std::size_t)m_segments.size()); | |
412 | return m_segments[segment_id].addr; | |
413 | } | |
414 | ||
415 | void clear_segments() | |
416 | { m_segments.clear(); } | |
417 | ||
418 | std::size_t get_size() const | |
419 | { return m_segments.size(); } | |
420 | ||
421 | multi_segment_services &get_multi_segment_services() const | |
422 | { return m_ms_services; } | |
423 | ||
424 | friend bool operator< (const segment_group_t&l, const segment_group_t &r) | |
425 | { return &l.m_ms_services < &r.m_ms_services; } | |
426 | }; | |
427 | ||
428 | struct segment_info_t | |
429 | { | |
430 | std::size_t size; | |
431 | std::size_t id; | |
432 | segment_group_t *group; | |
433 | segment_info_t() | |
434 | : size(0), id(0), group(0) | |
435 | {} | |
436 | }; | |
437 | ||
438 | typedef set<segment_group_t> segment_groups_t; | |
439 | ||
440 | typedef boost::interprocess::flat_map | |
441 | <const void * | |
442 | ,segment_info_t | |
443 | ,std::less<const void *> > ptr_to_segment_info_t; | |
444 | ||
445 | struct mappings_t : Mutex | |
446 | { | |
447 | //!Mutex to preserve integrity in multi-threaded | |
448 | //!enviroments | |
449 | typedef Mutex mutex_type; | |
450 | //!Maps base addresses and segment information | |
451 | //!(size and segment group and id)* | |
452 | ||
453 | ptr_to_segment_info_t m_ptr_to_segment_info; | |
454 | ||
455 | ~mappings_t() | |
456 | { | |
457 | //Check that all mappings have been erased | |
458 | BOOST_ASSERT(m_ptr_to_segment_info.empty()); | |
459 | } | |
460 | }; | |
461 | ||
462 | //Static members | |
463 | static mappings_t s_map; | |
464 | static segment_groups_t s_groups; | |
465 | public: | |
466 | ||
467 | typedef segment_group_t* segment_group_id; | |
468 | ||
469 | //!Returns the segment and offset | |
470 | //!of an address | |
471 | static void get_segment_info_and_offset(const void *ptr, segment_info_t &segment, std::size_t &offset, void *&base) | |
472 | { | |
473 | //------------------------------------------------------------------ | |
474 | boost::interprocess::scoped_lock<typename mappings_t::mutex_type> lock(s_map); | |
475 | //------------------------------------------------------------------ | |
476 | base = 0; | |
477 | if(s_map.m_ptr_to_segment_info.empty()){ | |
478 | segment = segment_info_t(); | |
479 | offset = reinterpret_cast<const char*>(ptr) - static_cast<const char*>(0); | |
480 | return; | |
481 | } | |
482 | //Find the first base address greater than ptr | |
483 | typename ptr_to_segment_info_t::iterator it | |
484 | = s_map.m_ptr_to_segment_info.upper_bound(ptr); | |
485 | if(it == s_map.m_ptr_to_segment_info.begin()){ | |
486 | segment = segment_info_t(); | |
487 | offset = reinterpret_cast<const char*>(ptr) - static_cast<const char *>(0); | |
488 | } | |
489 | //Go to the previous one | |
490 | --it; | |
491 | char * segment_base = const_cast<char*>(reinterpret_cast<const char*>(it->first)); | |
492 | std::size_t segment_size = it->second.size; | |
493 | ||
494 | if(segment_base <= reinterpret_cast<const char*>(ptr) && | |
495 | (segment_base + segment_size) >= reinterpret_cast<const char*>(ptr)){ | |
496 | segment = it->second; | |
497 | offset = reinterpret_cast<const char*>(ptr) - segment_base; | |
498 | base = segment_base; | |
499 | } | |
500 | else{ | |
501 | segment = segment_info_t(); | |
502 | offset = reinterpret_cast<const char*>(ptr) - static_cast<const char*>(0); | |
503 | } | |
504 | } | |
505 | ||
506 | //!Associates a segment defined by group/id with a base address and size. | |
507 | //!Returns false if the group is not found or there is an error | |
508 | static void insert_mapping(segment_group_id group_id, void *ptr, std::size_t size) | |
509 | { | |
510 | //------------------------------------------------------------------ | |
511 | boost::interprocess::scoped_lock<typename mappings_t::mutex_type> lock(s_map); | |
512 | //------------------------------------------------------------------ | |
513 | ||
514 | typedef typename ptr_to_segment_info_t::value_type value_type; | |
515 | typedef typename ptr_to_segment_info_t::iterator iterator; | |
516 | typedef std::pair<iterator, bool> it_b_t; | |
517 | ||
518 | segment_info_t info; | |
519 | info.group = group_id; | |
520 | info.size = size; | |
521 | info.id = group_id->get_size(); | |
522 | ||
523 | it_b_t ret = s_map.m_ptr_to_segment_info.insert(value_type(ptr, info)); | |
524 | BOOST_ASSERT(ret.second); | |
525 | ||
526 | value_eraser<ptr_to_segment_info_t> v_eraser(s_map.m_ptr_to_segment_info, ret.first); | |
527 | group_id->push_back(ptr, size); | |
528 | v_eraser.release(); | |
529 | } | |
530 | ||
531 | static bool erase_last_mapping(segment_group_id group_id) | |
532 | { | |
533 | //------------------------------------------------------------------ | |
534 | boost::interprocess::scoped_lock<typename mappings_t::mutex_type> lock(s_map); | |
535 | //------------------------------------------------------------------ | |
536 | if(!group_id->get_size()){ | |
537 | return false; | |
538 | } | |
539 | else{ | |
540 | void *addr = group_id->address_of(group_id->get_size()-1); | |
541 | group_id->pop_back(); | |
542 | std::size_t erased = s_map.m_ptr_to_segment_info.erase(addr); | |
543 | (void)erased; | |
544 | BOOST_ASSERT(erased); | |
545 | return true; | |
546 | } | |
547 | } | |
548 | ||
549 | static segment_group_id new_segment_group(multi_segment_services *services) | |
550 | { | |
551 | { //------------------------------------------------------------------ | |
552 | boost::interprocess::scoped_lock<typename mappings_t::mutex_type> lock(s_map); | |
553 | //------------------------------------------------------------------ | |
554 | typedef typename segment_groups_t::iterator iterator; | |
555 | std::pair<iterator, bool> ret = | |
556 | s_groups.insert(segment_group_t(*services)); | |
557 | BOOST_ASSERT(ret.second); | |
558 | return &*ret.first; | |
559 | } | |
560 | } | |
561 | ||
562 | static bool delete_group(segment_group_id id) | |
563 | { | |
564 | { //------------------------------------------------------------------ | |
565 | boost::interprocess::scoped_lock<typename mappings_t::mutex_type> lock(s_map); | |
566 | //------------------------------------------------------------------ | |
567 | bool success = 1u == s_groups.erase(segment_group_t(*id)); | |
568 | if(success){ | |
569 | typedef typename ptr_to_segment_info_t::iterator ptr_to_segment_info_it; | |
570 | ptr_to_segment_info_it it(s_map.m_ptr_to_segment_info.begin()); | |
571 | while(it != s_map.m_ptr_to_segment_info.end()){ | |
572 | if(it->second.group == id){ | |
573 | it = s_map.m_ptr_to_segment_info.erase(it); | |
574 | } | |
575 | else{ | |
576 | ++it; | |
577 | } | |
578 | } | |
579 | } | |
580 | return success; | |
581 | } | |
582 | } | |
583 | }; | |
584 | ||
585 | //!Static map-segment_info associated with | |
586 | //!flat_map_intersegment<> | |
587 | template <class Mutex> | |
588 | typename flat_map_intersegment<Mutex>::mappings_t | |
589 | flat_map_intersegment<Mutex>::s_map; | |
590 | ||
591 | //!Static segment group container associated with | |
592 | //!flat_map_intersegment<> | |
593 | template <class Mutex> | |
594 | typename flat_map_intersegment<Mutex>::segment_groups_t | |
595 | flat_map_intersegment<Mutex>::s_groups; | |
596 | ||
597 | //!A smart pointer that can point to a pointee that resides in another memory | |
598 | //!memory mapped or shared memory segment. | |
599 | template <class T> | |
600 | class intersegment_ptr : public flat_map_intersegment<interprocess_mutex> | |
601 | { | |
602 | typedef flat_map_intersegment<interprocess_mutex> PT; | |
603 | typedef intersegment_ptr<T> self_t; | |
604 | typedef PT base_t; | |
605 | ||
606 | void unspecified_bool_type_func() const {} | |
607 | typedef void (self_t::*unspecified_bool_type)() const; | |
608 | ||
609 | public: | |
610 | typedef T * pointer; | |
611 | typedef typename ipcdetail::add_reference<T>::type reference; | |
612 | typedef T value_type; | |
613 | typedef std::ptrdiff_t difference_type; | |
614 | typedef std::random_access_iterator_tag iterator_category; | |
615 | ||
616 | public: //Public Functions | |
617 | ||
618 | //!Constructor from raw pointer (allows "0" pointer conversion). | |
619 | //!Never throws. | |
620 | intersegment_ptr(pointer ptr = 0) | |
621 | { base_t::set_from_pointer(ptr); } | |
622 | ||
623 | //!Constructor from other pointer. | |
624 | //!Never throws. | |
625 | template <class U> | |
626 | intersegment_ptr(U *ptr){ base_t::set_from_pointer(pointer(ptr)); } | |
627 | ||
628 | //!Constructor from other intersegment_ptr | |
629 | //!Never throws | |
630 | intersegment_ptr(const intersegment_ptr& ptr) | |
631 | { base_t::set_from_other(ptr); } | |
632 | ||
633 | //!Constructor from other intersegment_ptr. If pointers of pointee types are | |
634 | //!convertible, intersegment_ptrs will be convertibles. Never throws. | |
635 | template<class T2> | |
636 | intersegment_ptr(const intersegment_ptr<T2> &ptr) | |
637 | { pointer p(ptr.get()); (void)p; base_t::set_from_other(ptr); } | |
638 | ||
639 | //!Emulates static_cast operator. | |
640 | //!Never throws. | |
641 | template<class U> | |
642 | intersegment_ptr(const intersegment_ptr<U> &r, ipcdetail::static_cast_tag) | |
643 | { base_t::set_from_pointer(static_cast<T*>(r.get())); } | |
644 | ||
645 | //!Emulates const_cast operator. | |
646 | //!Never throws. | |
647 | template<class U> | |
648 | intersegment_ptr(const intersegment_ptr<U> &r, ipcdetail::const_cast_tag) | |
649 | { base_t::set_from_pointer(const_cast<T*>(r.get())); } | |
650 | ||
651 | //!Emulates dynamic_cast operator. | |
652 | //!Never throws. | |
653 | template<class U> | |
654 | intersegment_ptr(const intersegment_ptr<U> &r, ipcdetail::dynamic_cast_tag) | |
655 | { base_t::set_from_pointer(dynamic_cast<T*>(r.get())); } | |
656 | ||
657 | //!Emulates reinterpret_cast operator. | |
658 | //!Never throws. | |
659 | template<class U> | |
660 | intersegment_ptr(const intersegment_ptr<U> &r, ipcdetail::reinterpret_cast_tag) | |
661 | { base_t::set_from_pointer(reinterpret_cast<T*>(r.get())); } | |
662 | ||
663 | //!Obtains raw pointer from offset. | |
664 | //!Never throws. | |
665 | pointer get()const | |
666 | { return static_cast<pointer>(base_t::to_raw_pointer()); } | |
667 | ||
668 | //!Pointer-like -> operator. It can return 0 pointer. | |
669 | //!Never throws. | |
670 | pointer operator->() const | |
671 | { return self_t::get(); } | |
672 | ||
673 | //!Dereferencing operator, if it is a null intersegment_ptr behavior | |
674 | //!is undefined. Never throws. | |
675 | reference operator* () const | |
676 | { return *(self_t::get()); } | |
677 | ||
678 | //!Indexing operator. | |
679 | //!Never throws. | |
680 | reference operator[](std::ptrdiff_t idx) const | |
681 | { return self_t::get()[idx]; } | |
682 | ||
683 | //!Assignment from pointer (saves extra conversion). | |
684 | //!Never throws. | |
685 | intersegment_ptr& operator= (pointer from) | |
686 | { base_t::set_from_pointer(from); return *this; } | |
687 | ||
688 | //!Assignment from other intersegment_ptr. | |
689 | //!Never throws. | |
690 | intersegment_ptr& operator= (const intersegment_ptr &ptr) | |
691 | { base_t::set_from_other(ptr); return *this; } | |
692 | ||
693 | //!Assignment from related intersegment_ptr. If pointers of pointee types | |
694 | //!are assignable, intersegment_ptrs will be assignable. Never throws. | |
695 | template <class T2> | |
696 | intersegment_ptr& operator= (const intersegment_ptr<T2> & ptr) | |
697 | { | |
698 | pointer p(ptr.get()); (void)p; | |
699 | base_t::set_from_other(ptr); return *this; | |
700 | } | |
701 | ||
702 | //!intersegment_ptr + std::ptrdiff_t. | |
703 | //!Never throws. | |
704 | intersegment_ptr operator+ (std::ptrdiff_t idx) const | |
705 | { | |
706 | intersegment_ptr result (*this); | |
707 | result.inc_offset(idx*sizeof(T)); | |
708 | return result; | |
709 | } | |
710 | ||
711 | //!intersegment_ptr - std::ptrdiff_t. | |
712 | //!Never throws. | |
713 | intersegment_ptr operator- (std::ptrdiff_t idx) const | |
714 | { | |
715 | intersegment_ptr result (*this); | |
716 | result.dec_offset(idx*sizeof(T)); | |
717 | return result; | |
718 | } | |
719 | ||
720 | //!intersegment_ptr += std::ptrdiff_t. | |
721 | //!Never throws. | |
722 | intersegment_ptr &operator+= (std::ptrdiff_t offset) | |
723 | { base_t::inc_offset(offset*sizeof(T)); return *this; } | |
724 | ||
725 | //!intersegment_ptr -= std::ptrdiff_t. | |
726 | //!Never throws. | |
727 | intersegment_ptr &operator-= (std::ptrdiff_t offset) | |
728 | { base_t::dec_offset(offset*sizeof(T)); return *this; } | |
729 | ||
730 | //!++intersegment_ptr. | |
731 | //!Never throws. | |
732 | intersegment_ptr& operator++ (void) | |
733 | { base_t::inc_offset(sizeof(T)); return *this; } | |
734 | ||
735 | //!intersegment_ptr++. | |
736 | //!Never throws. | |
737 | intersegment_ptr operator++ (int) | |
738 | { intersegment_ptr temp(*this); ++*this; return temp; } | |
739 | ||
740 | //!--intersegment_ptr. | |
741 | //!Never throws. | |
742 | intersegment_ptr& operator-- (void) | |
743 | { base_t::dec_offset(sizeof(T)); return *this; } | |
744 | ||
745 | //!intersegment_ptr--. | |
746 | //!Never throws. | |
747 | intersegment_ptr operator-- (int) | |
748 | { intersegment_ptr temp(*this); --*this; return temp; } | |
749 | ||
750 | //!Safe bool conversion operator. | |
751 | //!Never throws. | |
752 | operator unspecified_bool_type() const | |
753 | { return base_t::is_null()? 0 : &self_t::unspecified_bool_type_func; } | |
754 | ||
755 | //!Not operator. Not needed in theory, but improves portability. | |
756 | //!Never throws. | |
757 | bool operator! () const | |
758 | { return base_t::is_null(); } | |
759 | ||
760 | //!Swaps two intersegment_ptr-s. More efficient than standard swap. | |
761 | //!Never throws. | |
762 | void swap(intersegment_ptr &other) | |
763 | { base_t::swap(other); } | |
764 | ||
765 | //!Calculates the distance between two intersegment_ptr-s. | |
766 | //!This only works with two basic_intersegment_ptr pointing | |
767 | //!to the same segment. Otherwise undefined | |
768 | template <class T2> | |
769 | std::ptrdiff_t _diff(const intersegment_ptr<T2> &other) const | |
770 | { return base_t::diff(other); } | |
771 | ||
772 | //!Returns true if both point to the | |
773 | //!same object | |
774 | template <class T2> | |
775 | bool _equal(const intersegment_ptr<T2>&other) const | |
776 | { return base_t::equal(other); } | |
777 | ||
778 | //!Returns true if *this is less than other. | |
779 | //!This only works with two basic_intersegment_ptr pointing | |
780 | //!to the same segment group. Otherwise undefined. Never throws | |
781 | template <class T2> | |
782 | bool _less(const intersegment_ptr<T2> &other) const | |
783 | { return base_t::less(other); } | |
784 | }; | |
785 | ||
786 | //!Compares the equality of two intersegment_ptr-s. | |
787 | //!Never throws. | |
788 | template <class T1, class T2> inline | |
789 | bool operator ==(const intersegment_ptr<T1> &left, | |
790 | const intersegment_ptr<T2> &right) | |
791 | { | |
792 | //Make sure both pointers can be compared | |
793 | bool e = typename intersegment_ptr<T1>::pointer(0) == | |
794 | typename intersegment_ptr<T2>::pointer(0); | |
795 | (void)e; | |
796 | return left._equal(right); | |
797 | } | |
798 | ||
799 | //!Returns true if *this is less than other. | |
800 | //!This only works with two basic_intersegment_ptr pointing | |
801 | //!to the same segment group. Otherwise undefined. Never throws | |
802 | template <class T1, class T2> inline | |
803 | bool operator <(const intersegment_ptr<T1> &left, | |
804 | const intersegment_ptr<T2> &right) | |
805 | { | |
806 | //Make sure both pointers can be compared | |
807 | bool e = typename intersegment_ptr<T1>::pointer(0) < | |
808 | typename intersegment_ptr<T2>::pointer(0); | |
809 | (void)e; | |
810 | return left._less(right); | |
811 | } | |
812 | ||
813 | template<class T1, class T2> inline | |
814 | bool operator!= (const intersegment_ptr<T1> &pt1, | |
815 | const intersegment_ptr<T2> &pt2) | |
816 | { return !(pt1 ==pt2); } | |
817 | ||
818 | //!intersegment_ptr<T1> <= intersegment_ptr<T2>. | |
819 | //!Never throws. | |
820 | template<class T1, class T2> inline | |
821 | bool operator<= (const intersegment_ptr<T1> &pt1, | |
822 | const intersegment_ptr<T2> &pt2) | |
823 | { return !(pt1 > pt2); } | |
824 | ||
825 | //!intersegment_ptr<T1> > intersegment_ptr<T2>. | |
826 | //!Never throws. | |
827 | template<class T1, class T2> inline | |
828 | bool operator> (const intersegment_ptr<T1> &pt1, | |
829 | const intersegment_ptr<T2> &pt2) | |
830 | { return (pt2 < pt1); } | |
831 | ||
832 | //!intersegment_ptr<T1> >= intersegment_ptr<T2>. | |
833 | //!Never throws. | |
834 | template<class T1, class T2> inline | |
835 | bool operator>= (const intersegment_ptr<T1> &pt1, | |
836 | const intersegment_ptr<T2> &pt2) | |
837 | { return !(pt1 < pt2); } | |
838 | ||
839 | //!operator<< | |
840 | template<class E, class T, class U> inline | |
841 | std::basic_ostream<E, T> & operator<< | |
842 | (std::basic_ostream<E, T> & os, const intersegment_ptr<U> & p) | |
843 | { return os << p.get(); } | |
844 | ||
845 | //!operator>> | |
846 | template<class E, class T, class U> inline | |
847 | std::basic_istream<E, T> & operator>> | |
848 | (std::basic_istream<E, T> & os, intersegment_ptr<U> & p) | |
849 | { U * tmp; return os >> tmp; p = tmp; } | |
850 | ||
851 | //!std::ptrdiff_t + intersegment_ptr. | |
852 | //!The result is another pointer of the same segment | |
853 | template<class T> inline | |
854 | intersegment_ptr<T> operator+ | |
855 | (std::ptrdiff_t diff, const intersegment_ptr<T>& right) | |
856 | { return right + diff; } | |
857 | ||
858 | //!intersegment_ptr - intersegment_ptr. | |
859 | //!This only works with two intersegment_ptr-s that point to the | |
860 | //!same segment | |
861 | template <class T, class T2> inline | |
862 | std::ptrdiff_t operator- (const intersegment_ptr<T> &pt, | |
863 | const intersegment_ptr<T2> &pt2) | |
864 | { return pt._diff(pt2)/sizeof(T); } | |
865 | ||
866 | //! swap specialization | |
867 | template<class T> inline | |
868 | void swap (boost::interprocess::intersegment_ptr<T> &pt, | |
869 | boost::interprocess::intersegment_ptr<T> &pt2) | |
870 | { pt.swap(pt2); } | |
871 | ||
872 | //!to_raw_pointer() enables boost::mem_fn to recognize intersegment_ptr. | |
873 | //!Never throws. | |
874 | template<class T> inline | |
875 | T * to_raw_pointer(boost::interprocess::intersegment_ptr<T> const & p) | |
876 | { return p.get(); } | |
877 | ||
878 | //!Simulation of static_cast between pointers. | |
879 | //!Never throws. | |
880 | template<class T, class U> inline | |
881 | boost::interprocess::intersegment_ptr<T> static_pointer_cast(const boost::interprocess::intersegment_ptr<U> &r) | |
882 | { return boost::interprocess::intersegment_ptr<T>(r, boost::interprocess::ipcdetail::static_cast_tag()); } | |
883 | ||
884 | //!Simulation of const_cast between pointers. | |
885 | //!Never throws. | |
886 | template<class T, class U> inline | |
887 | boost::interprocess::intersegment_ptr<T> const_pointer_cast(const boost::interprocess::intersegment_ptr<U> &r) | |
888 | { return boost::interprocess::intersegment_ptr<T>(r, boost::interprocess::ipcdetail::const_cast_tag()); } | |
889 | ||
890 | //!Simulation of dynamic_cast between pointers. | |
891 | //!Never throws. | |
892 | template<class T, class U> inline | |
893 | boost::interprocess::intersegment_ptr<T> dynamic_pointer_cast(const boost::interprocess::intersegment_ptr<U> &r) | |
894 | { return boost::interprocess::intersegment_ptr<T>(r, boost::interprocess::ipcdetail::dynamic_cast_tag()); } | |
895 | ||
896 | //!Simulation of reinterpret_cast between pointers. | |
897 | //!Never throws. | |
898 | template<class T, class U> inline | |
899 | boost::interprocess::intersegment_ptr<T> reinterpret_pointer_cast(const boost::interprocess::intersegment_ptr<U> &r) | |
900 | { return boost::interprocess::intersegment_ptr<T>(r, boost::interprocess::ipcdetail::reinterpret_cast_tag()); } | |
901 | ||
902 | //!Trait class to detect if an smart pointer has | |
903 | //!multi-segment addressing capabilities. | |
904 | template <class T> | |
905 | struct is_multisegment_ptr | |
906 | <boost::interprocess::intersegment_ptr<T> > | |
907 | { | |
908 | static const bool value = true; | |
909 | }; | |
910 | ||
911 | } //namespace interprocess { | |
912 | ||
913 | #if defined(_MSC_VER) && (_MSC_VER < 1400) | |
914 | //!to_raw_pointer() enables boost::mem_fn to recognize intersegment_ptr. | |
915 | //!Never throws. | |
916 | template<class T> inline | |
917 | T * to_raw_pointer(boost::interprocess::intersegment_ptr<T> const & p) | |
918 | { return p.get(); } | |
919 | #endif | |
920 | ||
921 | //!has_trivial_constructor<> == true_type specialization | |
922 | //!for optimizations | |
923 | template <class T> | |
924 | struct has_trivial_constructor | |
925 | < boost::interprocess::intersegment_ptr<T> > | |
926 | : public true_type{}; | |
927 | ||
928 | //!has_trivial_destructor<> == true_type specialization | |
929 | //!for optimizations | |
930 | template <class T> | |
931 | struct has_trivial_destructor | |
932 | < boost::interprocess::intersegment_ptr<T> > | |
933 | : public true_type{}; | |
934 | ||
935 | } //namespace boost { | |
936 | ||
937 | #if 0 | |
938 | ||
939 | //bits | |
940 | //-> is_segmented | |
941 | //-> is_relative | |
942 | //-> is_in_stack | |
943 | //-> is_pointee_outside | |
944 | ||
945 | //Data | |
946 | ||
947 | ||
948 | ||
949 | ||
950 | //segmented: | |
951 | // | |
952 | // std::size_t ctrl : CTRL_BITS; | |
953 | // std::size_t segment : MAX_SEGMENT_BITS; | |
954 | // std::size_t offset; | |
955 | ||
956 | //RELATIVE_SIZE_BITS = SIZE_T_BITS - | |
957 | // MAX_SEGMENT_BITS - | |
958 | // CTRL_BITS 10 10 | |
959 | //MAX_SEGMENT_SIZE = SIZE_T_BITS - ALIGN_BITS 20 52 | |
960 | ||
961 | //SIZE_T_BITS - 1 - ALIGN_BITS 19 51 | |
962 | //POW_SIZE_BITS = upper_log2 | |
963 | // (SIZE_T_BITS - 1 - ALIGN_BITS) 5 6 | |
964 | //FRC_SIZE_BITS = SIZE_T_BITS - CTRL_BITS | |
965 | // MAX_SEGMENT_SIZE_ALIGNBITS - POW_SIZE_BITS 6 5 | |
966 | ||
967 | //relative: | |
968 | // | |
969 | // std::size_t ctrl : CTRL_BITS; 2 2 | |
970 | // std::size_t size_pow : POW_SIZE_BITS 5 6 | |
971 | // std::size_t size_frc : FRC_SIZE_BITS; 6 5 | |
972 | // std::size_t start : MAX_SEGMENT_SIZE_ALIGNBITS;19 51 | |
973 | // std::ptrdiff_t distance : SIZE_T_BITS; 32 64 | |
974 | ||
975 | //direct: | |
976 | // | |
977 | // std::size_t ctrl : CTRL_BITS; 2 2 | |
978 | // std::size_t dummy : SIZE_T_BITS - CTRL_BITS 30 62 | |
979 | // void *addr : SIZE_T_BITS; 32 64 | |
980 | ||
981 | //32 bits systems: | |
982 | //Page alignment: 2**12 | |
983 | // | |
984 | ||
985 | //!Obtains the address pointed by the | |
986 | //!object | |
987 | void *to_raw_pointer() const | |
988 | { | |
989 | if(this->is_pointee_outside() || this->is_in_stack()){ | |
990 | return raw_address(); | |
991 | } | |
992 | else if(this->is_relative()){ | |
993 | return (const_cast<char*>(reinterpret_cast<const char*>(this))) + this->relative_pointee_offset(); | |
994 | } | |
995 | else{ | |
996 | group_manager *m = get_segment_group_manager(addr); | |
997 | char *base = static_cast<char*>(m->get_id_address(this->segmented_id())); | |
998 | return base + this->segmented_offset(); | |
999 | } | |
1000 | } | |
1001 | ||
1002 | void set_from_pointer(const void *ptr) | |
1003 | { | |
1004 | if(!ptr){ | |
1005 | this->set_pointee_outside(); | |
1006 | this->raw_address(ptr); | |
1007 | } | |
1008 | else if(this->is_in_stack()){ | |
1009 | this->raw_address(ptr); | |
1010 | } | |
1011 | else if(this->is_relative() && | |
1012 | ( (ptr >= this->relative_start()) | |
1013 | &&(ptr < this->relative_start() + this->relative_size())) | |
1014 | ){ | |
1015 | this->relative_offset(ptr - this); | |
1016 | } | |
1017 | else{ | |
1018 | segment_info_t ptr_info = get_id_from_addr(ptr); | |
1019 | segment_info_t this_info = get_id_from_addr(this); | |
1020 | if(ptr_info.segment_group != this_info.segment_group){ | |
1021 | if(!ptr_info.segment_group){ | |
1022 | this->set_in_stack(); | |
1023 | } | |
1024 | else{ | |
1025 | this->set_pointee_outside(); | |
1026 | } | |
1027 | } | |
1028 | else if(ptr_info.segment_id == this_info.segment_id){ | |
1029 | set_relative(); | |
1030 | this->relative_size (ptr_info.size); | |
1031 | this->relative_offset(static_cast<const char*>(ptr) - reinterpret_cast<const char*>(this)); | |
1032 | this->relative_start (ptr_info.base); | |
1033 | } | |
1034 | } | |
1035 | } | |
1036 | ||
1037 | void set_from_other(const self_t &other) | |
1038 | { this->set_from_pointer(other.to_raw_pointer()); } | |
1039 | ||
1040 | #endif | |
1041 | ||
1042 | #include <boost/interprocess/detail/config_end.hpp> | |
1043 | ||
1044 | #endif //#ifndef BOOST_INTERPROCESS_INTERSEGMENT_PTR_HPP |