diff --git a/.vscode/settings.json b/.vscode/settings.json index 571ae2e..69ae3c3 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,5 +7,5 @@ "$(workspaceFolder)/include/", ], - "C_Cpp.default.cStandard": "gnu99" + "C_Cpp.default.cStandard": "gnu17" } diff --git a/include/ucore/spool.h b/include/ucore/spool.h index 4c9a2f4..17ae856 100644 --- a/include/ucore/spool.h +++ b/include/ucore/spool.h @@ -1,5 +1,5 @@ #ifndef UC_SPOOL_H_ -#define UC_SPOOL_H +#define UC_SPOOL_H_ #include #include @@ -7,6 +7,11 @@ extern "C" { #endif +typedef union UCPoolBlock UCPoolBlock; +union UCPoolBlock { + UCPoolBlock *next; // next free block (when not allocated) + unsigned char data[]; // data when allocated +}; /** @file * Static pool allocator. * @@ -23,12 +28,12 @@ extern "C" { */ typedef struct UCPool UCPool; struct UCPool { - unsigned char *free_list; // intrusive free list + UCPoolBlock *free_list; // free list size_t block_size; // aligned size of each block size_t capacity; // number of blocks size_t align; // alignment - unsigned char *start; // start of user buffer - unsigned char *end; // one past end of user buffer + UCPoolBlock *start; // start of user buffer + UCPoolBlock *end; // one past end of user buffer }; /** Initialize the pool. @@ -47,6 +52,7 @@ void uc_pool_init(UCPool *pool, size_t alignment); // Allocate a block from the pool. Returns NULL if no more space +[[gnu::assume_aligned(_Alignof(UCPoolBlock))]] void *uc_pool_alloc(UCPool *pool); // Free @p . Returns memory to the pool diff --git a/src/spool.c b/src/spool.c index de20831..c40116e 100644 --- a/src/spool.c +++ b/src/spool.c @@ -11,12 +11,12 @@ void uc_pool_init(UCPool *pool, void *buffer, size_t buffer_size, size_t block_s // enforce minimum for storing free list pointers - if (align < _Alignof(unsigned char *)) { - align = _Alignof(unsigned char *); + if (align < _Alignof(UCPoolBlock)) { + align = _Alignof(UCPoolBlock); } - if (block_size < sizeof(unsigned char *)) { - block_size = sizeof(unsigned char *); + if (block_size < sizeof(UCPoolBlock)) { + block_size = sizeof(UCPoolBlock); } // ensure initial alignment size_t stride = UC_ALIGN(block_size, align); @@ -34,19 +34,21 @@ void uc_pool_init(UCPool *pool, void *buffer, size_t buffer_size, size_t block_s pool->capacity = usable / stride; // build intrusive free list - unsigned char *p = (unsigned char *)first_addr; + UCPoolBlock *p = (UCPoolBlock*)first_addr; for (size_t i = 0; i < pool->capacity - 1; ++i) { - *(unsigned char **)p = p + stride; - p += stride; + void *punt = __builtin_assume_aligned(&p->data[0] + pool->block_size, _Alignof(UCPoolBlock)); + UCPoolBlock *next = punt; + p->next = next; + p = next; } - *(unsigned char **)p = NULL; // last element - pool->free_list = (unsigned char *)first_addr; + ((UCPoolBlock *)p)->next = NULL; // last element + pool->free_list = (UCPoolBlock *)first_addr; } pool->block_size = stride; pool->align = align; - pool->start = (unsigned char *)buffer; - pool->end = (unsigned char *)buffer + buffer_size; + pool->start = buffer; + pool->end = buffer + buffer_size; } @@ -55,13 +57,13 @@ void *uc_pool_alloc(UCPool *pool) if (!pool->free_list) { return NULL; } - unsigned char *block = pool->free_list; - pool->free_list = *(unsigned char **)block; + UCPoolBlock *block = pool->free_list; + pool->free_list = block->next; #ifdef DEBUG memset(block, 0xCB, pool->block_size); #endif - return block; + return block->data; } #include @@ -70,12 +72,13 @@ void uc_pool_free(UCPool *pool, void *p) if (p == NULL) { return; } + UCPoolBlock *block = p; #ifdef DEBUG - assert((unsigned char *)p >= pool->start && (unsigned char*)p < pool->end); + assert(block >= pool->start && block < 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) { + for (UCPoolBlock *f = pool->free_list; f; f = f->next) { if (f == p) { assert(0 && "Double free detected in pool!"); return; @@ -85,7 +88,7 @@ void uc_pool_free(UCPool *pool, void *p) 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; + block->next = pool->free_list; pool->free_list = p; } @@ -98,14 +101,18 @@ void uc_pool_reset(UCPool *pool) 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 + UCPoolBlock *p = (UCPoolBlock*)first_addr; for (size_t i = 0; i < pool->capacity - 1; ++i) { - *(unsigned char **)p = p + pool->block_size; - p += pool->block_size; + void *punt = __builtin_assume_aligned(&p->data[0] + pool->block_size, _Alignof(UCPoolBlock)); + UCPoolBlock *next = punt; + p->next = next; + p = next; + } - *(unsigned char **)p = NULL; // last element + p->next = NULL; // last element - pool->free_list = (unsigned char *)first_addr; + pool->free_list = (UCPoolBlock *)first_addr; } +