File:  [ELWIX - Embedded LightWeight unIX -] / libaitsess / src / Attic / mem.c
Revision 1.1.2.1: download - view: text, annotated - select for diffs - revision graph
Mon Feb 27 20:56:38 2012 UTC (12 years, 7 months ago) by misho
Branches: sess3_1
added mem apis

#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>