-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMemoryManager.c
226 lines (183 loc) · 5.89 KB
/
MemoryManager.c
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
#include "Z-OS.h"
#include <stdlib.h>
#include <string.h>
Int16 TotalMemAllocs = 0;
Int64 TotalMemUsage = 0;
#define Word UInt16
#define WordSize sizeof(Word)
#define HeapSize 5000
__attribute__ ((__far__)) Word MainHeap[HeapSize] = {0};
size_t FreeWords = HeapSize;
void HeapInit(void* heap, size_t size)
{
memset(heap,0,size);
}
void* HeapAlloc(Word* heap, UInt16 heapSize, size_t allocSize)
{
Word *block = heap;
size_t wallocSize;
Word backref = -1;
Word forwardref = 0;
// block represents a list node
// block[0] is an offset to the previous node
// block[1] is an offset to the next node
// Check for zero allocSize
if(!allocSize)
return NULL;
// Align allocSize to a word boundary
if(allocSize & (WordSize - 1))
allocSize = (allocSize | (WordSize - 1)) + 1;
wallocSize = allocSize / WordSize + 2;
EnterCriticalSection();
// Quick free space check
if(wallocSize > FreeWords)
{
ExitCriticalSection();
return NULL;
}
// Iterate through the list
do
{
// Move to the next block
block += forwardref;
// Back references are only needed to recombine blocks during freeing. So, free regions don't need
// a back reference. Therefore, a block will be marked as free if its back reference is null.
if(!block[0])
{
// If this is the last block, the forward reference will be null, and the block's allocSize is just the remaining heap
// length. Otherwise, the allocSize of this block is the value of the forward reference.
size_t ballocSize = block[1] ? block[1] : heapSize - (block - heap);
// Is free region large enough?
if(ballocSize >= wallocSize)
{
// Allocate the block by setting the back and forward references to their new values
block[0] = backref;
// Since a valid block must be at least 3 words long, if the allocSize of the free fragment left after this allocation
// would be less than 3, just allocate the remainder of the block to avoid unallocatable free fragments.
if(ballocSize - wallocSize >= 3)
{
Word *freefragment = block + wallocSize;
// Insert node for the remainder of the free space
freefragment[0] = 0;
if(block[1])
// Not the last block, inserted free fragment must have a forward reference and the proceeding block must
// be updated to point back to the new free fragment as well.
freefragment[1] = *(block + ballocSize) = ballocSize - wallocSize;
else
freefragment[1] = 0;
block[1] = wallocSize;
// Update free word count
FreeWords -= wallocSize;
}
// Else, the forward reference stays the same
else
FreeWords -= ballocSize;
// Zero the actual memory (depending on this in an allocator is bad practice, however)
memset(&block[2], 0, (wallocSize - 2) * WordSize);
TotalMemAllocs++;
TotalMemUsage += wallocSize * WordSize;
ExitCriticalSection();
return &block[2];
}
}
// Prepare to move to the next block in the next loop iteration
backref = forwardref = block[1];
} while(forwardref);
// No contiguous regions of free space were large enough to contain the allocation
ExitCriticalSection();
return NULL;
}
void HeapFree(Word* heap, UInt16 heapSize, void* pointer)
{
Word *block = (Word*) pointer; // This cast is not required in C, but C++ is retarded.
block -= 2;
EnterCriticalSection();
// Update free word count
FreeWords += block[1] ? block[1] : heapSize - (block - heap);
TotalMemUsage = (heapSize - FreeWords) * WordSize;
// Recombine a proceeding free region
if(block[1] && !((block + block[1])[0]))
{
Word *nextblock = block + block[1];
// Test if the proceeding free region is the last block
if(nextblock[1])
{
// Since we're recombining with the proceeding free block, the block after next, which was pointing to the block
// to be recombined, needs to have its back reference updated (we're removing the recombined node)
*(nextblock + nextblock[1]) += block[1];
block[1] += nextblock[1];
}
else
block[1] = 0;
}
// Recombine a preceeding free region (a value of -1 for the back reference indicates that the block is allocated and that it
// is the first block)
if(block[0] != -1 && !((block - block[0])[0]))
{
Word *prevblock = block - block[0];
if(block[1])
{
// This time, the proceeding block needs to have its back reference updated (we're removing the node being freed)
*(block + block[1]) += prevblock[1];
prevblock[1] += block[1];
}
else
prevblock[1] = 0;
}
// Free the block
else
block[0] = 0;
TotalMemAllocs--;
ExitCriticalSection();
}
// Returns the size of an allocated buffer
UInt16 HeapAllocSize(Word* heap, UInt16 heapSize, void* alloc)
{
Word* pointer = alloc;
Word index = pointer - heap;
Word next = heap[index - 1];
if (next)
{
return next * sizeof(Word);
}
else
{
return heapSize - index * sizeof(Word);
}
}
// Reimplementation of standard C malloc and free
void* malloc(size_t size)
{
return HeapAlloc(MainHeap, HeapSize * sizeof(UInt16), size);
}
void free(void* pointer)
{
HeapFree(MainHeap, HeapSize * sizeof(UInt16), pointer);
}
// Some safe-buffer routines for the IO manager and other debug purposes
void* mallocSafe(size_t size)
{
UInt16* ptr;
if (size & 1) size++;
ptr = malloc(size + 4);
ptr[0] = (UInt16)ptr;
ptr[(size >> 1) + 1] = ~(UInt16)ptr;
return ptr + 1;
}
// Frees a buffer allocated using mallocSafe
void freeSafe(void* ptr)
{
free((UInt16*)ptr - 1);
}
// Checks a buffer for possible corruption
// true - check succeeded
// false - check failed, corruption likely
Bool safeCheck(void* ptr, size_t size)
{
UInt16* p = ptr;
if ((*(p - 1) != (UInt16)(p - 1)) || (*(p + size) != ~(UInt16)(p - 1)))
{
return false;
}
return true;
}