--- libelwix/src/mem.c	2014/01/29 16:42:36	1.3.2.1
+++ libelwix/src/mem.c	2015/07/01 21:48:39	1.6
@@ -3,7 +3,7 @@
 *  by Michael Pounov <misho@openbsd-bg.org>
 *
 * $Author: misho $
-* $Id: mem.c,v 1.3.2.1 2014/01/29 16:42:36 misho Exp $
+* $Id: mem.c,v 1.6 2015/07/01 21:48:39 misho Exp $
 *
 **************************************************************************
 The ELWIX and AITNET software is distributed under the following
@@ -12,7 +12,7 @@ terms:
 All of the documentation and software included in the ELWIX and AITNET
 Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
 
-Copyright 2004 - 2014
+Copyright 2004 - 2015
 	by Michael Pounov <misho@elwix.org>.  All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -218,6 +218,7 @@ mpool_malloc(mpool_t * __restrict mp, u_int size, cons
 			return NULL;
 		} else {	/* quota */
 			mp->pool_quota.curr += size;
+			mp->pool_quota.real += 1 << (idx + MEM_MIN_BUCKET);
 			memset(m->alloc_mem, 0, align + 12);
 		}
 	}
@@ -246,10 +247,9 @@ mpool_malloc(mpool_t * __restrict mp, u_int size, cons
 void *
 mpool_realloc(mpool_t * __restrict mp, void * __restrict data, u_int newsize, const char *memname)
 {
-	struct tagAlloc *m, *tmp;
 	int idx, oidx;
 	void *p;
-	u_int align, osize;
+	u_int osize;
 
 	/* if !data execute mpool_malloc() */
 	if (!data)
@@ -263,21 +263,20 @@ mpool_realloc(mpool_t * __restrict mp, void * __restri
 	if (MEM_BADADDR(data) || MEM_CORRUPT(data)) {
 		elwix_SetErr(EFAULT, "Corrupted memory address");
 		return NULL;
-	} else {
-		osize = ((u_int*)data)[-2] * sizeof(u_int);
-		oidx = BucketIndex(osize);
 	}
 	/* prepare new size */
 	if (newsize > MEM_ALLOC_MAX) {
 		elwix_SetErr(ENOMEM, "Memory size is too large");
 		return NULL;
-	} else {
-		newsize = (newsize + 3) & ~3;	/* must align to 4 because needed room for sentinels */
-		idx = BucketIndex(newsize);
 	}
 
 	mpool_lock(mp);
 
+	osize = ((u_int*)data)[-2] * sizeof(u_int);
+	oidx = BucketIndex(osize);
+	newsize = (newsize + 3) & ~3;	/* must align to 4 because needed room for sentinels */
+	idx = BucketIndex(newsize);
+
 	/* quota */
 	if (mp->pool_quota.max && 
 			(mp->pool_quota.curr + ((u_long) newsize - osize)) > mp->pool_quota.max) {
@@ -286,63 +285,27 @@ mpool_realloc(mpool_t * __restrict mp, void * __restri
 		return NULL;
 	}
 
-	/* find old memory block */
-	TAILQ_FOREACH_SAFE(m, &mp->pool_active[oidx], alloc_node, tmp) {
-		if (mem_data(m, void*) == data && mem_size(m) == osize) {
-			/* case in different buckets */
-			if (oidx != idx) {
-				TAILQ_REMOVE(&mp->pool_active[oidx], m, alloc_node);
-				/* statistics */
-				mp->pool_calls.alloc--;
-			}
-			mp->pool_bytes.alloc -= osize;
-			break;
-		}
-	}
-	/* memory block not found! */
-	if (!m) {
+	if (oidx != idx) {
 		mpool_unlock(mp);
-		elwix_SetErr(EFAULT, "Memory block not found");
-		return NULL;
-	}
+		p = mpool_malloc(mp, newsize, memname);
+		if (!p)
+			return NULL;
 
-	/* try to reallocate memory block to new bucket */
-	if (oidx != idx) {
-		align = 1 << (idx + MEM_MIN_BUCKET);
-		p = realloc(m->alloc_mem, align + 12);
-		if (!p) {
-			LOGERR;
+		memcpy(p, data, osize);
+		mpool_free(mp, data, 0);
+	} else {
+		p = data;
 
-			/* restore to old bucket pulled memory block for reallocation */
-			TAILQ_INSERT_HEAD(&mp->pool_active[oidx], m, alloc_node);
-			/* statistics */
-			mp->pool_calls.alloc++;
-			mp->pool_bytes.alloc += osize;
+		((u_int*) p)[-2] = newsize / sizeof(u_int);
+		((u_int*) p)[newsize / sizeof(u_int)] = MEM_MAGIC_STOP;
 
-			mpool_unlock(mp);
-			return NULL;
-		} else
-			m->alloc_mem = (u_int*) p;
-	}
-	/* quota */
-	mp->pool_quota.curr += (u_long) newsize - osize;
+		mp->pool_bytes.alloc += (u_long) newsize - osize;
+		mp->pool_quota.curr += (u_long) newsize - osize;
 
-	m->alloc_mem[0] = newsize / sizeof(u_int);
-	m->alloc_mem[1] = MEM_MAGIC_START;
-	m->alloc_mem[2 + newsize / sizeof(u_int)] = MEM_MAGIC_STOP;
-
-	if (oidx != idx) {
-		TAILQ_INSERT_HEAD(&mp->pool_active[idx], m, alloc_node);
-		/* statistics */
-		mp->pool_calls.alloc++;
+		mpool_unlock(mp);
 	}
-	mp->pool_bytes.alloc += newsize;
 
-	if (memname)
-		strlcpy(m->alloc_name, memname, sizeof m->alloc_name);
-
-	mpool_unlock(mp);
-	return mem_data(m, void*);
+	return p;
 }
 
 /*
@@ -382,6 +345,7 @@ mpool_purge(mpool_t * __restrict mp, u_int atmost)
 			mp->pool_bytes.free += mem_size(m);
 			/* quota */
 			mp->pool_quota.curr -= mem_size(m);
+			mp->pool_quota.real -= 1 << (i + MEM_MIN_BUCKET);
 
 			if (m->alloc_mem)
 				free(m->alloc_mem);
@@ -440,6 +404,7 @@ mpool_free(mpool_t * __restrict mp, void * __restrict 
 				mp->pool_bytes.free += mem_size(m);
 				/* quota */
 				mp->pool_quota.curr -= mem_size(m);
+				mp->pool_quota.real -= 1 << (idx + MEM_MIN_BUCKET);
 
 				if (m->alloc_mem)
 					free(m->alloc_mem);
@@ -492,6 +457,7 @@ mpool_free2(mpool_t * __restrict mp, u_int size, const
 				mp->pool_bytes.free += mem_size(m);
 				/* quota */
 				mp->pool_quota.curr -= mem_size(m);
+				mp->pool_quota.real -= 1 << (idx + MEM_MIN_BUCKET);
 
 				if (m->alloc_mem)
 					free(m->alloc_mem);
@@ -627,18 +593,21 @@ mpool_setquota(mpool_t * __restrict mp, u_long maxmem)
  * mpool_getquota() - Get memory quota
  *
  * @mp = Memory pool
- * @currmem = Return current memory
+ * @currmem = Return current memory usage
+ * @realmem = Return current real memory usage
  * @maxmem = Return max quota size
  * return: none
  */
 void
-mpool_getquota(mpool_t * __restrict mp, u_long *currmem, u_long *maxmem)
+mpool_getquota(mpool_t * __restrict mp, u_long *currmem, u_long *realmem, u_long *maxmem)
 {
 	if (!mp)
 		return;
 
 	if (maxmem)
 		*maxmem = mp->pool_quota.max;
+	if (realmem)
+		*realmem = mp->pool_quota.real;
 	if (currmem)
 		*currmem = mp->pool_quota.curr;
 }
@@ -734,3 +703,68 @@ mpool_xstrdup(const char *str)
 {
 	return mpool_strdup(elwix_mpool, str, elwix_Prog);
 }
+
+/*
+ * mpool_xstatistics() - elwix memory pool statistics wrapper
+ *
+ * @cb = Export statistics to callback
+ * return: none
+ */
+void
+mpool_xstatistics(mpool_stat_cb cb)
+{
+	mpool_statistics(elwix_mpool, cb);
+}
+
+static void
+xdump_show(u_int size, u_int act, u_int inact)
+{
+	if (!act && !inact)
+		return;	/* skip empty bucket */
+
+	if (size < 1024)
+		printf("\t\t* BUCKET %uB size, %u active, %u inactive\n", 
+				size, act, inact);
+	else if (size < 1048576)
+		printf("\t\t* BUCKET %uKB size, %u active, %u inactive\n", 
+				size / 1024, act, inact);
+	else
+		printf("\t\t* BUCKET %uMB size, %u active, %u inactive\n", 
+				size / 1048576, act, inact);
+}
+
+/*
+ * mpool_dump() - Dump elwix memory pool statistics
+ *
+ * @mp = memory pool, if =NULL dump elwix default memory pool
+ * @fmt = prefix info format string
+ * @... = argument(s)
+ * return: none
+ */
+void
+mpool_dump(mpool_t * __restrict mp, const char *fmt, ...)
+{
+	va_list lst;
+	mpool_t *p = mp ? mp : elwix_mpool;
+
+	if (fmt) {
+		va_start(lst, fmt);
+		vprintf(fmt, lst);
+		va_end(lst);
+	} else
+		printf("\n%s(%d)\n", __func__, __LINE__);
+
+	printf("------------------------------------------------------------\n");
+	printf( " ELWIX memory pool ::\n"
+		"\t- quotas Current/Real/Max = %lu/%lu/%lu\n"
+		"\t- calls Alloc/Free/Cache = %lu/%lu/%lu\n"
+		"\t- bytes Alloc/Free/Cache = %lu/%lu/%lu\n"
+		"\t- buckets :\n", 
+		p->pool_quota.curr, p->pool_quota.real, p->pool_quota.max, 
+		p->pool_calls.alloc, p->pool_calls.free, p->pool_calls.cache, 
+		p->pool_bytes.alloc, p->pool_bytes.free, p->pool_bytes.cache);
+
+	mpool_statistics(p, xdump_show);
+	printf("------------------------------------------------------------\n");
+}
+