Compare commits

..

7 commits

3 changed files with 137 additions and 21 deletions

View file

@ -2,6 +2,7 @@
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#define DEFAUL_REGION_SIZE 1048576 /* 8 * 1024 * 1024 = 8MB */
@ -11,19 +12,67 @@ 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);
}
// Run deinit tasks before freeing data
while (arena->deinit_task_top != NULL) {
assert(arena->deinit_task_top->func_ptr != NULL);
arena->deinit_task_top->func_ptr(arena->deinit_task_top->func_param);
arena->deinit_task_top = arena->deinit_task_top->next;
}
// actually free the data
assert(arena->begin != NULL && arena->end != NULL);
Region *region = arena->begin;
while (region != NULL) {
@ -31,10 +80,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,10 +119,16 @@ void *arena_alloc(Arena *arena, size_t size) {
void *result = &region->data[region->cursor];
region->cursor += size;
// TODO: only align when needed
size = (size + 7) & ~7; // align size increase to multiple of 8
return result;
}
// void *arena_clear(Arena *arena) {
// arena->size = 0;
// return arena->data;
// }
void arena_run_on_deinit_push(Arena *arena, ArenaDeinitTask task) {
ArenaDeinitTask *job = arena_alloc(arena, sizeof(ArenaDeinitTask));
*job = task;
ArenaDeinitTask *next_job = arena->deinit_task_top;
arena->deinit_task_top = job;
job->next = next_job;
}

View file

@ -1,7 +1,6 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
typedef struct Region_s Region;
struct Region_s {
@ -11,13 +10,28 @@ struct Region_s {
unsigned char data[];
};
typedef struct {
typedef struct ArenaDeinitTask_s ArenaDeinitTask;
struct ArenaDeinitTask_s {
void *func_param;
void (*func_ptr)(void *);
ArenaDeinitTask *next;
};
ArenaDeinitTask ArenaDeinitTask_default = {NULL};
typedef struct Arena_s Arena;
struct Arena_s {
Arena *parent;
Arena *child;
Arena *sibling;
Region *begin;
Region *end;
} Arena;
ArenaDeinitTask *deinit_task_top;
};
Arena arena_init(size_t capacity);
Arena *arena_init(Arena *parent, size_t capacity);
void arena_deinit(Arena *arena);
void arena_run_on_deinit_push(Arena *arena, ArenaDeinitTask task);
void *arena_alloc(Arena *arena, size_t size);
// void *arena_clear(Arena *arena);

View file

@ -10,14 +10,37 @@
#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\n");
Arena *global_arena = arena_init(NULL, 0);
for (int i = 0; i <= 1048576 + 100; i++) {
int *number = arena_alloc(&global_arena, sizeof(int));
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};