Rework the arena once again...

This commit is contained in:
kamkow1
2025-06-01 13:24:14 +02:00
parent dd74b7f78a
commit ed39351983
2 changed files with 84 additions and 61 deletions

View File

@ -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));

133
gebs.h
View File

@ -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;
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 sz = (size + sizeof(uintptr_t) - 1)/sizeof(uintptr_t);
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))