version 1.3, 2014/01/29 14:16:54
|
version 1.11, 2024/10/28 09:58:51
|
Line 12 terms:
|
Line 12 terms:
|
All of the documentation and software included in the ELWIX and AITNET |
All of the documentation and software included in the ELWIX and AITNET |
Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org> |
Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org> |
|
|
Copyright 2004 - 2014 | Copyright 2004 - 2024 |
by Michael Pounov <misho@elwix.org>. All rights reserved. |
by Michael Pounov <misho@elwix.org>. All rights reserved. |
|
|
Redistribution and use in source and binary forms, with or without |
Redistribution and use in source and binary forms, with or without |
Line 91 mpool_init(u_long maxmem)
|
Line 91 mpool_init(u_long maxmem)
|
void |
void |
mpool_destroy(mpool_t ** __restrict mp) |
mpool_destroy(mpool_t ** __restrict mp) |
{ |
{ |
struct tagAlloc *m; | struct tagAlloc *m, *n; |
register int i; |
register int i; |
|
|
if (!mp && !*mp) | if (!mp || !*mp) |
return; |
return; |
|
|
mpool_lock(*mp); |
mpool_lock(*mp); |
|
|
for (i = 0; i < MEM_BUCKETS; i++) { |
for (i = 0; i < MEM_BUCKETS; i++) { |
while ((m = TAILQ_FIRST(&(*mp)->pool_active[i]))) { | for (m = TAILQ_FIRST(&(*mp)->pool_active[i]); m; m = n) { |
TAILQ_REMOVE(&(*mp)->pool_active[i], m, alloc_node); | n = TAILQ_NEXT(m, alloc_node); |
if (m->alloc_mem) |
if (m->alloc_mem) |
free(m->alloc_mem); |
free(m->alloc_mem); |
free(m); |
free(m); |
} |
} |
while ((m = TAILQ_FIRST(&(*mp)->pool_inactive[i]))) { | for (m = TAILQ_FIRST(&(*mp)->pool_inactive[i]); m; m = n) { |
TAILQ_REMOVE(&(*mp)->pool_inactive[i], m, alloc_node); | n = TAILQ_NEXT(m, alloc_node); |
if (m->alloc_mem) |
if (m->alloc_mem) |
free(m->alloc_mem); |
free(m->alloc_mem); |
free(m); |
free(m); |
Line 218 mpool_malloc(mpool_t * __restrict mp, u_int size, cons
|
Line 218 mpool_malloc(mpool_t * __restrict mp, u_int size, cons
|
return NULL; |
return NULL; |
} else { /* quota */ |
} else { /* quota */ |
mp->pool_quota.curr += size; |
mp->pool_quota.curr += size; |
|
mp->pool_quota.real += 1 << (idx + MEM_MIN_BUCKET); |
|
#ifdef MPOOL_MEM_ZERO |
memset(m->alloc_mem, 0, align + 12); |
memset(m->alloc_mem, 0, align + 12); |
|
#endif |
} |
} |
} |
} |
|
|
Line 235 mpool_malloc(mpool_t * __restrict mp, u_int size, cons
|
Line 238 mpool_malloc(mpool_t * __restrict mp, u_int size, cons
|
} |
} |
|
|
/* |
/* |
|
* mpool_calloc() - Multiple memory block allocation |
|
* |
|
* @mp = Memory pool |
|
* @nmemb = Number of memory blocks |
|
* @size = Size |
|
* @memname = Optional memory block name |
|
* return: NULL error or !=NULL ok allocated memory |
|
*/ |
|
void * |
|
mpool_calloc(mpool_t * __restrict mp, u_int nmemb, u_int size, const char *memname) |
|
{ |
|
void *m; |
|
u_int total = nmemb * size; |
|
|
|
m = mpool_malloc(mp, total, memname); |
|
#ifndef MPOOL_MEM_ZERO |
|
if (m) |
|
memset(m, 0, total); |
|
#endif |
|
return m; |
|
} |
|
|
|
/* |
* mpool_realloc() Reallocate memory block with new size |
* mpool_realloc() Reallocate memory block with new size |
* |
* |
* @mp = Memory pool |
* @mp = Memory pool |
Line 246 mpool_malloc(mpool_t * __restrict mp, u_int size, cons
|
Line 272 mpool_malloc(mpool_t * __restrict mp, u_int size, cons
|
void * |
void * |
mpool_realloc(mpool_t * __restrict mp, void * __restrict data, u_int newsize, const char *memname) |
mpool_realloc(mpool_t * __restrict mp, void * __restrict data, u_int newsize, const char *memname) |
{ |
{ |
struct tagAlloc *m, *tmp; |
|
int idx, oidx; |
int idx, oidx; |
void *p; |
void *p; |
u_int align, osize; | u_int osize; |
|
|
/* if !data execute mpool_malloc() */ |
/* if !data execute mpool_malloc() */ |
if (!data) |
if (!data) |
Line 263 mpool_realloc(mpool_t * __restrict mp, void * __restri
|
Line 288 mpool_realloc(mpool_t * __restrict mp, void * __restri
|
if (MEM_BADADDR(data) || MEM_CORRUPT(data)) { |
if (MEM_BADADDR(data) || MEM_CORRUPT(data)) { |
elwix_SetErr(EFAULT, "Corrupted memory address"); |
elwix_SetErr(EFAULT, "Corrupted memory address"); |
return NULL; |
return NULL; |
} else { |
|
osize = ((u_int*)data)[-2] * sizeof(u_int); |
|
oidx = BucketIndex(osize); |
|
} |
} |
/* prepare new size */ |
/* prepare new size */ |
if (newsize > MEM_ALLOC_MAX) { |
if (newsize > MEM_ALLOC_MAX) { |
elwix_SetErr(ENOMEM, "Memory size is too large"); |
elwix_SetErr(ENOMEM, "Memory size is too large"); |
return NULL; |
return NULL; |
} else { |
|
newsize = (newsize + 3) & ~3; /* must align to 4 because needed room for sentinels */ |
|
idx = BucketIndex(newsize); |
|
} |
} |
|
|
mpool_lock(mp); |
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 */ |
/* quota */ |
if (mp->pool_quota.max && |
if (mp->pool_quota.max && |
(mp->pool_quota.curr + ((u_long) newsize - osize)) > mp->pool_quota.max) { |
(mp->pool_quota.curr + ((u_long) newsize - osize)) > mp->pool_quota.max) { |
Line 286 mpool_realloc(mpool_t * __restrict mp, void * __restri
|
Line 310 mpool_realloc(mpool_t * __restrict mp, void * __restri
|
return NULL; |
return NULL; |
} |
} |
|
|
/* find old memory block */ | if (oidx != idx) { |
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); |
mpool_unlock(mp); |
elwix_SetErr(EFAULT, "Memory block not found"); | p = mpool_malloc(mp, newsize, memname); |
return NULL; | if (!p) |
} | return NULL; |
|
|
/* try to reallocate memory block to new bucket */ | memcpy(p, data, MIN(osize, newsize)); |
if (oidx != idx) { | mpool_free(mp, data, 0); |
align = 1 << (idx + MEM_MIN_BUCKET); | } else { |
p = realloc(m->alloc_mem, align + 12); | p = data; |
if (!p) { | |
LOGERR; | |
|
|
/* restore to old bucket pulled memory block for reallocation */ | ((u_int*) p)[-2] = newsize / sizeof(u_int); |
TAILQ_INSERT_HEAD(&mp->pool_active[oidx], m, alloc_node); | ((u_int*) p)[newsize / sizeof(u_int)] = MEM_MAGIC_STOP; |
/* statistics */ | |
mp->pool_calls.alloc++; | |
mp->pool_bytes.alloc += osize; | |
|
|
mpool_unlock(mp); | mp->pool_bytes.alloc += (u_long) newsize - osize; |
return NULL; | mp->pool_quota.curr += (u_long) newsize - osize; |
} else | |
m->alloc_mem = (u_int*) p; | |
} | |
/* quota */ | |
mp->pool_quota.curr += (u_long) newsize - osize; | |
|
|
m->alloc_mem[0] = newsize / sizeof(u_int); | mpool_unlock(mp); |
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) | return p; |
strlcpy(m->alloc_name, memname, sizeof m->alloc_name); | |
| |
mpool_unlock(mp); | |
return mem_data(m, void*); | |
} |
} |
|
|
/* |
/* |
Line 382 mpool_purge(mpool_t * __restrict mp, u_int atmost)
|
Line 370 mpool_purge(mpool_t * __restrict mp, u_int atmost)
|
mp->pool_bytes.free += mem_size(m); |
mp->pool_bytes.free += mem_size(m); |
/* quota */ |
/* quota */ |
mp->pool_quota.curr -= mem_size(m); |
mp->pool_quota.curr -= mem_size(m); |
|
mp->pool_quota.real -= 1 << (i + MEM_MIN_BUCKET); |
|
|
if (m->alloc_mem) |
if (m->alloc_mem) |
free(m->alloc_mem); |
free(m->alloc_mem); |
Line 407 mpool_free(mpool_t * __restrict mp, void * __restrict
|
Line 396 mpool_free(mpool_t * __restrict mp, void * __restrict
|
int idx; |
int idx; |
struct tagAlloc *m, *tmp; |
struct tagAlloc *m, *tmp; |
|
|
assert(data); | if (!data) |
| return 0; |
if (!mp) { |
if (!mp) { |
elwix_SetErr(EINVAL, "Pool not specified"); |
elwix_SetErr(EINVAL, "Pool not specified"); |
return -1; |
return -1; |
Line 439 mpool_free(mpool_t * __restrict mp, void * __restrict
|
Line 429 mpool_free(mpool_t * __restrict mp, void * __restrict
|
mp->pool_bytes.free += mem_size(m); |
mp->pool_bytes.free += mem_size(m); |
/* quota */ |
/* quota */ |
mp->pool_quota.curr -= mem_size(m); |
mp->pool_quota.curr -= mem_size(m); |
|
mp->pool_quota.real -= 1 << (idx + MEM_MIN_BUCKET); |
|
|
if (m->alloc_mem) |
if (m->alloc_mem) |
free(m->alloc_mem); |
free(m->alloc_mem); |
Line 491 mpool_free2(mpool_t * __restrict mp, u_int size, const
|
Line 482 mpool_free2(mpool_t * __restrict mp, u_int size, const
|
mp->pool_bytes.free += mem_size(m); |
mp->pool_bytes.free += mem_size(m); |
/* quota */ |
/* quota */ |
mp->pool_quota.curr -= mem_size(m); |
mp->pool_quota.curr -= mem_size(m); |
|
mp->pool_quota.real -= 1 << (idx + MEM_MIN_BUCKET); |
|
|
if (m->alloc_mem) |
if (m->alloc_mem) |
free(m->alloc_mem); |
free(m->alloc_mem); |
Line 626 mpool_setquota(mpool_t * __restrict mp, u_long maxmem)
|
Line 618 mpool_setquota(mpool_t * __restrict mp, u_long maxmem)
|
* mpool_getquota() - Get memory quota |
* mpool_getquota() - Get memory quota |
* |
* |
* @mp = Memory pool |
* @mp = Memory pool |
* @currmem = Return current memory | * @currmem = Return current memory usage |
| * @realmem = Return current real memory usage |
* @maxmem = Return max quota size |
* @maxmem = Return max quota size |
* return: none |
* return: none |
*/ |
*/ |
void |
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) |
if (!mp) |
return; |
return; |
|
|
if (maxmem) |
if (maxmem) |
*maxmem = mp->pool_quota.max; |
*maxmem = mp->pool_quota.max; |
|
if (realmem) |
|
*realmem = mp->pool_quota.real; |
if (currmem) |
if (currmem) |
*currmem = mp->pool_quota.curr; |
*currmem = mp->pool_quota.curr; |
} |
} |
Line 649 mpool_getquota(mpool_t * __restrict mp, u_long *currme
|
Line 644 mpool_getquota(mpool_t * __restrict mp, u_long *currme
|
* |
* |
* @mp = Memory pool |
* @mp = Memory pool |
* @cb = Export statistics to callback |
* @cb = Export statistics to callback |
* return: none | * return: -1 error or >0 bytes in data buffer |
*/ |
*/ |
void | int |
mpool_statistics(mpool_t * __restrict mp, mpool_stat_cb cb) | mpool_statistics(mpool_t * __restrict mp, mpool_stat_cb cb, void *data, u_int datlen) |
{ |
{ |
struct tagAlloc *m; |
struct tagAlloc *m; |
register int i, act, inact; |
register int i, act, inact; |
|
int len = 0; |
|
|
if (!mp || !cb) |
if (!mp || !cb) |
return; | return -1; |
|
|
for (i = act = inact = 0; i < MEM_BUCKETS; act = inact = 0, i++) { |
for (i = act = inact = 0; i < MEM_BUCKETS; act = inact = 0, i++) { |
TAILQ_FOREACH(m, &mp->pool_active[i], alloc_node) |
TAILQ_FOREACH(m, &mp->pool_active[i], alloc_node) |
Line 666 mpool_statistics(mpool_t * __restrict mp, mpool_stat_c
|
Line 662 mpool_statistics(mpool_t * __restrict mp, mpool_stat_c
|
TAILQ_FOREACH(m, &mp->pool_inactive[i], alloc_node) |
TAILQ_FOREACH(m, &mp->pool_inactive[i], alloc_node) |
inact++; |
inact++; |
|
|
cb(1 << (i + MEM_MIN_BUCKET), act, inact); | len += cb(1 << (i + MEM_MIN_BUCKET), act, inact, data, datlen); |
} |
} |
|
|
|
return len; |
} |
} |
|
|
/* ----------------------------------------------------------- */ |
/* ----------------------------------------------------------- */ |
Line 694 mpool_xmalloc(size_t size)
|
Line 692 mpool_xmalloc(size_t size)
|
void * |
void * |
mpool_xcalloc(size_t num, size_t size) |
mpool_xcalloc(size_t num, size_t size) |
{ |
{ |
return mpool_malloc(elwix_mpool, num * size, elwix_Prog); | return mpool_calloc(elwix_mpool, num, size, elwix_Prog); |
} |
} |
|
|
/* |
/* |
Line 732 char *
|
Line 730 char *
|
mpool_xstrdup(const char *str) |
mpool_xstrdup(const char *str) |
{ |
{ |
return mpool_strdup(elwix_mpool, str, elwix_Prog); |
return mpool_strdup(elwix_mpool, str, elwix_Prog); |
|
} |
|
|
|
/* |
|
* mpool_xstatistics() - elwix default memory pool statistics wrapper |
|
* |
|
* @cb = Export statistics to callback |
|
* @data = data buffer |
|
* @datlen = data buffer length |
|
* return: >0 data in string buffer |
|
*/ |
|
int |
|
mpool_xstatistics(mpool_stat_cb cb, void *data, u_int datlen) |
|
{ |
|
return mpool_statistics(elwix_mpool, cb, data, datlen); |
|
} |
|
|
|
static int |
|
xdump_show(u_int size, u_int act, u_int inact, void *data, u_int datlen) |
|
{ |
|
if (!act && !inact) |
|
return 0; /* 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); |
|
|
|
return 0; |
|
} |
|
|
|
static int |
|
xdump_show2(u_int size, u_int act, u_int inact, void *data, u_int datlen) |
|
{ |
|
char szStr[STRSIZ], *str = data; |
|
int len = 0; |
|
|
|
if (!data || !datlen) |
|
return 0; /* skip missing data buffer */ |
|
if (!act && !inact) |
|
return 0; /* skip empty bucket */ |
|
|
|
if (size < 1024) |
|
len = snprintf(szStr, sizeof szStr, "\t\t* BUCKET %uB size, %u active, %u inactive\n", |
|
size, act, inact); |
|
else if (size < 1048576) |
|
len = snprintf(szStr, sizeof szStr, "\t\t* BUCKET %uKB size, %u active, %u inactive\n", |
|
size / 1024, act, inact); |
|
else |
|
len = snprintf(szStr, sizeof szStr, "\t\t* BUCKET %uMB size, %u active, %u inactive\n", |
|
size / 1048576, act, inact); |
|
|
|
strlcat(str, szStr, datlen); |
|
return len; |
|
} |
|
|
|
/* |
|
* 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 %p ::\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", mp, |
|
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, NULL, 0); |
|
printf("------------------------------------------------------------\n"); |
|
} |
|
|
|
/* |
|
* mpool_dump2() - Dump elwix memory pool statistics to string |
|
* |
|
* @mp = memory pool, if =NULL dump elwix default memory pool |
|
* @str = string buffer |
|
* @strlen = string buffer length |
|
* return: >0 data in string buffer |
|
*/ |
|
int |
|
mpool_dump2(mpool_t * __restrict mp, char *str, int strlen) |
|
{ |
|
int len; |
|
mpool_t *p = mp ? mp : elwix_mpool; |
|
|
|
len = snprintf(str, strlen, |
|
"------------------------------------------------------------\n"); |
|
len += snprintf(str + len, strlen - len, " ELWIX memory pool %p ::\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", mp, |
|
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); |
|
len += mpool_statistics(p, xdump_show2, str + len, strlen - len); |
|
len += snprintf(str + len, strlen - len, |
|
"------------------------------------------------------------\n"); |
|
|
|
return len; |
} |
} |