PIVX Core  5.6.99
P2P Digital Currency
mt_pooled_secure.h
Go to the documentation of this file.
1 // Copyright (c) 2018-2021 The Dash Core developers
2 // Copyright (c) 2021 The PIVX Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #ifndef PIVX_SUPPORT_ALLOCATORS_MT_POOLED_SECURE_H
7 #define PIVX_SUPPORT_ALLOCATORS_MT_POOLED_SECURE_H
8 
9 #include "pooled_secure.h"
10 
11 #include <thread>
12 #include <mutex>
13 
14 //
15 // Manages a pool of pools to balance allocation between those when multiple threads are involved
16 // This allocator is fully thread safe
17 //
18 template <typename T>
19 struct mt_pooled_secure_allocator : public std::allocator<T> {
20  // MSVC8 default copy constructor is broken
21  typedef std::allocator<T> base;
22  typedef typename base::size_type size_type;
23  typedef typename base::difference_type difference_type;
24  typedef typename base::pointer pointer;
25  typedef typename base::const_pointer const_pointer;
26  typedef typename base::reference reference;
27  typedef typename base::const_reference const_reference;
28  typedef typename base::value_type value_type;
29  explicit mt_pooled_secure_allocator(size_type nrequested_size = 32,
30  size_type nnext_size = 32,
31  size_type nmax_size = 0) throw()
32  {
33  // we add enough bytes to the requested size so that we can store the bucket as well
34  nrequested_size += sizeof(size_t);
35 
36  size_t pools_count = std::thread::hardware_concurrency();
37  pools.resize(pools_count);
38  for (size_t i = 0; i < pools_count; i++) {
39  pools[i] = std::make_unique<internal_pool>(nrequested_size, nnext_size, nmax_size);
40  }
41  }
43 
44  T* allocate(std::size_t n, const void* hint = 0)
45  {
46  size_t bucket = get_bucket();
47  std::lock_guard<std::mutex> lock(pools[bucket]->mutex);
48  uint8_t* ptr = pools[bucket]->allocate(n * sizeof(T) + sizeof(size_t));
49  *(size_t*)ptr = bucket;
50  return static_cast<T*>(ptr + sizeof(size_t));
51  }
52 
53  void deallocate(T* p, std::size_t n)
54  {
55  if (!p) {
56  return;
57  }
58  uint8_t* ptr = (uint8_t*)p - sizeof(size_t);
59  size_t bucket = *(size_t*)ptr;
60  std::lock_guard<std::mutex> lock(pools[bucket]->mutex);
61  pools[bucket]->deallocate(ptr, n * sizeof(T));
62  }
63 
64 private:
65  size_t get_bucket()
66  {
67  size_t x = std::hash<std::thread::id>{}(std::this_thread::get_id());
68  return x % pools.size();
69  }
70 
72  internal_pool(size_type nrequested_size,
73  size_type nnext_size,
74  size_type nmax_size) :
75  pooled_secure_allocator(nrequested_size, nnext_size, nmax_size)
76  {
77  }
78  std::mutex mutex;
79  };
80 
81 private:
82  std::vector<std::unique_ptr<internal_pool>> pools;
83 };
84 
85 #endif // PIVX_SUPPORT_ALLOCATORS_MT_POOLED_SECURE_H
#define T(expected, seed, data)
internal_pool(size_type nrequested_size, size_type nnext_size, size_type nmax_size)
std::allocator< T > base
base::const_reference const_reference
base::const_pointer const_pointer
void deallocate(T *p, std::size_t n)
std::vector< std::unique_ptr< internal_pool > > pools
mt_pooled_secure_allocator(size_type nrequested_size=32, size_type nnext_size=32, size_type nmax_size=0)
base::difference_type difference_type
T * allocate(std::size_t n, const void *hint=0)