version 1.1, 2012/02/27 20:56:38
|
version 1.1.2.1, 2012/02/27 20:56:38
|
Line 0
|
Line 1
|
|
#include "global.h" |
|
|
|
|
|
/* |
|
* mpool_init() - Init memory pool |
|
* |
|
* return: =NULL error or !=NULL new allocated pool |
|
*/ |
|
mpool_t * |
|
mpool_init(void) |
|
{ |
|
mpool_t *mp; |
|
|
|
mp = malloc(sizeof(mpool_t)); |
|
if (!mp) { |
|
LOGERR; |
|
return NULL; |
|
} else |
|
memset(mp, 0, sizeof(mpool_t)); |
|
|
|
pthread_mutex_init(&mp->pool_mtx, NULL); |
|
return mp; |
|
} |
|
|
|
/* |
|
* mpool_destroy() - Destroy memory pool |
|
* |
|
* @mp = Memory pool |
|
* return: none |
|
*/ |
|
void |
|
mpool_destroy(mpool_t ** __restrict mp) |
|
{ |
|
struct tagAlloc *m; |
|
register int i; |
|
|
|
if (!mp && !*mp) |
|
return; |
|
|
|
mpool_lock(*mp); |
|
|
|
for (i = 0; i < MEM_BUCKETS; i++) { |
|
while ((m = TAILQ_FIRST(&(*mp)->pool_active[i]))) { |
|
TAILQ_REMOVE(&(*mp)->pool_active[i], m, alloc_node); |
|
if (m->alloc_mem) |
|
free(m->alloc_mem); |
|
free(m); |
|
} |
|
while ((m = TAILQ_FIRST(&(*mp)->pool_inactive[i]))) { |
|
TAILQ_REMOVE(&(*mp)->pool_inactive[i], m, alloc_node); |
|
if (m->alloc_mem) |
|
free(m->alloc_mem); |
|
free(m); |
|
} |
|
} |
|
|
|
mpool_unlock(*mp); |
|
pthread_mutex_destroy(&(*mp)->pool_mtx); |
|
|
|
free(*mp); |
|
*mp = NULL; |
|
} |
|
|
|
/* ----------------------------------------------------------- */ |
|
|
|
static inline long |
|
BucketIndex(u_int size) |
|
{ |
|
register long b; |
|
|
|
if (!size--) |
|
return 0; /* min bucket position in array */ |
|
|
|
for (b = MEM_MIN_BUCKET; b < MEM_MAX_BUCKET; b++) |
|
if (!(size >> b)) |
|
break; |
|
|
|
return b - MEM_MIN_BUCKET; /* convert to bucket array index */ |
|
} |
|
|
|
static inline struct tagAlloc * |
|
pullInactive(mpool_t * __restrict mp, int idx) |
|
{ |
|
struct tagAlloc *m = NULL; |
|
|
|
/* must be locked pool before use this function */ |
|
if ((m = TAILQ_FIRST(&mp->pool_inactive[idx]))) { |
|
TAILQ_REMOVE(&mp->pool_inactive[idx], m, alloc_node); |
|
|
|
/* clear name */ |
|
*m->alloc_name = 0; |
|
/* clear flags */ |
|
m->alloc_flags ^= m->alloc_flags; |
|
} |
|
|
|
return m; |
|
} |
|
|
|
/* |
|
* mpool_malloc() - Memory allocation |
|
* |
|
* @mp = Memory pool |
|
* @size = Size |
|
* @memname = Optional memory block name |
|
* return: NULL error or !=NULL ok allocated memory |
|
*/ |
|
void * |
|
mpool_malloc(mpool_t * __restrict mp, u_int size, const char *memname) |
|
{ |
|
struct tagAlloc *m; |
|
int idx, align; |
|
|
|
if (!mp) { |
|
sess_SetErr(EINVAL, "Pool not specified"); |
|
return NULL; |
|
} |
|
if (size > MEM_ALLOC_MAX) { |
|
sess_SetErr(ENOMEM, "Memory size is too large"); |
|
return NULL; |
|
} else |
|
size = (size + 3) & ~3; /* must align to 4 because needed room for sentinels */ |
|
|
|
idx = BucketIndex(size); |
|
|
|
mpool_lock(mp); |
|
|
|
/* get memory from cache if exists */ |
|
if (!(m = pullInactive(mp, idx))) { |
|
/* quota */ |
|
if (mp->pool_quota.max && |
|
(mp->pool_quota.curr + size) > mp->pool_quota.max) { |
|
sess_SetErr(ENOMEM, "Max.allocate memory quota has been reached"); |
|
mpool_unlock(mp); |
|
return NULL; |
|
} |
|
|
|
m = malloc(sizeof(struct tagAlloc)); |
|
if (!m) { |
|
LOGERR; |
|
mpool_unlock(mp); |
|
return NULL; |
|
} else |
|
memset(m, 0, sizeof(struct tagAlloc)); |
|
} |
|
|
|
if (memname) |
|
strlcpy(m->alloc_name, memname, sizeof m->alloc_name); |
|
|
|
if (!m->alloc_mem) { |
|
align = 1 << (idx + MEM_MIN_BUCKET); |
|
m->alloc_mem = malloc(align + 12); /* +12 sentinel bytes */ |
|
if (!m->alloc_mem) { |
|
LOGERR; |
|
free(m); |
|
mpool_unlock(mp); |
|
return NULL; |
|
} else /* quota */ |
|
mp->pool_quota.curr += size; |
|
} |
|
|
|
m->alloc_mem[0] = size / sizeof(u_int); |
|
m->alloc_mem[1] = MEM_MAGIC_START; |
|
m->alloc_mem[2 + size / sizeof(u_int)] = MEM_MAGIC_STOP; |
|
TAILQ_INSERT_HEAD(&mp->pool_active[idx], m, alloc_node); |
|
/* statistics */ |
|
mp->pool_calls.alloc++; |
|
mp->pool_bytes.alloc += size; |
|
|
|
mpool_unlock(mp); |
|
return mem_data(m, void*); |
|
} |
|
|
|
/* |
|
* mpool_free() Free allocated memory with mpool_alloc() |
|
* |
|
* @mp = Memory pool |
|
* @data = Allocated memory data |
|
* @purge = if !=0 force release memory block |
|
* return: <0 error or 0 ok released memory block |
|
*/ |
|
int |
|
mpool_free(mpool_t * __restrict mp, void * __restrict data, int purge) |
|
{ |
|
int idx; |
|
struct tagAlloc *m; |
|
|
|
if (!mp) { |
|
sess_SetErr(EINVAL, "Pool not specified"); |
|
return -1; |
|
} |
|
/* check address range & sentinel */ |
|
if (MEM_BADADDR(data) || MEM_CORRUPT(data)) { |
|
sess_SetErr(EFAULT, "Corrupted memory address"); |
|
return -2; |
|
} else |
|
idx = BucketIndex(((u_int*)data)[-2]); |
|
|
|
mpool_lock(mp); |
|
TAILQ_FOREACH(m, &mp->pool_active[idx], alloc_node) |
|
if (mem_data(m, void*) == data) { |
|
TAILQ_REMOVE(&mp->pool_active[idx], m, alloc_node); |
|
|
|
if (!purge) { |
|
TAILQ_INSERT_HEAD(&mp->pool_inactive[idx], m, alloc_node); |
|
/* statistics */ |
|
mp->pool_calls.cache++; |
|
mp->pool_bytes.cache += mem_size(m); |
|
} else { |
|
if (m->alloc_mem) |
|
free(m->alloc_mem); |
|
free(m); |
|
/* statistics */ |
|
mp->pool_calls.free++; |
|
mp->pool_bytes.free += mem_size(m); |
|
} |
|
break; |
|
} |
|
mpool_unlock(mp); |
|
|
|
return 0; |
|
} |
|
|
|
/* |
|
* mpool_free2() Free allocated memory with mpool_alloc() by size and memory name |
|
* |
|
* @mp = Memory pool |
|
* @size = Allocated memory data size |
|
* @memname = Memory name |
|
* @purge = if !=0 force release memory block |
|
* return: <0 error or 0 ok released memory block |
|
*/ |
|
int |
|
mpool_free2(mpool_t * __restrict mp, u_int size, const char *memname, int purge) |
|
{ |
|
int idx; |
|
struct tagAlloc *m; |
|
|
|
if (!mp || !memname) { |
|
sess_SetErr(EINVAL, "Pool or memory name is not specified"); |
|
return -1; |
|
} else |
|
idx = BucketIndex(size); |
|
|
|
mpool_lock(mp); |
|
TAILQ_FOREACH(m, &mp->pool_active[idx], alloc_node) |
|
if (!strcmp(m->alloc_name, memname)) { |
|
TAILQ_REMOVE(&mp->pool_active[idx], m, alloc_node); |
|
|
|
if (!purge) { |
|
TAILQ_INSERT_HEAD(&mp->pool_inactive[idx], m, alloc_node); |
|
/* statistics */ |
|
mp->pool_calls.cache++; |
|
mp->pool_bytes.cache += mem_size(m); |
|
} else { |
|
if (m->alloc_mem) |
|
free(m->alloc_mem); |
|
free(m); |
|
/* statistics */ |
|
mp->pool_calls.free++; |
|
mp->pool_bytes.free += mem_size(m); |
|
} |
|
break; |
|
} |
|
mpool_unlock(mp); |
|
|
|
return 0; |
|
} |
|
|
|
/* |
|
* mpool_getmembynam() Find allocated memory block by size and memory name |
|
* |
|
* @mp = Memory pool |
|
* @size = Memory size |
|
* @memname = Memory name |
|
* return: NULL error or not found and !=NULL allocated memory |
|
*/ |
|
inline struct tagAlloc * |
|
mpool_getmembynam(mpool_t * __restrict mp, u_int size, const char *memname) |
|
{ |
|
int idx; |
|
struct tagAlloc *m = NULL; |
|
|
|
if (!mp || !memname) |
|
return NULL; |
|
|
|
idx = BucketIndex(size); |
|
TAILQ_FOREACH(m, &mp->pool_active[idx], alloc_node) |
|
if (!strcmp(m->alloc_name, memname)) |
|
break; |
|
|
|
return mem_data(m, void*); |
|
} |