-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathumalloc.c
More file actions
254 lines (237 loc) · 8.6 KB
/
umalloc.c
File metadata and controls
254 lines (237 loc) · 8.6 KB
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
241
242
243
244
245
246
247
248
249
250
251
252
253
254
// user controlled memory library
#include "umalloc.h"
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
/**
* each block is preceded by 4 bytes of metadata.
* most significant bit of the 4 bytes denote whether the block is allocated or not
* if msb is 1, block is allocated otherwise free
* 3 bytes to store the size as an int
* minimum size is 1 byte, hence a total of 10*2^20 bytes in 10MB,
* requiring 24 bits or 3 bytes in int
* */
static char mem[MEM_SIZE];
char* head;
char* endOfMem;
char init = 'f';
/**
* using implicit free lists
*/
void initialize()
{
init = 't';
head = mem;
// maximum available bytes in the memory, excluding 4 bytes of metadata
uint defaultHeader = MEM_SIZE - HEADER_SIZE;
// printf("default head: %u\n", defaultHeader);
*((uint*)(&mem)) = defaultHeader;
memset(mem + HEADER_SIZE, '0', MEM_SIZE - HEADER_SIZE);
// set head to point to the beginning of the empty block
head += HEADER_SIZE;
// set endOfMem to the end of mem array
endOfMem = mem + MEM_SIZE - 1;
}
// return the size of the block after ignoring the MSB
uint getSize(char** block)
{
// printf("in get size, block*: %p\n", *block);
// *block -= HEADER_SIZE;
// printf("in get size, block* after decrement: %p\n", *block);
uint value = ((uint*)*block)[-1];
// printf("value: %u\n", value);
value &= ~(1U << (BITS - 1));
// printf("value: %u\n", value);
if (value > 0 && value < MEM_SIZE)
{
// printf("value: %u\n", value);
return value;
} else {
return 0;
}
}
// check if the block is free or not by checking the msb
// returns 1 if block is allocated, 0 if free
bool isAllocated(char** block)
{
// printf("is allocated##############\n");
uint value = ((uint*)*block)[-1];
// printf("value: %u\n", value);
uint bit = (value >> (BITS - 1)) & 1U;
// printf("bit: %u\n", bit);
return (bool) bit;
}
// split the empty block into used and free blocks
// ensures that the free space is kept before the used space
// returns pointer to the allocated space
char* splitAndAllocate(char** current, size_t sizeNewBlock)
{
// printf("split and allocateeeeeeeeeeeeee\n");
uint freeSpace = getSize(current);
// pointer to the beginnning of metadata for the new block
// char* pointerNewBlock = *current + freeSpace - sizeNewBlock - HEADER_SIZE;
// printf("size for block: %zu\n pointer to current: %p\t new block: %p\n", sizeNewBlock, *current, pointerNewBlock);
// uint head = (uint) sizeNewBlock;
// head |= 1 << (BITS - 1);
// printf("head of marked block: %u\n", head);
// uint *headPtr = (uint*)(pointerNewBlock);
// *headPtr = head;
// reduce amount of free space in original block
// modify existing block metadata to contain size requested
if (freeSpace - sizeNewBlock >= 0 && freeSpace - sizeNewBlock <= HEADER_SIZE)
{
uint size = (uint) sizeNewBlock;
size |= 1 << (BITS - 1);
((uint*)*current)[-1] = size;
return *current;
} else {
char* pointerNewBlock = *current + freeSpace - sizeNewBlock - HEADER_SIZE;
// printf("size for block: %zu\n pointer to current: %p\t new block: %p\n", sizeNewBlock, *current, pointerNewBlock);
uint head = (uint) sizeNewBlock;
head |= 1 << (BITS - 1);
// printf("head of marked block: %u\n", head);
uint *headPtr = (uint*)(pointerNewBlock);
*headPtr = head;
uint newSize = (uint) freeSpace - sizeNewBlock - HEADER_SIZE;
// printf("caluculation: %u\t", newSize);
((uint*)*current)[-1] = newSize;
// printf("current: %u\n", ((uint*)*current)[-1]);
pointerNewBlock += HEADER_SIZE;
return pointerNewBlock;
}
// pointerNewBlock += HEADER_SIZE;
// return pointerNewBlock;
}
// print all blocks in memory
void printMemoryBlocks()
{
printf("------------------------Memory snapshot------------------------\n");
char* temp = head;
// int i=0;
while (temp < endOfMem)
{
uint size = (uint) getSize(&temp);
printf("memory: %p \tsize of block: %u\t allocated: %d\n",(void *) temp, size, isAllocated(&temp));
temp += size + HEADER_SIZE;
// i++;
}
printf("---------------------------------------------------------------\n");
}
void* umalloc(size_t bytes, char* fileName, int lineNumber)
{
void* ptr = NULL;
int i=0;
if (init == 'f')
{
initialize();
}
char* current = head;
// printf("head: %p \t current: %p\n", head, current);
while (current < endOfMem && i < 20)
{
// printf("in malloc: %zu\t init: %c \t head: %p\t current: %p\n", bytes, init, head, current);
i++;
if (bytes + HEADER_SIZE > MEM_SIZE)
{
printf("Error on malloc(): size requested is too large. At line %d of %s.\n", lineNumber, fileName);
return NULL;
}
if (bytes <= 0)
{
printf("Error on malloc(): size requested is less than or equal to zero. At line %d of %s.\n", lineNumber, fileName);
return NULL;
}
// printMemoryBlocks(head);
// printf("in malloc bytes requested: %zu\tget size: %u\t is allocated: %d\n", bytes, getSize(¤t), isAllocated(¤t));
if (bytes <= getSize(¤t) && !isAllocated(¤t))
{
// printf("in malloc 1----------------------------------------------------------------\n");
ptr = splitAndAllocate(¤t, bytes);
if (ptr == NULL)
{
printf("Error on malloc(): cannot allocate %lu bytes, not enough space. At line %d of %s.\n", bytes, lineNumber, fileName);
return NULL;
}
break;
} else if (current + getSize(¤t) < endOfMem) {
current += getSize(¤t);
}
else {
// printf("in malloc 2222222222222222\n");
printf("Error on malloc(): cannot allocate %lu bytes, not enough space. At line %d of %s.\n", bytes, lineNumber, fileName);
return NULL;
}
// printf("outside if elseeeeeee\n");
}
return ptr;
}
// iterate through entire memory and merge consecutive free blocks
void coalescence()
{
char* current = head;
uint currentSize = getSize(¤t);
char* next = current + currentSize + HEADER_SIZE;
while (next < endOfMem)
{
// printf("current: %p \t current size: %u \t\t next: %p\t end of mem: %p\n", current, currentSize, next, endOfMem);
if (!isAllocated(¤t) && !isAllocated(&next))
{
// printf("------------------------------------current: %p \t current size: %u \t next: %p\t next size: %u\n", current, currentSize, next, getSize(&next));
uint newValue = currentSize + getSize(&next) + HEADER_SIZE;
((uint*)current)[-1] = newValue;
} else {
current = next;
}
// current += currentSize + HEADER_SIZE;
currentSize = getSize(¤t);
next += getSize(&next) + HEADER_SIZE;
// printf("......................................current: %p \t current size: %u \t\t next: %p\n", current, currentSize, next);
}
// printf("----------------------------------------------------------\n");
}
void ufree(void* pointer, char* fileName, int lineNumber)
{
char* ptr;
ptr = (char*) pointer;
// printf("pointer to free: ptr: %p\t pointer: %p\n", ptr, pointer);
if (ptr == NULL)
{
printf("Error on free(): trying to free a NULL pointer at line %d of %s.\n", lineNumber, fileName);
return;
}
if (ptr < head || ptr > endOfMem)
{
printf("Error on free(): attempted to free a pointer outside of mem in line %d of %s.\n", lineNumber, fileName);
return;
}
if (!isAllocated(&ptr))
{
printf("Error on free(): pointer already free at line %d of %s.\n", lineNumber, fileName);
return;
}
uint value = ((uint*)ptr)[-1];
value &= ~(1U << (BITS - 1));
((uint*)ptr)[-1] = value;
// printf("value: %u\n", value);
coalescence();
// printf("end of free\n");
return;
}
// int main() {
// initialize();
// char* ptr1 = malloc(2000);
// // free(ptr1);
// // printf("ptr1: %p \t %zu\n", ptr1, sizeof(ptr1));
// char* ptr2 = malloc(300);
// // printf("ptr2: %p \t %zu\n", ptr2, sizeof(ptr2));
// // char* ptr3 = malloc(500);
// // printf("ptr3: %p\n", ptr3);
// printMemoryBlocks();
// free(ptr1);
// printMemoryBlocks();
// free(ptr2);
// printMemoryBlocks();
// ptr2 = malloc(500);
// printMemoryBlocks();
// return 0;
// }