diff --git a/example/arena.c b/example/arena.c index f617994..422d73c 100644 --- a/example/arena.c +++ b/example/arena.c @@ -9,18 +9,14 @@ typedef struct { int main(void) { - /* Arena arena = gebs_arena_get(512); */ - Arena arena = gebs_arena_get(128); + Arena arena = gebs_arena_get(); defer { arena_destroy(&arena); } Ints ints = {0}; - for (size_t i = 0; i < 100; i++) { + for (size_t i = 0; i < 10000; i++) { list_append_alloc(&arena, &ints, i); - gebs_arena_reset(&arena); - } - for (size_t i = 0; i < ints.count; i++) { - printf("%zu\n", i); } + gebs_arena_reset(&arena); printf("%s\n", fmt("Hello formatting %d", 124)); diff --git a/gebs.h b/gebs.h index e7f1ca3..b7ceda2 100644 --- a/gebs.h +++ b/gebs.h @@ -169,36 +169,45 @@ 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 Gebs_Arena_Chunk { + struct Gebs_Arena_Chunk *next; + size_t size; + size_t capacity; + uintptr_t memory[]; +} Gebs_Arena_Chunk; + 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); - void *buffer; - void *end; - size_t capacity; - - void (*out_of_memory_handler)(struct Gebs_Arena *self, size_t requested); + Gebs_Arena_Chunk *begin; + Gebs_Arena_Chunk *end; } Gebs_Arena; -void gebs_arena_reset(Gebs_Arena *a); -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) \ +void gebs_arena_reset(Gebs_Arena *a); +void gebs_arena_destroy(Gebs_Arena *a); + +Gebs_Arena_Chunk *gebs_arena_create_chunk(size_t capacity); +void gebs_arena_destroy_chunk(Gebs_Arena_Chunk *chunk); + +#define gebs_arena_get() \ ({ \ Gebs_Arena __arena = {0}; \ __arena.malloc = &gebs_arena_malloc; \ __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; \ }) +#ifndef GEBS_ARENA_CHUNK_CAPACITY +# define GEBS_ARENA_CHUNK_CAPACITY (8*1024) +#endif + // ---------------------------------------------------------------------------- // Dynamic list // ---------------------------------------------------------------------------- @@ -375,10 +384,6 @@ void gebs_rebuild_self1_alloc(Gebs_Allocator *alloc, int argc, char ** argv, // Scratch arena // ---------------------------------------------------------------------------- -#ifndef GEBS_SCRATCH_ARENA_SIZE -# define GEBS_SCRATCH_ARENA_SIZE 4096 -#endif - extern Gebs_Arena gebs_scratch_arena; char *gebs_fmt(const char *fmt, ...); @@ -529,32 +534,52 @@ void *gebs_default_allocator_realloc(discard void *self, void *memory, return p; } +Gebs_Arena_Chunk *gebs_arena_create_chunk(size_t capacity) +{ + size_t size = sizeof(Gebs_Arena_Chunk) + sizeof(uintptr_t)*capacity; + Gebs_Arena_Chunk *chunk = (Gebs_Arena_Chunk *)malloc(size); + chunk->next = NULL; + chunk->size = 0; + chunk->capacity = capacity; + return chunk; +} + +void gebs_arena_destroy_chunk(Gebs_Arena_Chunk *chunk) +{ + free(chunk); +} + void *gebs_arena_malloc(void *self, size_t size) { Gebs_Arena *a = (Gebs_Arena *)self; + + size_t sz = (size + sizeof(uintptr_t) - 1)/sizeof(uintptr_t); - if (a->buffer == NULL) { -#if GEBS_PLATFORM == GEBS_PLATFORM_POSIX - int prot = PROT_READ | PROT_WRITE; - int vis = MAP_SHARED | MAP_ANONYMOUS; - a->buffer = mmap(0, a->capacity, prot, vis, -1, 0); -#else -# error "gebs_arena_malloc unknown platform" -#endif - a->end = a->buffer; - } - 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(); + if (a->end == NULL) { + size_t capacity = GEBS_ARENA_CHUNK_CAPACITY; + if (capacity < sz) { + capacity = sz; } - a->out_of_memory_handler(a, requested); + a->end = gebs_arena_create_chunk(capacity); + a->begin = a->end; } - return p; + while (a->end->size + sz > a->end->capacity && a->end->next != NULL) { + a->end = a->end->next; + } + + if (a->end->size + sz > a->end->capacity) { + size_t capacity = GEBS_ARENA_CHUNK_CAPACITY; + if (capacity < sz) { + capacity = sz; + } + a->end->next = gebs_arena_create_chunk(capacity); + a->end = a->end->next; + } + + void *result = &a->end->memory[a->end->size]; + a->end->size += sz; + return result; } void gebs_arena_free(discard void *self, discard void *memory) @@ -566,33 +591,35 @@ void *gebs_arena_realloc(void *self, void *memory, { Gebs_Arena *a = (Gebs_Arena *)self; - void *new = gebs_arena_malloc(a, new_size); - memcpy(new, memory, prev_size); - return new; + if (new_size <= prev_size) { + return memory; + } + + void *new_memory = gebs_arena_malloc(a, new_size); + for (size_t i = 0; i < prev_size; i++) { + ((char *)new_memory)[i] = ((char *)memory)[i]; + } + return new_memory; } void gebs_arena_reset(Gebs_Arena *a) { - a->end = a->buffer; + for (Gebs_Arena_Chunk *chunk = a->begin; chunk != NULL; chunk = chunk->next) { + chunk->size = 0; + } + a->end = a->begin; } void gebs_arena_destroy(Gebs_Arena *a) { -#if GEBS_PLATFORM == GEBS_PLATFORM_POSIX - munmap(a->buffer, a->capacity); -#else -# error "gebs_arena_destroy unknown platform" -#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(); + Gebs_Arena_Chunk *chunk = a->begin; + while (chunk) { + Gebs_Arena_Chunk *chunk1 = chunk; + chunk = chunk->next; + gebs_arena_destroy_chunk(chunk1); + } + a->begin = NULL; + a->end = NULL; } // ---------------------------------------------------------------------------- @@ -604,7 +631,7 @@ Gebs_Arena gebs_scratch_arena; __attribute__((constructor)) void gebs_scratch_areana_init(void) { - gebs_scratch_arena = gebs_arena_get(4*1024); + gebs_scratch_arena = gebs_arena_get(); } __attribute__((destructor))