diff --git a/src/arena_allocator.c b/src/arena_allocator.c index 1c94beb..4bdf4bc 100644 --- a/src/arena_allocator.c +++ b/src/arena_allocator.c @@ -2,6 +2,7 @@ #include #include #include +#include #define DEFAUL_REGION_SIZE 1048576 /* 8 * 1024 * 1024 = 8MB */ @@ -11,19 +12,60 @@ Region *new_region(size_t capacity) { } Region *region = malloc(capacity + sizeof(Region)); assert(region != NULL); - *region = (Region){.next = NULL, - .capacity = capacity, - .cursor = 0}; + *region = (Region){.next = NULL, .capacity = capacity, .cursor = 0}; + + // Zero initialise memory + memset(region->data, 0, capacity); + return region; } -Arena arena_init(size_t capacity) { +Arena *arena_init(Arena *parent, size_t capacity) { Region *region = new_region(capacity); - Arena arena = {.begin = region, .end = region}; + + if (parent != NULL) { + // Allocate new arena in parent to reduce likelyhood of loss + Arena *current_arena = arena_alloc(parent, sizeof(Arena)); + *current_arena = (Arena){.parent = parent, + .begin = region, + .end = region, + .child = NULL, + .sibling = NULL}; + + // if parent has no children this arena is now it's child + if (parent->child == NULL) { + parent->child = current_arena; + return current_arena; + } + + // Push the arena onto the first childs sibling list + current_arena->sibling = parent->child; + parent->child = current_arena; + return current_arena; + } + + // Create root of arena tree + Arena *arena = malloc(sizeof(Arena)); + *arena = (Arena){.parent = NULL, + .begin = region, + .end = region, + .child = NULL, + .sibling = NULL}; return arena; } void arena_deinit(Arena *arena) { + if (arena == NULL) { + return; + } + // Recursively deinit children + while (arena->child != NULL) { + Arena *current_child = arena->child; + arena->child = current_child->sibling; + arena_deinit(current_child); + } + + // actually free the data assert(arena->begin != NULL && arena->end != NULL); Region *region = arena->begin; while (region != NULL) { @@ -31,10 +73,34 @@ void arena_deinit(Arena *arena) { free(region); region = next_region; } - *arena = (Arena){.begin = NULL, .end = NULL}; + + arena->begin = NULL; + arena->end = NULL; + + // If we're the tree root free us from malloc + if (arena->parent == NULL) { + free(arena); + return; + } + + // Now that we have no descendants tell our parent and siblings of our death + if (arena->parent->child == arena) { + arena->parent->child = arena->sibling; + return; + } + + Arena *previous_sibling = arena->parent->child; + while (previous_sibling != NULL && previous_sibling->sibling != arena) { + previous_sibling = previous_sibling->sibling; + } + if (previous_sibling != NULL) { + previous_sibling->sibling = arena->sibling; + } } void *arena_alloc(Arena *arena, size_t size) { + // TODO: only align when needed + size = (size + 7) & ~7; // align size increase to multiple of 8 Region *region = arena->end; assert(region != NULL); @@ -46,6 +112,8 @@ void *arena_alloc(Arena *arena, size_t size) { void *result = ®ion->data[region->cursor]; region->cursor += size; + // TODO: only align when needed + size = (size + 7) & ~7; // align size increase to multiple of 8 return result; } diff --git a/src/arena_allocator.h b/src/arena_allocator.h index 9209bb7..0c48a10 100644 --- a/src/arena_allocator.h +++ b/src/arena_allocator.h @@ -1,7 +1,6 @@ #pragma once #include -#include typedef struct Region_s Region; struct Region_s { @@ -11,13 +10,17 @@ struct Region_s { unsigned char data[]; }; -typedef struct { +typedef struct Arena_s Arena; +struct Arena_s { + Arena *parent; + Arena *child; + Arena *sibling; Region *begin; Region *end; -} Arena; +}; -Arena arena_init(size_t capacity); +Arena *arena_init(Arena *parent, size_t capacity); void arena_deinit(Arena *arena); void *arena_alloc(Arena *arena, size_t size); -//void *arena_clear(Arena *arena); +// void *arena_clear(Arena *arena); diff --git a/src/main.c b/src/main.c index 4c2facd..867478d 100644 --- a/src/main.c +++ b/src/main.c @@ -10,14 +10,37 @@ #include "arena_allocator.h" -/*int main(int argc, char *argv[]) { - Arena global_arena = arena_init(0); - for (int i = 0; i <= 1048576+100; i++) { - int *number = arena_alloc(&global_arena, sizeof(int)); +/* +int main(int argc, char *argv[]) { + // arena allocation test + printf("Allocation test\n"); + Arena *global_arena = arena_init(NULL, 0); + for (int i = 0; i <= 1048576 + 100; i++) { + int *number = arena_alloc(global_arena, sizeof(int)); *number = 42; } - arena_deinit(&global_arena); -}*/ + + // arena children test + printf("children test\n"); + Arena *child_arena = arena_init(global_arena, 0); + Arena *sibling_arena = arena_init(global_arena, 0); + Arena *grandchild_arena = arena_init(child_arena, 0); + Arena *greatgrandchild_arena = arena_init(grandchild_arena, 0); + Arena *greatgrandchildsibling_arena = arena_init(grandchild_arena, 0); + Arena *greatgrandchildsiblingsibling_arena = arena_init(grandchild_arena, 0); + Arena *greategreatgrandchild_arena = + arena_init(greatgrandchildsibling_arena, 0); + Arena *greatsiblinggreatgrandchild_arena = + arena_init(greatgrandchildsiblingsibling_arena, 0); + + printf("deinit tests\n"); + arena_deinit(greatgrandchild_arena); + + arena_deinit(global_arena); + + printf("tests complete\n"); +} +*/ int main(int argc, char *argv[]) { wn_window window = {0};