#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*);
}
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>