--- libaitsess/src/Attic/mem.c 2012/02/27 20:56:38 1.1 +++ libaitsess/src/Attic/mem.c 2012/02/27 20:56:38 1.1.2.1 @@ -0,0 +1,292 @@ +#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*); +}