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