Skip to content

Commit 06a5487

Browse files
committed
[malloc] Keep track of allocated memory in linkedlist
1 parent a812978 commit 06a5487

File tree

5 files changed

+144
-20
lines changed

5 files changed

+144
-20
lines changed

src/usr/include/stddef.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ namespace std {
99
#define NULL 0
1010
#endif
1111

12+
typedef char int8_t;
13+
typedef short int16_t;
14+
typedef int int32_t;
15+
1216
typedef unsigned char uint8_t;
1317
typedef unsigned short uint16_t;
1418
typedef unsigned int uint32_t;

src/usr/include/stdlib.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ int max(int, int);
1919
int abs(int a);
2020

2121
int benchmark_get_heap_usage();
22+
int benchmark_get_heap_area();
2223
void* malloc(size_t size);
2324
void free(void* ptr);
2425

src/usr/include/vector.tcc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ template <typename T>
7070
typename vector<T>::const_iterator vector<T>::end() const { return this->_data + this->_size; }
7171

7272
template <typename T>
73-
void vector<T>::resize_capacity(volatile std::size_t capacity) {
73+
void vector<T>::resize_capacity(std::size_t capacity) {
7474
// internal; assumes capacity to be power of 2
7575
// and will also make a copy of array and move _data pointer.
7676
// assumes size<=current_capacity and size<=new_capacity

src/usr/lib/stdlib.c

Lines changed: 133 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -141,42 +141,162 @@ void exit(int status) {
141141
}
142142

143143
/*
144-
non-optimal malloc
144+
malloc implementation
145+
- linear allocation based on first come first served
146+
- allocate first free block >= requested size
147+
148+
pros
149+
- easy to implement as the initial implementation
150+
cons
151+
- malloc is slow
152+
- as we are not using virtual addressing the physical
153+
allocated memory is limited slowly ness shouldn't be
154+
noticeable.
155+
156+
memory_layout
157+
-------------
158+
_heap_start: # static marker defined at link time
159+
heap_entry{is_free, size}
160+
heap_entry{is_free, size}
161+
heap_entry{is_free, size}
162+
...
163+
... heap_entry_count times
164+
... unused memory
165+
_heap_end: # dynamic marker based on current esp
166+
145167
*/
146168
extern void* get_current_esp(); // defined in stdlib.asm
147169
extern char _heap_start[]; // defined in linker.ld
148-
static int heap_head_offset = 0;
170+
static int heap_entry_count = 0;
149171
static const int heap_stack_safety_gap = 1024; // keep 1 kb free between stack and heap
150172

151173
// benchmarking
152174
static int benchmark_heap_inuse = 0;
175+
static int benchmark_heap_area = 0;
153176

154177
int benchmark_get_heap_usage() {
178+
// heap memory in use
155179
return benchmark_heap_inuse;
156180
}
157181

158-
void* malloc(size_t size) {
159-
size = ((size + 3) >> 2 ) << 2;
160-
size += 4; // 4 bytes to store size
182+
int benchmark_get_heap_area() {
183+
// overall memory area ever occupied by heap area
184+
return benchmark_heap_area;
185+
}
161186

162-
void* loc = _heap_start + heap_head_offset;
187+
static union heap_entry {
188+
// header of each allocated or unallocated block
189+
struct {
190+
uint32_t size; // including the header size
191+
uint8_t is_free;
192+
} content;
193+
uint32_t __padding[2]; // force heap_entry size to be 8 bytes.
194+
};
195+
196+
static union heap_entry *malloc_allocate_new_block(union heap_entry *block, size_t size) {
163197
void* max_loc = get_current_esp()-heap_stack_safety_gap-size;
164-
if(loc>max_loc) {
198+
if ((void*)block>max_loc) {
199+
// panic if no memory to allocate
165200
printf("failed to allocate more memory\n");
166201
exit(-1);
167-
return NULL;
168202
}
169-
heap_head_offset += size;
170-
benchmark_heap_inuse += size;
203+
benchmark_heap_area = max(benchmark_heap_area, (int)(((void*)block) + size - (void*)_heap_start));
204+
205+
block->content.size = size;
206+
block->content.is_free = 1; // new block is free at init.
207+
heap_entry_count++;
208+
printf("[log] malloc_allocate_new_block: %x, %d\n", block, size);
209+
return block;
210+
}
211+
212+
static union heap_entry *malloc_split_block(union heap_entry *block, size_t size) {
213+
214+
// returns the first one of the two splitted blocks
215+
216+
// [ --------- old-free-block-------------- ]
217+
// [ allocating-block] [new-left-over-block]
218+
const int TODO_NEVER_SPLIT = 1;
219+
size_t left_over_size = block->content.size - size;
220+
if (TODO_NEVER_SPLIT || left_over_size < sizeof(union heap_entry)+8) {
221+
// do not split block if left-over block for less than 8 bytes allocation.
222+
// i.e. do not split block
223+
// printf("[log] malloc_split_block: %x, %d out of %d [no-split]\n", block, size, block->content.size);
224+
return block;
225+
}
226+
// allocate new-left-over-block
227+
union heap_entry *block_second = malloc_allocate_new_block((union heap_entry *)(((void*)block)+size), left_over_size);
228+
// resize first block
229+
block->content.size = size;
230+
printf("[log] malloc_split_block: %x, %d [split]\n", block, size);
231+
return block;
232+
}
233+
234+
static void malloc_merge_onfree(union heap_entry *block) {
235+
// merge recently free block to neighboring block
236+
// if they are free are also free to form large free
237+
// block.
238+
if (!block->content.is_free) return;
171239

172-
*((uint32_t*)loc) = size;
173-
return (loc+4);
240+
// TODO(scopeinfinity): implement
174241
}
175242

243+
static union heap_entry *malloc_find_freeblock(size_t size) {
244+
if(size>200)
245+
printf("[log] malloc_find_freeblock: %d, block_count: %d\n", size, heap_entry_count);
246+
// size includes header size
247+
void* loc = _heap_start; // start
248+
int block_id = 0;
249+
while(1) {
250+
// printf("[log] searching %d at %x\n", block_id, loc);
251+
252+
union heap_entry *block = loc;
253+
if (block_id==heap_entry_count) {
254+
// create new node
255+
return malloc_allocate_new_block(block, size);
256+
}
257+
const int TODO_ALWAYS_ALLOCATE_LAST = 1;
258+
if (TODO_ALWAYS_ALLOCATE_LAST || (!block->content.is_free) || block->content.size < size) {
259+
// block is not free
260+
// not sufficient memory in this block
261+
loc += block->content.size;
262+
block_id++;
263+
continue;
264+
}
265+
// returns the block after split or no-split
266+
return malloc_split_block(block, size);
267+
}
268+
}
269+
270+
void* malloc(size_t size) {
271+
// allocates in chunk of 4
272+
size = ((size + 3) >> 2 ) << 2;
273+
// allocate header
274+
size += sizeof(union heap_entry);
275+
276+
union heap_entry *header = malloc_find_freeblock(size);
277+
278+
benchmark_heap_inuse += size;
279+
header->content.size = size;
280+
header->content.is_free = 0; // false
281+
return (((void*)header)+sizeof(union heap_entry));
282+
}
283+
284+
// TODO(scopeinfinity): Cleanup before submit
285+
// - LOGO empty : 372 bytes
286+
// - Now: 188 bytes
287+
176288
void free(void* ptr) {
177289
if(ptr == NULL) return;
178290
// current version of malloc is non-optimal and doesn't
179291
// do any free operation.
180-
size_t size = *((uint32_t*)(ptr-4));
292+
union heap_entry *header = ptr-sizeof(union heap_entry);
293+
if (header->content.is_free!=0) {
294+
// trying to free unallocated memory
295+
printf("[log] trying to free unallocated memory: %x", ptr);
296+
return;
297+
}
298+
header->content.is_free = 1; // true
299+
size_t size = header->content.size;
181300
benchmark_heap_inuse -= size;
301+
malloc_merge_onfree(header);
182302
}

src/usr/local/src/logo.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ void frame_wait() {
2020
while (counter--);
2121
}
2222

23-
bool graceful_exit = false;
24-
2523
std::vector<std::string> split(std::string &str) {
2624
std::vector<std::string> rv;
2725
std::size_t len = str.length();
@@ -194,8 +192,7 @@ class Display {
194192
return 0;
195193
}
196194
if (cmd == "exit") {
197-
graceful_exit = true;
198-
return 0;
195+
std::exit(0);
199196
}
200197
return 10;
201198
}
@@ -388,7 +385,7 @@ class Interpreter {
388385
Interpreter() : display(console.get_y_offset()) {
389386
}
390387
void execute() {
391-
while(!graceful_exit) {
388+
while(1) {
392389
console.update_status(display);
393390
display.draw();
394391
console.draw();
@@ -410,8 +407,10 @@ void start_logo() {
410407
void cleanup_graphics() {
411408
std::graphics::closegraph();
412409
std::cout << "logo graphics closed" << std::endl;
413-
std::cout << "heap memory at exit " <<
410+
std::cout << "heap memory usage at exit " <<
414411
(std::benchmark_get_heap_usage()) << " bytes" << std::endl;
412+
std::cout << "heap memory area at exit " <<
413+
(std::benchmark_get_heap_area()) << " bytes" << std::endl;
415414
}
416415

417416
int show_usage() {

0 commit comments

Comments
 (0)