From 90ff13c07a3259d423be832c7b62439a44b47b9a Mon Sep 17 00:00:00 2001 From: Warwick Date: Sun, 23 Nov 2025 21:11:07 +0000 Subject: [PATCH 1/5] Added subarenas but currently run into memory alignment issues --- src/arena_allocator.c | 41 ++++++++++++++++++++++++++++++++++++----- src/arena_allocator.h | 12 +++++++----- src/main.c | 25 +++++++++++++++++++------ 3 files changed, 62 insertions(+), 16 deletions(-) diff --git a/src/arena_allocator.c b/src/arena_allocator.c index 1c94beb..2656040 100644 --- a/src/arena_allocator.c +++ b/src/arena_allocator.c @@ -11,19 +11,49 @@ 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}; 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){ + .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; + } + + // This is the root of the arena tree + Arena arena = { + .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,6 +61,7 @@ void arena_deinit(Arena *arena) { free(region); region = next_region; } + *arena = (Arena){.begin = NULL, .end = NULL}; } diff --git a/src/arena_allocator.h b/src/arena_allocator.h index 9209bb7..423eedf 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,16 @@ struct Region_s { unsigned char data[]; }; -typedef struct { +typedef struct Arena_s Arena; +struct Arena_s { + 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..2f94416 100644 --- a/src/main.c +++ b/src/main.c @@ -1,5 +1,6 @@ #include #include +#include #include #include "SDL3/SDL_events.h" @@ -10,16 +11,28 @@ #include "arena_allocator.h" -/*int main(int argc, char *argv[]) { - Arena global_arena = arena_init(0); +int main(int argc, char *argv[]) { + // arena allocation test + printf("Allocation test"); + 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); -}*/ -int main(int argc, char *argv[]) { + printf("children test"); + + // arena children test + 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_deinit(&global_arena); + + +} + +/*int main(int argc, char *argv[]) { wn_window window = {0}; if (!wn_window_init(&window)) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize wn_window"); @@ -132,4 +145,4 @@ int main(int argc, char *argv[]) { wn_window_deinit(&window); return EXIT_SUCCESS; -} +}*/ From 257012f6ac2ee95b51eb265ac6991e46b10f82f2 Mon Sep 17 00:00:00 2001 From: Warwick Date: Sun, 23 Nov 2025 21:36:13 +0000 Subject: [PATCH 2/5] Added a forced alignment. Shame it makes small allocations bigger but it works for now --- src/arena_allocator.c | 6 ++++-- src/main.c | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/arena_allocator.c b/src/arena_allocator.c index 2656040..233d6e2 100644 --- a/src/arena_allocator.c +++ b/src/arena_allocator.c @@ -21,8 +21,8 @@ Arena arena_init(Arena *parent, size_t capacity) { if (parent != NULL) { // Allocate new arena in parent to reduce likelyhood of loss Arena *current_arena = arena_alloc(parent, sizeof(Arena)); - *current_arena = (Arena){ - .begin = region, .end = region, .child = NULL, .sibling = NULL}; + *current_arena = + (Arena){.begin = region, .end = region, .child = NULL, .sibling = NULL}; // if parent has no children this arena is now it's child if (parent->child == NULL) { @@ -66,6 +66,8 @@ void arena_deinit(Arena *arena) { } 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); diff --git a/src/main.c b/src/main.c index 2f94416..9eeb1ca 100644 --- a/src/main.c +++ b/src/main.c @@ -13,14 +13,14 @@ int main(int argc, char *argv[]) { // arena allocation test - printf("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; } - printf("children test"); + printf("children test\n"); // arena children test Arena child_arena = arena_init(&global_arena, 0); @@ -29,6 +29,7 @@ int main(int argc, char *argv[]) { arena_deinit(&global_arena); + printf("tests complete\n"); } From 19e27ca78233b752759b7b8365e31982937db615 Mon Sep 17 00:00:00 2001 From: Warwick Date: Mon, 24 Nov 2025 09:58:04 +0000 Subject: [PATCH 3/5] Fixed tree deallocation by preventing the creation of copies on arena initialisation --- src/arena_allocator.c | 36 +++++++++++++++++++++++++++--------- src/arena_allocator.h | 4 +++- src/main.c | 19 +++++++++---------- 3 files changed, 39 insertions(+), 20 deletions(-) diff --git a/src/arena_allocator.c b/src/arena_allocator.c index 233d6e2..86057df 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 */ @@ -12,33 +13,44 @@ Region *new_region(size_t capacity) { Region *region = malloc(capacity + sizeof(Region)); assert(region != NULL); *region = (Region){.next = NULL, .capacity = capacity, .cursor = 0}; + + // Zero initialise memory + memset(region->data, 0, capacity); + return region; } -Arena arena_init(Arena *parent, size_t capacity) { +Arena *arena_init(Arena *parent, size_t capacity) { Region *region = new_region(capacity); if (parent != NULL) { // Allocate new arena in parent to reduce likelyhood of loss Arena *current_arena = arena_alloc(parent, sizeof(Arena)); - *current_arena = - (Arena){.begin = region, .end = region, .child = NULL, .sibling = NULL}; + *current_arena = (Arena){.is_root = false, + .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; + return current_arena; } // Push the arena onto the first childs sibling list current_arena->sibling = parent->child; parent->child = current_arena; - return *current_arena; + return current_arena; } - // This is the root of the arena tree - Arena arena = { - .begin = region, .end = region, .child = NULL, .sibling = NULL}; + // Create root of arena tree + Arena *arena = malloc(sizeof(Arena)); + *arena = (Arena){.is_root = true, + .begin = region, + .end = region, + .child = NULL, + .sibling = NULL}; return arena; } @@ -62,7 +74,11 @@ void arena_deinit(Arena *arena) { region = next_region; } - *arena = (Arena){.begin = NULL, .end = NULL}; + arena->begin = NULL; + arena->end = NULL; + if (arena->is_root) { + free(arena); + } } void *arena_alloc(Arena *arena, size_t size) { @@ -79,6 +95,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 423eedf..6dbe772 100644 --- a/src/arena_allocator.h +++ b/src/arena_allocator.h @@ -1,5 +1,6 @@ #pragma once +#include #include typedef struct Region_s Region; @@ -12,13 +13,14 @@ struct Region_s { typedef struct Arena_s Arena; struct Arena_s { + bool is_root; Arena *child; Arena *sibling; Region *begin; Region *end; }; -Arena arena_init(Arena *parent, size_t capacity); +Arena *arena_init(Arena *parent, size_t capacity); void arena_deinit(Arena *arena); void *arena_alloc(Arena *arena, size_t size); diff --git a/src/main.c b/src/main.c index 9eeb1ca..a0404d2 100644 --- a/src/main.c +++ b/src/main.c @@ -14,23 +14,22 @@ 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)); + 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; } - printf("children test\n"); - // arena children test - Arena child_arena = arena_init(&global_arena, 0); - //Arena sibling_arena = arena_init(&global_arena, 0); - //Arena grandchild_arena = arena_init(&child_arena, 0); + 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_deinit(&global_arena); + printf("deinit test\n"); + arena_deinit(global_arena); printf("tests complete\n"); - } /*int main(int argc, char *argv[]) { From e0f0bb0713c45de883456f50a14558352f06cec9 Mon Sep 17 00:00:00 2001 From: Warwick Date: Mon, 24 Nov 2025 11:18:19 +0000 Subject: [PATCH 4/5] Remove dangling pointers on arena parents --- src/arena_allocator.c | 12 +++++++++--- src/arena_allocator.h | 3 +-- src/main.c | 4 ++++ 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/arena_allocator.c b/src/arena_allocator.c index 86057df..d11a6e3 100644 --- a/src/arena_allocator.c +++ b/src/arena_allocator.c @@ -26,7 +26,7 @@ Arena *arena_init(Arena *parent, size_t capacity) { if (parent != NULL) { // Allocate new arena in parent to reduce likelyhood of loss Arena *current_arena = arena_alloc(parent, sizeof(Arena)); - *current_arena = (Arena){.is_root = false, + *current_arena = (Arena){.parent = parent, .begin = region, .end = region, .child = NULL, @@ -46,7 +46,7 @@ Arena *arena_init(Arena *parent, size_t capacity) { // Create root of arena tree Arena *arena = malloc(sizeof(Arena)); - *arena = (Arena){.is_root = true, + *arena = (Arena){.parent = NULL, .begin = region, .end = region, .child = NULL, @@ -76,9 +76,15 @@ void arena_deinit(Arena *arena) { arena->begin = NULL; arena->end = NULL; - if (arena->is_root) { + + // 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 of our death + arena->parent->child = arena->sibling; } void *arena_alloc(Arena *arena, size_t size) { diff --git a/src/arena_allocator.h b/src/arena_allocator.h index 6dbe772..0c48a10 100644 --- a/src/arena_allocator.h +++ b/src/arena_allocator.h @@ -1,6 +1,5 @@ #pragma once -#include #include typedef struct Region_s Region; @@ -13,7 +12,7 @@ struct Region_s { typedef struct Arena_s Arena; struct Arena_s { - bool is_root; + Arena *parent; Arena *child; Arena *sibling; Region *begin; diff --git a/src/main.c b/src/main.c index a0404d2..5dae4d4 100644 --- a/src/main.c +++ b/src/main.c @@ -25,8 +25,12 @@ int main(int argc, char *argv[]) { 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 *greategreatgrandchild_arena = arena_init(greatgrandchild_arena, 0); printf("deinit test\n"); + arena_deinit(greatgrandchild_arena); + arena_deinit(global_arena); printf("tests complete\n"); From bd957d1c799c2e6b171b1842603556753f57140c Mon Sep 17 00:00:00 2001 From: Warwick Date: Mon, 24 Nov 2025 13:42:14 +0000 Subject: [PATCH 5/5] I dunno why this works but it does for some miraculous reason --- src/arena_allocator.c | 15 +++++++++++++-- src/main.c | 9 +++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/arena_allocator.c b/src/arena_allocator.c index d11a6e3..4bdf4bc 100644 --- a/src/arena_allocator.c +++ b/src/arena_allocator.c @@ -83,8 +83,19 @@ void arena_deinit(Arena *arena) { return; } - // Now that we have no descendants tell our parent of our death - arena->parent->child = arena->sibling; + // 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) { diff --git a/src/main.c b/src/main.c index 5dae4d4..42575b3 100644 --- a/src/main.c +++ b/src/main.c @@ -26,9 +26,14 @@ int main(int argc, char *argv[]) { 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 *greategreatgrandchild_arena = arena_init(greatgrandchild_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 test\n"); + printf("deinit tests\n"); arena_deinit(greatgrandchild_arena); arena_deinit(global_arena);