diff --git a/example/arena.c b/example/arena.c index 6d66ac7..f617994 100644 --- a/example/arena.c +++ b/example/arena.c @@ -9,7 +9,8 @@ typedef struct { int main(void) { - Arena arena = gebs_arena_get(4*1024); + /* Arena arena = gebs_arena_get(512); */ + Arena arena = gebs_arena_get(128); defer { arena_destroy(&arena); } Ints ints = {0}; diff --git a/gebs.h b/gebs.h index 1b3c13e..e7f1ca3 100644 --- a/gebs.h +++ b/gebs.h @@ -169,7 +169,7 @@ void gebs_default_allocator_free(void *self, void *memory); void *gebs_default_allocator_realloc(void *self, void *memory, size_t prev_size, size_t new_size); -typedef struct { +typedef struct Gebs_Arena { void *(*malloc)(void *self, size_t size); void (*free)(void *self, void *memory); void *(*realloc)(void *self, void *memory, size_t prev_size, size_t new_size); @@ -177,6 +177,8 @@ typedef struct { void *buffer; void *end; size_t capacity; + + void (*out_of_memory_handler)(struct Gebs_Arena *self, size_t requested); } Gebs_Arena; void gebs_arena_reset(Gebs_Arena *a); @@ -184,6 +186,7 @@ void gebs_arena_destroy(Gebs_Arena *a); void *gebs_arena_malloc(void *self, size_t size); void gebs_arena_free(void *self, void *memory); void *gebs_arena_realloc(void *self, void *memory, size_t prev_size, size_t new_size); +void gebs_arena_out_of_memory_handler(Gebs_Arena *self, size_t requested); #define gebs_arena_get(cap) \ ({ \ @@ -192,6 +195,7 @@ void *gebs_arena_realloc(void *self, void *memory, size_t prev_size, size_t new_ __arena.realloc = &gebs_arena_realloc; \ __arena.free = &gebs_arena_free; \ __arena.capacity = (cap); \ + __arena.out_of_memory_handler = &gebs_arena_out_of_memory_handler; \ __arena; \ }) @@ -541,6 +545,15 @@ void *gebs_arena_malloc(void *self, size_t size) } void *p = a->end; a->end = (void *)((uintptr_t)a->end + size); + + size_t requested = (uintptr_t)a->end - (uintptr_t)a->buffer; + if (requested > a->capacity) { + if (a->out_of_memory_handler == NULL) { + abort(); + } + a->out_of_memory_handler(a, requested); + } + return p; } @@ -572,6 +585,16 @@ void gebs_arena_destroy(Gebs_Arena *a) #endif } +void gebs_arena_out_of_memory_handler(Gebs_Arena *self, size_t requested) +{ + GEBS_LOGE("Arena ran out of memory. capacity = %zu, requested %zu\n", + self->capacity, requested); + GEBS_LOGI("Arena: buffer %p, end %p, diff %zu\n", + self->buffer, self->end, + (size_t)((uintptr_t)self->end - (uintptr_t)self->buffer)); + abort(); +} + // ---------------------------------------------------------------------------- // Scratch arena // ----------------------------------------------------------------------------