Botan 1.10.17

mem_pool.cpp
Go to the documentation of this file.
1 /*
2 * Pooling Allocator
3 * (C) 1999-2008 Jack Lloyd
4 * 2005 Matthew Gregan
5 * 2005-2006 Matt Johnston
6 *
7 * Distributed under the terms of the Botan license
8 */
9
10 #include <botan/internal/mem_pool.h>
11 #include <botan/internal/rounding.h>
12 #include <botan/mem_ops.h>
13 #include <algorithm>
14 #include <exception>
15
16 namespace Botan {
17
18 /*
19 * Memory_Block Constructor
20 */
21 Pooling_Allocator::Memory_Block::Memory_Block(void* buf)
22 {
23 buffer = static_cast<byte*>(buf);
24 bitmap = 0;
25 buffer_end = buffer + (BLOCK_SIZE * BITMAP_SIZE);
26 }
27
28 /*
29 * See if ptr is contained by this block
30 */
31 bool Pooling_Allocator::Memory_Block::contains(void* ptr,
32 size_t length) const
33 {
34 return ((buffer <= ptr) &&
35 (buffer_end >= static_cast<byte*>(ptr) + length * BLOCK_SIZE));
36 }
37
38 /*
39 * Allocate some memory, if possible
40 */
41 byte* Pooling_Allocator::Memory_Block::alloc(size_t n)
42 {
43 if(n == 0 || n > BITMAP_SIZE)
44 return 0;
45
46 if(n == BITMAP_SIZE)
47 {
48 if(bitmap)
49 return 0;
50 else
51 {
52 bitmap = ~bitmap;
53 return buffer;
54 }
55 }
56
57 bitmap_type mask = (static_cast<bitmap_type>(1) << n) - 1;
58 size_t offset = 0;
59
60 while(bitmap & mask)
61 {
62 mask <<= 1;
63 ++offset;
64
65 if((bitmap & mask) == 0)
66 break;
67 if(mask >> 63)
68 break;
69 }
70
71 if(bitmap & mask)
72 return 0;
73
74 bitmap |= mask;
75 return buffer + offset * BLOCK_SIZE;
76 }
77
78 /*
79 * Mark this memory as free, if we own it
80 */
81 void Pooling_Allocator::Memory_Block::free(void* ptr, size_t blocks)
82 {
83 clear_mem(static_cast<byte*>(ptr), blocks * BLOCK_SIZE);
84
85 const size_t offset = (static_cast<byte*>(ptr) - buffer) / BLOCK_SIZE;
86
87 if(offset == 0 && blocks == BITMAP_SIZE)
88 bitmap = ~bitmap;
89 else
90 {
91 for(size_t j = 0; j != blocks; ++j)
92 bitmap &= ~(static_cast<bitmap_type>(1) << (j+offset));
93 }
94 }
95
96 /*
97 * Pooling_Allocator Constructor
98 */
99 Pooling_Allocator::Pooling_Allocator(Mutex* m) : mutex(m)
100 {
101 last_used = blocks.begin();
102 }
103
104 /*
105 * Pooling_Allocator Destructor
106 */
107 Pooling_Allocator::~Pooling_Allocator()
108 {
109 delete mutex;
110 #if 0
111 if(blocks.size())
112 throw Invalid_State("Pooling_Allocator: Never released memory");
113 #endif
114 }
115
116 /*
117 * Free all remaining memory
118 */
119 void Pooling_Allocator::destroy()
120 {
121 Mutex_Holder lock(mutex);
122
123 blocks.clear();
124
125 for(size_t j = 0; j != allocated.size(); ++j)
126 dealloc_block(allocated[j].first, allocated[j].second);
127 allocated.clear();
128 }
129
130 /*
131 * Allocation
132 */
133 void* Pooling_Allocator::allocate(size_t n)
134 {
135 const size_t BITMAP_SIZE = Memory_Block::bitmap_size();
136 const size_t BLOCK_SIZE = Memory_Block::block_size();
137
138 Mutex_Holder lock(mutex);
139
140 if(n <= BITMAP_SIZE * BLOCK_SIZE)
141 {
142 const size_t block_no = round_up(n, BLOCK_SIZE) / BLOCK_SIZE;
143
144 byte* mem = allocate_blocks(block_no);
145 if(mem)
146 return mem;
147
148 get_more_core(BOTAN_MEM_POOL_CHUNK_SIZE);
149
150 mem = allocate_blocks(block_no);
151 if(mem)
152 return mem;
153
154 throw Memory_Exhaustion();
155 }
156
157 void* new_buf = alloc_block(n);
158 if(new_buf)
159 return new_buf;
160
161 throw Memory_Exhaustion();
162 }
163
164 /*
165 * Deallocation
166 */
167 void Pooling_Allocator::deallocate(void* ptr, size_t n)
168 {
169 const size_t BITMAP_SIZE = Memory_Block::bitmap_size();
170 const size_t BLOCK_SIZE = Memory_Block::block_size();
171
172 if(ptr == 0 || n == 0)
173 return;
174
175 Mutex_Holder lock(mutex);
176
177 if(n > BITMAP_SIZE * BLOCK_SIZE)
178 dealloc_block(ptr, n);
179 else
180 {
181 const size_t block_no = round_up(n, BLOCK_SIZE) / BLOCK_SIZE;
182
183 std::vector<Memory_Block>::iterator i =
184 std::lower_bound(blocks.begin(), blocks.end(), Memory_Block(ptr));
185
186 if(i == blocks.end() || !i->contains(ptr, block_no))
187 throw Invalid_State("Pointer released to the wrong allocator");
188
189 i->free(ptr, block_no);
190 }
191 }
192
193 /*
194 * Try to get some memory from an existing block
195 */
196 byte* Pooling_Allocator::allocate_blocks(size_t n)
197 {
198 if(blocks.empty())
199 return 0;
200
201 std::vector<Memory_Block>::iterator i = last_used;
202
203 do
204 {
205 byte* mem = i->alloc(n);
206 if(mem)
207 {
208 last_used = i;
209 return mem;
210 }
211
212 ++i;
213 if(i == blocks.end())
214 i = blocks.begin();
215 }
216 while(i != last_used);
217
218 return 0;
219 }
220
221 /*
222 * Allocate more memory for the pool
223 */
224 void Pooling_Allocator::get_more_core(size_t in_bytes)
225 {
226 const size_t BITMAP_SIZE = Memory_Block::bitmap_size();
227 const size_t BLOCK_SIZE = Memory_Block::block_size();
228
229 const size_t TOTAL_BLOCK_SIZE = BLOCK_SIZE * BITMAP_SIZE;
230
231 // upper bound on allocation is 1 MiB
232 in_bytes = std::min<size_t>(in_bytes, 1024 * 1024);
233
234 const size_t in_blocks = round_up(in_bytes, BLOCK_SIZE) / TOTAL_BLOCK_SIZE;
235 const size_t to_allocate = in_blocks * TOTAL_BLOCK_SIZE;
236
237 void* ptr = alloc_block(to_allocate);
238 if(ptr == 0)
239 throw Memory_Exhaustion();
240
241 allocated.push_back(std::make_pair(ptr, to_allocate));
242
243 for(size_t j = 0; j != in_blocks; ++j)
244 {
245 byte* byte_ptr = static_cast<byte*>(ptr);
246 blocks.push_back(Memory_Block(byte_ptr + j * TOTAL_BLOCK_SIZE));
247 }
248
249 std::sort(blocks.begin(), blocks.end());
250 last_used = std::lower_bound(blocks.begin(), blocks.end(),
251 Memory_Block(ptr));
252 }
253
254 }
Botan::Pooling_Allocator::~Pooling_Allocator
~Pooling_Allocator()
Definition: mem_pool.cpp:107
Botan::Memory_Exhaustion
Definition: exceptn.h:185
Botan::Pooling_Allocator::deallocate
void deallocate(void *, size_t)
Definition: mem_pool.cpp:167
Botan::clear_mem
void clear_mem(T *ptr, size_t n)
Definition: mem_ops.h:32
Botan::Invalid_State
Definition: exceptn.h:25
Botan::Pooling_Allocator::Pooling_Allocator
Pooling_Allocator(Mutex *mutex)
Definition: mem_pool.cpp:99
Botan::Pooling_Allocator::allocate
void * allocate(size_t)
Definition: mem_pool.cpp:133
Botan::byte
unsigned char byte
Definition: types.h:22
Botan::Pooling_Allocator::destroy
void destroy()
Definition: mem_pool.cpp:119
Botan
Definition: algo_base.h:14
Botan::Mutex
Definition: mutex.h:18
Botan::Mutex_Holder
Definition: mutex.h:50
Botan::round_up
T round_up(T n, T align_to)
Definition: rounding.h:22
alloc
Allocator * alloc
Definition: bzip2.cpp:29