diff --git a/Makefile b/Makefile index c3c7e84..6638a47 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ test: yatest %.o: %.c $(CC) -c $^ $(CPPFLAGS) $(CFLAGS) -yatest: yatest.o yamalloc.o ya_block.o +yatest: yatest.o yamalloc.o ya_freelist.o ya_block.o $(CC) -o $@ $^ $(CFLAGS) clean: diff --git a/ya_freelist.c b/ya_freelist.c new file mode 100644 index 0000000..b551799 --- /dev/null +++ b/ya_freelist.c @@ -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 + +#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); +} + diff --git a/ya_freelist.h b/ya_freelist.h index c8f4cde..a02576d 100644 --- a/ya_freelist.h +++ b/ya_freelist.h @@ -12,28 +12,49 @@ #include // for intptr_t -/*------------*/ -/* Data types */ -/*------------*/ +#include "ya_block.h" -struct fl { - intptr_t *block; - struct fl *prev; - struct fl *next; -}; +/*---------*/ +/* Inlines */ +/*---------*/ + +static inline intptr_t *fl_prev(intptr_t *block) { + return (intptr_t *) block[-2]; +} + +static inline intptr_t *fl_next(intptr_t *block) { + return (intptr_t *) block[block_size(block)-3]; +} + +static inline void fl_set_prev(intptr_t *block, intptr_t *prev) { + block[-2] = (intptr_t) prev; +} + +static inline void fl_set_next(intptr_t *block, intptr_t *next) { + block[block_size(block)-3] = (intptr_t) next; +} /*--------------*/ /* Declarations */ /*--------------*/ -struct fl *fl_find(intptr_t min_size); +#ifdef YA_DEBUG +void fl_debug_print(); +#endif + +/* Splices the allocated block out of the free list. */ +void fl_alloc(intptr_t *block); -void fl_split(struct fl *fl); +/* Adds the freed block to the start of the free list. */ +void fl_free(intptr_t *block); -void fl_join_prev(struct fl *fl); +/* 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); -void fl_join_next(struct fl *fl); +/* Force split of block [block_size] into [size, block_size - size]. */ +void fl_split(intptr_t *block, intptr_t size); -void fl_join(struct fl *fl); +/* Joins are unnecessary because the pointers will still be ok after a join. */ #endif diff --git a/yamalloc.c b/yamalloc.c index bcefeec..830b4e5 100644 --- a/yamalloc.c +++ b/yamalloc.c @@ -3,38 +3,14 @@ * yamalloc.c */ -/*---------------------*/ -/* Feature test macros */ -/*---------------------*/ - -#define _DEFAULT_SOURCE // for sbrk - /*----------*/ /* Includes */ /*----------*/ -#include -#include -#include - #include "yamalloc.h" #include "ya_debug.h" #include "ya_block.h" - -/*-----------*/ -/* Constants */ -/*-----------*/ - - -/*--------*/ -/* Macros */ -/*--------*/ - - -/*--------------------*/ -/* Local declarations */ -/*--------------------*/ - +#include "ya_freelist.h" /*----------------------*/ /* Function definitions */ @@ -43,7 +19,10 @@ #ifdef YA_DEBUG /* Print all blocks in the heap */ void ya_print_blocks() { + ya_debug("All blocks:\n"); block_print_range(heap_start, heap_end); + ya_debug("Free blocks:\n"); + fl_debug_print(); } #endif