Botan  2.11.0
Crypto and TLS for C++11
Public Member Functions | List of all members
Botan::Memory_Pool Class Referencefinal

#include <mem_pool.h>

Public Member Functions

void * allocate (size_t size)
 
bool deallocate (void *p, size_t size) noexcept
 
 Memory_Pool (const std::vector< void *> &pages, size_t page_size)
 
 Memory_Pool (const Memory_Pool &)=delete
 
 Memory_Pool (Memory_Pool &&)=delete
 
Memory_Pooloperator= (const Memory_Pool &)=delete
 
Memory_Pooloperator= (Memory_Pool &&)=delete
 
 ~Memory_Pool ()
 

Detailed Description

Definition at line 20 of file mem_pool.h.

Constructor & Destructor Documentation

◆ Memory_Pool() [1/3]

Botan::Memory_Pool::Memory_Pool ( const std::vector< void *> &  pages,
size_t  page_size 
)

Initialize a memory pool. The memory is not owned by *this, it must be freed by the caller.

Parameters
pagesa list of pages to allocate from
page_sizethe system page size, each page should point to exactly this much memory.

Definition at line 293 of file mem_pool.cpp.

References Botan::clear_bytes(), and Botan::OS::page_prohibit_access().

293  :
294  m_page_size(page_size)
295  {
296  m_min_page_ptr = ~static_cast<uintptr_t>(0);
297  m_max_page_ptr = 0;
298 
299  for(size_t i = 0; i != pages.size(); ++i)
300  {
301  const uintptr_t p = reinterpret_cast<uintptr_t>(pages[i]);
302 
303  m_min_page_ptr = std::min(p, m_min_page_ptr);
304  m_max_page_ptr = std::max(p, m_max_page_ptr);
305 
306  clear_bytes(pages[i], m_page_size);
307 #if defined(BOTAN_MEM_POOL_USE_MMU_PROTECTIONS)
308  OS::page_prohibit_access(pages[i]);
309 #endif
310  m_free_pages.push_back(static_cast<uint8_t*>(pages[i]));
311  }
312 
313  /*
314  Right now this points to the start of the last page, adjust it to instead
315  point to the first byte of the following page
316  */
317  m_max_page_ptr += page_size;
318  }
void clear_bytes(void *ptr, size_t bytes)
Definition: mem_ops.h:93
void page_prohibit_access(void *page)
Definition: os_utils.cpp:488

◆ ~Memory_Pool()

Botan::Memory_Pool::~Memory_Pool ( )

Definition at line 320 of file mem_pool.cpp.

References Botan::OS::page_allow_access().

321  {
322 #if defined(BOTAN_MEM_POOL_USE_MMU_PROTECTIONS)
323  for(size_t i = 0; i != m_free_pages.size(); ++i)
324  {
325  OS::page_allow_access(m_free_pages[i]);
326  }
327 #endif
328  }
void page_allow_access(void *page)
Definition: os_utils.cpp:476

◆ Memory_Pool() [2/3]

Botan::Memory_Pool::Memory_Pool ( const Memory_Pool )
delete

◆ Memory_Pool() [3/3]

Botan::Memory_Pool::Memory_Pool ( Memory_Pool &&  )
delete

Member Function Documentation

◆ allocate()

void * Botan::Memory_Pool::allocate ( size_t  size)

Definition at line 330 of file mem_pool.cpp.

References BOTAN_ASSERT_NOMSG, and Botan::OS::page_allow_access().

331  {
332  if(n > m_page_size)
333  return nullptr;
334 
335  const size_t n_bucket = choose_bucket(n);
336 
337  if(n_bucket > 0)
338  {
339  lock_guard_type<mutex_type> lock(m_mutex);
340 
341  std::deque<Bucket>& buckets = m_buckets_for[n_bucket];
342 
343  /*
344  It would be optimal to pick the bucket with the most usage,
345  since a bucket with say 1 item allocated out of it has a high
346  chance of becoming later freed and then the whole page can be
347  recycled.
348  */
349  for(auto& bucket : buckets)
350  {
351  if(uint8_t* p = bucket.alloc())
352  return p;
353 
354  // If the bucket is full, maybe move it to the end of the list?
355  // Otoh bucket search should be very fast
356  }
357 
358  if(m_free_pages.size() > 0)
359  {
360  uint8_t* ptr = m_free_pages[0];
361  m_free_pages.pop_front();
362 #if defined(BOTAN_MEM_POOL_USE_MMU_PROTECTIONS)
364 #endif
365  buckets.push_front(Bucket(ptr, m_page_size, n_bucket));
366  void* p = buckets[0].alloc();
367  BOTAN_ASSERT_NOMSG(p != nullptr);
368  return p;
369  }
370  }
371 
372  // out of room
373  return nullptr;
374  }
#define BOTAN_ASSERT_NOMSG(expr)
Definition: assert.h:68
void page_allow_access(void *page)
Definition: os_utils.cpp:476

◆ deallocate()

bool Botan::Memory_Pool::deallocate ( void *  p,
size_t  size 
)
noexcept

Definition at line 376 of file mem_pool.cpp.

377  {
378  // Do a fast range check first, before taking the lock
379  const uintptr_t p_val = reinterpret_cast<uintptr_t>(p);
380  if(p_val < m_min_page_ptr || p_val > m_max_page_ptr)
381  return false;
382 
383  const size_t n_bucket = choose_bucket(len);
384 
385  if(n_bucket != 0)
386  {
387  try
388  {
389  lock_guard_type<mutex_type> lock(m_mutex);
390 
391  std::deque<Bucket>& buckets = m_buckets_for[n_bucket];
392 
393  for(size_t i = 0; i != buckets.size(); ++i)
394  {
395  Bucket& bucket = buckets[i];
396  if(bucket.free(p))
397  {
398  if(bucket.empty())
399  {
400 #if defined(BOTAN_MEM_POOL_USE_MMU_PROTECTIONS)
401  OS::page_prohibit_access(bucket.ptr());
402 #endif
403  m_free_pages.push_back(bucket.ptr());
404 
405  if(i != buckets.size() - 1)
406  std::swap(buckets.back(), buckets[i]);
407  buckets.pop_back();
408  }
409  return true;
410  }
411  }
412  }
413  catch(...)
414  {
415  /*
416  * The only exception throws that can occur in the above code are from
417  * either the STL or BOTAN_ASSERT failures. In either case, such an
418  * error indicates a logic error or data corruption in the memory
419  * allocator such that it is no longer safe to continue executing.
420  *
421  * Since this function is noexcept, simply letting the exception escape
422  * is sufficient for terminate to be called. However in this scenario
423  * it is implementation defined if any stack unwinding is performed.
424  * Since stack unwinding could cause further memory deallocations this
425  * could result in further corruption in this allocator state. To prevent
426  * this, call terminate directly.
427  */
428  std::terminate();
429  }
430  }
431 
432  return false;
433  }
void page_prohibit_access(void *page)
Definition: os_utils.cpp:488

◆ operator=() [1/2]

Memory_Pool& Botan::Memory_Pool::operator= ( const Memory_Pool )
delete

◆ operator=() [2/2]

Memory_Pool& Botan::Memory_Pool::operator= ( Memory_Pool &&  )
delete

The documentation for this class was generated from the following files: