#include #include "ucore/spool.h" #include "ucore/utils.h" #include void uc_pool_init(UCPool *pool, void *buffer, size_t buffer_size, size_t block_size, size_t align) { assert(align > 0); assert((align & (align - 1)) == 0); // power of 2 // enforce minimum for storing free list pointers if (align < _Alignof(unsigned char *)) { align = _Alignof(unsigned char *); } if (block_size < sizeof(unsigned char *)) { block_size = sizeof(unsigned char *); } // ensure initial alignment size_t stride = UC_ALIGN(block_size, align); // align first usable block uintptr_t start_addr = (uintptr_t)buffer; uintptr_t first_addr = UC_ALIGN(start_addr, align); size_t padding = first_addr - start_addr; if (padding + stride > buffer_size) { pool->capacity = 0; pool->free_list = NULL; } else { size_t usable = buffer_size - padding; pool->capacity = usable / stride; // build intrusive free list unsigned char *p = (unsigned char *)first_addr; for (size_t i = 0; i < pool->capacity - 1; ++i) { *(unsigned char **)p = p + stride; p += stride; } *(unsigned char **)p = NULL; // last element pool->free_list = (unsigned char *)first_addr; } pool->block_size = stride; pool->align = align; pool->start = (unsigned char *)buffer; pool->end = (unsigned char *)buffer + buffer_size; } void *uc_pool_alloc(UCPool *pool) { if (!pool->free_list) { return NULL; } unsigned char *block = pool->free_list; pool->free_list = *(unsigned char **)block; #ifdef DEBUG memset(block, 0xCB, pool->block_size); #endif return block; } #include void uc_pool_free(UCPool *pool, void *p) { if (p == NULL) { return; } #ifdef DEBUG assert((unsigned char *)p >= pool->start && (unsigned char*)p < pool->end); assert(((uintptr_t)p - (uintptr_t)pool->start) % pool->block_size == 0); // double-free detection for (unsigned char *f = pool->free_list; f; f = *(unsigned char**)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 *(unsigned char **)p = pool->free_list; pool->free_list = p; } void uc_pool_reset(UCPool *pool) { if (pool->capacity == 0) return; uintptr_t start_addr = (uintptr_t)pool->start; uintptr_t first_addr = UC_ALIGN(start_addr, pool->align); unsigned char *p = (unsigned char *)first_addr; // build intrusive free list for (size_t i = 0; i < pool->capacity - 1; ++i) { *(unsigned char **)p = p + pool->block_size; p += pool->block_size; } *(unsigned char **)p = NULL; // last element pool->free_list = (unsigned char *)first_addr; }