1 //////////////////////////////////////////////////////////////////////////////
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)
7 // See http://www.boost.org/libs/interprocess for documentation.
9 //////////////////////////////////////////////////////////////////////////////
11 #ifndef BOOST_INTERPROCESS_PRIVATE_ADAPTIVE_POOL_HPP
12 #define BOOST_INTERPROCESS_PRIVATE_ADAPTIVE_POOL_HPP
14 #ifndef BOOST_CONFIG_HPP
15 # include <boost/config.hpp>
18 #if defined(BOOST_HAS_PRAGMA_ONCE)
22 #include <boost/interprocess/detail/config_begin.hpp>
23 #include <boost/interprocess/detail/workaround.hpp>
25 #include <boost/intrusive/pointer_traits.hpp>
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>
40 //!Describes private_adaptive_pool_base pooled shared memory STL compatible allocator
43 namespace interprocess {
45 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
49 template < unsigned int Version
51 , class SegmentManager
52 , std::size_t NodesPerBlock
53 , std::size_t MaxFreeBlocks
54 , unsigned char OverheadPercent
56 class private_adaptive_pool_base
57 : public node_pool_allocation_impl
58 < private_adaptive_pool_base < Version, T, SegmentManager, NodesPerBlock
59 , MaxFreeBlocks, OverheadPercent>
67 typedef SegmentManager segment_manager;
68 typedef typename SegmentManager::void_pointer void_pointer;
70 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
72 typedef private_adaptive_pool_base
73 < Version, T, SegmentManager, NodesPerBlock
74 , MaxFreeBlocks, OverheadPercent> self_t;
75 typedef ipcdetail::private_adaptive_node_pool
77 , sizeof_value<T>::value
83 BOOST_STATIC_ASSERT((Version <=2));
85 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
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;
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;
106 //!Obtains node_allocator from other node_allocator
110 typedef private_adaptive_pool_base
111 <Version, T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
114 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
119 typedef ipcdetail::private_adaptive_node_pool
121 , sizeof_value<T>::value
127 static type *get(void *p)
128 { return static_cast<type*>(p); }
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>&);
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
142 //!Constructor from a segment manager
143 private_adaptive_pool_base(segment_manager *segment_mngr)
144 : m_node_pool(segment_mngr)
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())
152 //!Copy constructor from related private_adaptive_pool_base. Never throws.
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())
160 //!Destructor, frees all used memory. Never throws
161 ~private_adaptive_pool_base()
164 //!Returns the segment manager. Never throws
165 segment_manager* get_segment_manager()const
166 { return m_node_pool.get_segment_manager(); }
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); }
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); }
177 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
179 node_pool_t m_node_pool;
180 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
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; }
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; }
196 , class SegmentManager
197 , std::size_t NodesPerBlock = 64
198 , std::size_t MaxFreeBlocks = 2
199 , unsigned char OverheadPercent = 5
201 class private_adaptive_pool_v1
202 : public private_adaptive_pool_base
212 typedef ipcdetail::private_adaptive_pool_base
213 < 1, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t;
218 typedef private_adaptive_pool_v1<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
221 private_adaptive_pool_v1(SegmentManager *segment_mngr)
222 : base_t(segment_mngr)
226 private_adaptive_pool_v1
227 (const private_adaptive_pool_v1<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
232 } //namespace ipcdetail {
234 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
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.
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.
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)
250 , class SegmentManager
251 , std::size_t NodesPerBlock
252 , std::size_t MaxFreeBlocks
253 , unsigned char OverheadPercent
255 class private_adaptive_pool
256 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
257 : public ipcdetail::private_adaptive_pool_base
265 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
268 #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
269 typedef ipcdetail::private_adaptive_pool_base
270 < 2, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t;
272 typedef boost::interprocess::version_type<private_adaptive_pool, 2> version;
277 typedef private_adaptive_pool
278 <T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
281 private_adaptive_pool(SegmentManager *segment_mngr)
282 : base_t(segment_mngr)
286 private_adaptive_pool
287 (const private_adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
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;
305 //!Obtains private_adaptive_pool from
306 //!private_adaptive_pool
310 typedef private_adaptive_pool
311 <T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
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>&);
321 //!Not assignable from
322 //!other private_adaptive_pool
323 private_adaptive_pool& operator=(const private_adaptive_pool&);
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);
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);
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
339 private_adaptive_pool
340 (const private_adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other);
342 //!Destructor, removes node_pool_t from memory
343 //!if its reference count reaches to zero. Never throws
344 ~private_adaptive_pool();
346 //!Returns a pointer to the node pool.
348 node_pool_t* get_node_pool() const;
350 //!Returns the segment manager.
352 segment_manager* get_segment_manager()const;
354 //!Returns the number of elements that could be allocated.
356 size_type max_size() const;
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);
362 //!Deallocate allocated memory.
364 void deallocate(const pointer &ptr, size_type count);
366 //!Deallocates all free blocks
368 void deallocate_free_blocks();
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);
374 //!Returns address of mutable object.
376 pointer address(reference value) const;
378 //!Returns address of non mutable object.
380 const_pointer address(const_reference value) const;
382 //!Copy construct an object.
383 //!Throws if T's copy constructor throws
384 void construct(const pointer &ptr, const_reference v);
386 //!Destroys object. Throws if object's
388 void destroy(const pointer &ptr);
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;
395 pointer allocation_command(boost::interprocess::allocation_type command,
396 size_type limit_size, size_type &prefer_in_recvd_out_size, pointer &reuse);
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);
406 //!Allocates n_elements elements, each one of size elem_sizes[i]in a
408 //!of memory. The elements must be deallocated
409 void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain);
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);
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();
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);
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);
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);
447 #ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
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);
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);
463 } //namespace interprocess {
464 } //namespace boost {
466 #include <boost/interprocess/detail/config_end.hpp>
468 #endif //#ifndef BOOST_INTERPROCESS_PRIVATE_ADAPTIVE_POOL_HPP