140 lines
3.7 KiB
C
140 lines
3.7 KiB
C
#include <c_Pool.h>
|
|||
|
|
#include <assert.h>
|
||
|
|
#include <stdlib.h>
|
||
|
|
#include "c_Alignment.h"
|
||
|
|
|
||
|
|
/* ------------------------------------------------------------------------------------------------------------------ */
|
||
|
|
/* */
|
||
|
|
|
||
|
|
#define FREE(x) do{ \
|
||
|
|
if(x){ \
|
||
|
|
free(x); \
|
||
|
|
(x) = NULL; \
|
||
|
|
} \
|
||
|
|
}while(0)
|
||
|
|
|
||
|
|
#define ALLOC(x) malloc(x)
|
||
|
|
#define NEW(p) (p)=ALLOC(sizeof(*(p)))
|
||
|
|
|
||
|
|
#define DEFAULT_CHUNK_SIZE 10
|
||
|
|
|
||
|
|
/* ------------------------------------------------------------------------------------------------------------------ */
|
||
|
|
/* */
|
||
|
|
|
||
|
|
|
||
|
|
typedef struct c_PoolBlockLink_t {
|
||
|
|
void* block;
|
||
|
|
struct c_PoolBlockLink_t* next;
|
||
|
|
}c_PoolBlockLink_t;
|
||
|
|
|
||
|
|
struct c_PoolBlockList_t{
|
||
|
|
c_PoolBlockLink_t* list;
|
||
|
|
};
|
||
|
|
|
||
|
|
/* ------------------------------------------------------------------------------------------------------------------ */
|
||
|
|
/* */
|
||
|
|
|
||
|
|
C_STATIC_FORCE_INLINE
|
||
|
|
void c_PoolBlockLink_Init(c_PoolBlockLink_t* self, void* p, c_PoolBlockLink_t* next) {
|
||
|
|
self->block = p;
|
||
|
|
self->next = next;
|
||
|
|
}
|
||
|
|
|
||
|
|
C_STATIC_FORCE_INLINE
|
||
|
|
void c_PoolBlockList_Init(c_PoolBlockList_t* self) {
|
||
|
|
self->list = NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
C_STATIC_FORCE_INLINE
|
||
|
|
void c_PoolBlockList_Destroy(c_PoolBlockList_t* self) {
|
||
|
|
if (!self) return;
|
||
|
|
while (self->list){
|
||
|
|
c_PoolBlockLink_t* q = self->list;
|
||
|
|
self->list = q->next;
|
||
|
|
FREE(q);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
C_STATIC_FORCE_INLINE
|
||
|
|
void* c_PoolBlockList_Alloc(c_PoolBlockList_t* self, c_size_t bytes) {
|
||
|
|
c_size_t block_size = bytes + sizeof(c_PoolBlockLink_t);
|
||
|
|
block_size = C_ALIGN_UPB(block_size, C_ALIGN_SIZE);
|
||
|
|
c_PoolBlockLink_t* p = ALLOC(block_size);
|
||
|
|
if (!p) {
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
c_PoolBlockLink_Init(p, p+1, self->list);
|
||
|
|
self->list = p;
|
||
|
|
return p->block;
|
||
|
|
}
|
||
|
|
|
||
|
|
C_STATIC_FORCE_INLINE
|
||
|
|
c_err_t c_Pool_Replenish(c_Pool_t* self) {
|
||
|
|
c_size_t size = self->chunkSize * self->objSize;
|
||
|
|
uint8_t* start = (uint8_t*)c_PoolBlockList_Alloc(self->blockAllocator, size);
|
||
|
|
if (!start) return C_ERR_NOMEM;
|
||
|
|
uint8_t* last = &start[(self->chunkSize - 1) * self->objSize];
|
||
|
|
for (uint8_t* p = start; p<last; p+=self->objSize) {
|
||
|
|
((struct c_PoolLink_t*)p)->next = (struct c_PoolLink_t*)(p + self->objSize);
|
||
|
|
}
|
||
|
|
((struct c_PoolLink_t*)last)->next = NULL;
|
||
|
|
self->freelist = (struct c_PoolLink_t*)start;
|
||
|
|
return C_ERR_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* ------------------------------------------------------------------------------------------------------------------ */
|
||
|
|
/* */
|
||
|
|
|
||
|
|
c_err_t c_Pool_Init(c_Pool_t* self, int objSize, int chunkSize) {
|
||
|
|
self->freelist = 0;
|
||
|
|
self->objSize = objSize>=sizeof(struct c_PoolLink_t)?objSize:sizeof(struct c_PoolLink_t);
|
||
|
|
self->chunkSize = (chunkSize > 0)?chunkSize:DEFAULT_CHUNK_SIZE;
|
||
|
|
self->instanceCount = 0;
|
||
|
|
NEW(self->blockAllocator);
|
||
|
|
if (!self->blockAllocator) {
|
||
|
|
return C_ERR_NOMEM;
|
||
|
|
}
|
||
|
|
c_PoolBlockList_Init(self->blockAllocator);
|
||
|
|
|
||
|
|
return C_ERR_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
void c_Pool_Destroy(c_Pool_t* self) {
|
||
|
|
if (0==self->instanceCount) {
|
||
|
|
c_PoolBlockList_Destroy(self->blockAllocator);
|
||
|
|
FREE(self->blockAllocator);
|
||
|
|
self->freelist = NULL;
|
||
|
|
}
|
||
|
|
assert(0==self->instanceCount);
|
||
|
|
}
|
||
|
|
|
||
|
|
void* c_Pool_Alloc(c_Pool_t* self) {
|
||
|
|
if (!self->freelist) {
|
||
|
|
if (c_Pool_Replenish(self)!=C_ERR_SUCCESS) {
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
struct c_PoolLink_t* p = self->freelist;
|
||
|
|
self->freelist = p->next;
|
||
|
|
++self->instanceCount;
|
||
|
|
return p;
|
||
|
|
}
|
||
|
|
|
||
|
|
void c_Pool_Free(c_Pool_t* self, void* ptr) {
|
||
|
|
if (!self || !ptr) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
struct c_PoolLink_t* p = (struct c_PoolLink_t*)ptr;
|
||
|
|
p->next = self->freelist;
|
||
|
|
self->freelist = p;
|
||
|
|
--self->instanceCount;
|
||
|
|
}
|
||
|
|
|
||
|
|
void c_Pool_DryUp(c_Pool_t* self) {
|
||
|
|
c_PoolBlockList_Destroy(self->blockAllocator);
|
||
|
|
FREE(self->blockAllocator);
|
||
|
|
self->instanceCount = 0;
|
||
|
|
}
|
||
|
|
|