From c71788ba727c3a271a250d66c00d14b22632e8e8 Mon Sep 17 00:00:00 2001 From: Ole Morud Date: Sat, 3 Jun 2023 16:04:24 +0200 Subject: [PATCH] Rewrite everything --- Makefile | 4 +- include/alloc_backend.h | 9 ---- include/arena.h | 11 ++--- src/alloc_backend.c | 29 ------------ src/arena.c | 98 +++++++++++++++++++++-------------------- src/test_arena.c | 14 +++--- 6 files changed, 64 insertions(+), 101 deletions(-) delete mode 100644 include/alloc_backend.h delete mode 100644 src/alloc_backend.c diff --git a/Makefile b/Makefile index 859c75e..a264171 100644 --- a/Makefile +++ b/Makefile @@ -6,8 +6,8 @@ BUILD_DIR := build BIN_DIR := lib TEST_DIR := test -OBJS := $(BUILD_DIR)/arena.o $(BUILD_DIR)/alloc_backend.o -FPIC_OBJS := $(BUILD_DIR)/fpic/arena.o $(BUILD_DIR)/fpic/alloc_backend.o +OBJS := $(BUILD_DIR)/arena.o +FPIC_OBJS := $(BUILD_DIR)/fpic/arena.o static : $(BIN_DIR)/libarena.a diff --git a/include/alloc_backend.h b/include/alloc_backend.h deleted file mode 100644 index b234ea9..0000000 --- a/include/alloc_backend.h +++ /dev/null @@ -1,9 +0,0 @@ - -#ifndef ALLOC_BACKEND_H -#define ALLOC_BACKEND_H - -#include - -void* call_alloc_backend(size_t size); - -#endif diff --git a/include/arena.h b/include/arena.h index 97d908a..e4d1f22 100644 --- a/include/arena.h +++ b/include/arena.h @@ -4,16 +4,17 @@ #include // ptrdiff_t +typedef unsigned char byte_t; + typedef struct arena { - void *begin, - *next, - *prev; - size_t cap; + size_t next, prev, cap; + void* data; } __attribute__((aligned(sizeof(void*)))) arena_t; -arena_t* arena_new(); +arena_t arena_new(); void arena_reset(arena_t* a); void* arena_alloc(arena_t* a, size_t len); +void* arena_calloc(arena_t* a, size_t nmemb, size_t size); void* arena_realloc_tail(arena_t* a, size_t len); #endif diff --git a/src/alloc_backend.c b/src/alloc_backend.c deleted file mode 100644 index 6da4ffe..0000000 --- a/src/alloc_backend.c +++ /dev/null @@ -1,29 +0,0 @@ - -#include "alloc_backend.h" - -#define _GNU_SOURCE -#include - -/* - * Separate function to make switching - * allocation backend easier - * - * must take size_t size as an argument - * must return NULL on failure - */ -void* call_alloc_backend(size_t size) -{ - void* p = mmap( - NULL, - size, - PROT_READ | PROT_WRITE, - MAP_ANONYMOUS | MAP_PRIVATE, - -1, /* man mmap(2): "[...], some implementations require fd to be - -1 if MAP_ANONYMOUS is specified [...]" */ - 0); - - if (p == MAP_FAILED) - return NULL; - - return p; -} diff --git a/src/arena.c b/src/arena.c index 6a11669..43989a4 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1,77 +1,79 @@ #include "arena.h" -#include "alloc_backend.h" #include +#include +#include +#include #include -#define ARENA_SIZE ((size_t)(128 * sysconf(_SC_PAGE_SIZE))) +#include -typedef unsigned char byte; +// (sizeof(intptr_t) isn't guaranteed to be the machine word size but on most +// compilers it is) +#define WORD_SIZE (sizeof(intptr_t)) -/* - * Allocates and returns new arena - */ -struct arena* arena_new() +#define ARENA_SIZE ((size_t)(1 * sysconf(_SC_PAGE_SIZE))) + +struct arena arena_new() { - size_t size = ARENA_SIZE; + arena_t a = { + .next = 0, + .prev = 0, + .cap = ARENA_SIZE, + .data = malloc(ARENA_SIZE) + }; - byte* p = call_alloc_backend(size); - - if (p == NULL) - return NULL; - - arena_t* a = (arena_t*)p; - - void* beg = p + sizeof(struct arena); - a->begin = beg; - a->next = beg; - a->prev = beg; - a->cap = size - sizeof(struct arena); + if (a.data == NULL) + exit(errno); return a; } -/* - * Frees all memory in arena - */ -void arena_reset(struct arena* a) +void _arena_realloc_or_panic(arena_t* a, size_t len) { - a->next = a->begin; - a->prev = a->begin; + // TODO: gracefully recover. + // although unlikely to be recoverable in most use cases + a->data = realloc(a->data, len); + + if (a->data == NULL) + exit(errno); + + a->cap = len; +} + +void arena_reset(struct arena* a) +{ + a->next = 0; + a->prev = 0; } -/* - * Allocate new memory using arena - */ void* arena_alloc(struct arena* a, size_t len) { - void* p = a->next; + // align len to machine word size + len = (len + WORD_SIZE - 1) & ~(WORD_SIZE - 1); + fprintf(stderr, "allocating %zu bytes\n", len); - if ((byte*)p + len > (byte*)(a->begin) + a->cap) { - errno = ENOMEM; - return NULL; - } + a->prev = a->next; + a->next += len; - a->next = (byte*)(a->next) + len; - a->prev = p; + if (a->next > a->cap) + _arena_realloc_or_panic(a, a->cap * 2); + + return (byte_t*)(a->data) + a->prev; +} + +void* arena_calloc(struct arena* a, size_t nmemb, size_t size) +{ + void* p = arena_alloc(a, nmemb * size); + memset((byte_t*)(a->data) + a->prev, 0, size); return p; } -/* - * Reallocate last block in arena - */ void* arena_realloc_tail(struct arena* a, size_t len) { - void* p = a->prev; + a->next = a->prev; - if ((byte*)p + len > (byte*)(a->begin) + a->cap) { - errno = ENOMEM; - return NULL; - } - - a->next = (byte*)p + len; - - return a->prev; + return arena_alloc(a, len); } diff --git a/src/test_arena.c b/src/test_arena.c index 2209ae7..93c66f4 100644 --- a/src/test_arena.c +++ b/src/test_arena.c @@ -8,25 +8,23 @@ #include #include -static struct arena* default_arena = NULL; +static struct arena default_arena = { 0 }; int main() { default_arena = arena_new(); - if (default_arena == NULL) { - err(errno, "failed to allocate arena"); - } + printf("\nAttempt to do allocations of 1 byte, cap is %zu, ", default_arena.cap); - printf("\nAttempt to do `arena->cap` allocations of 1 byte"); - - for (size_t i = 0; i < default_arena->cap; i++) { - char* c = arena_alloc(default_arena, 1); + size_t i; + for (i = 0; default_arena.next < default_arena.cap; i++) { + char* c = arena_alloc(&default_arena, 1); *c = i & 0xff; if (c == NULL) { err(EXIT_FAILURE, "failed to allocate memory"); } } + printf("did %zu allocations", i); printf("\n OK");