/* * Yet Another Malloc * ya_freelist.c */ /* Block layout: * * -2 -1 0 size-4 size-3 * +------+------+-------- - - - - - - - --------+------+------+ * | prev | size | data... | size | next | * +------+------+-------- - - - - - - - --------+------+------+ * */ /*----------*/ /* Includes */ /*----------*/ #include #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); }