Rework the arena once again...
This commit is contained in:
@ -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));
|
||||
|
||||
|
135
gebs.h
135
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))
|
||||
|
Reference in New Issue
Block a user