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