Annotation of libelwix/src/mem.c, revision 1.10
1.1 misho 1: /*************************************************************************
2: * (C) 2012 AITNET ltd - Sofia/Bulgaria - <misho@elwix.org>
3: * by Michael Pounov <misho@openbsd-bg.org>
4: *
5: * $Author: misho $
1.10 ! misho 6: * $Id: mem.c,v 1.9.12.1 2024/08/14 16:01:10 misho Exp $
1.1 misho 7: *
8: **************************************************************************
9: The ELWIX and AITNET software is distributed under the following
10: terms:
11:
12: All of the documentation and software included in the ELWIX and AITNET
13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
14:
1.10 ! misho 15: Copyright 2004 - 2024
1.1 misho 16: by Michael Pounov <misho@elwix.org>. All rights reserved.
17:
18: Redistribution and use in source and binary forms, with or without
19: modification, are permitted provided that the following conditions
20: are met:
21: 1. Redistributions of source code must retain the above copyright
22: notice, this list of conditions and the following disclaimer.
23: 2. Redistributions in binary form must reproduce the above copyright
24: notice, this list of conditions and the following disclaimer in the
25: documentation and/or other materials provided with the distribution.
26: 3. All advertising materials mentioning features or use of this software
27: must display the following acknowledgement:
28: This product includes software developed by Michael Pounov <misho@elwix.org>
29: ELWIX - Embedded LightWeight unIX and its contributors.
30: 4. Neither the name of AITNET nor the names of its contributors
31: may be used to endorse or promote products derived from this software
32: without specific prior written permission.
33:
34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44: SUCH DAMAGE.
45: */
46: #include "global.h"
47:
48:
49: mpool_t *elwix_mpool;
50:
51:
52: /*
53: * mpool_init() - Init memory pool
54: *
55: * @maxmem = If !=0 set maximum memory quota
56: * return: =NULL error or !=NULL new allocated pool
57: */
58: mpool_t *
59: mpool_init(u_long maxmem)
60: {
61: mpool_t *mp;
62: register int i;
63:
64: mp = malloc(sizeof(mpool_t));
65: if (!mp) {
66: LOGERR;
67: return NULL;
68: } else
69: memset(mp, 0, sizeof(mpool_t));
70:
71: pthread_mutex_init(&mp->pool_mtx, NULL);
72:
73: mp->pool_quota.max = maxmem;
74:
75: mpool_lock(mp);
76: for (i = 0; i < MEM_BUCKETS; i++) {
77: TAILQ_INIT(&mp->pool_active[i]);
78: TAILQ_INIT(&mp->pool_inactive[i]);
79: }
80: mpool_unlock(mp);
81:
82: return mp;
83: }
84:
85: /*
86: * mpool_destroy() - Destroy memory pool
87: *
88: * @mp = Memory pool
89: * return: none
90: */
91: void
92: mpool_destroy(mpool_t ** __restrict mp)
93: {
94: struct tagAlloc *m;
95: register int i;
96:
1.10 ! misho 97: if (!mp || !*mp)
1.1 misho 98: return;
99:
100: mpool_lock(*mp);
101:
102: for (i = 0; i < MEM_BUCKETS; i++) {
103: while ((m = TAILQ_FIRST(&(*mp)->pool_active[i]))) {
104: TAILQ_REMOVE(&(*mp)->pool_active[i], m, alloc_node);
105: if (m->alloc_mem)
106: free(m->alloc_mem);
107: free(m);
108: }
109: while ((m = TAILQ_FIRST(&(*mp)->pool_inactive[i]))) {
110: TAILQ_REMOVE(&(*mp)->pool_inactive[i], m, alloc_node);
111: if (m->alloc_mem)
112: free(m->alloc_mem);
113: free(m);
114: }
115: }
116:
117: mpool_unlock(*mp);
118: pthread_mutex_destroy(&(*mp)->pool_mtx);
119:
120: free(*mp);
121: *mp = NULL;
122: }
123:
124: /* ----------------------------------------------------------- */
125:
126: static inline long
127: BucketIndex(u_int size)
128: {
129: register long b;
130:
131: if (!size--)
132: return 0; /* min bucket position in array */
133:
134: for (b = MEM_MIN_BUCKET; b < MEM_MAX_BUCKET; b++)
135: if (!(size >> b))
136: break;
137:
138: return b - MEM_MIN_BUCKET; /* convert to bucket array index */
139: }
140:
141: static inline struct tagAlloc *
142: pullInactive(mpool_t * __restrict mp, int idx)
143: {
144: struct tagAlloc *m = NULL;
145:
146: /* must be locked pool before use this function */
147: if ((m = TAILQ_FIRST(&mp->pool_inactive[idx]))) {
148: TAILQ_REMOVE(&mp->pool_inactive[idx], m, alloc_node);
149: /* statistics */
150: mp->pool_calls.cache--;
151: mp->pool_bytes.cache -= mem_size(m);
152:
153: /* clear name */
154: *m->alloc_name = 0;
155: }
156:
157: return m;
158: }
159:
160: /*
161: * mpool_malloc() - Memory allocation
162: *
163: * @mp = Memory pool
164: * @size = Size
165: * @memname = Optional memory block name
166: * return: NULL error or !=NULL ok allocated memory
167: */
168: void *
169: mpool_malloc(mpool_t * __restrict mp, u_int size, const char *memname)
170: {
171: struct tagAlloc *m;
172: int idx;
173: u_int align;
174:
175: if (!mp) {
176: elwix_SetErr(EINVAL, "Pool not specified");
177: return NULL;
178: }
179: if (size > MEM_ALLOC_MAX) {
180: elwix_SetErr(ENOMEM, "Memory size is too large");
181: return NULL;
182: } else
183: size = (size + 3) & ~3; /* must align to 4 because needed room for sentinels */
184:
185: idx = BucketIndex(size);
186:
187: mpool_lock(mp);
188:
189: /* get memory from cache if exists */
190: if (!(m = pullInactive(mp, idx))) {
191: /* quota */
192: if (mp->pool_quota.max &&
193: (mp->pool_quota.curr + size) > mp->pool_quota.max) {
194: elwix_SetErr(ENOMEM, "Max.allocate memory quota has been reached");
195: mpool_unlock(mp);
196: return NULL;
197: }
198:
199: m = malloc(sizeof(struct tagAlloc));
200: if (!m) {
201: LOGERR;
202: mpool_unlock(mp);
203: return NULL;
204: } else
205: memset(m, 0, sizeof(struct tagAlloc));
206: }
207:
208: if (memname)
209: strlcpy(m->alloc_name, memname, sizeof m->alloc_name);
210:
211: if (!m->alloc_mem) {
212: align = 1 << (idx + MEM_MIN_BUCKET);
213: m->alloc_mem = malloc(align + 12); /* +12 sentinel bytes */
214: if (!m->alloc_mem) {
215: LOGERR;
216: free(m);
217: mpool_unlock(mp);
218: return NULL;
219: } else { /* quota */
220: mp->pool_quota.curr += size;
1.5 misho 221: mp->pool_quota.real += 1 << (idx + MEM_MIN_BUCKET);
1.10 ! misho 222: #ifdef MPOOL_MEM_ZERO
1.1 misho 223: memset(m->alloc_mem, 0, align + 12);
1.10 ! misho 224: #endif
1.1 misho 225: }
226: }
227:
228: m->alloc_mem[0] = size / sizeof(u_int);
229: m->alloc_mem[1] = MEM_MAGIC_START;
230: m->alloc_mem[2 + size / sizeof(u_int)] = MEM_MAGIC_STOP;
231: TAILQ_INSERT_HEAD(&mp->pool_active[idx], m, alloc_node);
232: /* statistics */
233: mp->pool_calls.alloc++;
234: mp->pool_bytes.alloc += size;
235:
236: mpool_unlock(mp);
237: return mem_data(m, void*);
238: }
239:
240: /*
1.10 ! misho 241: * mpool_calloc() - Multiple memory block allocation
! 242: *
! 243: * @mp = Memory pool
! 244: * @nmemb = Number of memory blocks
! 245: * @size = Size
! 246: * @memname = Optional memory block name
! 247: * return: NULL error or !=NULL ok allocated memory
! 248: */
! 249: void *
! 250: mpool_calloc(mpool_t * __restrict mp, u_int nmemb, u_int size, const char *memname)
! 251: {
! 252: void *m;
! 253: u_int total = nmemb * size;
! 254:
! 255: m = mpool_malloc(mp, total, memname);
! 256: #ifndef MPOOL_MEM_ZERO
! 257: if (m)
! 258: memset(m, 0, total);
! 259: #endif
! 260: return m;
! 261: }
! 262:
! 263: /*
1.1 misho 264: * mpool_realloc() Reallocate memory block with new size
265: *
266: * @mp = Memory pool
267: * @data = Allocated memory data
268: * @newsize = New size of memory block
269: * @memname = Optional new memory block name
270: * return: NULL error or !=NULL new reallocated memory block
271: */
272: void *
273: mpool_realloc(mpool_t * __restrict mp, void * __restrict data, u_int newsize, const char *memname)
274: {
275: int idx, oidx;
276: void *p;
1.6 misho 277: u_int osize;
1.1 misho 278:
279: /* if !data execute mpool_malloc() */
280: if (!data)
281: return mpool_malloc(mp, newsize, memname);
282:
283: if (!mp) {
284: elwix_SetErr(EINVAL, "Pool not specified");
285: return NULL;
286: }
287: /* check address range & sentinel */
288: if (MEM_BADADDR(data) || MEM_CORRUPT(data)) {
289: elwix_SetErr(EFAULT, "Corrupted memory address");
290: return NULL;
291: }
292: /* prepare new size */
293: if (newsize > MEM_ALLOC_MAX) {
294: elwix_SetErr(ENOMEM, "Memory size is too large");
295: return NULL;
296: }
297:
298: mpool_lock(mp);
299:
1.6 misho 300: osize = ((u_int*)data)[-2] * sizeof(u_int);
301: oidx = BucketIndex(osize);
302: newsize = (newsize + 3) & ~3; /* must align to 4 because needed room for sentinels */
303: idx = BucketIndex(newsize);
304:
1.1 misho 305: /* quota */
306: if (mp->pool_quota.max &&
307: (mp->pool_quota.curr + ((u_long) newsize - osize)) > mp->pool_quota.max) {
308: elwix_SetErr(ENOMEM, "Max.allocate memory quota has been reached");
309: mpool_unlock(mp);
310: return NULL;
311: }
312:
1.6 misho 313: if (oidx != idx) {
1.1 misho 314: mpool_unlock(mp);
1.6 misho 315: p = mpool_malloc(mp, newsize, memname);
316: if (!p)
317: return NULL;
1.1 misho 318:
1.7 misho 319: memcpy(p, data, MIN(osize, newsize));
1.6 misho 320: mpool_free(mp, data, 0);
1.8 misho 321: data = p;
1.6 misho 322: } else {
323: p = data;
1.1 misho 324:
1.6 misho 325: ((u_int*) p)[-2] = newsize / sizeof(u_int);
326: ((u_int*) p)[newsize / sizeof(u_int)] = MEM_MAGIC_STOP;
1.1 misho 327:
1.6 misho 328: mp->pool_bytes.alloc += (u_long) newsize - osize;
329: mp->pool_quota.curr += (u_long) newsize - osize;
1.1 misho 330:
1.6 misho 331: mpool_unlock(mp);
1.1 misho 332: }
333:
1.6 misho 334: return p;
1.1 misho 335: }
336:
337: /*
338: * mpool_purge() - Purge memory block cache and release resources
339: *
340: * @mp = Memory pool
341: * @atmost = Free at most in buckets
342: * return: -1 error or 0 ok
343: */
344: int
345: mpool_purge(mpool_t * __restrict mp, u_int atmost)
346: {
347: register int i, cx;
348: struct tagAlloc *m, *tmp;
349:
350: if (!mp) {
351: elwix_SetErr(EINVAL, "Pool not specified");
352: return -1;
353: }
354:
355: mpool_lock(mp);
356:
357: for (i = cx = 0; i < MEM_BUCKETS; cx = 0, i++) {
358: TAILQ_FOREACH_SAFE(m, &mp->pool_inactive[i], alloc_node, tmp) {
359: /* barrier for purge */
360: if (cx < atmost) {
361: cx++;
362: continue;
363: }
364:
365: TAILQ_REMOVE(&mp->pool_inactive[i], m, alloc_node);
366: /* statistics */
367: mp->pool_calls.cache--;
368: mp->pool_bytes.cache -= mem_size(m);
369:
370: mp->pool_calls.free++;
371: mp->pool_bytes.free += mem_size(m);
372: /* quota */
373: mp->pool_quota.curr -= mem_size(m);
1.5 misho 374: mp->pool_quota.real -= 1 << (i + MEM_MIN_BUCKET);
1.1 misho 375:
376: if (m->alloc_mem)
377: free(m->alloc_mem);
378: free(m);
379: }
380: }
381:
382: mpool_unlock(mp);
383: return 0;
384: }
385:
386: /*
387: * mpool_free() Free allocated memory with mpool_alloc()
388: *
389: * @mp = Memory pool
390: * @data = Allocated memory data
391: * @purge = if !=0 force release memory block
392: * return: <0 error or 0 ok released memory block
393: */
394: int
395: mpool_free(mpool_t * __restrict mp, void * __restrict data, int purge)
396: {
397: int idx;
398: struct tagAlloc *m, *tmp;
399:
1.4 misho 400: if (!data)
401: return 0;
1.1 misho 402: if (!mp) {
403: elwix_SetErr(EINVAL, "Pool not specified");
404: return -1;
405: }
406: /* check address range & sentinel */
407: assert(!MEM_BADADDR(data) && !MEM_CORRUPT(data));
408: if (MEM_BADADDR(data) || MEM_CORRUPT(data)) {
409: elwix_SetErr(EFAULT, "Corrupted memory address");
410: return -2;
411: } else
412: idx = BucketIndex(((u_int*)data)[-2] * sizeof(u_int));
413:
414: mpool_lock(mp);
415: TAILQ_FOREACH_SAFE(m, &mp->pool_active[idx], alloc_node, tmp)
416: if (mem_data(m, void*) == data) {
417: TAILQ_REMOVE(&mp->pool_active[idx], m, alloc_node);
418: /* statistics */
419: mp->pool_calls.alloc--;
420: mp->pool_bytes.alloc -= mem_size(m);
421:
422: if (!purge) {
423: TAILQ_INSERT_HEAD(&mp->pool_inactive[idx], m, alloc_node);
424: /* statistics */
425: mp->pool_calls.cache++;
426: mp->pool_bytes.cache += mem_size(m);
427: } else {
428: /* statistics */
429: mp->pool_calls.free++;
430: mp->pool_bytes.free += mem_size(m);
431: /* quota */
432: mp->pool_quota.curr -= mem_size(m);
1.5 misho 433: mp->pool_quota.real -= 1 << (idx + MEM_MIN_BUCKET);
1.1 misho 434:
435: if (m->alloc_mem)
436: free(m->alloc_mem);
437: free(m);
438: }
439: break;
440: }
441: mpool_unlock(mp);
442:
443: return 0;
444: }
445:
446: /*
447: * mpool_free2() Free allocated memory with mpool_alloc() by size and memory name
448: *
449: * @mp = Memory pool
450: * @size = Allocated memory data size
451: * @memname = Memory name
452: * @purge = if !=0 force release memory block
453: * return: <0 error or 0 ok released memory block
454: */
455: int
456: mpool_free2(mpool_t * __restrict mp, u_int size, const char *memname, int purge)
457: {
458: int idx;
459: struct tagAlloc *m, *tmp;
460:
461: if (!mp || !memname) {
462: elwix_SetErr(EINVAL, "Pool or memory name is not specified");
463: return -1;
464: } else
465: idx = BucketIndex(size);
466:
467: mpool_lock(mp);
468: TAILQ_FOREACH_SAFE(m, &mp->pool_active[idx], alloc_node, tmp)
469: if (!strcmp(m->alloc_name, memname)) {
470: TAILQ_REMOVE(&mp->pool_active[idx], m, alloc_node);
471: /* statistics */
472: mp->pool_calls.alloc--;
473: mp->pool_bytes.alloc -= mem_size(m);
474:
475: if (!purge) {
476: TAILQ_INSERT_HEAD(&mp->pool_inactive[idx], m, alloc_node);
477: /* statistics */
478: mp->pool_calls.cache++;
479: mp->pool_bytes.cache += mem_size(m);
480: } else {
481: /* statistics */
482: mp->pool_calls.free++;
483: mp->pool_bytes.free += mem_size(m);
484: /* quota */
485: mp->pool_quota.curr -= mem_size(m);
1.5 misho 486: mp->pool_quota.real -= 1 << (idx + MEM_MIN_BUCKET);
1.1 misho 487:
488: if (m->alloc_mem)
489: free(m->alloc_mem);
490: free(m);
491: }
492: break;
493: }
494: mpool_unlock(mp);
495:
496: return 0;
497: }
498:
499: /*
500: * mpool_strdup() - String duplicate
501: *
502: * @mp = Memory pool
503: * @str = String
504: * @memname = Memory name
505: * return: NULL error or !=NULL new string
506: */
507: char *
508: mpool_strdup(mpool_t * __restrict mp, const char *str, const char *memname)
509: {
510: char *s = NULL;
511: u_int len;
512:
513: if (!mp) {
514: elwix_SetErr(EINVAL, "Pool not specified");
515: return NULL;
516: }
517: if (!str) {
518: elwix_SetErr(EINVAL, "String is NULL");
519: return NULL;
520: } else
521: len = strlen(str) + 1;
522:
523: s = mpool_malloc(mp, len, memname);
524: if (!s)
525: return NULL;
526: else
527: memcpy(s, str, len);
528:
529: return s;
530: }
531:
532: /*
533: * mpool_getmembynam() Find allocated memory block by size and memory name
534: *
535: * @mp = Memory pool
536: * @size = Memory size
537: * @memname = Memory name
538: * return: NULL error or not found and !=NULL allocated memory
539: */
1.2 misho 540: struct tagAlloc *
1.1 misho 541: mpool_getmembynam(mpool_t * __restrict mp, u_int size, const char *memname)
542: {
543: int idx;
544: struct tagAlloc *m = NULL;
545:
546: if (!mp || !memname)
547: return NULL;
548:
549: idx = BucketIndex(size);
550: TAILQ_FOREACH(m, &mp->pool_active[idx], alloc_node)
551: if (!strcmp(m->alloc_name, memname))
552: break;
553:
554: return mem_data(m, void*);
555: }
556:
557: /*
558: * mpool_getsizebyaddr() - Get size of allocated memory block by address
559: *
560: * @addr = allocated memory from mpool_malloc()
561: * return: usable size of allocated memory block
562: */
1.2 misho 563: u_int
1.1 misho 564: mpool_getsizebyaddr(void * __restrict data)
565: {
566: if (mpool_chkaddr(data))
567: return 0;
568:
569: return (((u_int*) data)[-2] * sizeof(u_int));
570: }
571:
572: /*
573: * mpool_chkaddr() - Check validity of given address
574: *
575: * @data = allocated memory from mpool_malloc()
576: * return: -1 bad address, 1 corrupted address or 0 ok
577: */
1.2 misho 578: int
1.1 misho 579: mpool_chkaddr(void * __restrict data)
580: {
581: /* check address range */
582: if (MEM_BADADDR(data))
583: return -1;
584: /* check sentinel */
585: if (MEM_CORRUPT(data))
586: return 1;
587: /* data address is ok! */
588: return 0;
589: }
590:
591: /*
592: * mpool_setquota() - Change maximum memory quota
593: *
594: * @mp = Memory pool
595: * @maxmem = New max quota size
596: * return: old maximum memory quota size
597: */
1.2 misho 598: u_long
1.1 misho 599: mpool_setquota(mpool_t * __restrict mp, u_long maxmem)
600: {
601: u_long ret;
602:
603: if (!mp)
604: return 0;
605:
606: ret = mp->pool_quota.max;
607: mp->pool_quota.max = maxmem;
608:
609: /* if new max quota is less then current allocated memory,
610: * try to purge memory cache blocks
611: */
612: if (mp->pool_quota.max < mp->pool_quota.curr)
613: mpool_purge(mp, 0);
614:
615: return ret;
616: }
617:
618: /*
619: * mpool_getquota() - Get memory quota
620: *
621: * @mp = Memory pool
1.5 misho 622: * @currmem = Return current memory usage
623: * @realmem = Return current real memory usage
1.1 misho 624: * @maxmem = Return max quota size
625: * return: none
626: */
1.2 misho 627: void
1.5 misho 628: mpool_getquota(mpool_t * __restrict mp, u_long *currmem, u_long *realmem, u_long *maxmem)
1.1 misho 629: {
630: if (!mp)
631: return;
632:
633: if (maxmem)
634: *maxmem = mp->pool_quota.max;
1.5 misho 635: if (realmem)
636: *realmem = mp->pool_quota.real;
1.1 misho 637: if (currmem)
638: *currmem = mp->pool_quota.curr;
639: }
640:
641: /* ----------------------------------------------------------- */
642:
643: /*
644: * mpool_statistics() - Dump statistics from memory pool buckets
645: *
646: * @mp = Memory pool
647: * @cb = Export statistics to callback
1.9 misho 648: * return: -1 error or >0 bytes in data buffer
1.1 misho 649: */
1.9 misho 650: int
651: mpool_statistics(mpool_t * __restrict mp, mpool_stat_cb cb, void *data, u_int datlen)
1.1 misho 652: {
653: struct tagAlloc *m;
654: register int i, act, inact;
1.9 misho 655: int len = 0;
1.1 misho 656:
657: if (!mp || !cb)
1.9 misho 658: return -1;
1.1 misho 659:
660: for (i = act = inact = 0; i < MEM_BUCKETS; act = inact = 0, i++) {
661: TAILQ_FOREACH(m, &mp->pool_active[i], alloc_node)
662: act++;
663: TAILQ_FOREACH(m, &mp->pool_inactive[i], alloc_node)
664: inact++;
665:
1.9 misho 666: len += cb(1 << (i + MEM_MIN_BUCKET), act, inact, data, datlen);
1.1 misho 667: }
1.9 misho 668:
669: return len;
1.1 misho 670: }
671:
672: /* ----------------------------------------------------------- */
673:
674: /*
675: * mpool_xmalloc() - malloc wrapper
676: *
677: * @size = Size
678: * return: NULL error or !=NULL ok allocated memory
679: */
680: void *
681: mpool_xmalloc(size_t size)
682: {
683: return mpool_malloc(elwix_mpool, size, elwix_Prog);
684: }
685:
686: /*
687: * mpool_xcalloc() - calloc wrapper
688: *
689: * @num = number of elements
690: * @size = Size of element
691: * return: NULL error or !=NULL ok allocated memory
692: */
693: void *
694: mpool_xcalloc(size_t num, size_t size)
695: {
1.10 ! misho 696: return mpool_calloc(elwix_mpool, num, size, elwix_Prog);
1.1 misho 697: }
698:
699: /*
700: * mpool_xrealloc() - realloc wrapper
701: *
702: * @data = Allocated memory data
703: * @newsize = New size of memory block
704: * return: NULL error or !=NULL new reallocated memory block
705: */
706: void *
707: mpool_xrealloc(void * __restrict data, size_t newsize)
708: {
709: return mpool_realloc(elwix_mpool, data, newsize, elwix_Prog);
710: }
711:
712: /*
713: * mpool_xfree() - free wrapper
714: *
715: * @data = Allocated memory data
716: * return: none
717: */
718: void
719: mpool_xfree(void * __restrict data)
720: {
721: mpool_free(elwix_mpool, data, 0);
722: }
723:
724: /*
725: * mpool_xstrdup() - strdup wrapper
726: *
727: * @str = string
728: * return: =NULL error or !=NULL new allocated string
729: */
730: char *
731: mpool_xstrdup(const char *str)
732: {
733: return mpool_strdup(elwix_mpool, str, elwix_Prog);
734: }
1.5 misho 735:
736: /*
1.9 misho 737: * mpool_xstatistics() - elwix default memory pool statistics wrapper
1.5 misho 738: *
739: * @cb = Export statistics to callback
1.9 misho 740: * @data = data buffer
741: * @datlen = data buffer length
742: * return: >0 data in string buffer
1.5 misho 743: */
1.9 misho 744: int
745: mpool_xstatistics(mpool_stat_cb cb, void *data, u_int datlen)
1.5 misho 746: {
1.9 misho 747: return mpool_statistics(elwix_mpool, cb, data, datlen);
1.5 misho 748: }
749:
1.9 misho 750: static int
751: xdump_show(u_int size, u_int act, u_int inact, void *data, u_int datlen)
1.5 misho 752: {
753: if (!act && !inact)
1.9 misho 754: return 0; /* skip empty bucket */
1.5 misho 755:
756: if (size < 1024)
757: printf("\t\t* BUCKET %uB size, %u active, %u inactive\n",
758: size, act, inact);
759: else if (size < 1048576)
760: printf("\t\t* BUCKET %uKB size, %u active, %u inactive\n",
761: size / 1024, act, inact);
762: else
763: printf("\t\t* BUCKET %uMB size, %u active, %u inactive\n",
764: size / 1048576, act, inact);
1.9 misho 765:
766: return 0;
767: }
768:
769: static int
770: xdump_show2(u_int size, u_int act, u_int inact, void *data, u_int datlen)
771: {
772: char szStr[STRSIZ], *str = data;
773: int len = 0;
774:
775: if (!data || !datlen)
776: return 0; /* skip missing data buffer */
777: if (!act && !inact)
778: return 0; /* skip empty bucket */
779:
780: if (size < 1024)
781: len = snprintf(szStr, sizeof szStr, "\t\t* BUCKET %uB size, %u active, %u inactive\n",
782: size, act, inact);
783: else if (size < 1048576)
784: len = snprintf(szStr, sizeof szStr, "\t\t* BUCKET %uKB size, %u active, %u inactive\n",
785: size / 1024, act, inact);
786: else
787: len = snprintf(szStr, sizeof szStr, "\t\t* BUCKET %uMB size, %u active, %u inactive\n",
788: size / 1048576, act, inact);
789:
790: strlcat(str, szStr, datlen);
791: return len;
1.5 misho 792: }
793:
794: /*
1.6 misho 795: * mpool_dump() - Dump elwix memory pool statistics
1.5 misho 796: *
1.6 misho 797: * @mp = memory pool, if =NULL dump elwix default memory pool
798: * @fmt = prefix info format string
1.5 misho 799: * @... = argument(s)
800: * return: none
801: */
802: void
1.6 misho 803: mpool_dump(mpool_t * __restrict mp, const char *fmt, ...)
1.5 misho 804: {
805: va_list lst;
1.6 misho 806: mpool_t *p = mp ? mp : elwix_mpool;
1.5 misho 807:
808: if (fmt) {
809: va_start(lst, fmt);
810: vprintf(fmt, lst);
811: va_end(lst);
812: } else
813: printf("\n%s(%d)\n", __func__, __LINE__);
814:
815: printf("------------------------------------------------------------\n");
1.9 misho 816: printf( " ELWIX memory pool %p ::\n"
1.5 misho 817: "\t- quotas Current/Real/Max = %lu/%lu/%lu\n"
818: "\t- calls Alloc/Free/Cache = %lu/%lu/%lu\n"
819: "\t- bytes Alloc/Free/Cache = %lu/%lu/%lu\n"
1.9 misho 820: "\t- buckets :\n", mp,
1.6 misho 821: p->pool_quota.curr, p->pool_quota.real, p->pool_quota.max,
822: p->pool_calls.alloc, p->pool_calls.free, p->pool_calls.cache,
823: p->pool_bytes.alloc, p->pool_bytes.free, p->pool_bytes.cache);
1.5 misho 824:
1.9 misho 825: mpool_statistics(p, xdump_show, NULL, 0);
1.5 misho 826: printf("------------------------------------------------------------\n");
827: }
828:
1.9 misho 829: /*
830: * mpool_dump2() - Dump elwix memory pool statistics to string
831: *
832: * @mp = memory pool, if =NULL dump elwix default memory pool
833: * @str = string buffer
834: * @strlen = string buffer length
835: * return: >0 data in string buffer
836: */
837: int
838: mpool_dump2(mpool_t * __restrict mp, char *str, int strlen)
839: {
840: int len;
841: mpool_t *p = mp ? mp : elwix_mpool;
842:
843: len = snprintf(str, strlen,
844: "------------------------------------------------------------\n");
845: len += snprintf(str + len, strlen - len, " ELWIX memory pool %p ::\n"
846: "\t- quotas Current/Real/Max = %lu/%lu/%lu\n"
847: "\t- calls Alloc/Free/Cache = %lu/%lu/%lu\n"
848: "\t- bytes Alloc/Free/Cache = %lu/%lu/%lu\n"
849: "\t- buckets :\n", mp,
850: p->pool_quota.curr, p->pool_quota.real, p->pool_quota.max,
851: p->pool_calls.alloc, p->pool_calls.free, p->pool_calls.cache,
852: p->pool_bytes.alloc, p->pool_bytes.free, p->pool_bytes.cache);
853: len += mpool_statistics(p, xdump_show2, str + len, strlen - len);
854: len += snprintf(str + len, strlen - len,
855: "------------------------------------------------------------\n");
856:
857: return len;
858: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>