diff options
Diffstat (limited to 'core/alloc.c')
-rw-r--r-- | core/alloc.c | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/core/alloc.c b/core/alloc.c new file mode 100644 index 0000000..88ebb8f --- /dev/null +++ b/core/alloc.c @@ -0,0 +1,105 @@ +#include <rune/core/alloc.h> +#include <rune/core/logging.h> +#include <stdlib.h> + +// TODO: implement block coalescing so we can reuse freed blocks + +#define DEADBLOCK ((void*)0xDEADBEEF) + +static struct mem_block first_block; + +static struct mem_block* _find_free_block(size_t sz) { + struct list_head *temp = &first_block.list; + struct mem_block *block; + while (temp != NULL) { + block = (struct mem_block*)((void*)temp - offsetof(struct mem_block, list)); + if (block->sz == sz && block->free == 1) + return block; + temp = temp->next; + } + return NULL; +} + +static struct mem_block* _find_block(void *ptr) { + struct list_head *temp = &first_block.list; + struct mem_block *block; + while (temp != NULL) { + block = (struct mem_block*)((void*)temp - offsetof(struct mem_block, list)); + if (block->ptr == ptr) + return block; + temp = temp->next; + } + return NULL; +} + +void* rune_alloc(size_t sz) { + if (sz == 0) + return NULL; + + if (first_block.ptr == NULL) { + first_block.ptr = DEADBLOCK; + first_block.sz = 0; + } + + struct mem_block *block = _find_free_block(sz); + if (block != NULL) { + block->free = 0; + return block->ptr; + } + + block = malloc(sizeof(struct mem_block)); + if (block == NULL) { + log_output(LOG_ERROR, "Cannot allocate block of size %d", sz); + return NULL; + } + block->ptr = malloc(sz); + block->sz = sz; + block->free = 0; + list_add(&block->list, &first_block.list); + log_output(LOG_DEBUG, "Alloc'd block of size %d", sz); + return block->ptr; +} + +void* rune_calloc(size_t nmemb, size_t sz) { + void *ret = rune_alloc(sz); + for (size_t *i = (size_t*)ret; i < (size_t*)ret+sz; i++) + *i = nmemb; + return ret; +} + +void* rune_realloc(void *ptr, size_t sz) { + if (ptr == NULL || sz == 0) + return NULL; + + struct mem_block *block = _find_block(ptr); + if (block == NULL) + return rune_alloc(sz); + return block->ptr; +} + +void rune_free(void *ptr) { + if (ptr == NULL) + return; + + struct mem_block *block = _find_block(ptr); + if (block->free == 1) + return; + block->free = 1; + log_output(LOG_DEBUG, "Freed block of size %d", block->sz); +} + +void rune_free_all(void) { + struct list_head *temp = &first_block.list; + struct mem_block *block; + while (temp != NULL) { + block = (struct mem_block*)((void*)temp - offsetof(struct mem_block, list)); + if (block->ptr == DEADBLOCK) { + temp = temp->next; + continue; + } + + if (block->ptr != NULL) + free(block->ptr); + temp = temp->next; + } +} |