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