| @ -0,0 +1,109 @@ | |||
| /* | |||
| * Yet Another Malloc | |||
| * ya_freelist.c | |||
| */ | |||
| /* Block layout: | |||
| * | |||
| * -2 -1 0 size-4 size-3 | |||
| * +------+------+-------- - - - - - - - --------+------+------+ | |||
| * | prev | size | data... | size | next | | |||
| * +------+------+-------- - - - - - - - --------+------+------+ | |||
| * | |||
| */ | |||
| /*----------*/ | |||
| /* Includes */ | |||
| /*----------*/ | |||
| #include <stdio.h> | |||
| #include "ya_freelist.h" | |||
| #include "ya_block.h" | |||
| /*---------*/ | |||
| /* Globals */ | |||
| /*---------*/ | |||
| intptr_t *fl_start = NULL; // sorted increasing | |||
| intptr_t *fl_end = NULL; // sorted decreasing | |||
| /*-----------*/ | |||
| /* Functions */ | |||
| /*-----------*/ | |||
| #ifdef YA_DEBUG | |||
| void fl_debug_print() { | |||
| for (intptr_t *block = fl_start; block != NULL; block = fl_next(block)) { | |||
| printf("Free block %p:%ld\n", block, block_size(block)); | |||
| } | |||
| } | |||
| #endif | |||
| /* Splices the allocated block out of the free list. */ | |||
| void fl_alloc(intptr_t *block) { | |||
| intptr_t size = block_size(block); | |||
| intptr_t *prev = fl_prev(block); | |||
| intptr_t *next = fl_next(block); | |||
| fl_set_prev(block, NULL); | |||
| fl_set_next(block, NULL); | |||
| if (prev) { | |||
| fl_set_next(prev, next); | |||
| } else { | |||
| fl_start = next; | |||
| } | |||
| if (next) { | |||
| fl_set_prev(next, prev); | |||
| } else { | |||
| fl_end = prev; | |||
| } | |||
| } | |||
| /* Adds the freed block to the appropriate in the free list, which is kept | |||
| * in sorted increasing order. */ | |||
| void fl_free(intptr_t *block) { | |||
| intptr_t *next; | |||
| for (next = fl_start; next && block < next; next = fl_next(next)) { | |||
| // *whistle* | |||
| } | |||
| if (next == fl_start) { | |||
| // preprend block to the free list | |||
| fl_set_prev(block, NULL); | |||
| fl_set_next(block, fl_start); | |||
| fl_set_prev(fl_start, block); | |||
| fl_start = block; | |||
| return; | |||
| } | |||
| if (!next) { | |||
| // append block to the free list | |||
| fl_set_prev(block, fl_end); | |||
| fl_set_next(block, NULL); | |||
| fl_set_next(fl_end, block); | |||
| fl_end = block; | |||
| return; | |||
| } | |||
| // splice the block in the middle of the list | |||
| intptr_t *prev = fl_prev(next); | |||
| fl_set_prev(block, prev); | |||
| fl_set_next(block, next); | |||
| fl_set_prev(next, block); | |||
| fl_set_next(prev, block); | |||
| } | |||
| /* Returns the first block in the free list at min_size words long. | |||
| * Returns NULL if no adequate block is found. Does not grow the heap. */ | |||
| intptr_t *fl_find(intptr_t min_size) { | |||
| for (intptr_t *block = fl_start; block != NULL; block = fl_next(block)) { | |||
| if (min_size <= block_size(block)) { | |||
| return block; | |||
| } | |||
| } | |||
| return NULL; | |||
| } | |||
| /* Force split of free block [block_size] into [size, block_size - size]. */ | |||
| void fl_split(intptr_t *block, intptr_t size) { | |||
| fl_set_next(block, block+size); | |||
| fl_set_prev(block+size, block); | |||
| } | |||