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
18 #include <boost/interprocess/detail/config_begin.hpp>
19 #include <boost/interprocess/detail/workaround.hpp>
21 #include <boost/intrusive/pointer_traits.hpp>
23 #include <boost/interprocess/interprocess_fwd.hpp>
24 #include <boost/assert.hpp>
25 #include <boost/utility/addressof.hpp>
26 #include <boost/interprocess/allocators/detail/adaptive_node_pool.hpp>
27 #include <boost/container/detail/multiallocation_chain.hpp>
28 #include <boost/interprocess/exceptions.hpp>
29 #include <boost/interprocess/detail/utilities.hpp>
30 #include <boost/interprocess/detail/workaround.hpp>
36 //!Describes private_adaptive_pool_base pooled shared memory STL compatible allocator
39 namespace interprocess {
41 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
45 template < unsigned int Version
47 , class SegmentManager
48 , std::size_t NodesPerBlock
49 , std::size_t MaxFreeBlocks
50 , unsigned char OverheadPercent
52 class private_adaptive_pool_base
53 : public node_pool_allocation_impl
54 < private_adaptive_pool_base < Version, T, SegmentManager, NodesPerBlock
55 , MaxFreeBlocks, OverheadPercent>
63 typedef SegmentManager segment_manager;
64 typedef typename SegmentManager::void_pointer void_pointer;
66 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
68 typedef private_adaptive_pool_base
69 < Version, T, SegmentManager, NodesPerBlock
70 , MaxFreeBlocks, OverheadPercent> self_t;
71 typedef ipcdetail::private_adaptive_node_pool
73 , sizeof_value<T>::value
79 BOOST_STATIC_ASSERT((Version <=2));
81 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
84 typedef typename boost::intrusive::
85 pointer_traits<void_pointer>::template
86 rebind_pointer<T>::type pointer;
87 typedef typename boost::intrusive::
88 pointer_traits<void_pointer>::template
89 rebind_pointer<const T>::type const_pointer;
91 typedef typename ipcdetail::add_reference
92 <value_type>::type reference;
93 typedef typename ipcdetail::add_reference
94 <const value_type>::type const_reference;
95 typedef typename segment_manager::size_type size_type;
96 typedef typename segment_manager::size_type difference_type;
97 typedef boost::interprocess::version_type
98 <private_adaptive_pool_base, Version> version;
99 typedef boost::container::container_detail::transform_multiallocation_chain
100 <typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
102 //!Obtains node_allocator from other node_allocator
106 typedef private_adaptive_pool_base
107 <Version, T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
110 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
115 typedef ipcdetail::private_adaptive_node_pool
117 , sizeof_value<T>::value
123 static type *get(void *p)
124 { return static_cast<type*>(p); }
128 //!Not assignable from related private_adaptive_pool_base
129 template<unsigned int Version2, class T2, class MemoryAlgorithm2, std::size_t N2, std::size_t F2, unsigned char OP2>
130 private_adaptive_pool_base& operator=
131 (const private_adaptive_pool_base<Version2, T2, MemoryAlgorithm2, N2, F2, OP2>&);
133 //!Not assignable from other private_adaptive_pool_base
134 private_adaptive_pool_base& operator=(const private_adaptive_pool_base&);
135 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
138 //!Constructor from a segment manager
139 private_adaptive_pool_base(segment_manager *segment_mngr)
140 : m_node_pool(segment_mngr)
143 //!Copy constructor from other private_adaptive_pool_base. Never throws
144 private_adaptive_pool_base(const private_adaptive_pool_base &other)
145 : m_node_pool(other.get_segment_manager())
148 //!Copy constructor from related private_adaptive_pool_base. Never throws.
150 private_adaptive_pool_base
151 (const private_adaptive_pool_base
152 <Version, T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
153 : m_node_pool(other.get_segment_manager())
156 //!Destructor, frees all used memory. Never throws
157 ~private_adaptive_pool_base()
160 //!Returns the segment manager. Never throws
161 segment_manager* get_segment_manager()const
162 { return m_node_pool.get_segment_manager(); }
164 //!Returns the internal node pool. Never throws
165 node_pool_t* get_node_pool() const
166 { return const_cast<node_pool_t*>(&m_node_pool); }
168 //!Swaps allocators. Does not throw. If each allocator is placed in a
169 //!different shared memory segments, the result is undefined.
170 friend void swap(self_t &alloc1,self_t &alloc2)
171 { alloc1.m_node_pool.swap(alloc2.m_node_pool); }
173 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
175 node_pool_t m_node_pool;
176 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
179 //!Equality test for same type of private_adaptive_pool_base
180 template<unsigned int V, class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
181 bool operator==(const private_adaptive_pool_base<V, T, S, NodesPerBlock, F, OP> &alloc1,
182 const private_adaptive_pool_base<V, T, S, NodesPerBlock, F, OP> &alloc2)
183 { return &alloc1 == &alloc2; }
185 //!Inequality test for same type of private_adaptive_pool_base
186 template<unsigned int V, class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
187 bool operator!=(const private_adaptive_pool_base<V, T, S, NodesPerBlock, F, OP> &alloc1,
188 const private_adaptive_pool_base<V, T, S, NodesPerBlock, F, OP> &alloc2)
189 { return &alloc1 != &alloc2; }
192 , class SegmentManager
193 , std::size_t NodesPerBlock = 64
194 , std::size_t MaxFreeBlocks = 2
195 , unsigned char OverheadPercent = 5
197 class private_adaptive_pool_v1
198 : public private_adaptive_pool_base
208 typedef ipcdetail::private_adaptive_pool_base
209 < 1, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t;
214 typedef private_adaptive_pool_v1<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
217 private_adaptive_pool_v1(SegmentManager *segment_mngr)
218 : base_t(segment_mngr)
222 private_adaptive_pool_v1
223 (const private_adaptive_pool_v1<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
228 } //namespace ipcdetail {
230 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
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 allocator has its own node pool.
238 //!NodesPerBlock is the minimum number of nodes of nodes allocated at once when
239 //!the allocator needs runs out of nodes. MaxFreeBlocks is the maximum number of totally free blocks
240 //!that the adaptive node pool will hold. The rest of the totally free blocks will be
241 //!deallocated with the segment manager.
243 //!OverheadPercent is the (approximated) maximum size overhead (1-20%) of the allocator:
244 //!(memory usable for nodes / total memory allocated from the segment manager)
246 , class SegmentManager
247 , std::size_t NodesPerBlock
248 , std::size_t MaxFreeBlocks
249 , unsigned char OverheadPercent
251 class private_adaptive_pool
252 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
253 : public ipcdetail::private_adaptive_pool_base
261 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
264 #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
265 typedef ipcdetail::private_adaptive_pool_base
266 < 2, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t;
268 typedef boost::interprocess::version_type<private_adaptive_pool, 2> version;
273 typedef private_adaptive_pool
274 <T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
277 private_adaptive_pool(SegmentManager *segment_mngr)
278 : base_t(segment_mngr)
282 private_adaptive_pool
283 (const private_adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
289 typedef implementation_defined::segment_manager segment_manager;
290 typedef segment_manager::void_pointer void_pointer;
291 typedef implementation_defined::pointer pointer;
292 typedef implementation_defined::const_pointer const_pointer;
293 typedef T value_type;
294 typedef typename ipcdetail::add_reference
295 <value_type>::type reference;
296 typedef typename ipcdetail::add_reference
297 <const value_type>::type const_reference;
298 typedef typename segment_manager::size_type size_type;
299 typedef typename segment_manager::difference_type difference_type;
301 //!Obtains private_adaptive_pool from
302 //!private_adaptive_pool
306 typedef private_adaptive_pool
307 <T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
311 //!Not assignable from
312 //!related private_adaptive_pool
313 template<class T2, class SegmentManager2, std::size_t N2, std::size_t F2, unsigned char OP2>
314 private_adaptive_pool& operator=
315 (const private_adaptive_pool<T2, SegmentManager2, N2, F2>&);
317 //!Not assignable from
318 //!other private_adaptive_pool
319 private_adaptive_pool& operator=(const private_adaptive_pool&);
322 //!Constructor from a segment manager. If not present, constructs a node
323 //!pool. Increments the reference count of the associated node pool.
324 //!Can throw boost::interprocess::bad_alloc
325 private_adaptive_pool(segment_manager *segment_mngr);
327 //!Copy constructor from other private_adaptive_pool. Increments the reference
328 //!count of the associated node pool. Never throws
329 private_adaptive_pool(const private_adaptive_pool &other);
331 //!Copy constructor from related private_adaptive_pool. If not present, constructs
332 //!a node pool. Increments the reference count of the associated node pool.
333 //!Can throw boost::interprocess::bad_alloc
335 private_adaptive_pool
336 (const private_adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other);
338 //!Destructor, removes node_pool_t from memory
339 //!if its reference count reaches to zero. Never throws
340 ~private_adaptive_pool();
342 //!Returns a pointer to the node pool.
344 node_pool_t* get_node_pool() const;
346 //!Returns the segment manager.
348 segment_manager* get_segment_manager()const;
350 //!Returns the number of elements that could be allocated.
352 size_type max_size() const;
354 //!Allocate memory for an array of count elements.
355 //!Throws boost::interprocess::bad_alloc if there is no enough memory
356 pointer allocate(size_type count, cvoid_pointer hint = 0);
358 //!Deallocate allocated memory.
360 void deallocate(const pointer &ptr, size_type count);
362 //!Deallocates all free blocks
364 void deallocate_free_blocks();
366 //!Swaps allocators. Does not throw. If each allocator is placed in a
367 //!different memory segment, the result is undefined.
368 friend void swap(self_t &alloc1, self_t &alloc2);
370 //!Returns address of mutable object.
372 pointer address(reference value) const;
374 //!Returns address of non mutable object.
376 const_pointer address(const_reference value) const;
378 //!Copy construct an object.
379 //!Throws if T's copy constructor throws
380 void construct(const pointer &ptr, const_reference v);
382 //!Destroys object. Throws if object's
384 void destroy(const pointer &ptr);
386 //!Returns maximum the number of objects the previously allocated memory
387 //!pointed by p can hold. This size only works for memory allocated with
388 //!allocate, allocation_command and allocate_many.
389 size_type size(const pointer &p) const;
391 std::pair<pointer, bool>
392 allocation_command(boost::interprocess::allocation_type command,
393 size_type limit_size,
394 size_type preferred_size,
395 size_type &received_size, const pointer &reuse = 0);
397 //!Allocates many elements of size elem_size in a contiguous block
398 //!of memory. The minimum number to be allocated is min_elements,
399 //!the preferred and maximum number is
400 //!preferred_elements. The number of actually allocated elements is
401 //!will be assigned to received_size. The elements must be deallocated
402 //!with deallocate(...)
403 void allocate_many(size_type elem_size, size_type num_elements, multiallocation_chain &chain);
405 //!Allocates n_elements elements, each one of size elem_sizes[i]in a
407 //!of memory. The elements must be deallocated
408 void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain);
410 //!Allocates many elements of size elem_size in a contiguous block
411 //!of memory. The minimum number to be allocated is min_elements,
412 //!the preferred and maximum number is
413 //!preferred_elements. The number of actually allocated elements is
414 //!will be assigned to received_size. The elements must be deallocated
415 //!with deallocate(...)
416 void deallocate_many(multiallocation_chain &chain);
418 //!Allocates just one object. Memory allocated with this function
419 //!must be deallocated only with deallocate_one().
420 //!Throws boost::interprocess::bad_alloc if there is no enough memory
421 pointer allocate_one();
423 //!Allocates many elements of size == 1 in a contiguous block
424 //!of memory. The minimum number to be allocated is min_elements,
425 //!the preferred and maximum number is
426 //!preferred_elements. The number of actually allocated elements is
427 //!will be assigned to received_size. Memory allocated with this function
428 //!must be deallocated only with deallocate_one().
429 void allocate_individual(size_type num_elements, multiallocation_chain &chain);
431 //!Deallocates memory previously allocated with allocate_one().
432 //!You should never use deallocate_one to deallocate memory allocated
433 //!with other functions different from allocate_one(). Never throws
434 void deallocate_one(const pointer &p);
436 //!Allocates many elements of size == 1 in a contiguous block
437 //!of memory. The minimum number to be allocated is min_elements,
438 //!the preferred and maximum number is
439 //!preferred_elements. The number of actually allocated elements is
440 //!will be assigned to received_size. Memory allocated with this function
441 //!must be deallocated only with deallocate_one().
442 void deallocate_individual(multiallocation_chain &chain);
446 #ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
448 //!Equality test for same type
449 //!of private_adaptive_pool
450 template<class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
451 bool operator==(const private_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc1,
452 const private_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc2);
454 //!Inequality test for same type
455 //!of private_adaptive_pool
456 template<class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
457 bool operator!=(const private_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc1,
458 const private_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc2);
462 } //namespace interprocess {
463 } //namespace boost {
465 #include <boost/interprocess/detail/config_end.hpp>
467 #endif //#ifndef BOOST_INTERPROCESS_PRIVATE_ADAPTIVE_POOL_HPP