From c89b4d1d3c94aa3fc9a686f9cdd129236b945cc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Tue, 12 May 2026 20:18:25 +0200 Subject: [PATCH] lpool: use offset to next, avoids pointer alignment requirments --- include/lpool.h | 6 +++--- src/lpool.c | 50 +++++++++++++++++++++++++++++++---------------- test/lpool_test.c | 1 + 3 files changed, 37 insertions(+), 20 deletions(-) diff --git a/include/lpool.h b/include/lpool.h index 88d4576..cfd46cd 100644 --- a/include/lpool.h +++ b/include/lpool.h @@ -9,7 +9,7 @@ extern "C" { typedef union LPoolBlock LPoolBlock; union LPoolBlock { - LPoolBlock *next; // next free block (when not allocated) + uint32_t next; // offset from start to next free block (when not allocated) unsigned char data[0]; // data when allocated }; @@ -30,8 +30,8 @@ union LPoolBlock { typedef struct LPool LPool; struct LPool { LPoolBlock *free_list; // free list - LPoolBlock *start; // start of user buffer - LPoolBlock *end; // one past end of user buffer + uint8_t *start; // start of user buffer + uint8_t *end; // one past end of user buffer uint32_t block_size; // aligned size of each block uint32_t capacity; // number of blocks uint32_t align; // alignment diff --git a/src/lpool.c b/src/lpool.c index 88cce77..d0e4d1d 100644 --- a/src/lpool.c +++ b/src/lpool.c @@ -3,6 +3,23 @@ #include "lpool.h" #define ALIGN_UP(n, alignment) (((n) + (__typeof__(n))(alignment) - 1) & ~((__typeof__(n))(alignment) - 1)) +#define NULL_BLOCK (0xffffffff) + +static inline LPoolBlock *lpool_next(LPool *pool, LPoolBlock *block) +{ + if (block->next == NULL_BLOCK) { + return NULL; + } + return (LPoolBlock *)(pool->start + block->next); +} + +static inline uint32_t lpool_offset(LPool *pool, LPoolBlock *block) +{ + if (block == NULL) { + return NULL_BLOCK; + } + return (uint8_t *)block - pool->start; +} void lpool_init(LPool *pool, void *buffer, size_t buffer_size, uint32_t block_size, uint32_t align) { @@ -37,11 +54,11 @@ void lpool_init(LPool *pool, void *buffer, size_t buffer_size, uint32_t block_si LPoolBlock *block = (LPoolBlock *)first_addr; pool->free_list = block; for (uint32_t i = 0; i < pool->capacity - 1; i++) { - LPoolBlock *next = __builtin_assume_aligned(&block->data[0] + stride, _Alignof(LPoolBlock)); + uint32_t next = (i + 1) * stride; block->next = next; - block = next; + block = (LPoolBlock *)(first_addr + next); } - block->next = NULL; // last element + block->next = NULL_BLOCK; // last element } pool->block_size = stride; pool->align = align; @@ -51,11 +68,12 @@ void lpool_init(LPool *pool, void *buffer, size_t buffer_size, uint32_t block_si void *lpool_alloc(LPool *pool) { - if (!pool->free_list) { + if (pool->free_list == NULL) { return NULL; } LPoolBlock *block = pool->free_list; - pool->free_list = block->next; + LPoolBlock *next = lpool_next(pool, block); + pool->free_list = next; #ifdef DEBUG memset(block, 0xCB, pool->block_size); @@ -70,22 +88,21 @@ void lpool_free(LPool *pool, void *p) } LPoolBlock *block = p; #ifdef DEBUG - assert(block >= pool->start && block < pool->end); + assert((uint8_t *)p >= pool->start && (uint8_t *)p < pool->end); assert(((uintptr_t)p - (uintptr_t)pool->start) % pool->block_size == 0); // double-free detection - for (LPoolBlock *f = pool->free_list; f; f = f->next) { + for (LPoolBlock *f = pool->free_list; f; f = lpool_next(pool, f)) { if (f == p) { assert(0 && "Double free detected in pool!"); return; } } - memset(p, 0xDD, pool->block_size); #endif // When not in use, store pointer to next free element inline in the block - block->next = pool->free_list; - pool->free_list = p; + block->next = lpool_offset(pool, pool->free_list); + pool->free_list = block; } void lpool_reset(LPool *pool) @@ -96,14 +113,13 @@ void lpool_reset(LPool *pool) uintptr_t first_addr = ALIGN_UP(start_addr, pool->align); // build intrusive free list - LPoolBlock *p = (LPoolBlock *)first_addr; + LPoolBlock *block = (LPoolBlock *)first_addr; + pool->free_list = block; for (size_t i = 0; i < pool->capacity - 1; ++i) { - LPoolBlock *next = __builtin_assume_aligned(&p->data[0] + pool->block_size, _Alignof(LPoolBlock)); - p->next = next; - p = next; + uint32_t next = i * pool->block_size; + block->next = next; + block = (LPoolBlock *)(first_addr + next); } - p->next = NULL; // last element - - pool->free_list = (LPoolBlock *)first_addr; + block->next = NULL_BLOCK; // last element } diff --git a/test/lpool_test.c b/test/lpool_test.c index 624ad77..5532f56 100644 --- a/test/lpool_test.c +++ b/test/lpool_test.c @@ -26,6 +26,7 @@ int main(int argc, char *argv[]) printf("Total allocs = %zu\n", allocs); printf("alloc succeded = %d\n", lpool_alloc(&pool) != NULL); lpool_free(&pool, data); + printf("alloc succeded = %d\n", lpool_alloc(&pool) != NULL); return 0;