Annotation of libelwix/src/mem.c, revision 1.5
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.5 ! misho 6: * $Id: mem.c,v 1.4.18.5 2015/06/25 17:52:41 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.5 ! misho 15: Copyright 2004 - 2015
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:
97: if (!mp && !*mp)
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.1 misho 222: memset(m->alloc_mem, 0, align + 12);
223: }
224: }
225:
226: m->alloc_mem[0] = size / sizeof(u_int);
227: m->alloc_mem[1] = MEM_MAGIC_START;
228: m->alloc_mem[2 + size / sizeof(u_int)] = MEM_MAGIC_STOP;
229: TAILQ_INSERT_HEAD(&mp->pool_active[idx], m, alloc_node);
230: /* statistics */
231: mp->pool_calls.alloc++;
232: mp->pool_bytes.alloc += size;
233:
234: mpool_unlock(mp);
235: return mem_data(m, void*);
236: }
237:
238: /*
239: * mpool_realloc() Reallocate memory block with new size
240: *
241: * @mp = Memory pool
242: * @data = Allocated memory data
243: * @newsize = New size of memory block
244: * @memname = Optional new memory block name
245: * return: NULL error or !=NULL new reallocated memory block
246: */
247: void *
248: mpool_realloc(mpool_t * __restrict mp, void * __restrict data, u_int newsize, const char *memname)
249: {
250: struct tagAlloc *m, *tmp;
251: int idx, oidx;
252: void *p;
253: u_int align, osize;
254:
255: /* if !data execute mpool_malloc() */
256: if (!data)
257: return mpool_malloc(mp, newsize, memname);
258:
259: if (!mp) {
260: elwix_SetErr(EINVAL, "Pool not specified");
261: return NULL;
262: }
263: /* check address range & sentinel */
264: if (MEM_BADADDR(data) || MEM_CORRUPT(data)) {
265: elwix_SetErr(EFAULT, "Corrupted memory address");
266: return NULL;
267: } else {
268: osize = ((u_int*)data)[-2] * sizeof(u_int);
269: oidx = BucketIndex(osize);
270: }
271: /* prepare new size */
272: if (newsize > MEM_ALLOC_MAX) {
273: elwix_SetErr(ENOMEM, "Memory size is too large");
274: return NULL;
275: } else {
276: newsize = (newsize + 3) & ~3; /* must align to 4 because needed room for sentinels */
277: idx = BucketIndex(newsize);
278: }
279:
280: mpool_lock(mp);
281:
282: /* quota */
283: if (mp->pool_quota.max &&
284: (mp->pool_quota.curr + ((u_long) newsize - osize)) > mp->pool_quota.max) {
285: elwix_SetErr(ENOMEM, "Max.allocate memory quota has been reached");
286: mpool_unlock(mp);
287: return NULL;
288: }
289:
290: /* find old memory block */
291: TAILQ_FOREACH_SAFE(m, &mp->pool_active[oidx], alloc_node, tmp) {
292: if (mem_data(m, void*) == data && mem_size(m) == osize) {
293: /* case in different buckets */
294: if (oidx != idx) {
295: TAILQ_REMOVE(&mp->pool_active[oidx], m, alloc_node);
296: /* statistics */
297: mp->pool_calls.alloc--;
298: }
299: mp->pool_bytes.alloc -= osize;
300: break;
301: }
302: }
303: /* memory block not found! */
304: if (!m) {
305: mpool_unlock(mp);
306: elwix_SetErr(EFAULT, "Memory block not found");
307: return NULL;
308: }
309:
310: /* try to reallocate memory block to new bucket */
311: if (oidx != idx) {
312: align = 1 << (idx + MEM_MIN_BUCKET);
313: p = realloc(m->alloc_mem, align + 12);
314: if (!p) {
315: LOGERR;
316:
317: /* restore to old bucket pulled memory block for reallocation */
318: TAILQ_INSERT_HEAD(&mp->pool_active[oidx], m, alloc_node);
319: /* statistics */
320: mp->pool_calls.alloc++;
321: mp->pool_bytes.alloc += osize;
322:
323: mpool_unlock(mp);
324: return NULL;
325: } else
326: m->alloc_mem = (u_int*) p;
327: }
328: /* quota */
329: mp->pool_quota.curr += (u_long) newsize - osize;
1.5 ! misho 330: mp->pool_quota.real += (1 << (idx + MEM_MIN_BUCKET)) - (1 << (oidx + MEM_MIN_BUCKET));
1.1 misho 331:
332: m->alloc_mem[0] = newsize / sizeof(u_int);
333: m->alloc_mem[1] = MEM_MAGIC_START;
334: m->alloc_mem[2 + newsize / sizeof(u_int)] = MEM_MAGIC_STOP;
335:
336: if (oidx != idx) {
337: TAILQ_INSERT_HEAD(&mp->pool_active[idx], m, alloc_node);
338: /* statistics */
339: mp->pool_calls.alloc++;
340: }
341: mp->pool_bytes.alloc += newsize;
342:
343: if (memname)
344: strlcpy(m->alloc_name, memname, sizeof m->alloc_name);
345:
346: mpool_unlock(mp);
347: return mem_data(m, void*);
348: }
349:
350: /*
351: * mpool_purge() - Purge memory block cache and release resources
352: *
353: * @mp = Memory pool
354: * @atmost = Free at most in buckets
355: * return: -1 error or 0 ok
356: */
357: int
358: mpool_purge(mpool_t * __restrict mp, u_int atmost)
359: {
360: register int i, cx;
361: struct tagAlloc *m, *tmp;
362:
363: if (!mp) {
364: elwix_SetErr(EINVAL, "Pool not specified");
365: return -1;
366: }
367:
368: mpool_lock(mp);
369:
370: for (i = cx = 0; i < MEM_BUCKETS; cx = 0, i++) {
371: TAILQ_FOREACH_SAFE(m, &mp->pool_inactive[i], alloc_node, tmp) {
372: /* barrier for purge */
373: if (cx < atmost) {
374: cx++;
375: continue;
376: }
377:
378: TAILQ_REMOVE(&mp->pool_inactive[i], m, alloc_node);
379: /* statistics */
380: mp->pool_calls.cache--;
381: mp->pool_bytes.cache -= mem_size(m);
382:
383: mp->pool_calls.free++;
384: mp->pool_bytes.free += mem_size(m);
385: /* quota */
386: mp->pool_quota.curr -= mem_size(m);
1.5 ! misho 387: mp->pool_quota.real -= 1 << (i + MEM_MIN_BUCKET);
1.1 misho 388:
389: if (m->alloc_mem)
390: free(m->alloc_mem);
391: free(m);
392: }
393: }
394:
395: mpool_unlock(mp);
396: return 0;
397: }
398:
399: /*
400: * mpool_free() Free allocated memory with mpool_alloc()
401: *
402: * @mp = Memory pool
403: * @data = Allocated memory data
404: * @purge = if !=0 force release memory block
405: * return: <0 error or 0 ok released memory block
406: */
407: int
408: mpool_free(mpool_t * __restrict mp, void * __restrict data, int purge)
409: {
410: int idx;
411: struct tagAlloc *m, *tmp;
412:
1.4 misho 413: if (!data)
414: return 0;
1.1 misho 415: if (!mp) {
416: elwix_SetErr(EINVAL, "Pool not specified");
417: return -1;
418: }
419: /* check address range & sentinel */
420: assert(!MEM_BADADDR(data) && !MEM_CORRUPT(data));
421: if (MEM_BADADDR(data) || MEM_CORRUPT(data)) {
422: elwix_SetErr(EFAULT, "Corrupted memory address");
423: return -2;
424: } else
425: idx = BucketIndex(((u_int*)data)[-2] * sizeof(u_int));
426:
427: mpool_lock(mp);
428: TAILQ_FOREACH_SAFE(m, &mp->pool_active[idx], alloc_node, tmp)
429: if (mem_data(m, void*) == data) {
430: TAILQ_REMOVE(&mp->pool_active[idx], m, alloc_node);
431: /* statistics */
432: mp->pool_calls.alloc--;
433: mp->pool_bytes.alloc -= mem_size(m);
434:
435: if (!purge) {
436: TAILQ_INSERT_HEAD(&mp->pool_inactive[idx], m, alloc_node);
437: /* statistics */
438: mp->pool_calls.cache++;
439: mp->pool_bytes.cache += mem_size(m);
440: } else {
441: /* statistics */
442: mp->pool_calls.free++;
443: mp->pool_bytes.free += mem_size(m);
444: /* quota */
445: mp->pool_quota.curr -= mem_size(m);
1.5 ! misho 446: mp->pool_quota.real -= 1 << (idx + MEM_MIN_BUCKET);
1.1 misho 447:
448: if (m->alloc_mem)
449: free(m->alloc_mem);
450: free(m);
451: }
452: break;
453: }
454: mpool_unlock(mp);
455:
456: return 0;
457: }
458:
459: /*
460: * mpool_free2() Free allocated memory with mpool_alloc() by size and memory name
461: *
462: * @mp = Memory pool
463: * @size = Allocated memory data size
464: * @memname = Memory name
465: * @purge = if !=0 force release memory block
466: * return: <0 error or 0 ok released memory block
467: */
468: int
469: mpool_free2(mpool_t * __restrict mp, u_int size, const char *memname, int purge)
470: {
471: int idx;
472: struct tagAlloc *m, *tmp;
473:
474: if (!mp || !memname) {
475: elwix_SetErr(EINVAL, "Pool or memory name is not specified");
476: return -1;
477: } else
478: idx = BucketIndex(size);
479:
480: mpool_lock(mp);
481: TAILQ_FOREACH_SAFE(m, &mp->pool_active[idx], alloc_node, tmp)
482: if (!strcmp(m->alloc_name, memname)) {
483: TAILQ_REMOVE(&mp->pool_active[idx], m, alloc_node);
484: /* statistics */
485: mp->pool_calls.alloc--;
486: mp->pool_bytes.alloc -= mem_size(m);
487:
488: if (!purge) {
489: TAILQ_INSERT_HEAD(&mp->pool_inactive[idx], m, alloc_node);
490: /* statistics */
491: mp->pool_calls.cache++;
492: mp->pool_bytes.cache += mem_size(m);
493: } else {
494: /* statistics */
495: mp->pool_calls.free++;
496: mp->pool_bytes.free += mem_size(m);
497: /* quota */
498: mp->pool_quota.curr -= mem_size(m);
1.5 ! misho 499: mp->pool_quota.real -= 1 << (idx + MEM_MIN_BUCKET);
1.1 misho 500:
501: if (m->alloc_mem)
502: free(m->alloc_mem);
503: free(m);
504: }
505: break;
506: }
507: mpool_unlock(mp);
508:
509: return 0;
510: }
511:
512: /*
513: * mpool_strdup() - String duplicate
514: *
515: * @mp = Memory pool
516: * @str = String
517: * @memname = Memory name
518: * return: NULL error or !=NULL new string
519: */
520: char *
521: mpool_strdup(mpool_t * __restrict mp, const char *str, const char *memname)
522: {
523: char *s = NULL;
524: u_int len;
525:
526: if (!mp) {
527: elwix_SetErr(EINVAL, "Pool not specified");
528: return NULL;
529: }
530: if (!str) {
531: elwix_SetErr(EINVAL, "String is NULL");
532: return NULL;
533: } else
534: len = strlen(str) + 1;
535:
536: s = mpool_malloc(mp, len, memname);
537: if (!s)
538: return NULL;
539: else
540: memcpy(s, str, len);
541:
542: return s;
543: }
544:
545: /*
546: * mpool_getmembynam() Find allocated memory block by size and memory name
547: *
548: * @mp = Memory pool
549: * @size = Memory size
550: * @memname = Memory name
551: * return: NULL error or not found and !=NULL allocated memory
552: */
1.2 misho 553: struct tagAlloc *
1.1 misho 554: mpool_getmembynam(mpool_t * __restrict mp, u_int size, const char *memname)
555: {
556: int idx;
557: struct tagAlloc *m = NULL;
558:
559: if (!mp || !memname)
560: return NULL;
561:
562: idx = BucketIndex(size);
563: TAILQ_FOREACH(m, &mp->pool_active[idx], alloc_node)
564: if (!strcmp(m->alloc_name, memname))
565: break;
566:
567: return mem_data(m, void*);
568: }
569:
570: /*
571: * mpool_getsizebyaddr() - Get size of allocated memory block by address
572: *
573: * @addr = allocated memory from mpool_malloc()
574: * return: usable size of allocated memory block
575: */
1.2 misho 576: u_int
1.1 misho 577: mpool_getsizebyaddr(void * __restrict data)
578: {
579: if (mpool_chkaddr(data))
580: return 0;
581:
582: return (((u_int*) data)[-2] * sizeof(u_int));
583: }
584:
585: /*
586: * mpool_chkaddr() - Check validity of given address
587: *
588: * @data = allocated memory from mpool_malloc()
589: * return: -1 bad address, 1 corrupted address or 0 ok
590: */
1.2 misho 591: int
1.1 misho 592: mpool_chkaddr(void * __restrict data)
593: {
594: /* check address range */
595: if (MEM_BADADDR(data))
596: return -1;
597: /* check sentinel */
598: if (MEM_CORRUPT(data))
599: return 1;
600: /* data address is ok! */
601: return 0;
602: }
603:
604: /*
605: * mpool_setquota() - Change maximum memory quota
606: *
607: * @mp = Memory pool
608: * @maxmem = New max quota size
609: * return: old maximum memory quota size
610: */
1.2 misho 611: u_long
1.1 misho 612: mpool_setquota(mpool_t * __restrict mp, u_long maxmem)
613: {
614: u_long ret;
615:
616: if (!mp)
617: return 0;
618:
619: ret = mp->pool_quota.max;
620: mp->pool_quota.max = maxmem;
621:
622: /* if new max quota is less then current allocated memory,
623: * try to purge memory cache blocks
624: */
625: if (mp->pool_quota.max < mp->pool_quota.curr)
626: mpool_purge(mp, 0);
627:
628: return ret;
629: }
630:
631: /*
632: * mpool_getquota() - Get memory quota
633: *
634: * @mp = Memory pool
1.5 ! misho 635: * @currmem = Return current memory usage
! 636: * @realmem = Return current real memory usage
1.1 misho 637: * @maxmem = Return max quota size
638: * return: none
639: */
1.2 misho 640: void
1.5 ! misho 641: mpool_getquota(mpool_t * __restrict mp, u_long *currmem, u_long *realmem, u_long *maxmem)
1.1 misho 642: {
643: if (!mp)
644: return;
645:
646: if (maxmem)
647: *maxmem = mp->pool_quota.max;
1.5 ! misho 648: if (realmem)
! 649: *realmem = mp->pool_quota.real;
1.1 misho 650: if (currmem)
651: *currmem = mp->pool_quota.curr;
652: }
653:
654: /* ----------------------------------------------------------- */
655:
656: /*
657: * mpool_statistics() - Dump statistics from memory pool buckets
658: *
659: * @mp = Memory pool
660: * @cb = Export statistics to callback
661: * return: none
662: */
663: void
664: mpool_statistics(mpool_t * __restrict mp, mpool_stat_cb cb)
665: {
666: struct tagAlloc *m;
667: register int i, act, inact;
668:
669: if (!mp || !cb)
670: return;
671:
672: for (i = act = inact = 0; i < MEM_BUCKETS; act = inact = 0, i++) {
673: TAILQ_FOREACH(m, &mp->pool_active[i], alloc_node)
674: act++;
675: TAILQ_FOREACH(m, &mp->pool_inactive[i], alloc_node)
676: inact++;
677:
678: cb(1 << (i + MEM_MIN_BUCKET), act, inact);
679: }
680: }
681:
682: /* ----------------------------------------------------------- */
683:
684: /*
685: * mpool_xmalloc() - malloc wrapper
686: *
687: * @size = Size
688: * return: NULL error or !=NULL ok allocated memory
689: */
690: void *
691: mpool_xmalloc(size_t size)
692: {
693: return mpool_malloc(elwix_mpool, size, elwix_Prog);
694: }
695:
696: /*
697: * mpool_xcalloc() - calloc wrapper
698: *
699: * @num = number of elements
700: * @size = Size of element
701: * return: NULL error or !=NULL ok allocated memory
702: */
703: void *
704: mpool_xcalloc(size_t num, size_t size)
705: {
706: return mpool_malloc(elwix_mpool, num * size, elwix_Prog);
707: }
708:
709: /*
710: * mpool_xrealloc() - realloc wrapper
711: *
712: * @data = Allocated memory data
713: * @newsize = New size of memory block
714: * return: NULL error or !=NULL new reallocated memory block
715: */
716: void *
717: mpool_xrealloc(void * __restrict data, size_t newsize)
718: {
719: return mpool_realloc(elwix_mpool, data, newsize, elwix_Prog);
720: }
721:
722: /*
723: * mpool_xfree() - free wrapper
724: *
725: * @data = Allocated memory data
726: * return: none
727: */
728: void
729: mpool_xfree(void * __restrict data)
730: {
731: mpool_free(elwix_mpool, data, 0);
732: }
733:
734: /*
735: * mpool_xstrdup() - strdup wrapper
736: *
737: * @str = string
738: * return: =NULL error or !=NULL new allocated string
739: */
740: char *
741: mpool_xstrdup(const char *str)
742: {
743: return mpool_strdup(elwix_mpool, str, elwix_Prog);
744: }
1.5 ! misho 745:
! 746: /*
! 747: * mpool_xstatistics() - elwix memory pool statistics wrapper
! 748: *
! 749: * @cb = Export statistics to callback
! 750: * return: none
! 751: */
! 752: void
! 753: mpool_xstatistics(mpool_stat_cb cb)
! 754: {
! 755: mpool_statistics(elwix_mpool, cb);
! 756: }
! 757:
! 758: static void
! 759: xdump_show(u_int size, u_int act, u_int inact)
! 760: {
! 761: if (!act && !inact)
! 762: return; /* skip empty bucket */
! 763:
! 764: if (size < 1024)
! 765: printf("\t\t* BUCKET %uB size, %u active, %u inactive\n",
! 766: size, act, inact);
! 767: else if (size < 1048576)
! 768: printf("\t\t* BUCKET %uKB size, %u active, %u inactive\n",
! 769: size / 1024, act, inact);
! 770: else
! 771: printf("\t\t* BUCKET %uMB size, %u active, %u inactive\n",
! 772: size / 1048576, act, inact);
! 773: }
! 774:
! 775: /*
! 776: * mpool_xdump() - Dump elwix memory pool statistics
! 777: *
! 778: * @fmt = format string
! 779: * @... = argument(s)
! 780: * return: none
! 781: */
! 782: void
! 783: mpool_xdump(const char *fmt, ...)
! 784: {
! 785: va_list lst;
! 786:
! 787: if (fmt) {
! 788: va_start(lst, fmt);
! 789: vprintf(fmt, lst);
! 790: va_end(lst);
! 791: } else
! 792: printf("\n%s(%d)\n", __func__, __LINE__);
! 793:
! 794: printf("------------------------------------------------------------\n");
! 795: printf( " ELWIX memory pool ::\n"
! 796: "\t- quotas Current/Real/Max = %lu/%lu/%lu\n"
! 797: "\t- calls Alloc/Free/Cache = %lu/%lu/%lu\n"
! 798: "\t- bytes Alloc/Free/Cache = %lu/%lu/%lu\n"
! 799: "\t- buckets :\n",
! 800: elwix_mpool->pool_quota.curr, elwix_mpool->pool_quota.real, elwix_mpool->pool_quota.max,
! 801: elwix_mpool->pool_calls.alloc, elwix_mpool->pool_calls.free,
! 802: elwix_mpool->pool_calls.cache, elwix_mpool->pool_bytes.alloc,
! 803: elwix_mpool->pool_bytes.free, elwix_mpool->pool_bytes.cache);
! 804:
! 805: mpool_statistics(elwix_mpool, xdump_show);
! 806: printf("------------------------------------------------------------\n");
! 807: }
! 808:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>