-
Notifications
You must be signed in to change notification settings - Fork 0
/
PoolBitmappedMemoryManager.cpp
240 lines (209 loc) · 8.41 KB
/
PoolBitmappedMemoryManager.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
#include "PoolBitmappedMemoryManager.h"
#include "Complex.h"
#include "Globals.h"
#include "Utils.h"
void PoolBitmappedMemoryManager::BitMapEntry::SetBit(int position, bool flag) {
BlocksAvailable += flag ? 1 : -1;
//index of block
int elementNo = position / INT_SIZE;
//position of bit inside the block
int bitNo = position % INT_SIZE;
//in the block, store the needed displacement of bits to set it as zero
BitMap[elementNo] = (flag) ? BitMap[elementNo] | (1 << bitNo)
: BitMap[elementNo] & ~(1 << bitNo);
}
void PoolBitmappedMemoryManager::BitMapEntry::SetMultipleBits(int position, bool flag, int count) {
BlocksAvailable += flag ? count : -count;
int elementNo = position / INT_SIZE;
int bitNo = position % INT_SIZE;
int bitSize = (count <= INT_SIZE - bitNo) ? count : INT_SIZE - bitNo;
SetRangeOfInt(&BitMap[elementNo], bitNo + bitSize - 1, bitNo, flag);
count -= bitSize;
if (!count) return;
int i = ++elementNo;
//for every block to set
while (count >= 0) {
if (count <= INT_SIZE) {
SetRangeOfInt(&BitMap[i], count - 1, 0, flag);
return;
} else
BitMap[i] = flag ? unsigned(-1) : 0;
count -= 32;
i++;
}
}
void PoolBitmappedMemoryManager::BitMapEntry::SetRangeOfInt(int* element, int msb, int lsb, bool flag) {
if (flag) {
int mask = (unsigned(-1) << lsb) & (unsigned(-1) >> (INT_SIZE - msb - 1));
*element |= mask;
} else {
int mask = (unsigned(-1) << lsb) & (unsigned(-1) >> (INT_SIZE - msb - 1));
*element &= ~mask;
}
}
void* PoolBitmappedMemoryManager::BitMapEntry::FirstFreeBlock(size_t size) {
//iterate all positions (in blocks) of the bitmap
for (int i = 0; i < BIT_MAP_ELEMENTS; ++i) {
if (BitMap[i] == 0) //if is zero, no free bit was found, see below for explanation
continue;
// this expression yields the first
// bit position which is 1 in an int from right.
int result = BitMap[i] & -(BitMap[i]);
//better explanation, a free block is all 1'
//the bits & bits(-number) leads to all bits to zero except
//the position in which is 1
//example, 00110100 leads to 00100000
void* address = 0;
//position of the first bit of the block
int basePos = (INT_SIZE * i);
//plus the bit position inside the block
switch (result) {
//make the corresponding bit 0 meaning block is no longer free
case 0x00000001: return ObjectAddress(basePos + 0);
case 0x00000002: return ObjectAddress(basePos + 1);
case 0x00000004: return ObjectAddress(basePos + 2);
case 0x00000008: return ObjectAddress(basePos + 3);
case 0x00000010: return ObjectAddress(basePos + 4);
case 0x00000020: return ObjectAddress(basePos + 5);
case 0x00000040: return ObjectAddress(basePos + 6);
case 0x00000080: return ObjectAddress(basePos + 7);
case 0x00000100: return ObjectAddress(basePos + 8);
case 0x00000200: return ObjectAddress(basePos + 9);
case 0x00000400: return ObjectAddress(basePos + 10);
case 0x00000800: return ObjectAddress(basePos + 11);
case 0x00001000: return ObjectAddress(basePos + 12);
case 0x00002000: return ObjectAddress(basePos + 13);
case 0x00004000: return ObjectAddress(basePos + 14);
case 0x00008000: return ObjectAddress(basePos + 15);
case 0x00010000: return ObjectAddress(basePos + 16);
case 0x00020000: return ObjectAddress(basePos + 17);
case 0x00040000: return ObjectAddress(basePos + 18);
case 0x00080000: return ObjectAddress(basePos + 19);
case 0x00100000: return ObjectAddress(basePos + 20);
case 0x00200000: return ObjectAddress(basePos + 21);
case 0x00400000: return ObjectAddress(basePos + 22);
case 0x00800000: return ObjectAddress(basePos + 23);
case 0x01000000: return ObjectAddress(basePos + 24);
case 0x02000000: return ObjectAddress(basePos + 25);
case 0x04000000: return ObjectAddress(basePos + 26);
case 0x08000000: return ObjectAddress(basePos + 27);
case 0x10000000: return ObjectAddress(basePos + 28);
case 0x20000000: return ObjectAddress(basePos + 29);
case 0x40000000: return ObjectAddress(basePos + 30);
case 0x80000000: return ObjectAddress(basePos + 31);
default: break;
}
}
return 0;
}
void* PoolBitmappedMemoryManager::BitMapEntry::ObjectAddress(int pos) {
SetBit(pos, false);
//to the head plus the blocks of memory and the concrete bit of the block
return &((static_cast<Complex*>(Head()) + (pos / INT_SIZE))
[INT_SIZE - ((pos % INT_SIZE) + 1)]);
}
void* PoolBitmappedMemoryManager::BitMapEntry::Head() {
return poolBitmapMemory->GetMemoryPoolList()[Index];
}
PoolBitmappedMemoryManager::PoolBitmappedMemoryManager() {}
PoolBitmappedMemoryManager::~PoolBitmappedMemoryManager() {}
void* PoolBitmappedMemoryManager::allocate(size_t size) {
//non array version
if (size == sizeof(Complex)) {
std::set<BitMapEntry*>::iterator freeMapI = FreeMapEntries.begin();
if (freeMapI != FreeMapEntries.end()) {
BitMapEntry* mapEntry = *freeMapI;
return mapEntry->FirstFreeBlock(size);
} else {
AllocateChunkAndInitBitMap();
FreeMapEntries.insert(&(BitMapEntryList[BitMapEntryList.size() - 1]));
return BitMapEntryList[BitMapEntryList.size() - 1].FirstFreeBlock(size);
}
//array version
} else {
if (ArrayMemoryList.empty()) {
return AllocateArrayMemory(size);
} else {
std::map<void*, ArrayMemoryInfo>::iterator infoI = ArrayMemoryList.begin();
std::map<void*, ArrayMemoryInfo>::iterator infoEndI = ArrayMemoryList.end();
while (infoI != infoEndI) {
ArrayMemoryInfo info = (*infoI).second;
// search only in those mem blocks
// where allocation is done from first byte
if (info.StartPosition != 0) continue;
else {
BitMapEntry* entry = &BitMapEntryList[info.MemPoolListIndex];
if (entry->BlocksAvailable < (size / sizeof(Complex)))
return AllocateArrayMemory(size);
else {
info.StartPosition = BIT_MAP_SIZE - entry->BlocksAvailable;
info.Size = static_cast<int>(size / sizeof(Complex));
Complex* baseAddress = static_cast<Complex*>(
MemoryPoolList[info.MemPoolListIndex]) + info.StartPosition;
ArrayMemoryList[baseAddress] = info;
SetMultipleBlockBits(&info, false);
return baseAddress;
}
}
}
}
}
return nullptr;
}
void PoolBitmappedMemoryManager::freeMemory(void* pointer) {
if (ArrayMemoryList.find(pointer) == ArrayMemoryList.end())
SetBlockBit(pointer, true); // simple block deletion
else {//memory block deletion
ArrayMemoryInfo *info = &ArrayMemoryList[pointer];
SetMultipleBlockBits(info, true);
}
}
std::vector<void*>& PoolBitmappedMemoryManager::GetMemoryPoolList() {
return MemoryPoolList;
}
void PoolBitmappedMemoryManager::SetBlockBit(void* object, bool flag) {
int i = static_cast<int>(BitMapEntryList.size()) - 1;
//iterate the list of bitmap entries
for (; i >= 0; i--) {
BitMapEntry* bitMap = &BitMapEntryList[i];
if ((bitMap->Head() <= object) &&
(&(static_cast<Complex*>(bitMap->Head()))[BIT_MAP_SIZE - 1] >= object)) {
int position = static_cast<Complex*>(object) -
static_cast<Complex*>(bitMap->Head());
bitMap->SetBit(position, flag);
flag ? bitMap->BlocksAvailable++ : bitMap->BlocksAvailable--;
}
}
}
void PoolBitmappedMemoryManager::SetMultipleBlockBits(ArrayMemoryInfo* info, bool flag) {
//get the bitmap entry of the specified index
BitMapEntry* mapEntry = &BitMapEntryList[info->MemPoolListIndex];
//set the requested bits of the chunk of memory
mapEntry->SetMultipleBits(info->StartPosition, flag, info->Size);
}
void* PoolBitmappedMemoryManager::AllocateArrayMemory(size_t size) {
void* chunkAddress = AllocateChunkAndInitBitMap();
ArrayMemoryInfo info;
info.MemPoolListIndex = static_cast<int>(MemoryPoolList.size()) - 1;
info.StartPosition = 0;
info.Size = static_cast<int>(size) / sizeof(Complex);
ArrayMemoryList[chunkAddress] = info;
SetMultipleBlockBits(&info, false);
return chunkAddress;
}
void* PoolBitmappedMemoryManager::AllocateChunkAndInitBitMap() {
//prepare a chunk of memory (bitmap entry
BitMapEntry mapEntry;
//allocate a char space for various complex data
Complex* memoryBeginAddress = reinterpret_cast<Complex*>
(new char[sizeof(Complex) * BIT_MAP_SIZE]);
//store the pointer/address to the memory pool list
MemoryPoolList.push_back(memoryBeginAddress);
//set the index in the bitmap memory
//this bitmap memory has a index X on memory pool list
mapEntry.Index = static_cast<int>(MemoryPoolList.size()) - 1;
//store the bitmap memory in its list
BitMapEntryList.push_back(mapEntry);
//return the new begin of the memory
return memoryBeginAddress;
}