]>
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_NODE_ALLOCATOR_HPP | |
12 | #define BOOST_INTERPROCESS_NODE_ALLOCATOR_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/intrusive/pointer_traits.hpp> | |
26 | ||
27 | #include <boost/interprocess/interprocess_fwd.hpp> | |
28 | #include <boost/assert.hpp> | |
29 | #include <boost/utility/addressof.hpp> | |
30 | #include <boost/interprocess/detail/utilities.hpp> | |
31 | #include <boost/interprocess/detail/type_traits.hpp> | |
32 | #include <boost/interprocess/allocators/detail/node_pool.hpp> | |
33 | #include <boost/interprocess/containers/version_type.hpp> | |
34 | #include <boost/container/detail/multiallocation_chain.hpp> | |
35 | #include <boost/interprocess/exceptions.hpp> | |
36 | #include <boost/interprocess/allocators/detail/allocator_common.hpp> | |
37 | #include <boost/move/adl_move_swap.hpp> | |
38 | #include <cstddef> | |
39 | ||
40 | //!\file | |
41 | //!Describes node_allocator pooled shared memory STL compatible allocator | |
42 | ||
43 | namespace boost { | |
44 | namespace interprocess { | |
45 | ||
46 | #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) | |
47 | ||
48 | namespace ipcdetail{ | |
49 | ||
50 | template < unsigned int Version | |
51 | , class T | |
52 | , class SegmentManager | |
53 | , std::size_t NodesPerBlock | |
54 | > | |
55 | class node_allocator_base | |
56 | : public node_pool_allocation_impl | |
57 | < node_allocator_base | |
58 | < Version, T, SegmentManager, NodesPerBlock> | |
59 | , Version | |
60 | , T | |
61 | , SegmentManager | |
62 | > | |
63 | { | |
64 | public: | |
65 | typedef typename SegmentManager::void_pointer void_pointer; | |
66 | typedef SegmentManager segment_manager; | |
67 | typedef node_allocator_base | |
68 | <Version, T, SegmentManager, NodesPerBlock> self_t; | |
69 | ||
70 | #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) | |
71 | ||
72 | template <int dummy> | |
73 | struct node_pool | |
74 | { | |
75 | typedef ipcdetail::shared_node_pool | |
76 | < SegmentManager, sizeof_value<T>::value, NodesPerBlock> type; | |
77 | ||
78 | static type *get(void *p) | |
79 | { return static_cast<type*>(p); } | |
80 | }; | |
81 | #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED | |
82 | ||
83 | BOOST_STATIC_ASSERT((Version <=2)); | |
84 | ||
85 | public: | |
86 | //------- | |
87 | typedef typename boost::intrusive:: | |
88 | pointer_traits<void_pointer>::template | |
89 | rebind_pointer<T>::type pointer; | |
90 | typedef typename boost::intrusive:: | |
91 | pointer_traits<void_pointer>::template | |
92 | rebind_pointer<const T>::type const_pointer; | |
93 | typedef T value_type; | |
94 | typedef typename ipcdetail::add_reference | |
95 | <value_type>::type reference; | |
96 | typedef typename ipcdetail::add_reference | |
97 | <const value_type>::type const_reference; | |
98 | typedef typename segment_manager::size_type size_type; | |
99 | typedef typename segment_manager::difference_type difference_type; | |
100 | ||
101 | typedef boost::interprocess::version_type<node_allocator_base, Version> version; | |
102 | typedef boost::container::container_detail::transform_multiallocation_chain | |
103 | <typename SegmentManager::multiallocation_chain, T>multiallocation_chain; | |
104 | ||
105 | //!Obtains node_allocator_base from | |
106 | //!node_allocator_base | |
107 | template<class T2> | |
108 | struct rebind | |
109 | { | |
110 | typedef node_allocator_base<Version, T2, SegmentManager, NodesPerBlock> other; | |
111 | }; | |
112 | ||
113 | #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) | |
114 | private: | |
115 | //!Not assignable from related node_allocator_base | |
116 | template<unsigned int Version2, class T2, class SegmentManager2, std::size_t N2> | |
117 | node_allocator_base& operator= | |
118 | (const node_allocator_base<Version2, T2, SegmentManager2, N2>&); | |
119 | ||
120 | //!Not assignable from other node_allocator_base | |
121 | //node_allocator_base& operator=(const node_allocator_base&); | |
122 | #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED | |
123 | ||
124 | public: | |
125 | //!Constructor from a segment manager. If not present, constructs a node | |
126 | //!pool. Increments the reference count of the associated node pool. | |
127 | //!Can throw boost::interprocess::bad_alloc | |
128 | node_allocator_base(segment_manager *segment_mngr) | |
129 | : mp_node_pool(ipcdetail::get_or_create_node_pool<typename node_pool<0>::type>(segment_mngr)) { } | |
130 | ||
131 | //!Copy constructor from other node_allocator_base. Increments the reference | |
132 | //!count of the associated node pool. Never throws | |
133 | node_allocator_base(const node_allocator_base &other) | |
134 | : mp_node_pool(other.get_node_pool()) | |
135 | { | |
136 | node_pool<0>::get(ipcdetail::to_raw_pointer(mp_node_pool))->inc_ref_count(); | |
137 | } | |
138 | ||
139 | //!Copy constructor from related node_allocator_base. If not present, constructs | |
140 | //!a node pool. Increments the reference count of the associated node pool. | |
141 | //!Can throw boost::interprocess::bad_alloc | |
142 | template<class T2> | |
143 | node_allocator_base | |
144 | (const node_allocator_base<Version, T2, SegmentManager, NodesPerBlock> &other) | |
145 | : mp_node_pool(ipcdetail::get_or_create_node_pool<typename node_pool<0>::type>(other.get_segment_manager())) { } | |
146 | ||
147 | //!Assignment from other node_allocator_base | |
148 | node_allocator_base& operator=(const node_allocator_base &other) | |
149 | { | |
150 | node_allocator_base c(other); | |
151 | boost::adl_move_swap(*this, c); | |
152 | return *this; | |
153 | } | |
154 | ||
155 | //!Destructor, removes node_pool_t from memory | |
156 | //!if its reference count reaches to zero. Never throws | |
157 | ~node_allocator_base() | |
158 | { ipcdetail::destroy_node_pool_if_last_link(node_pool<0>::get(ipcdetail::to_raw_pointer(mp_node_pool))); } | |
159 | ||
160 | //!Returns a pointer to the node pool. | |
161 | //!Never throws | |
162 | void* get_node_pool() const | |
163 | { return ipcdetail::to_raw_pointer(mp_node_pool); } | |
164 | ||
165 | //!Returns the segment manager. | |
166 | //!Never throws | |
167 | segment_manager* get_segment_manager()const | |
168 | { return node_pool<0>::get(ipcdetail::to_raw_pointer(mp_node_pool))->get_segment_manager(); } | |
169 | ||
170 | //!Swaps allocators. Does not throw. If each allocator is placed in a | |
171 | //!different memory segment, the result is undefined. | |
172 | friend void swap(self_t &alloc1, self_t &alloc2) | |
173 | { boost::adl_move_swap(alloc1.mp_node_pool, alloc2.mp_node_pool); } | |
174 | ||
175 | #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) | |
176 | private: | |
177 | void_pointer mp_node_pool; | |
178 | #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED | |
179 | }; | |
180 | ||
181 | //!Equality test for same type | |
182 | //!of node_allocator_base | |
183 | template<unsigned int V, class T, class S, std::size_t NPC> inline | |
184 | bool operator==(const node_allocator_base<V, T, S, NPC> &alloc1, | |
185 | const node_allocator_base<V, T, S, NPC> &alloc2) | |
186 | { return alloc1.get_node_pool() == alloc2.get_node_pool(); } | |
187 | ||
188 | //!Inequality test for same type | |
189 | //!of node_allocator_base | |
190 | template<unsigned int V, class T, class S, std::size_t NPC> inline | |
191 | bool operator!=(const node_allocator_base<V, T, S, NPC> &alloc1, | |
192 | const node_allocator_base<V, T, S, NPC> &alloc2) | |
193 | { return alloc1.get_node_pool() != alloc2.get_node_pool(); } | |
194 | ||
195 | template < class T | |
196 | , class SegmentManager | |
197 | , std::size_t NodesPerBlock = 64 | |
198 | > | |
199 | class node_allocator_v1 | |
200 | : public node_allocator_base | |
201 | < 1 | |
202 | , T | |
203 | , SegmentManager | |
204 | , NodesPerBlock | |
205 | > | |
206 | { | |
207 | public: | |
208 | typedef ipcdetail::node_allocator_base | |
209 | < 1, T, SegmentManager, NodesPerBlock> base_t; | |
210 | ||
211 | template<class T2> | |
212 | struct rebind | |
213 | { | |
214 | typedef node_allocator_v1<T2, SegmentManager, NodesPerBlock> other; | |
215 | }; | |
216 | ||
217 | node_allocator_v1(SegmentManager *segment_mngr) | |
218 | : base_t(segment_mngr) | |
219 | {} | |
220 | ||
221 | template<class T2> | |
222 | node_allocator_v1 | |
223 | (const node_allocator_v1<T2, SegmentManager, NodesPerBlock> &other) | |
224 | : base_t(other) | |
225 | {} | |
226 | }; | |
227 | ||
228 | } //namespace ipcdetail{ | |
229 | ||
230 | #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED | |
231 | ||
232 | //!An STL node allocator that uses a segment manager as memory | |
233 | //!source. The internal pointer type will of the same type (raw, smart) as | |
234 | //!"typename SegmentManager::void_pointer" type. This allows | |
235 | //!placing the allocator in shared memory, memory mapped-files, etc... | |
236 | //!This node allocator shares a segregated storage between all instances | |
237 | //!of node_allocator with equal sizeof(T) placed in the same segment | |
238 | //!group. NodesPerBlock is the number of nodes allocated at once when the allocator | |
239 | //!runs out of nodes | |
240 | template < class T | |
241 | , class SegmentManager | |
242 | , std::size_t NodesPerBlock | |
243 | > | |
244 | class node_allocator | |
245 | #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) | |
246 | : public ipcdetail::node_allocator_base | |
247 | < 2 | |
248 | , T | |
249 | , SegmentManager | |
250 | , NodesPerBlock | |
251 | > | |
252 | #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED | |
253 | { | |
254 | ||
255 | #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED | |
256 | typedef ipcdetail::node_allocator_base | |
257 | < 2, T, SegmentManager, NodesPerBlock> base_t; | |
258 | public: | |
259 | typedef boost::interprocess::version_type<node_allocator, 2> version; | |
260 | ||
261 | template<class T2> | |
262 | struct rebind | |
263 | { | |
264 | typedef node_allocator<T2, SegmentManager, NodesPerBlock> other; | |
265 | }; | |
266 | ||
267 | node_allocator(SegmentManager *segment_mngr) | |
268 | : base_t(segment_mngr) | |
269 | {} | |
270 | ||
271 | template<class T2> | |
272 | node_allocator | |
273 | (const node_allocator<T2, SegmentManager, NodesPerBlock> &other) | |
274 | : base_t(other) | |
275 | {} | |
276 | ||
277 | #else //BOOST_INTERPROCESS_DOXYGEN_INVOKED | |
278 | public: | |
279 | typedef implementation_defined::segment_manager segment_manager; | |
280 | typedef segment_manager::void_pointer void_pointer; | |
281 | typedef implementation_defined::pointer pointer; | |
282 | typedef implementation_defined::const_pointer const_pointer; | |
283 | typedef T value_type; | |
284 | typedef typename ipcdetail::add_reference | |
285 | <value_type>::type reference; | |
286 | typedef typename ipcdetail::add_reference | |
287 | <const value_type>::type const_reference; | |
288 | typedef typename segment_manager::size_type size_type; | |
289 | typedef typename segment_manager::difference_type difference_type; | |
290 | ||
291 | //!Obtains node_allocator from | |
292 | //!node_allocator | |
293 | template<class T2> | |
294 | struct rebind | |
295 | { | |
296 | typedef node_allocator<T2, SegmentManager, NodesPerBlock> other; | |
297 | }; | |
298 | ||
299 | private: | |
300 | //!Not assignable from | |
301 | //!related node_allocator | |
302 | template<class T2, class SegmentManager2, std::size_t N2> | |
303 | node_allocator& operator= | |
304 | (const node_allocator<T2, SegmentManager2, N2>&); | |
305 | ||
306 | //!Not assignable from | |
307 | //!other node_allocator | |
308 | //node_allocator& operator=(const node_allocator&); | |
309 | ||
310 | public: | |
311 | //!Constructor from a segment manager. If not present, constructs a node | |
312 | //!pool. Increments the reference count of the associated node pool. | |
313 | //!Can throw boost::interprocess::bad_alloc | |
314 | node_allocator(segment_manager *segment_mngr); | |
315 | ||
316 | //!Copy constructor from other node_allocator. Increments the reference | |
317 | //!count of the associated node pool. Never throws | |
318 | node_allocator(const node_allocator &other); | |
319 | ||
320 | //!Copy constructor from related node_allocator. If not present, constructs | |
321 | //!a node pool. Increments the reference count of the associated node pool. | |
322 | //!Can throw boost::interprocess::bad_alloc | |
323 | template<class T2> | |
324 | node_allocator | |
325 | (const node_allocator<T2, SegmentManager, NodesPerBlock> &other); | |
326 | ||
327 | //!Destructor, removes node_pool_t from memory | |
328 | //!if its reference count reaches to zero. Never throws | |
329 | ~node_allocator(); | |
330 | ||
331 | //!Returns a pointer to the node pool. | |
332 | //!Never throws | |
333 | void* get_node_pool() const; | |
334 | ||
335 | //!Returns the segment manager. | |
336 | //!Never throws | |
337 | segment_manager* get_segment_manager()const; | |
338 | ||
339 | //!Returns the number of elements that could be allocated. | |
340 | //!Never throws | |
341 | size_type max_size() const; | |
342 | ||
343 | //!Allocate memory for an array of count elements. | |
344 | //!Throws boost::interprocess::bad_alloc if there is no enough memory | |
345 | pointer allocate(size_type count, cvoid_pointer hint = 0); | |
346 | ||
347 | //!Deallocate allocated memory. | |
348 | //!Never throws | |
349 | void deallocate(const pointer &ptr, size_type count); | |
350 | ||
351 | //!Deallocates all free blocks | |
352 | //!of the pool | |
353 | void deallocate_free_blocks(); | |
354 | ||
355 | //!Swaps allocators. Does not throw. If each allocator is placed in a | |
356 | //!different memory segment, the result is undefined. | |
357 | friend void swap(self_t &alloc1, self_t &alloc2); | |
358 | ||
359 | //!Returns address of mutable object. | |
360 | //!Never throws | |
361 | pointer address(reference value) const; | |
362 | ||
363 | //!Returns address of non mutable object. | |
364 | //!Never throws | |
365 | const_pointer address(const_reference value) const; | |
366 | ||
367 | //!Copy construct an object. | |
368 | //!Throws if T's copy constructor throws | |
369 | void construct(const pointer &ptr, const_reference v); | |
370 | ||
371 | //!Destroys object. Throws if object's | |
372 | //!destructor throws | |
373 | void destroy(const pointer &ptr); | |
374 | ||
375 | //!Returns maximum the number of objects the previously allocated memory | |
376 | //!pointed by p can hold. This size only works for memory allocated with | |
377 | //!allocate, allocation_command and allocate_many. | |
378 | size_type size(const pointer &p) const; | |
379 | ||
380 | pointer allocation_command(boost::interprocess::allocation_type command, | |
381 | size_type limit_size, size_type &prefer_in_recvd_out_size, pointer &reuse); | |
382 | ||
383 | //!Allocates many elements of size elem_size in a contiguous block | |
384 | //!of memory. The minimum number to be allocated is min_elements, | |
385 | //!the preferred and maximum number is | |
386 | //!preferred_elements. The number of actually allocated elements is | |
387 | //!will be assigned to received_size. The elements must be deallocated | |
388 | //!with deallocate(...) | |
389 | void allocate_many(size_type elem_size, size_type num_elements, multiallocation_chain &chain); | |
390 | ||
391 | //!Allocates n_elements elements, each one of size elem_sizes[i]in a | |
392 | //!contiguous block | |
393 | //!of memory. The elements must be deallocated | |
394 | void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain); | |
395 | ||
396 | //!Allocates many elements of size elem_size in a contiguous block | |
397 | //!of memory. The minimum number to be allocated is min_elements, | |
398 | //!the preferred and maximum number is | |
399 | //!preferred_elements. The number of actually allocated elements is | |
400 | //!will be assigned to received_size. The elements must be deallocated | |
401 | //!with deallocate(...) | |
402 | void deallocate_many(multiallocation_chain &chain); | |
403 | ||
404 | //!Allocates just one object. Memory allocated with this function | |
405 | //!must be deallocated only with deallocate_one(). | |
406 | //!Throws boost::interprocess::bad_alloc if there is no enough memory | |
407 | pointer allocate_one(); | |
408 | ||
409 | //!Allocates many elements of size == 1 in a contiguous block | |
410 | //!of memory. The minimum number to be allocated is min_elements, | |
411 | //!the preferred and maximum number is | |
412 | //!preferred_elements. The number of actually allocated elements is | |
413 | //!will be assigned to received_size. Memory allocated with this function | |
414 | //!must be deallocated only with deallocate_one(). | |
415 | void allocate_individual(size_type num_elements, multiallocation_chain &chain); | |
416 | ||
417 | //!Deallocates memory previously allocated with allocate_one(). | |
418 | //!You should never use deallocate_one to deallocate memory allocated | |
419 | //!with other functions different from allocate_one(). Never throws | |
420 | void deallocate_one(const pointer &p); | |
421 | ||
422 | //!Allocates many elements of size == 1 in a contiguous block | |
423 | //!of memory. The minimum number to be allocated is min_elements, | |
424 | //!the preferred and maximum number is | |
425 | //!preferred_elements. The number of actually allocated elements is | |
426 | //!will be assigned to received_size. Memory allocated with this function | |
427 | //!must be deallocated only with deallocate_one(). | |
428 | void deallocate_individual(multiallocation_chain &chain); | |
429 | #endif | |
430 | }; | |
431 | ||
432 | #ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED | |
433 | ||
434 | //!Equality test for same type | |
435 | //!of node_allocator | |
436 | template<class T, class S, std::size_t NPC> inline | |
437 | bool operator==(const node_allocator<T, S, NPC> &alloc1, | |
438 | const node_allocator<T, S, NPC> &alloc2); | |
439 | ||
440 | //!Inequality test for same type | |
441 | //!of node_allocator | |
442 | template<class T, class S, std::size_t NPC> inline | |
443 | bool operator!=(const node_allocator<T, S, NPC> &alloc1, | |
444 | const node_allocator<T, S, NPC> &alloc2); | |
445 | ||
446 | #endif | |
447 | ||
448 | } //namespace interprocess { | |
449 | } //namespace boost { | |
450 | ||
451 | #include <boost/interprocess/detail/config_end.hpp> | |
452 | ||
453 | #endif //#ifndef BOOST_INTERPROCESS_NODE_ALLOCATOR_HPP |