diff --git a/src/allocator.c b/src/allocator.c index 258edfa5643a6123a4ca3ce640b06e89bd39a5a2..4646dd81ea70111378fd2dce28d8a5a36fbc2275 100644 --- a/src/allocator.c +++ b/src/allocator.c @@ -18,6 +18,7 @@ #include <string.h> #include <stdint.h> #include <sys/types.h> +#include <setjmp.h> #include "hammer.h" #include "internal.h" @@ -42,6 +43,8 @@ struct HArena_ { size_t block_size; size_t used; size_t wasted; + + jmp_buf *except; }; HArena *h_new_arena(HAllocator* mm__, size_t block_size) { @@ -62,9 +65,26 @@ HArena *h_new_arena(HAllocator* mm__, size_t block_size) { ret->used = 0; ret->mm__ = mm__; ret->wasted = sizeof(struct arena_link) + sizeof(struct HArena_) + block_size; + ret->except = NULL; return ret; } +void h_arena_set_except(HArena *arena, jmp_buf *except) +{ + arena->except = except; +} + +static void *alloc_block(HArena *arena, size_t size) +{ + void *block = arena->mm__->alloc(arena->mm__, size); + if (!block) { + if (arena->except) + longjmp(*arena->except, 1); + h_platform_errx(1, "memory allocation failed (%uB requested)\n", (unsigned int)size); + } + return block; +} + void* h_arena_malloc(HArena *arena, size_t size) { if (size <= arena->head->free) { // fast path.. @@ -79,22 +99,16 @@ void* h_arena_malloc(HArena *arena, size_t size) { // This involves some annoying casting... arena->used += size; arena->wasted += sizeof(struct arena_link*); - void* link = arena->mm__->alloc(arena->mm__, size + sizeof(struct arena_link*)); - if (!link) { - // TODO: error-reporting -- let user know that arena link couldn't be allocated - return NULL; - } + void* link = alloc_block(arena, size + sizeof(struct arena_link*)); + assert(link != NULL); memset(link, 0, size + sizeof(struct arena_link*)); *(struct arena_link**)link = arena->head->next; arena->head->next = (struct arena_link*)link; return (void*)(((uint8_t*)link) + sizeof(struct arena_link*)); } else { // we just need to allocate an ordinary new block. - struct arena_link *link = (struct arena_link*)arena->mm__->alloc(arena->mm__, sizeof(struct arena_link) + arena->block_size); - if (!link) { - // TODO: error-reporting -- let user know that arena link couldn't be allocated - return NULL; - } + struct arena_link *link = alloc_block(arena, sizeof(struct arena_link) + arena->block_size); + assert(link != NULL); memset(link, 0, sizeof(struct arena_link) + arena->block_size); link->free = arena->block_size - size; link->used = size; diff --git a/src/allocator.h b/src/allocator.h index 4a486936a058c0a619a83e7afdf0c5dfffc50d48..d80209db04dd748839e8287900a4f1602362879a 100644 --- a/src/allocator.h +++ b/src/allocator.h @@ -18,6 +18,7 @@ #ifndef HAMMER_ALLOCATOR__H__ #define HAMMER_ALLOCATOR__H__ #include <sys/types.h> +#include <setjmp.h> #ifdef __cplusplus extern "C" { @@ -51,6 +52,7 @@ HArena *h_new_arena(HAllocator* allocator, size_t block_size); // pass 0 for def void* h_arena_malloc(HArena *arena, size_t count) ATTR_MALLOC(2); void h_arena_free(HArena *arena, void* ptr); // For future expansion, with alternate memory managers. void h_delete_arena(HArena *arena); +void h_arena_set_except(HArena *arena, jmp_buf *except); typedef struct { size_t used;