Rework the arena once again...
This commit is contained in:
@ -9,18 +9,14 @@ typedef struct {
|
|||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
/* Arena arena = gebs_arena_get(512); */
|
Arena arena = gebs_arena_get();
|
||||||
Arena arena = gebs_arena_get(128);
|
|
||||||
defer { arena_destroy(&arena); }
|
defer { arena_destroy(&arena); }
|
||||||
|
|
||||||
Ints ints = {0};
|
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);
|
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));
|
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,
|
void *gebs_default_allocator_realloc(void *self, void *memory,
|
||||||
size_t prev_size, size_t new_size);
|
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 {
|
typedef struct Gebs_Arena {
|
||||||
void *(*malloc)(void *self, size_t size);
|
void *(*malloc)(void *self, size_t size);
|
||||||
void (*free)(void *self, void *memory);
|
void (*free)(void *self, void *memory);
|
||||||
void *(*realloc)(void *self, void *memory, size_t prev_size, size_t new_size);
|
void *(*realloc)(void *self, void *memory, size_t prev_size, size_t new_size);
|
||||||
|
|
||||||
void *buffer;
|
Gebs_Arena_Chunk *begin;
|
||||||
void *end;
|
Gebs_Arena_Chunk *end;
|
||||||
size_t capacity;
|
|
||||||
|
|
||||||
void (*out_of_memory_handler)(struct Gebs_Arena *self, size_t requested);
|
|
||||||
} Gebs_Arena;
|
} 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_malloc(void *self, size_t size);
|
||||||
void gebs_arena_free(void *self, void *memory);
|
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_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}; \
|
Gebs_Arena __arena = {0}; \
|
||||||
__arena.malloc = &gebs_arena_malloc; \
|
__arena.malloc = &gebs_arena_malloc; \
|
||||||
__arena.realloc = &gebs_arena_realloc; \
|
__arena.realloc = &gebs_arena_realloc; \
|
||||||
__arena.free = &gebs_arena_free; \
|
__arena.free = &gebs_arena_free; \
|
||||||
__arena.capacity = (cap); \
|
|
||||||
__arena.out_of_memory_handler = &gebs_arena_out_of_memory_handler; \
|
|
||||||
__arena; \
|
__arena; \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
#ifndef GEBS_ARENA_CHUNK_CAPACITY
|
||||||
|
# define GEBS_ARENA_CHUNK_CAPACITY (8*1024)
|
||||||
|
#endif
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Dynamic list
|
// Dynamic list
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@ -375,10 +384,6 @@ void gebs_rebuild_self1_alloc(Gebs_Allocator *alloc, int argc, char ** argv,
|
|||||||
// Scratch arena
|
// Scratch arena
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
#ifndef GEBS_SCRATCH_ARENA_SIZE
|
|
||||||
# define GEBS_SCRATCH_ARENA_SIZE 4096
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern Gebs_Arena gebs_scratch_arena;
|
extern Gebs_Arena gebs_scratch_arena;
|
||||||
|
|
||||||
char *gebs_fmt(const char *fmt, ...);
|
char *gebs_fmt(const char *fmt, ...);
|
||||||
@ -529,32 +534,52 @@ void *gebs_default_allocator_realloc(discard void *self, void *memory,
|
|||||||
return p;
|
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)
|
void *gebs_arena_malloc(void *self, size_t size)
|
||||||
{
|
{
|
||||||
Gebs_Arena *a = (Gebs_Arena *)self;
|
Gebs_Arena *a = (Gebs_Arena *)self;
|
||||||
|
|
||||||
|
size_t sz = (size + sizeof(uintptr_t) - 1)/sizeof(uintptr_t);
|
||||||
|
|
||||||
if (a->buffer == NULL) {
|
if (a->end == NULL) {
|
||||||
#if GEBS_PLATFORM == GEBS_PLATFORM_POSIX
|
size_t capacity = GEBS_ARENA_CHUNK_CAPACITY;
|
||||||
int prot = PROT_READ | PROT_WRITE;
|
if (capacity < sz) {
|
||||||
int vis = MAP_SHARED | MAP_ANONYMOUS;
|
capacity = sz;
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
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)
|
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;
|
Gebs_Arena *a = (Gebs_Arena *)self;
|
||||||
|
|
||||||
void *new = gebs_arena_malloc(a, new_size);
|
if (new_size <= prev_size) {
|
||||||
memcpy(new, memory, prev_size);
|
return memory;
|
||||||
return new;
|
}
|
||||||
|
|
||||||
|
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)
|
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)
|
void gebs_arena_destroy(Gebs_Arena *a)
|
||||||
{
|
{
|
||||||
#if GEBS_PLATFORM == GEBS_PLATFORM_POSIX
|
Gebs_Arena_Chunk *chunk = a->begin;
|
||||||
munmap(a->buffer, a->capacity);
|
while (chunk) {
|
||||||
#else
|
Gebs_Arena_Chunk *chunk1 = chunk;
|
||||||
# error "gebs_arena_destroy unknown platform"
|
chunk = chunk->next;
|
||||||
#endif
|
gebs_arena_destroy_chunk(chunk1);
|
||||||
}
|
}
|
||||||
|
a->begin = NULL;
|
||||||
void gebs_arena_out_of_memory_handler(Gebs_Arena *self, size_t requested)
|
a->end = NULL;
|
||||||
{
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@ -604,7 +631,7 @@ Gebs_Arena gebs_scratch_arena;
|
|||||||
__attribute__((constructor))
|
__attribute__((constructor))
|
||||||
void gebs_scratch_areana_init(void)
|
void gebs_scratch_areana_init(void)
|
||||||
{
|
{
|
||||||
gebs_scratch_arena = gebs_arena_get(4*1024);
|
gebs_scratch_arena = gebs_arena_get();
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((destructor))
|
__attribute__((destructor))
|
||||||
|
Reference in New Issue
Block a user