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