mem_pool.h
Go to the documentation of this file.
1 //
2 // Bareflank Hypervisor
3 //
4 // Copyright (C) 2015 Assured Information Security, Inc.
5 // Author: Rian Quinn <quinnr@ainfosec.com>
6 // Author: Brendan Kerrigan <kerriganb@ainfosec.com>
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Lesser General Public
10 // License as published by the Free Software Foundation; either
11 // version 2.1 of the License, or (at your option) any later version.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Lesser General Public License for more details.
17 //
18 // You should have received a copy of the GNU Lesser General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 
22 #ifndef MEM_POOL_H
23 #define MEM_POOL_H
24 
25 #include <gsl/gsl>
26 
27 #include <mutex>
28 #include <array>
29 
30 #include <constants.h>
31 
32 // -----------------------------------------------------------------------------
33 // Testing Switch
34 // -----------------------------------------------------------------------------
35 
36 #ifdef TESTING_MEM_POOL
37 #define noexcept_testing
38 #define static_construction_error() throw std::logic_error("static_construction_error")
39 #else
40 #define noexcept_testing noexcept
41 #define static_construction_error() std::terminate()
42 #endif
43 
44 // -----------------------------------------------------------------------------
45 // Constants
46 // -----------------------------------------------------------------------------
47 
48 constexpr const auto mem_pool_used_index = 0xFFFFFFFFFFFFFFFEUL;
49 constexpr const auto mem_pool_free_index = 0xFFFFFFFFFFFFFFFFUL;
50 
51 // -----------------------------------------------------------------------------
52 // Definition
53 // -----------------------------------------------------------------------------
54 
58 
80 template<size_t total_size, size_t block_shift>
81 class mem_pool
82 {
83  static_assert(total_size > 0, "total size must be larger than 0");
84  static_assert(total_size % (1 << block_shift) == 0, "total size must be a multiple of block size");
85  static_assert((MAX_PAGE_SHIFT >= block_shift) &&(block_shift > 0), "block shift must be larger than 0");
86 
87 public:
88 
89  using size_type = size_t;
90  using shift_type = size_t;
91  using integer_pointer = uintptr_t;
92 
102  m_addr(addr),
103  m_size(total_size >> block_shift)
104  {
105  if (addr == 0)
107 
109  if (__builtin_uaddl_overflow(m_addr, total_size, &end))
111 
112  clear();
113  }
114 
117  ~mem_pool() = default;
118 
138  {
139  // [[ensures ret: ret != 0]]
140  expects(size > 0);
141  expects(size <= total_size);
142 
143  std::lock_guard<std::mutex> lock(m_mutex);
144 
146  integer_pointer total = total_blocks(size);
147 
148  if ((start = next_search(m_next, total)) != mem_pool_used_index)
149  {
150  m_next = start + total;
151  gsl::at(m_allocated, start) = total;
152 
153  return m_addr + (start << block_shift);
154  }
155 
156  throw std::bad_alloc();
157  }
158 
168  void
170  {
171  if (addr < m_addr)
172  return;
173 
174  integer_pointer start = (addr - m_addr) >> block_shift;
175 
176  if (start >= m_allocated.size())
177  return;
178 
179  {
180  std::lock_guard<std::mutex> lock(m_mutex);
181  gsl::at(m_allocated, start) = mem_pool_free_index;
182  }
183  }
184 
195  bool
197  { return (addr >= m_addr && addr < m_addr + total_size); }
198 
210  size_type
212  {
213  std::lock_guard<std::mutex> lock(m_mutex);
214 
215  if (!contains(addr))
216  return 0;
217 
218  auto size = gsl::at(m_allocated, (addr - m_addr) >> block_shift);
219 
220  if (size == mem_pool_free_index)
221  return 0;
222 
223  return size << block_shift;
224  }
225 
234  void
236  {
237  std::lock_guard<std::mutex> lock(m_mutex);
238 
239  m_next = 0;
240  __builtin_memset(m_allocated.data(), 0xFF, sizeof(m_allocated));
241  }
242 
243 private:
244 
246  next_search(integer_pointer initial, integer_pointer total) const
247  {
249  integer_pointer count = 0;
251  integer_pointer index = initial;
252 
253  while (true)
254  {
255  if (index >= m_size)
256  {
257  count = 0;
258  index = 0;
259  }
260 
261  if (gsl::at(m_allocated, index) == mem_pool_free_index)
262  {
263  if (count == 0)
264  start = index;
265 
266  count++;
267  index++;
268  check++;
269  }
270  else
271  {
272  auto blocks = gsl::at(m_allocated, index);
273 
274  count = 0;
275  index += blocks;
276  check += blocks;
277  }
278 
279  if (count >= total)
280  return start;
281 
282  if (check >= (total_size >> block_shift))
283  return mem_pool_used_index;
284  }
285  }
286 
288  total_blocks(size_type size) const noexcept
289  {
290  integer_pointer total = size >> block_shift;
291 
292  if ((size & ((1 << block_shift) - 1)) != 0)
293  total++;
294 
295  return total;
296  }
297 
298 private:
299 
300  integer_pointer m_next;
301  integer_pointer m_addr;
302  integer_pointer m_size;
303 
304  mutable std::mutex m_mutex;
305  std::array < integer_pointer, (total_size >> block_shift) > m_allocated;
306 
307 public:
308 
309  mem_pool(const mem_pool &) = delete;
310  mem_pool &operator=(const mem_pool &) = delete;
311  mem_pool(mem_pool &&) noexcept = delete;
312  mem_pool &operator=(mem_pool &&) noexcept = delete;
313 };
314 
318 
319 #endif
~mem_pool()=default
expects(rbx)
#define noexcept_testing
Definition: mem_pool.h:40
#define static_construction_error()
Definition: mem_pool.h:41
void clear() noexcept
Definition: mem_pool.h:235
void uint64_t uint64_t uint64_t *rdx noexcept
auto index(const T virt, const F from)
constexpr const auto addr
Definition: cpuid_x64.h:80
size_type size(integer_pointer addr) const noexcept
Definition: mem_pool.h:211
void free(integer_pointer addr) noexcept
Definition: mem_pool.h:169
#define MAX_PAGE_SHIFT
Definition: constants.h:102
integer_pointer alloc(size_type size)
Definition: mem_pool.h:137
auto end(reversed_container< T > container) -> decltype(container.container.rend())
Definition: reverse.h:43
constexpr const auto mem_pool_used_index
Definition: mem_pool.h:48
mem_pool(integer_pointer addr) noexcept _testing
Definition: mem_pool.h:101
mem_pool & operator=(const mem_pool &)=delete
bool contains(integer_pointer addr) const noexcept
Definition: mem_pool.h:196
constexpr const auto mem_pool_free_index
Definition: mem_pool.h:49