--- libaitsess/src/Attic/mem.c 2012/02/27 23:57:12 1.1.2.3 +++ libaitsess/src/Attic/mem.c 2012/02/28 12:58:10 1.1.2.11 @@ -3,7 +3,7 @@ * by Michael Pounov * * $Author: misho $ -* $Id: mem.c,v 1.1.2.3 2012/02/27 23:57:12 misho Exp $ +* $Id: mem.c,v 1.1.2.11 2012/02/28 12:58:10 misho Exp $ * ************************************************************************** The ELWIX and AITNET software is distributed under the following @@ -49,10 +49,11 @@ SUCH DAMAGE. /* * mpool_init() - Init memory pool * + * @maxmem = If !=0 set maximum memory quota * return: =NULL error or !=NULL new allocated pool */ mpool_t * -mpool_init(void) +mpool_init(u_long maxmem) { mpool_t *mp; register int i; @@ -66,6 +67,8 @@ mpool_init(void) pthread_mutex_init(&mp->pool_mtx, NULL); + mp->pool_quota.max = maxmem; + mpool_lock(mp); for (i = 0; i < MEM_BUCKETS; i++) { TAILQ_INIT(&mp->pool_active[i]); @@ -146,8 +149,6 @@ pullInactive(mpool_t * __restrict mp, int idx) /* clear name */ *m->alloc_name = 0; - /* clear flags */ - m->alloc_flags ^= m->alloc_flags; } return m; @@ -165,7 +166,8 @@ void * mpool_malloc(mpool_t * __restrict mp, u_int size, const char *memname) { struct tagAlloc *m; - int idx, align; + int idx; + u_int align; if (!mp) { sess_SetErr(EINVAL, "Pool not specified"); @@ -228,6 +230,117 @@ mpool_malloc(mpool_t * __restrict mp, u_int size, cons } /* + * mpool_realloc() Reallocate memory block with new size + * + * @mp = Memory pool + * @data = Allocated memory data + * @newsize = New size of memory block + * @memname = Optional new memory block name + * return: NULL error or !=NULL new reallocated memory block + */ +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; + + /* if !data execute mpool_malloc() */ + if (!data) + return mpool_malloc(mp, newsize, memname); + + if (!mp) { + sess_SetErr(EINVAL, "Pool not specified"); + return NULL; + } + /* check address range & sentinel */ + if (MEM_BADADDR(data) || MEM_CORRUPT(data)) { + sess_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) { + sess_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); + + /* quota */ + if (mp->pool_quota.max && + (mp->pool_quota.curr + ((u_long) newsize - osize)) > mp->pool_quota.max) { + sess_SetErr(ENOMEM, "Max.allocate memory quota has been reached"); + mpool_unlock(mp); + 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) { + mpool_unlock(mp); + sess_SetErr(EFAULT, "Memory block not found"); + 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; + + /* 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; + + mpool_unlock(mp); + return NULL; + } else + m->alloc_mem = (u_int*) p; + } + /* quota */ + 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++; + } + mp->pool_bytes.alloc += newsize; + + if (memname) + strlcpy(m->alloc_name, memname, sizeof m->alloc_name); + + mpool_unlock(mp); + return mem_data(m, void*); +} + +/* * mpool_purge() - Purge memory block cache and release resources * * @mp = Memory pool @@ -235,9 +348,9 @@ mpool_malloc(mpool_t * __restrict mp, u_int size, cons * return: -1 error or 0 ok */ int -mpool_purge(mpool_t * __restrict mp, int atmost) +mpool_purge(mpool_t * __restrict mp, u_int atmost) { - register int i, cx = 0; + register int i, cx; struct tagAlloc *m, *tmp; if (!mp) { @@ -247,11 +360,13 @@ mpool_purge(mpool_t * __restrict mp, int atmost) mpool_lock(mp); - for (i = 0; i < MEM_BUCKETS; i++) { + for (i = cx = 0; i < MEM_BUCKETS; cx = 0, i++) { TAILQ_FOREACH_SAFE(m, &mp->pool_inactive[i], alloc_node, tmp) { - /* count barrier for purge */ - if (cx++ < atmost) + /* barrier for purge */ + if (cx < atmost) { + cx++; continue; + } TAILQ_REMOVE(&mp->pool_inactive[i], m, alloc_node); /* statistics */ @@ -285,7 +400,7 @@ int mpool_free(mpool_t * __restrict mp, void * __restrict data, int purge) { int idx; - struct tagAlloc *m; + struct tagAlloc *m, *tmp; if (!mp) { sess_SetErr(EINVAL, "Pool not specified"); @@ -296,10 +411,10 @@ mpool_free(mpool_t * __restrict mp, void * __restrict sess_SetErr(EFAULT, "Corrupted memory address"); return -2; } else - idx = BucketIndex(((u_int*)data)[-2]); + idx = BucketIndex(((u_int*)data)[-2] * sizeof(u_int)); mpool_lock(mp); - TAILQ_FOREACH(m, &mp->pool_active[idx], alloc_node) + TAILQ_FOREACH_SAFE(m, &mp->pool_active[idx], alloc_node, tmp) if (mem_data(m, void*) == data) { TAILQ_REMOVE(&mp->pool_active[idx], m, alloc_node); /* statistics */ @@ -342,7 +457,7 @@ int mpool_free2(mpool_t * __restrict mp, u_int size, const char *memname, int purge) { int idx; - struct tagAlloc *m; + struct tagAlloc *m, *tmp; if (!mp || !memname) { sess_SetErr(EINVAL, "Pool or memory name is not specified"); @@ -351,7 +466,7 @@ mpool_free2(mpool_t * __restrict mp, u_int size, const idx = BucketIndex(size); mpool_lock(mp); - TAILQ_FOREACH(m, &mp->pool_active[idx], alloc_node) + TAILQ_FOREACH_SAFE(m, &mp->pool_active[idx], alloc_node, tmp) if (!strcmp(m->alloc_name, memname)) { TAILQ_REMOVE(&mp->pool_active[idx], m, alloc_node); /* statistics */ @@ -438,4 +553,79 @@ mpool_chkaddr(void * __restrict data) return 1; /* data address is ok! */ return 0; +} + +/* + * mpool_setquota() - Change maximum memory quota + * + * @mp = Memory pool + * @maxmem = New max quota size + * return: old maximum memory quota size + */ +inline u_long +mpool_setquota(mpool_t * __restrict mp, u_long maxmem) +{ + u_long ret; + + if (!mp) + return 0; + + ret = mp->pool_quota.max; + mp->pool_quota.max = maxmem; + + /* if new max quota is less then current allocated memory, + * try to purge memory cache blocks + */ + if (mp->pool_quota.max < mp->pool_quota.curr) + mpool_purge(mp, 0); + + return ret; +} + +/* + * mpool_getquota() - Get memory quota + * + * @mp = Memory pool + * @currmem = Return current memory + * @maxmem = Return max quota size + * return: none + */ +inline void +mpool_getquota(mpool_t * __restrict mp, u_long *currmem, u_long *maxmem) +{ + if (!mp) + return; + + if (maxmem) + *maxmem = mp->pool_quota.max; + if (currmem) + *currmem = mp->pool_quota.curr; +} + +/* ----------------------------------------------------------- */ + +/* + * mpool_statistics() - Dump statistics from memory pool buckets + * + * @mp = Memory pool + * @cb = Export statistics to callback + * return: none + */ +void +mpool_statistics(mpool_t * __restrict mp, mpool_stat_cb cb) +{ + struct tagAlloc *m; + register int i, act, inact; + + if (!mp || !cb) + return; + + for (i = act = inact = 0; i < MEM_BUCKETS; act = inact = 0, i++) { + TAILQ_FOREACH(m, &mp->pool_active[i], alloc_node) + act++; + TAILQ_FOREACH(m, &mp->pool_inactive[i], alloc_node) + inact++; + + cb(1 << (i + MEM_MIN_BUCKET), act, inact); + } }