From 4ecee016349efc4ce759f7e0404fd3fee93227cf Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Wed, 11 Mar 2026 09:34:00 -0400 Subject: [PATCH] add a `pm_arena_reset` API method --- include/prism/util/pm_arena.h | 13 +++++++++++++ src/util/pm_arena.c | 36 +++++++++++++++++++++++++++++------ 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/include/prism/util/pm_arena.h b/include/prism/util/pm_arena.h index f376d13459..4356a3f502 100644 --- a/include/prism/util/pm_arena.h +++ b/include/prism/util/pm_arena.h @@ -78,6 +78,19 @@ void * pm_arena_zalloc(pm_arena_t *arena, size_t size, size_t alignment); */ void * pm_arena_memdup(pm_arena_t *arena, const void *src, size_t size, size_t alignment); +/** + * Resets the arena. If no memory has been allocated from this arena, this + * call is a no-op. + * + * Otherwise, a single block is retained and other blocks are freed. + * + * After this call, all pointers returned by pm_arena_alloc and + * pm_arena_zalloc are invalid. + * + * @param arena The arena to reset. + */ +void pm_arena_reset(pm_arena_t *arena); + /** * Free all blocks in the arena. After this call, all pointers returned by * pm_arena_alloc and pm_arena_zalloc are invalid. diff --git a/src/util/pm_arena.c b/src/util/pm_arena.c index a9b69b3c8d..fdf760905d 100644 --- a/src/util/pm_arena.c +++ b/src/util/pm_arena.c @@ -88,18 +88,42 @@ pm_arena_memdup(pm_arena_t *arena, const void *src, size_t size, size_t alignmen return dst; } -/** - * Free all blocks in the arena. - */ void -pm_arena_free(pm_arena_t *arena) { - pm_arena_block_t *block = arena->current; - +free_blocks(pm_arena_block_t *block) { while (block != NULL) { pm_arena_block_t *prev = block->prev; xfree_sized(block, PM_ARENA_BLOCK_SIZE(block->capacity)); block = prev; } +} + +/** + * Free all but one block in the arena and mark the block as freshly allocated. + * + * Does nothing if the arena has never been used. + */ +void +pm_arena_reset(pm_arena_t *arena) { + pm_arena_block_t *block = arena->current; + + if (block == NULL) { + return; + } + + free_blocks(block->prev); + + block->prev = NULL; + block->used = 0; + + arena->block_count = 1; +} + +/** + * Free all blocks in the arena. + */ +void +pm_arena_free(pm_arena_t *arena) { + free_blocks(arena->current); *arena = (pm_arena_t) { 0 }; }