2 Copyright 2005-2011 Intel Corporation. All Rights Reserved.
4 This file is part of Threading Building Blocks.
6 Threading Building Blocks is free software; you can redistribute it
7 and/or modify it under the terms of the GNU General Public License
8 version 2 as published by the Free Software Foundation.
10 Threading Building Blocks is distributed in the hope that it will be
11 useful, but WITHOUT ANY WARRANTY; without even the implied warranty
12 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with Threading Building Blocks; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 As a special exception, you may use this file as part of a free software
20 library without restriction. Specifically, if other files instantiate
21 templates or use macros or inline functions from this file, or you compile
22 this file and link it with other files to produce an executable, this
23 file does not by itself cause the resulting executable to be covered by
24 the GNU General Public License. This exception does not however
25 invalidate any other reasons why the executable file might be covered by
26 the GNU General Public License.
29 #ifndef __TBB_memory_pool_H
30 #define __TBB_memory_pool_H
32 #if !TBB_PREVIEW_MEMORY_POOL
33 #error Set TBB_PREVIEW_MEMORY_POOL to include memory_pool.h
37 #include "scalable_allocator.h"
38 #include "tbb_stddef.h"
39 #include "tbb_machine.h" // TODO: Itanium requires linkage with TBB library
40 #include <new> // std::bad_alloc
43 #define __TBBMALLOC_ASSERT ASSERT
45 #define __TBBMALLOC_ASSERT(a,b) ((void)0)
49 namespace interface6 {
53 //! Base of thread-safe pool allocator for variable-size requests
54 class pool_base : tbb::internal::no_copy {
55 // Pool interface is separate from standard allocator classes because it has
56 // to maintain internal state, no copy or assignment. Move and swap are possible.
58 //! Reset pool to reuse its memory (free all objects at once)
59 void recycle() { rml::pool_reset(my_pool); }
61 //! The "malloc" analogue to allocate block of memory of size bytes
62 void *malloc(size_t size) { return rml::pool_malloc(my_pool, size); }
64 //! The "free" analogue to discard a previously allocated piece of memory.
65 void free(void* ptr) { rml::pool_free(my_pool, ptr); }
67 //! The "realloc" analogue complementing pool_malloc.
68 // Enables some low-level optimization possibilities
69 void *realloc(void* ptr, size_t size) {
70 return rml::pool_realloc(my_pool, ptr, size);
74 //! destroy pool - must be called in a child class
75 void destroy() { rml::pool_destroy(my_pool); }
77 rml::MemoryPool *my_pool;
80 } // namespace internal
83 #if _MSC_VER && !defined(__INTEL_COMPILER)
84 // Workaround for erroneous "unreferenced parameter" warning in method destroy.
85 #pragma warning (push)
86 #pragma warning (disable: 4100)
89 //! Meets "allocator" requirements of ISO C++ Standard, Section 20.1.5
90 /** @ingroup memory_allocation */
91 template<typename T, typename P = internal::pool_base>
92 class memory_pool_allocator {
96 template<typename U, typename R>
97 friend class memory_pool_allocator;
98 template<typename V, typename U, typename R>
99 friend bool operator==( const memory_pool_allocator<V,R>& a, const memory_pool_allocator<U,R>& b);
100 template<typename V, typename U, typename R>
101 friend bool operator!=( const memory_pool_allocator<V,R>& a, const memory_pool_allocator<U,R>& b);
103 typedef typename tbb::internal::allocator_type<T>::value_type value_type;
104 typedef value_type* pointer;
105 typedef const value_type* const_pointer;
106 typedef value_type& reference;
107 typedef const value_type& const_reference;
108 typedef size_t size_type;
109 typedef ptrdiff_t difference_type;
110 template<typename U> struct rebind {
111 typedef memory_pool_allocator<U, P> other;
114 memory_pool_allocator(pool_type &pool) throw() : my_pool(&pool) {}
115 memory_pool_allocator(const memory_pool_allocator& src) throw() : my_pool(src.my_pool) {}
117 memory_pool_allocator(const memory_pool_allocator<U,P>& src) throw() : my_pool(src.my_pool) {}
119 pointer address(reference x) const { return &x; }
120 const_pointer address(const_reference x) const { return &x; }
122 //! Allocate space for n objects.
123 pointer allocate( size_type n, const void* /*hint*/ = 0) {
124 return static_cast<pointer>( my_pool->malloc( n*sizeof(value_type) ) );
126 //! Free previously allocated block of memory.
127 void deallocate( pointer p, size_type ) {
130 //! Largest value for which method allocate might succeed.
131 size_type max_size() const throw() {
132 size_type max = static_cast<size_type>(-1) / sizeof (value_type);
133 return (max > 0 ? max : 1);
135 //! Copy-construct value at location pointed to by p.
136 void construct( pointer p, const value_type& value ) { ::new((void*)(p)) value_type(value); }
138 //! Destroy value at location pointed to by p.
139 void destroy( pointer p ) { p->~value_type(); }
143 #if _MSC_VER && !defined(__INTEL_COMPILER)
144 #pragma warning (pop)
145 #endif // warning 4100 is back
147 //! Analogous to std::allocator<void>, as defined in ISO C++ Standard, Section 20.4.1
148 /** @ingroup memory_allocation */
150 class memory_pool_allocator<void, P> {
153 typedef void* pointer;
154 typedef const void* const_pointer;
155 typedef void value_type;
156 template<typename U> struct rebind {
157 typedef memory_pool_allocator<U, P> other;
160 memory_pool_allocator( pool_type &pool) throw() : my_pool(&pool) {}
161 memory_pool_allocator( const memory_pool_allocator& src) throw() : my_pool(src.my_pool) {}
163 memory_pool_allocator(const memory_pool_allocator<U,P>& src) throw() : my_pool(src.my_pool) {}
167 template<typename U, typename R>
168 friend class memory_pool_allocator;
169 template<typename V, typename U, typename R>
170 friend bool operator==( const memory_pool_allocator<V,R>& a, const memory_pool_allocator<U,R>& b);
171 template<typename V, typename U, typename R>
172 friend bool operator!=( const memory_pool_allocator<V,R>& a, const memory_pool_allocator<U,R>& b);
175 template<typename T, typename U, typename P>
176 inline bool operator==( const memory_pool_allocator<T,P>& a, const memory_pool_allocator<U,P>& b) {return a.my_pool==b.my_pool;}
178 template<typename T, typename U, typename P>
179 inline bool operator!=( const memory_pool_allocator<T,P>& a, const memory_pool_allocator<U,P>& b) {return a.my_pool!=b.my_pool;}
182 //! Thread-safe growable pool allocator for variable-size requests
183 template <typename Alloc>
184 class memory_pool : public internal::pool_base {
185 Alloc my_alloc; // TODO: base-class optimization
186 static void *allocate_request(intptr_t pool_id, size_t & bytes);
187 static int deallocate_request(intptr_t pool_id, void*, size_t raw_bytes);
190 //! construct pool with underlying allocator
191 memory_pool(const Alloc &src = Alloc());
194 ~memory_pool() { destroy(); } // call the callbacks first and destroy my_alloc latter
198 class fixed_pool : public internal::pool_base {
201 inline static void *allocate_request(intptr_t pool_id, size_t & bytes);
204 //! construct pool with underlying allocator
205 inline fixed_pool(void *buf, size_t size);
207 ~fixed_pool() { destroy(); }
210 //////////////// Implementation ///////////////
212 template <typename Alloc>
213 memory_pool<Alloc>::memory_pool(const Alloc &src) : my_alloc(src) {
214 rml::MemPoolPolicy args = {
215 allocate_request, deallocate_request, sizeof(typename Alloc::value_type)
217 my_pool = rml::pool_create(intptr_t(this), &args);
218 __TBBMALLOC_ASSERT(my_pool, "Pool is not created");
219 if( !my_pool ) __TBB_THROW(std::bad_alloc());
221 template <typename Alloc>
222 void *memory_pool<Alloc>::allocate_request(intptr_t pool_id, size_t & bytes) {
223 memory_pool<Alloc> &self = *reinterpret_cast<memory_pool<Alloc>*>(pool_id);
224 const size_t unit_size = sizeof(typename Alloc::value_type);
225 __TBBMALLOC_ASSERT( 0 == bytes%unit_size, NULL);
227 __TBB_TRY { ptr = self.my_alloc.allocate( bytes/unit_size ); }
228 __TBB_CATCH(...) { return 0; }
231 template <typename Alloc>
232 int memory_pool<Alloc>::deallocate_request(intptr_t pool_id, void* raw_ptr, size_t raw_bytes) {
233 memory_pool<Alloc> &self = *reinterpret_cast<memory_pool<Alloc>*>(pool_id);
234 const size_t unit_size = sizeof(typename Alloc::value_type);
235 __TBBMALLOC_ASSERT( 0 == raw_bytes%unit_size, NULL);
236 self.my_alloc.deallocate( static_cast<typename Alloc::value_type*>(raw_ptr), raw_bytes/unit_size );
239 inline fixed_pool::fixed_pool(void *buf, size_t size) : my_buffer(buf), my_size(size) {
240 rml::MemPoolPolicy args = { allocate_request, 0, size };
241 my_pool = rml::pool_create(intptr_t(this), &args);
242 __TBBMALLOC_ASSERT(my_pool, "Pool is not created");
243 if( !my_pool ) __TBB_THROW(std::bad_alloc());
245 inline void *fixed_pool::allocate_request(intptr_t pool_id, size_t & bytes) {
246 fixed_pool &self = *reinterpret_cast<fixed_pool*>(pool_id);
247 if( bytes > self.my_size || !__TBB_CompareAndSwapW(&self.my_size, 0, (bytes=self.my_size)) )
248 return 0; // all the memory was given already
249 return self.my_buffer;
252 } //namespace interface6
253 using interface6::memory_pool_allocator;
254 using interface6::memory_pool;
255 using interface6::fixed_pool;
258 #undef __TBBMALLOC_ASSERT
259 #endif// __TBB_memory_pool_H