BRE12
memory_pool.h
Go to the documentation of this file.
1 /*
2  Copyright 2005-2016 Intel Corporation. All Rights Reserved.
3 
4  This file is part of Threading Building Blocks. Threading Building Blocks is free software;
5  you can redistribute it and/or modify it under the terms of the GNU General Public License
6  version 2 as published by the Free Software Foundation. Threading Building Blocks is
7  distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
8  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
9  See the GNU General Public License for more details. You should have received a copy of
10  the GNU General Public License along with Threading Building Blocks; if not, write to the
11  Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
12 
13  As a special exception, you may use this file as part of a free software library without
14  restriction. Specifically, if other files instantiate templates or use macros or inline
15  functions from this file, or you compile this file and link it with other files to produce
16  an executable, this file does not by itself cause the resulting executable to be covered
17  by the GNU General Public License. This exception does not however invalidate any other
18  reasons why the executable file might be covered by the GNU General Public License.
19 */
20 
21 #ifndef __TBB_memory_pool_H
22 #define __TBB_memory_pool_H
23 
24 #if !TBB_PREVIEW_MEMORY_POOL
25 #error Set TBB_PREVIEW_MEMORY_POOL to include memory_pool.h
26 #endif
27 
29 #include "scalable_allocator.h"
30 #include <new> // std::bad_alloc
31 #include <stdexcept> // std::runtime_error, std::invalid_argument
32 // required in C++03 to construct std::runtime_error and std::invalid_argument
33 #include <string>
34 #if __TBB_ALLOCATOR_CONSTRUCT_VARIADIC
35 #include <utility> // std::forward
36 #endif
37 
38 #if __TBB_EXTRA_DEBUG
39 #define __TBBMALLOC_ASSERT ASSERT
40 #else
41 #define __TBBMALLOC_ASSERT(a,b) ((void)0)
42 #endif
43 
44 namespace tbb {
45 namespace interface6 {
47 namespace internal {
48 
50 class pool_base : tbb::internal::no_copy {
51  // Pool interface is separate from standard allocator classes because it has
52  // to maintain internal state, no copy or assignment. Move and swap are possible.
53 public:
55  void recycle() { rml::pool_reset(my_pool); }
56 
58  void *malloc(size_t size) { return rml::pool_malloc(my_pool, size); }
59 
61  void free(void* ptr) { rml::pool_free(my_pool, ptr); }
62 
64  // Enables some low-level optimization possibilities
65  void *realloc(void* ptr, size_t size) {
66  return rml::pool_realloc(my_pool, ptr, size);
67  }
68 
69 protected:
71  void destroy() { rml::pool_destroy(my_pool); }
72 
73  rml::MemoryPool *my_pool;
74 };
75 
76 } // namespace internal
78 
79 #if _MSC_VER && !defined(__INTEL_COMPILER)
80  // Workaround for erroneous "unreferenced parameter" warning in method destroy.
81  #pragma warning (push)
82  #pragma warning (disable: 4100)
83 #endif
84 
86 
87 template<typename T, typename P = internal::pool_base>
89 protected:
90  typedef P pool_type;
91  pool_type *my_pool;
92  template<typename U, typename R>
93  friend class memory_pool_allocator;
94  template<typename V, typename U, typename R>
95  friend bool operator==( const memory_pool_allocator<V,R>& a, const memory_pool_allocator<U,R>& b);
96  template<typename V, typename U, typename R>
97  friend bool operator!=( const memory_pool_allocator<V,R>& a, const memory_pool_allocator<U,R>& b);
98 public:
99  typedef typename tbb::internal::allocator_type<T>::value_type value_type;
100  typedef value_type* pointer;
101  typedef const value_type* const_pointer;
102  typedef value_type& reference;
103  typedef const value_type& const_reference;
104  typedef size_t size_type;
105  typedef ptrdiff_t difference_type;
106  template<typename U> struct rebind {
108  };
109 
110  memory_pool_allocator(pool_type &pool) throw() : my_pool(&pool) {}
111  memory_pool_allocator(const memory_pool_allocator& src) throw() : my_pool(src.my_pool) {}
112  template<typename U>
113  memory_pool_allocator(const memory_pool_allocator<U,P>& src) throw() : my_pool(src.my_pool) {}
114 
115  pointer address(reference x) const { return &x; }
116  const_pointer address(const_reference x) const { return &x; }
117 
119  pointer allocate( size_type n, const void* /*hint*/ = 0) {
120  pointer p = static_cast<pointer>( my_pool->malloc( n*sizeof(value_type) ) );
121  if (!p)
122  tbb::internal::throw_exception(std::bad_alloc());
123  return p;
124  }
126  void deallocate( pointer p, size_type ) {
127  my_pool->free(p);
128  }
130  size_type max_size() const throw() {
131  size_type max = static_cast<size_type>(-1) / sizeof (value_type);
132  return (max > 0 ? max : 1);
133  }
135 #if __TBB_ALLOCATOR_CONSTRUCT_VARIADIC
136  template<typename U, typename... Args>
137  void construct(U *p, Args&&... args)
138  { ::new((void *)p) U(std::forward<Args>(args)...); }
139 #else // __TBB_ALLOCATOR_CONSTRUCT_VARIADIC
140 #if __TBB_CPP11_RVALUE_REF_PRESENT
141  void construct( pointer p, value_type&& value ) {::new((void*)(p)) value_type(std::move(value));}
142 #endif
143  void construct( pointer p, const value_type& value ) { ::new((void*)(p)) value_type(value); }
144 #endif // __TBB_ALLOCATOR_CONSTRUCT_VARIADIC
145 
147  void destroy( pointer p ) { p->~value_type(); }
148 
149 };
150 
151 #if _MSC_VER && !defined(__INTEL_COMPILER)
152  #pragma warning (pop)
153 #endif // warning 4100 is back
154 
156 
157 template<typename P>
158 class memory_pool_allocator<void, P> {
159 public:
160  typedef P pool_type;
161  typedef void* pointer;
162  typedef const void* const_pointer;
163  typedef void value_type;
164  template<typename U> struct rebind {
166  };
167 
168  memory_pool_allocator( pool_type &pool) throw() : my_pool(&pool) {}
169  memory_pool_allocator( const memory_pool_allocator& src) throw() : my_pool(src.my_pool) {}
170  template<typename U>
171  memory_pool_allocator(const memory_pool_allocator<U,P>& src) throw() : my_pool(src.my_pool) {}
172 
173 protected:
174  pool_type *my_pool;
175  template<typename U, typename R>
176  friend class memory_pool_allocator;
177  template<typename V, typename U, typename R>
178  friend bool operator==( const memory_pool_allocator<V,R>& a, const memory_pool_allocator<U,R>& b);
179  template<typename V, typename U, typename R>
180  friend bool operator!=( const memory_pool_allocator<V,R>& a, const memory_pool_allocator<U,R>& b);
181 };
182 
183 template<typename T, typename U, typename P>
184 inline bool operator==( const memory_pool_allocator<T,P>& a, const memory_pool_allocator<U,P>& b) {return a.my_pool==b.my_pool;}
185 
186 template<typename T, typename U, typename P>
187 inline bool operator!=( const memory_pool_allocator<T,P>& a, const memory_pool_allocator<U,P>& b) {return a.my_pool!=b.my_pool;}
188 
189 
191 template <typename Alloc>
192 class memory_pool : public internal::pool_base {
193  Alloc my_alloc; // TODO: base-class optimization
194  static void *allocate_request(intptr_t pool_id, size_t & bytes);
195  static int deallocate_request(intptr_t pool_id, void*, size_t raw_bytes);
196 
197 public:
199  memory_pool(const Alloc &src = Alloc());
200 
202  ~memory_pool() { destroy(); } // call the callbacks first and destroy my_alloc latter
203 
204 };
205 
206 class fixed_pool : public internal::pool_base {
207  void *my_buffer;
208  size_t my_size;
209  inline static void *allocate_request(intptr_t pool_id, size_t & bytes);
210 
211 public:
213  inline fixed_pool(void *buf, size_t size);
215  ~fixed_pool() { destroy(); }
216 };
217 
219 
220 template <typename Alloc>
221 memory_pool<Alloc>::memory_pool(const Alloc &src) : my_alloc(src) {
222  rml::MemPoolPolicy args(allocate_request, deallocate_request,
223  sizeof(typename Alloc::value_type));
224  rml::MemPoolError res = rml::pool_create_v1(intptr_t(this), &args, &my_pool);
225  if (res!=rml::POOL_OK)
226  tbb::internal::throw_exception(std::runtime_error("Can't create pool"));
227 }
228 template <typename Alloc>
229 void *memory_pool<Alloc>::allocate_request(intptr_t pool_id, size_t & bytes) {
230  memory_pool<Alloc> &self = *reinterpret_cast<memory_pool<Alloc>*>(pool_id);
231  const size_t unit_size = sizeof(typename Alloc::value_type);
232  __TBBMALLOC_ASSERT( 0 == bytes%unit_size, NULL);
233  void *ptr;
234  __TBB_TRY { ptr = self.my_alloc.allocate( bytes/unit_size ); }
235  __TBB_CATCH(...) { return 0; }
236  return ptr;
237 }
238 #if __TBB_MSVC_UNREACHABLE_CODE_IGNORED
239  // Workaround for erroneous "unreachable code" warning in the template below.
240  // Specific for VC++ 17-18 compiler
241  #pragma warning (push)
242  #pragma warning (disable: 4702)
243 #endif
244 template <typename Alloc>
245 int memory_pool<Alloc>::deallocate_request(intptr_t pool_id, void* raw_ptr, size_t raw_bytes) {
246  memory_pool<Alloc> &self = *reinterpret_cast<memory_pool<Alloc>*>(pool_id);
247  const size_t unit_size = sizeof(typename Alloc::value_type);
248  __TBBMALLOC_ASSERT( 0 == raw_bytes%unit_size, NULL);
249  self.my_alloc.deallocate( static_cast<typename Alloc::value_type*>(raw_ptr), raw_bytes/unit_size );
250  return 0;
251 }
252 #if __TBB_MSVC_UNREACHABLE_CODE_IGNORED
253  #pragma warning (pop)
254 #endif
255 inline fixed_pool::fixed_pool(void *buf, size_t size) : my_buffer(buf), my_size(size) {
256  if (!buf || !size)
257  // TODO: improve support for mode with exceptions disabled
258  tbb::internal::throw_exception(std::invalid_argument("Zero in parameter is invalid"));
259  rml::MemPoolPolicy args(allocate_request, 0, size, /*fixedPool=*/true);
260  rml::MemPoolError res = rml::pool_create_v1(intptr_t(this), &args, &my_pool);
261  if (res!=rml::POOL_OK)
262  tbb::internal::throw_exception(std::runtime_error("Can't create pool"));
263 }
264 inline void *fixed_pool::allocate_request(intptr_t pool_id, size_t & bytes) {
265  fixed_pool &self = *reinterpret_cast<fixed_pool*>(pool_id);
266  __TBBMALLOC_ASSERT(0 != self.my_size, "The buffer must not be used twice.");
267  bytes = self.my_size;
268  self.my_size = 0; // remember that buffer has been used
269  return self.my_buffer;
270 }
271 
272 } //namespace interface6
276 } //namespace tbb
277 
278 #undef __TBBMALLOC_ASSERT
279 #endif// __TBB_memory_pool_H
~fixed_pool()
destroy pool
Definition: memory_pool.h:215
~memory_pool()
destroy pool
Definition: memory_pool.h:202
fixed_pool(void *buf, size_t size)
construct pool with underlying allocator
Definition: memory_pool.h:255
void construct(pointer p, const value_type &value)
Copy-construct value at location pointed to by p.
Definition: memory_pool.h:143
memory_pool(const Alloc &src=Alloc())
construct pool with underlying allocator
Definition: memory_pool.h:221
Meets "allocator" requirements of ISO C++ Standard, Section 20.1.5.
Definition: memory_pool.h:88
size_type max_size() const
Largest value for which method allocate might succeed.
Definition: memory_pool.h:130
void deallocate(pointer p, size_type)
Free previously allocated block of memory.
Definition: memory_pool.h:126
Definition: _flow_graph_async_msg_impl.h:32
Definition: memory_pool.h:206
The namespace tbb contains all components of the library.
Definition: parallel_for.h:44
pointer allocate(size_type n, const void *=0)
Allocate space for n objects.
Definition: memory_pool.h:119
Thread-safe growable pool allocator for variable-size requests.
Definition: memory_pool.h:192
void destroy(pointer p)
Destroy value at location pointed to by p.
Definition: memory_pool.h:147