]>
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_DETAIL_MANAGED_MEMORY_IMPL_HPP | |
12 | #define BOOST_INTERPROCESS_DETAIL_MANAGED_MEMORY_IMPL_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/interprocess/interprocess_fwd.hpp> | |
26 | #include <boost/interprocess/detail/utilities.hpp> | |
27 | #include <boost/interprocess/detail/os_file_functions.hpp> | |
28 | #include <boost/interprocess/creation_tags.hpp> | |
29 | #include <boost/interprocess/exceptions.hpp> | |
30 | #include <boost/interprocess/segment_manager.hpp> | |
31 | #include <boost/interprocess/sync/scoped_lock.hpp> | |
32 | #include <boost/interprocess/detail/nothrow.hpp> | |
33 | #include <boost/interprocess/detail/simple_swap.hpp> | |
34 | // | |
35 | #include <boost/core/no_exceptions_support.hpp> | |
36 | // | |
37 | #include <boost/intrusive/detail/minimal_pair_header.hpp> | |
38 | #include <boost/assert.hpp> | |
39 | ||
40 | //!\file | |
41 | //!Describes a named shared memory allocation user class. | |
42 | //! | |
43 | ||
44 | namespace boost { | |
45 | namespace interprocess { | |
46 | namespace ipcdetail { | |
47 | ||
48 | template<class BasicManagedMemoryImpl> | |
49 | class create_open_func; | |
50 | ||
51 | template< | |
52 | class CharType, | |
53 | class MemoryAlgorithm, | |
54 | template<class IndexConfig> class IndexType | |
55 | > | |
56 | struct segment_manager_type | |
57 | { | |
58 | typedef segment_manager<CharType, MemoryAlgorithm, IndexType> type; | |
59 | }; | |
60 | ||
61 | //!This class is designed to be a base class to classes that manage | |
62 | //!creation of objects in a fixed size memory buffer. Apart | |
63 | //!from allocating raw memory, the user can construct named objects. To | |
64 | //!achieve this, this class uses the reserved space provided by the allocation | |
65 | //!algorithm to place a named_allocator_algo, who takes care of name mappings. | |
66 | //!The class can be customized with the char type used for object names | |
67 | //!and the memory allocation algorithm to be used.*/ | |
68 | template < class CharType | |
69 | , class MemoryAlgorithm | |
70 | , template<class IndexConfig> class IndexType | |
71 | , std::size_t Offset = 0 | |
72 | > | |
73 | class basic_managed_memory_impl | |
74 | { | |
75 | //Non-copyable | |
76 | basic_managed_memory_impl(const basic_managed_memory_impl &); | |
77 | basic_managed_memory_impl &operator=(const basic_managed_memory_impl &); | |
78 | ||
79 | template<class BasicManagedMemoryImpl> | |
80 | friend class create_open_func; | |
81 | ||
82 | public: | |
83 | typedef typename segment_manager_type | |
84 | <CharType, MemoryAlgorithm, IndexType>::type segment_manager; | |
85 | typedef CharType char_type; | |
86 | typedef MemoryAlgorithm memory_algorithm; | |
87 | typedef typename MemoryAlgorithm::mutex_family mutex_family; | |
88 | typedef CharType char_t; | |
89 | typedef typename MemoryAlgorithm::size_type size_type; | |
90 | typedef typename MemoryAlgorithm::difference_type difference_type; | |
91 | typedef difference_type handle_t; | |
92 | typedef typename segment_manager:: | |
93 | const_named_iterator const_named_iterator; | |
94 | typedef typename segment_manager:: | |
95 | const_unique_iterator const_unique_iterator; | |
96 | ||
97 | #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) | |
98 | ||
99 | typedef typename | |
100 | segment_manager::char_ptr_holder_t char_ptr_holder_t; | |
101 | //Experimental. Don't use. | |
102 | ||
103 | typedef typename segment_manager::multiallocation_chain multiallocation_chain; | |
104 | ||
105 | #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED | |
106 | ||
107 | static const size_type PayloadPerAllocation = segment_manager::PayloadPerAllocation; | |
108 | ||
109 | private: | |
110 | typedef basic_managed_memory_impl | |
111 | <CharType, MemoryAlgorithm, IndexType, Offset> self_t; | |
112 | protected: | |
113 | template<class ManagedMemory> | |
114 | static bool grow(const char *filename, size_type extra_bytes) | |
115 | { | |
116 | typedef typename ManagedMemory::device_type device_type; | |
117 | //Increase file size | |
118 | try{ | |
119 | offset_t old_size; | |
120 | { | |
121 | device_type f(open_or_create, filename, read_write); | |
122 | if(!f.get_size(old_size)) | |
123 | return false; | |
124 | f.truncate(old_size + extra_bytes); | |
125 | } | |
126 | ManagedMemory managed_memory(open_only, filename); | |
127 | //Grow always works | |
128 | managed_memory.self_t::grow(extra_bytes); | |
129 | } | |
130 | catch(...){ | |
131 | return false; | |
132 | } | |
133 | return true; | |
134 | } | |
135 | ||
136 | template<class ManagedMemory> | |
137 | static bool shrink_to_fit(const char *filename) | |
138 | { | |
139 | typedef typename ManagedMemory::device_type device_type; | |
140 | size_type new_size; | |
141 | try{ | |
142 | ManagedMemory managed_memory(open_only, filename); | |
143 | managed_memory.get_size(); | |
144 | managed_memory.self_t::shrink_to_fit(); | |
145 | new_size = managed_memory.get_size(); | |
146 | } | |
147 | catch(...){ | |
148 | return false; | |
149 | } | |
150 | ||
151 | //Decrease file size | |
152 | { | |
153 | device_type f(open_or_create, filename, read_write); | |
154 | f.truncate(new_size); | |
155 | } | |
156 | return true; | |
157 | } | |
158 | ||
159 | //!Constructor. Allocates basic resources. Never throws. | |
160 | basic_managed_memory_impl() | |
161 | : mp_header(0){} | |
162 | ||
163 | //!Destructor. Calls close. Never throws. | |
164 | ~basic_managed_memory_impl() | |
165 | { this->close_impl(); } | |
166 | ||
167 | //!Places segment manager in the reserved space. This can throw. | |
168 | bool create_impl (void *addr, size_type size) | |
169 | { | |
170 | if(mp_header) return false; | |
171 | ||
172 | //Check if there is enough space | |
173 | if(size < segment_manager::get_min_size()) | |
174 | return false; | |
175 | ||
176 | //This function should not throw. The index construction can | |
177 | //throw if constructor allocates memory. So we must catch it. | |
178 | BOOST_TRY{ | |
179 | //Let's construct the allocator in memory | |
180 | mp_header = ::new(addr, boost_container_new_t()) segment_manager(size); | |
181 | } | |
182 | BOOST_CATCH(...){ | |
183 | return false; | |
184 | } | |
185 | BOOST_CATCH_END | |
186 | return true; | |
187 | } | |
188 | ||
189 | //!Connects to a segment manager in the reserved buffer. Never throws. | |
190 | bool open_impl (void *addr, size_type) | |
191 | { | |
192 | if(mp_header) return false; | |
193 | mp_header = static_cast<segment_manager*>(addr); | |
194 | return true; | |
195 | } | |
196 | ||
197 | //!Frees resources. Never throws. | |
198 | bool close_impl() | |
199 | { | |
200 | bool ret = mp_header != 0; | |
201 | mp_header = 0; | |
202 | return ret; | |
203 | } | |
204 | ||
205 | //!Frees resources and destroys common resources. Never throws. | |
206 | bool destroy_impl() | |
207 | { | |
208 | if(mp_header == 0) | |
209 | return false; | |
210 | mp_header->~segment_manager(); | |
211 | this->close_impl(); | |
212 | return true; | |
213 | } | |
214 | ||
215 | //! | |
216 | void grow(size_type extra_bytes) | |
217 | { mp_header->grow(extra_bytes); } | |
218 | ||
219 | void shrink_to_fit() | |
220 | { mp_header->shrink_to_fit(); } | |
221 | ||
222 | public: | |
223 | ||
224 | //!Returns segment manager. Never throws. | |
225 | segment_manager *get_segment_manager() const | |
226 | { return mp_header; } | |
227 | ||
228 | //!Returns the base address of the memory in this process. Never throws. | |
229 | void * get_address () const | |
230 | { return reinterpret_cast<char*>(mp_header) - Offset; } | |
231 | ||
232 | //!Returns the size of memory segment. Never throws. | |
233 | size_type get_size () const | |
234 | { return mp_header->get_size() + Offset; } | |
235 | ||
236 | //!Returns the number of free bytes of the memory | |
237 | //!segment | |
238 | size_type get_free_memory() const | |
239 | { return mp_header->get_free_memory(); } | |
240 | ||
241 | //!Returns the result of "all_memory_deallocated()" function | |
242 | //!of the used memory algorithm | |
243 | bool all_memory_deallocated() | |
244 | { return mp_header->all_memory_deallocated(); } | |
245 | ||
246 | //!Returns the result of "check_sanity()" function | |
247 | //!of the used memory algorithm | |
248 | bool check_sanity() | |
249 | { return mp_header->check_sanity(); } | |
250 | ||
251 | //!Writes to zero free memory (memory not yet allocated) of | |
252 | //!the memory algorithm | |
253 | void zero_free_memory() | |
254 | { mp_header->zero_free_memory(); } | |
255 | ||
256 | //!Transforms an absolute address into an offset from base address. | |
257 | //!The address must belong to the memory segment. Never throws. | |
258 | handle_t get_handle_from_address (const void *ptr) const | |
259 | { | |
260 | return (handle_t)(reinterpret_cast<const char*>(ptr) - | |
261 | reinterpret_cast<const char*>(this->get_address())); | |
262 | } | |
263 | ||
264 | //!Returns true if the address belongs to the managed memory segment | |
265 | bool belongs_to_segment (const void *ptr) const | |
266 | { | |
267 | return ptr >= this->get_address() && | |
268 | ptr < (reinterpret_cast<const char*>(this->get_address()) + this->get_size()); | |
269 | } | |
270 | ||
271 | //!Transforms previously obtained offset into an absolute address in the | |
272 | //!process space of the current process. Never throws.*/ | |
273 | void * get_address_from_handle (handle_t offset) const | |
274 | { return reinterpret_cast<char*>(this->get_address()) + offset; } | |
275 | ||
276 | //!Searches for nbytes of free memory in the segment, marks the | |
277 | //!memory as used and return the pointer to the memory. If no | |
278 | //!memory is available throws a boost::interprocess::bad_alloc exception | |
279 | void* allocate (size_type nbytes) | |
280 | { return mp_header->allocate(nbytes); } | |
281 | ||
282 | //!Searches for nbytes of free memory in the segment, marks the | |
283 | //!memory as used and return the pointer to the memory. If no memory | |
284 | //!is available returns 0. Never throws. | |
285 | void* allocate (size_type nbytes, const std::nothrow_t &tag) | |
286 | { return mp_header->allocate(nbytes, tag); } | |
287 | ||
288 | //!Allocates nbytes bytes aligned to "alignment" bytes. "alignment" | |
289 | //!must be power of two. If no memory | |
290 | //!is available returns 0. Never throws. | |
291 | void * allocate_aligned (size_type nbytes, size_type alignment, const std::nothrow_t &tag) | |
292 | { return mp_header->allocate_aligned(nbytes, alignment, tag); } | |
293 | ||
294 | template<class T> | |
295 | T * allocation_command (boost::interprocess::allocation_type command, size_type limit_size, | |
296 | size_type &prefer_in_recvd_out_size, T *&reuse) | |
297 | { return mp_header->allocation_command(command, limit_size, prefer_in_recvd_out_size, reuse); } | |
298 | ||
299 | //!Allocates nbytes bytes aligned to "alignment" bytes. "alignment" | |
300 | //!must be power of two. If no | |
301 | //!memory is available throws a boost::interprocess::bad_alloc exception | |
302 | void * allocate_aligned(size_type nbytes, size_type alignment) | |
303 | { return mp_header->allocate_aligned(nbytes, alignment); } | |
304 | ||
305 | #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) | |
306 | ||
307 | //Experimental. Don't use. | |
308 | ||
309 | //!Allocates n_elements of elem_bytes bytes. | |
310 | //!Throws bad_alloc on failure. chain.size() is not increased on failure. | |
311 | void allocate_many(size_type elem_bytes, size_type n_elements, multiallocation_chain &chain) | |
312 | { mp_header->allocate_many(elem_bytes, n_elements, chain); } | |
313 | ||
314 | //!Allocates n_elements, each one of element_lengths[i]*sizeof_element bytes. | |
315 | //!Throws bad_alloc on failure. chain.size() is not increased on failure. | |
316 | void allocate_many(const size_type *element_lengths, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain) | |
317 | { mp_header->allocate_many(element_lengths, n_elements, sizeof_element, chain); } | |
318 | ||
319 | //!Allocates n_elements of elem_bytes bytes. | |
320 | //!Non-throwing version. chain.size() is not increased on failure. | |
321 | void allocate_many(const std::nothrow_t &tag, size_type elem_bytes, size_type n_elements, multiallocation_chain &chain) | |
322 | { mp_header->allocate_many(tag, elem_bytes, n_elements, chain); } | |
323 | ||
324 | //!Allocates n_elements, each one of | |
325 | //!element_lengths[i]*sizeof_element bytes. | |
326 | //!Non-throwing version. chain.size() is not increased on failure. | |
327 | void allocate_many(const std::nothrow_t &tag, const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain) | |
328 | { mp_header->allocate_many(tag, elem_sizes, n_elements, sizeof_element, chain); } | |
329 | ||
330 | //!Deallocates all elements contained in chain. | |
331 | //!Never throws. | |
332 | void deallocate_many(multiallocation_chain &chain) | |
333 | { mp_header->deallocate_many(chain); } | |
334 | ||
335 | #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED | |
336 | ||
337 | //!Marks previously allocated memory as free. Never throws. | |
338 | void deallocate (void *addr) | |
339 | { if (mp_header) mp_header->deallocate(addr); } | |
340 | ||
341 | //!Tries to find a previous named allocation address. Returns a memory | |
342 | //!buffer and the object count. If not found returned pointer is 0. | |
343 | //!Never throws. | |
344 | template <class T> | |
345 | std::pair<T*, size_type> find (char_ptr_holder_t name) | |
346 | { return mp_header->template find<T>(name); } | |
347 | ||
348 | //!Creates a named object or array in memory | |
349 | //! | |
350 | //!Allocates and constructs a T object or an array of T in memory, | |
351 | //!associates this with the given name and returns a pointer to the | |
352 | //!created object. If an array is being constructed all objects are | |
353 | //!created using the same parameters given to this function. | |
354 | //! | |
355 | //!-> If the name was previously used, returns 0. | |
356 | //! | |
357 | //!-> Throws boost::interprocess::bad_alloc if there is no available memory | |
358 | //! | |
359 | //!-> If T's constructor throws, the function throws that exception. | |
360 | //! | |
361 | //!Memory is freed automatically if T's constructor throws and if an | |
362 | //!array was being constructed, destructors of created objects are called | |
363 | //!before freeing the memory. | |
364 | template <class T> | |
365 | typename segment_manager::template construct_proxy<T>::type | |
366 | construct(char_ptr_holder_t name) | |
367 | { return mp_header->template construct<T>(name); } | |
368 | ||
369 | //!Finds or creates a named object or array in memory | |
370 | //! | |
371 | //!Tries to find an object with the given name in memory. If | |
372 | //!found, returns the pointer to this pointer. If the object is not found, | |
373 | //!allocates and constructs a T object or an array of T in memory, | |
374 | //!associates this with the given name and returns a pointer to the | |
375 | //!created object. If an array is being constructed all objects are | |
376 | //!created using the same parameters given to this function. | |
377 | //! | |
378 | //!-> Throws boost::interprocess::bad_alloc if there is no available memory | |
379 | //! | |
380 | //!-> If T's constructor throws, the function throws that exception. | |
381 | //! | |
382 | //!Memory is freed automatically if T's constructor throws and if an | |
383 | //!array was being constructed, destructors of created objects are called | |
384 | //!before freeing the memory. | |
385 | template <class T> | |
386 | typename segment_manager::template construct_proxy<T>::type | |
387 | find_or_construct(char_ptr_holder_t name) | |
388 | { return mp_header->template find_or_construct<T>(name); } | |
389 | ||
390 | //!Creates a named object or array in memory | |
391 | //! | |
392 | //!Allocates and constructs a T object or an array of T in memory, | |
393 | //!associates this with the given name and returns a pointer to the | |
394 | //!created object. If an array is being constructed all objects are | |
395 | //!created using the same parameters given to this function. | |
396 | //! | |
397 | //!-> If the name was previously used, returns 0. | |
398 | //! | |
399 | //!-> Returns 0 if there is no available memory | |
400 | //! | |
401 | //!-> If T's constructor throws, the function throws that exception. | |
402 | //! | |
403 | //!Memory is freed automatically if T's constructor throws and if an | |
404 | //!array was being constructed, destructors of created objects are called | |
405 | //!before freeing the memory. | |
406 | template <class T> | |
407 | typename segment_manager::template construct_proxy<T>::type | |
408 | construct(char_ptr_holder_t name, const std::nothrow_t &tag) | |
409 | { return mp_header->template construct<T>(name, tag); } | |
410 | ||
411 | //!Finds or creates a named object or array in memory | |
412 | //! | |
413 | //!Tries to find an object with the given name in memory. If | |
414 | //!found, returns the pointer to this pointer. If the object is not found, | |
415 | //!allocates and constructs a T object or an array of T in memory, | |
416 | //!associates this with the given name and returns a pointer to the | |
417 | //!created object. If an array is being constructed all objects are | |
418 | //!created using the same parameters given to this function. | |
419 | //! | |
420 | //!-> Returns 0 if there is no available memory | |
421 | //! | |
422 | //!-> If T's constructor throws, the function throws that exception. | |
423 | //! | |
424 | //!Memory is freed automatically if T's constructor throws and if an | |
425 | //!array was being constructed, destructors of created objects are called | |
426 | //!before freeing the memory. | |
427 | template <class T> | |
428 | typename segment_manager::template construct_proxy<T>::type | |
429 | find_or_construct(char_ptr_holder_t name, const std::nothrow_t &tag) | |
430 | { return mp_header->template find_or_construct<T>(name, tag); } | |
431 | ||
432 | //!Creates a named array from iterators in memory | |
433 | //! | |
434 | //!Allocates and constructs an array of T in memory, | |
435 | //!associates this with the given name and returns a pointer to the | |
436 | //!created object. Each element in the array is created using the | |
437 | //!objects returned when dereferencing iterators as parameters | |
438 | //!and incrementing all iterators for each element. | |
439 | //! | |
440 | //!-> If the name was previously used, returns 0. | |
441 | //! | |
442 | //!-> Throws boost::interprocess::bad_alloc if there is no available memory | |
443 | //! | |
444 | //!-> If T's constructor throws, the function throws that exception. | |
445 | //! | |
446 | //!Memory is freed automatically if T's constructor throws and | |
447 | //!destructors of created objects are called before freeing the memory. | |
448 | template <class T> | |
449 | typename segment_manager::template construct_iter_proxy<T>::type | |
450 | construct_it(char_ptr_holder_t name) | |
451 | { return mp_header->template construct_it<T>(name); } | |
452 | ||
453 | //!Finds or creates a named array from iterators in memory | |
454 | //! | |
455 | //!Tries to find an object with the given name in memory. If | |
456 | //!found, returns the pointer to this pointer. If the object is not found, | |
457 | //!allocates and constructs an array of T in memory, | |
458 | //!associates this with the given name and returns a pointer to the | |
459 | //!created object. Each element in the array is created using the | |
460 | //!objects returned when dereferencing iterators as parameters | |
461 | //!and incrementing all iterators for each element. | |
462 | //! | |
463 | //!-> If the name was previously used, returns 0. | |
464 | //! | |
465 | //!-> Throws boost::interprocess::bad_alloc if there is no available memory | |
466 | //! | |
467 | //!-> If T's constructor throws, the function throws that exception. | |
468 | //! | |
469 | //!Memory is freed automatically if T's constructor throws and | |
470 | //!destructors of created objects are called before freeing the memory. | |
471 | template <class T> | |
472 | typename segment_manager::template construct_iter_proxy<T>::type | |
473 | find_or_construct_it(char_ptr_holder_t name) | |
474 | { return mp_header->template find_or_construct_it<T>(name); } | |
475 | ||
476 | //!Creates a named array from iterators in memory | |
477 | //! | |
478 | //!Allocates and constructs an array of T in memory, | |
479 | //!associates this with the given name and returns a pointer to the | |
480 | //!created object. Each element in the array is created using the | |
481 | //!objects returned when dereferencing iterators as parameters | |
482 | //!and incrementing all iterators for each element. | |
483 | //! | |
484 | //!-> If the name was previously used, returns 0. | |
485 | //! | |
486 | //!-> If there is no available memory, returns 0. | |
487 | //! | |
488 | //!-> If T's constructor throws, the function throws that exception. | |
489 | //! | |
490 | //!Memory is freed automatically if T's constructor throws and | |
491 | //!destructors of created objects are called before freeing the memory.*/ | |
492 | template <class T> | |
493 | typename segment_manager::template construct_iter_proxy<T>::type | |
494 | construct_it(char_ptr_holder_t name, const std::nothrow_t &tag) | |
495 | { return mp_header->template construct_it<T>(name, tag); } | |
496 | ||
497 | //!Finds or creates a named array from iterators in memory | |
498 | //! | |
499 | //!Tries to find an object with the given name in memory. If | |
500 | //!found, returns the pointer to this pointer. If the object is not found, | |
501 | //!allocates and constructs an array of T in memory, | |
502 | //!associates this with the given name and returns a pointer to the | |
503 | //!created object. Each element in the array is created using the | |
504 | //!objects returned when dereferencing iterators as parameters | |
505 | //!and incrementing all iterators for each element. | |
506 | //! | |
507 | //!-> If the name was previously used, returns 0. | |
508 | //! | |
509 | //!-> If there is no available memory, returns 0. | |
510 | //! | |
511 | //!-> If T's constructor throws, the function throws that exception. | |
512 | //! | |
513 | //!Memory is freed automatically if T's constructor throws and | |
514 | //!destructors of created objects are called before freeing the memory.*/ | |
515 | template <class T> | |
516 | typename segment_manager::template construct_iter_proxy<T>::type | |
517 | find_or_construct_it(char_ptr_holder_t name, const std::nothrow_t &tag) | |
518 | { return mp_header->template find_or_construct_it<T>(name, tag); } | |
519 | ||
520 | //!Calls a functor and guarantees that no new construction, search or | |
521 | //!destruction will be executed by any process while executing the object | |
522 | //!function call. If the functor throws, this function throws. | |
523 | template <class Func> | |
524 | void atomic_func(Func &f) | |
525 | { mp_header->atomic_func(f); } | |
526 | ||
527 | //!Tries to call a functor guaranteeing that no new construction, search or | |
528 | //!destruction will be executed by any process while executing the object | |
529 | //!function call. If the atomic function can't be immediatelly executed | |
530 | //!because the internal mutex is already locked, returns false. | |
531 | //!If the functor throws, this function throws. | |
532 | template <class Func> | |
533 | bool try_atomic_func(Func &f) | |
534 | { return mp_header->try_atomic_func(f); } | |
535 | ||
536 | //!Destroys a named memory object or array. | |
537 | //! | |
538 | //!Finds the object with the given name, calls its destructors, | |
539 | //!frees used memory and returns true. | |
540 | //! | |
541 | //!-> If the object is not found, it returns false. | |
542 | //! | |
543 | //!Exception Handling: | |
544 | //! | |
545 | //!When deleting a dynamically object or array, the Standard | |
546 | //!does not guarantee that dynamically allocated memory, will be released. | |
547 | //!Also, when deleting arrays, the Standard doesn't require calling | |
548 | //!destructors for the rest of the objects if for one of them the destructor | |
549 | //!terminated with an exception. | |
550 | //! | |
551 | //!Destroying an object: | |
552 | //! | |
553 | //!If the destructor throws, the memory will be freed and that exception | |
554 | //!will be thrown. | |
555 | //! | |
556 | //!Destroying an array: | |
557 | //! | |
558 | //!When destroying an array, if a destructor throws, the rest of | |
559 | //!destructors are called. If any of these throws, the exceptions are | |
560 | //!ignored. The name association will be erased, memory will be freed and | |
561 | //!the first exception will be thrown. This guarantees the unlocking of | |
562 | //!mutexes and other resources. | |
563 | //! | |
564 | //!For all theses reasons, classes with throwing destructors are not | |
565 | //!recommended. | |
566 | template <class T> | |
567 | bool destroy(const CharType *name) | |
568 | { return mp_header->template destroy<T>(name); } | |
569 | ||
570 | //!Destroys the unique instance of type T | |
571 | //! | |
572 | //!Calls the destructor, frees used memory and returns true. | |
573 | //! | |
574 | //!Exception Handling: | |
575 | //! | |
576 | //!When deleting a dynamically object, the Standard does not | |
577 | //!guarantee that dynamically allocated memory will be released. | |
578 | //! | |
579 | //!Destroying an object: | |
580 | //! | |
581 | //!If the destructor throws, the memory will be freed and that exception | |
582 | //!will be thrown. | |
583 | //! | |
584 | //!For all theses reasons, classes with throwing destructors are not | |
585 | //!recommended for memory. | |
586 | template <class T> | |
587 | bool destroy(const unique_instance_t *const ) | |
588 | { return mp_header->template destroy<T>(unique_instance); } | |
589 | ||
590 | //!Destroys the object (named, unique, or anonymous) | |
591 | //! | |
592 | //!Calls the destructor, frees used memory and returns true. | |
593 | //! | |
594 | //!Exception Handling: | |
595 | //! | |
596 | //!When deleting a dynamically object, the Standard does not | |
597 | //!guarantee that dynamically allocated memory will be released. | |
598 | //! | |
599 | //!Destroying an object: | |
600 | //! | |
601 | //!If the destructor throws, the memory will be freed and that exception | |
602 | //!will be thrown. | |
603 | //! | |
604 | //!For all theses reasons, classes with throwing destructors are not | |
605 | //!recommended for memory. | |
606 | template <class T> | |
607 | void destroy_ptr(const T *ptr) | |
608 | { mp_header->template destroy_ptr<T>(ptr); } | |
609 | ||
610 | //!Returns the name of an object created with construct/find_or_construct | |
611 | //!functions. If ptr points to an unique instance typeid(T).name() is returned. | |
612 | template<class T> | |
613 | static const char_type *get_instance_name(const T *ptr) | |
614 | { return segment_manager::get_instance_name(ptr); } | |
615 | ||
616 | //!Returns is the type an object created with construct/find_or_construct | |
617 | //!functions. Does not throw. | |
618 | template<class T> | |
619 | static instance_type get_instance_type(const T *ptr) | |
620 | { return segment_manager::get_instance_type(ptr); } | |
621 | ||
622 | //!Returns the length of an object created with construct/find_or_construct | |
623 | //!functions (1 if is a single element, >=1 if it's an array). Does not throw. | |
624 | template<class T> | |
625 | static size_type get_instance_length(const T *ptr) | |
626 | { return segment_manager::get_instance_length(ptr); } | |
627 | ||
628 | //!Preallocates needed index resources to optimize the | |
629 | //!creation of "num" named objects in the memory segment. | |
630 | //!Can throw boost::interprocess::bad_alloc if there is no enough memory. | |
631 | void reserve_named_objects(size_type num) | |
632 | { mp_header->reserve_named_objects(num); } | |
633 | ||
634 | //!Preallocates needed index resources to optimize the | |
635 | //!creation of "num" unique objects in the memory segment. | |
636 | //!Can throw boost::interprocess::bad_alloc if there is no enough memory. | |
637 | void reserve_unique_objects(size_type num) | |
638 | { mp_header->reserve_unique_objects(num); } | |
639 | ||
640 | //!Calls shrink_to_fit in both named and unique object indexes | |
641 | //to try to free unused memory from those indexes. | |
642 | void shrink_to_fit_indexes() | |
643 | { mp_header->shrink_to_fit_indexes(); } | |
644 | ||
645 | //!Returns the number of named objects stored | |
646 | //!in the managed segment. | |
647 | size_type get_num_named_objects() | |
648 | { return mp_header->get_num_named_objects(); } | |
649 | ||
650 | //!Returns the number of unique objects stored | |
651 | //!in the managed segment. | |
652 | size_type get_num_unique_objects() | |
653 | { return mp_header->get_num_unique_objects(); } | |
654 | ||
655 | //!Returns a constant iterator to the index storing the | |
656 | //!named allocations. NOT thread-safe. Never throws. | |
657 | const_named_iterator named_begin() const | |
658 | { return mp_header->named_begin(); } | |
659 | ||
660 | //!Returns a constant iterator to the end of the index | |
661 | //!storing the named allocations. NOT thread-safe. Never throws. | |
662 | const_named_iterator named_end() const | |
663 | { return mp_header->named_end(); } | |
664 | ||
665 | //!Returns a constant iterator to the index storing the | |
666 | //!unique allocations. NOT thread-safe. Never throws. | |
667 | const_unique_iterator unique_begin() const | |
668 | { return mp_header->unique_begin(); } | |
669 | ||
670 | //!Returns a constant iterator to the end of the index | |
671 | //!storing the unique allocations. NOT thread-safe. Never throws. | |
672 | const_unique_iterator unique_end() const | |
673 | { return mp_header->unique_end(); } | |
674 | ||
675 | //!This is the default allocator to allocate types T | |
676 | //!from this managed segment | |
677 | template<class T> | |
678 | struct allocator | |
679 | { | |
680 | typedef typename segment_manager::template allocator<T>::type type; | |
681 | }; | |
682 | ||
683 | //!Returns an instance of the default allocator for type T | |
684 | //!initialized that allocates memory from this segment manager. | |
685 | template<class T> | |
686 | typename allocator<T>::type | |
687 | get_allocator() | |
688 | { return mp_header->template get_allocator<T>(); } | |
689 | ||
690 | //!This is the default deleter to delete types T | |
691 | //!from this managed segment. | |
692 | template<class T> | |
693 | struct deleter | |
694 | { | |
695 | typedef typename segment_manager::template deleter<T>::type type; | |
696 | }; | |
697 | ||
698 | //!Returns an instance of the default allocator for type T | |
699 | //!initialized that allocates memory from this segment manager. | |
700 | template<class T> | |
701 | typename deleter<T>::type | |
702 | get_deleter() | |
703 | { return mp_header->template get_deleter<T>(); } | |
704 | ||
705 | #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) | |
706 | //!Tries to find a previous named allocation address. Returns a memory | |
707 | //!buffer and the object count. If not found returned pointer is 0. | |
708 | //!Never throws. | |
709 | template <class T> | |
710 | std::pair<T*, size_type> find_no_lock (char_ptr_holder_t name) | |
711 | { return mp_header->template find_no_lock<T>(name); } | |
712 | #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED | |
713 | ||
714 | protected: | |
715 | //!Swaps the segment manager's managed by this managed memory segment. | |
716 | //!NOT thread-safe. Never throws. | |
717 | void swap(basic_managed_memory_impl &other) | |
718 | { (simple_swap)(mp_header, other.mp_header); } | |
719 | ||
720 | private: | |
721 | segment_manager *mp_header; | |
722 | }; | |
723 | ||
724 | template<class BasicManagedMemoryImpl> | |
725 | class create_open_func | |
726 | { | |
727 | typedef typename BasicManagedMemoryImpl::size_type size_type; | |
728 | ||
729 | public: | |
730 | ||
731 | create_open_func(BasicManagedMemoryImpl * const frontend, create_enum_t type) | |
732 | : m_frontend(frontend), m_type(type){} | |
733 | ||
734 | bool operator()(void *addr, std::size_t size, bool created) const | |
735 | { | |
736 | if( ((m_type == DoOpen) && created) || | |
737 | ((m_type == DoCreate) && !created) || | |
738 | //Check for overflow | |
739 | size_type(-1) < size ){ | |
740 | return false; | |
741 | } | |
742 | else if(created){ | |
743 | return m_frontend->create_impl(addr, static_cast<size_type>(size)); | |
744 | } | |
745 | else{ | |
746 | return m_frontend->open_impl (addr, static_cast<size_type>(size)); | |
747 | } | |
748 | } | |
749 | ||
750 | static std::size_t get_min_size() | |
751 | { | |
752 | const size_type sz = BasicManagedMemoryImpl::segment_manager::get_min_size(); | |
753 | if(sz > std::size_t(-1)){ | |
754 | //The minimum size is not representable by std::size_t | |
755 | BOOST_ASSERT(false); | |
756 | return std::size_t(-1); | |
757 | } | |
758 | else{ | |
759 | return static_cast<std::size_t>(sz); | |
760 | } | |
761 | } | |
762 | ||
763 | private: | |
764 | BasicManagedMemoryImpl *m_frontend; | |
765 | create_enum_t m_type; | |
766 | }; | |
767 | ||
768 | } //namespace ipcdetail { | |
769 | } //namespace interprocess { | |
770 | } //namespace boost { | |
771 | ||
772 | #include <boost/interprocess/detail/config_end.hpp> | |
773 | ||
774 | #endif //BOOST_INTERPROCESS_DETAIL_MANAGED_MEMORY_IMPL_HPP | |
775 |