diff --git a/include/lpool.h b/include/lpool.h index cfd46cd..5b29ad1 100644 --- a/include/lpool.h +++ b/include/lpool.h @@ -31,9 +31,9 @@ typedef struct LPool LPool; struct LPool { LPoolBlock *free_list; // free list 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 capacity; // total number of blocks + uint32_t used; // used number of blocks uint32_t align; // alignment }; diff --git a/src/lpool.c b/src/lpool.c index d0e4d1d..61a00be 100644 --- a/src/lpool.c +++ b/src/lpool.c @@ -36,34 +36,34 @@ void lpool_init(LPool *pool, void *buffer, size_t buffer_size, uint32_t block_si block_size = sizeof(LPoolBlock); } // ensure initial alignment - uint32_t stride = ALIGN_UP(block_size, align); + block_size = ALIGN_UP(block_size, align); // align first usable block - uintptr_t start_addr = (uintptr_t)buffer; - uintptr_t first_addr = ALIGN_UP(start_addr, align); - size_t padding = first_addr - start_addr; + uintptr_t buffer_addr = (uintptr_t)buffer; + uintptr_t first_addr = ALIGN_UP(buffer_addr, align); + size_t padding = first_addr - buffer_addr; - if (padding + stride > buffer_size) { + if (padding + block_size > buffer_size) { pool->capacity = 0; pool->free_list = NULL; } else { size_t usable = buffer_size - padding; - pool->capacity = usable / stride; + pool->capacity = usable / block_size; // build intrusive free list LPoolBlock *block = (LPoolBlock *)first_addr; pool->free_list = block; - for (uint32_t i = 0; i < pool->capacity - 1; i++) { - uint32_t next = (i + 1) * stride; + for (uint32_t i = 1; i < pool->capacity; i++) { + uint32_t next = i * block_size; block->next = next; block = (LPoolBlock *)(first_addr + next); } block->next = NULL_BLOCK; // last element } - pool->block_size = stride; + pool->block_size = block_size; pool->align = align; pool->start = buffer; - pool->end = buffer + buffer_size; + pool->used = 0; } void *lpool_alloc(LPool *pool) @@ -78,48 +78,52 @@ void *lpool_alloc(LPool *pool) #ifdef DEBUG memset(block, 0xCB, pool->block_size); #endif + pool->used++; return block->data; } -void lpool_free(LPool *pool, void *p) +void lpool_free(LPool *pool, void *ptr) { - if (p == NULL) { + if (ptr == NULL) { return; } - LPoolBlock *block = p; #ifdef DEBUG - assert((uint8_t *)p >= pool->start && (uint8_t *)p < pool->end); - assert(((uintptr_t)p - (uintptr_t)pool->start) % pool->block_size == 0); + assert(pool->used > 0); + uint8_t *end = pool->start + (pool->capacity * pool->block_size); + assert((uint8_t *)ptr >= pool->start && (uint8_t *)ptr < end); + assert((((uintptr_t)ptr - (uintptr_t)pool->start) & (pool->block_size - 1)) == 0); // double-free detection - for (LPoolBlock *f = pool->free_list; f; f = lpool_next(pool, f)) { - if (f == p) { + for (LPoolBlock *block = pool->free_list; block != NULL; block = lpool_next(pool, block)) { + if (block == ptr) { assert(0 && "Double free detected in pool!"); return; } } - memset(p, 0xDD, pool->block_size); + memset(ptr, 0xDD, pool->block_size); #endif + LPoolBlock *block = ptr; // When not in use, store pointer to next free element inline in the block block->next = lpool_offset(pool, pool->free_list); pool->free_list = block; + pool->used--; } void lpool_reset(LPool *pool) { if (pool->capacity == 0) return; - uintptr_t start_addr = (uintptr_t)pool->start; - uintptr_t first_addr = ALIGN_UP(start_addr, pool->align); + uintptr_t first_addr = (uintptr_t)pool->start; // build intrusive free list LPoolBlock *block = (LPoolBlock *)first_addr; pool->free_list = block; - for (size_t i = 0; i < pool->capacity - 1; ++i) { + for (size_t i = 1; i < pool->capacity; ++i) { uint32_t next = i * pool->block_size; block->next = next; block = (LPoolBlock *)(first_addr + next); } block->next = NULL_BLOCK; // last element + pool->used = 0; } diff --git a/test/lpool_test.c b/test/lpool_test.c index 5532f56..28d0ba8 100644 --- a/test/lpool_test.c +++ b/test/lpool_test.c @@ -1,4 +1,6 @@ #include +#include + #include "lpool.h" struct TestData { @@ -10,9 +12,11 @@ struct TestData { int main(int argc, char *argv[]) { - _Alignas(16) uint8_t store[2048]; + //_Alignas(16) uint8_t store[2048]; + uint8_t *store = malloc(2048); + LPool pool; - lpool_init(&pool, store, sizeof store, sizeof(struct TestData), _Alignof(struct TestData)); + lpool_init(&pool, store, 2048, sizeof(struct TestData), _Alignof(struct TestData)); printf("align=%u capacity=%u block_size=%u\n", pool.align, pool.capacity, pool.block_size); struct TestData *data = lpool_alloc(&pool); size_t allocs = 1; @@ -23,11 +27,21 @@ int main(int argc, char *argv[]) } allocs++; } - printf("Total allocs = %zu\n", allocs); - printf("alloc succeded = %d\n", lpool_alloc(&pool) != NULL); + printf("Total allocs = %zu, used = %u\n", allocs, pool.used); + printf("alloc succeded = %d used = %u\n", lpool_alloc(&pool) != NULL, pool.used); lpool_free(&pool, data); + printf("alloc succeded = %d used = %u\n", lpool_alloc(&pool) != NULL, pool.used); - printf("alloc succeded = %d\n", lpool_alloc(&pool) != NULL); + lpool_reset(&pool); + allocs = 0; + for (;;) { + struct TestData *t = lpool_alloc(&pool); + if (t == NULL) { + break; + } + allocs++; + } + printf("Total allocs = %zu, used = %u\n", allocs, pool.used); return 0; }