1: /*
2: * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
3: * Copyright (C) 1997-2003 Internet Software Consortium.
4: *
5: * Permission to use, copy, modify, and/or distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10: * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11: * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12: * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13: * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14: * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15: * PERFORMANCE OF THIS SOFTWARE.
16: */
17:
18: /* $Id: mem.c,v 1.1.1.1 2012/05/29 12:08:38 misho Exp $ */
19:
20: /*! \file */
21:
22: #include <config.h>
23:
24: #include <stdio.h>
25: #include <stdlib.h>
26: #include <stddef.h>
27:
28: #include <limits.h>
29:
30: #include <isc/magic.h>
31: #include <isc/mem.h>
32: #include <isc/msgs.h>
33: #include <isc/once.h>
34: #include <isc/ondestroy.h>
35: #include <isc/string.h>
36: #include <isc/mutex.h>
37: #include <isc/print.h>
38: #include <isc/util.h>
39: #include <isc/xml.h>
40:
41: #define MCTXLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) LOCK(l)
42: #define MCTXUNLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) UNLOCK(l)
43:
44: #ifndef ISC_MEM_DEBUGGING
45: #define ISC_MEM_DEBUGGING 0
46: #endif
47: LIBISC_EXTERNAL_DATA unsigned int isc_mem_debugging = ISC_MEM_DEBUGGING;
48:
49: /*
50: * Constants.
51: */
52:
53: #define DEF_MAX_SIZE 1100
54: #define DEF_MEM_TARGET 4096
55: #define ALIGNMENT_SIZE 8U /*%< must be a power of 2 */
56: #define NUM_BASIC_BLOCKS 64 /*%< must be > 1 */
57: #define TABLE_INCREMENT 1024
58: #define DEBUGLIST_COUNT 1024
59:
60: /*
61: * Types.
62: */
63: #if ISC_MEM_TRACKLINES
64: typedef struct debuglink debuglink_t;
65: struct debuglink {
66: ISC_LINK(debuglink_t) link;
67: const void *ptr[DEBUGLIST_COUNT];
68: unsigned int size[DEBUGLIST_COUNT];
69: const char *file[DEBUGLIST_COUNT];
70: unsigned int line[DEBUGLIST_COUNT];
71: unsigned int count;
72: };
73:
74: #define FLARG_PASS , file, line
75: #define FLARG , const char *file, int line
76: #else
77: #define FLARG_PASS
78: #define FLARG
79: #endif
80:
81: typedef struct element element;
82: struct element {
83: element * next;
84: };
85:
86: typedef struct {
87: /*!
88: * This structure must be ALIGNMENT_SIZE bytes.
89: */
90: union {
91: size_t size;
92: isc_mem_t *ctx;
93: char bytes[ALIGNMENT_SIZE];
94: } u;
95: } size_info;
96:
97: struct stats {
98: unsigned long gets;
99: unsigned long totalgets;
100: unsigned long blocks;
101: unsigned long freefrags;
102: };
103:
104: #define MEM_MAGIC ISC_MAGIC('M', 'e', 'm', 'C')
105: #define VALID_CONTEXT(c) ISC_MAGIC_VALID(c, MEM_MAGIC)
106:
107: #if ISC_MEM_TRACKLINES
108: typedef ISC_LIST(debuglink_t) debuglist_t;
109: #endif
110:
111: /* List of all active memory contexts. */
112:
113: static ISC_LIST(isc_mem_t) contexts;
114: static isc_once_t once = ISC_ONCE_INIT;
115: static isc_mutex_t lock;
116:
117: /*%
118: * Total size of lost memory due to a bug of external library.
119: * Locked by the global lock.
120: */
121: static isc_uint64_t totallost;
122:
123: struct isc_mem {
124: unsigned int magic;
125: isc_ondestroy_t ondestroy;
126: unsigned int flags;
127: isc_mutex_t lock;
128: isc_memalloc_t memalloc;
129: isc_memfree_t memfree;
130: void * arg;
131: size_t max_size;
132: isc_boolean_t checkfree;
133: struct stats * stats;
134: unsigned int references;
135: char name[16];
136: void * tag;
137: size_t quota;
138: size_t total;
139: size_t inuse;
140: size_t maxinuse;
141: size_t hi_water;
142: size_t lo_water;
143: isc_boolean_t hi_called;
144: isc_mem_water_t water;
145: void * water_arg;
146: ISC_LIST(isc_mempool_t) pools;
147: unsigned int poolcnt;
148:
149: /* ISC_MEMFLAG_INTERNAL */
150: size_t mem_target;
151: element ** freelists;
152: element * basic_blocks;
153: unsigned char ** basic_table;
154: unsigned int basic_table_count;
155: unsigned int basic_table_size;
156: unsigned char * lowest;
157: unsigned char * highest;
158:
159: #if ISC_MEM_TRACKLINES
160: debuglist_t * debuglist;
161: unsigned int debuglistcnt;
162: #endif
163:
164: unsigned int memalloc_failures;
165: ISC_LINK(isc_mem_t) link;
166: };
167:
168: #define MEMPOOL_MAGIC ISC_MAGIC('M', 'E', 'M', 'p')
169: #define VALID_MEMPOOL(c) ISC_MAGIC_VALID(c, MEMPOOL_MAGIC)
170:
171: struct isc_mempool {
172: /* always unlocked */
173: unsigned int magic; /*%< magic number */
174: isc_mutex_t *lock; /*%< optional lock */
175: isc_mem_t *mctx; /*%< our memory context */
176: /*%< locked via the memory context's lock */
177: ISC_LINK(isc_mempool_t) link; /*%< next pool in this mem context */
178: /*%< optionally locked from here down */
179: element *items; /*%< low water item list */
180: size_t size; /*%< size of each item on this pool */
181: unsigned int maxalloc; /*%< max number of items allowed */
182: unsigned int allocated; /*%< # of items currently given out */
183: unsigned int freecount; /*%< # of items on reserved list */
184: unsigned int freemax; /*%< # of items allowed on free list */
185: unsigned int fillcount; /*%< # of items to fetch on each fill */
186: /*%< Stats only. */
187: unsigned int gets; /*%< # of requests to this pool */
188: /*%< Debugging only. */
189: #if ISC_MEMPOOL_NAMES
190: char name[16]; /*%< printed name in stats reports */
191: #endif
192: };
193:
194: /*
195: * Private Inline-able.
196: */
197:
198: #if ! ISC_MEM_TRACKLINES
199: #define ADD_TRACE(a, b, c, d, e)
200: #define DELETE_TRACE(a, b, c, d, e)
201: #else
202: #define ADD_TRACE(a, b, c, d, e) \
203: do { \
204: if ((isc_mem_debugging & (ISC_MEM_DEBUGTRACE | \
205: ISC_MEM_DEBUGRECORD)) != 0 && \
206: b != NULL) \
207: add_trace_entry(a, b, c, d, e); \
208: } while (0)
209: #define DELETE_TRACE(a, b, c, d, e) delete_trace_entry(a, b, c, d, e)
210:
211: static void
212: print_active(isc_mem_t *ctx, FILE *out);
213:
214: /*!
215: * mctx must be locked.
216: */
217: static inline void
218: add_trace_entry(isc_mem_t *mctx, const void *ptr, unsigned int size
219: FLARG)
220: {
221: debuglink_t *dl;
222: unsigned int i;
223:
224: if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
225: fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
226: ISC_MSG_ADDTRACE,
227: "add %p size %u "
228: "file %s line %u mctx %p\n"),
229: ptr, size, file, line, mctx);
230:
231: if (mctx->debuglist == NULL)
232: return;
233:
234: if (size > mctx->max_size)
235: size = mctx->max_size;
236:
237: dl = ISC_LIST_HEAD(mctx->debuglist[size]);
238: while (dl != NULL) {
239: if (dl->count == DEBUGLIST_COUNT)
240: goto next;
241: for (i = 0; i < DEBUGLIST_COUNT; i++) {
242: if (dl->ptr[i] == NULL) {
243: dl->ptr[i] = ptr;
244: dl->size[i] = size;
245: dl->file[i] = file;
246: dl->line[i] = line;
247: dl->count++;
248: return;
249: }
250: }
251: next:
252: dl = ISC_LIST_NEXT(dl, link);
253: }
254:
255: dl = malloc(sizeof(debuglink_t));
256: INSIST(dl != NULL);
257:
258: ISC_LINK_INIT(dl, link);
259: for (i = 1; i < DEBUGLIST_COUNT; i++) {
260: dl->ptr[i] = NULL;
261: dl->size[i] = 0;
262: dl->file[i] = NULL;
263: dl->line[i] = 0;
264: }
265:
266: dl->ptr[0] = ptr;
267: dl->size[0] = size;
268: dl->file[0] = file;
269: dl->line[0] = line;
270: dl->count = 1;
271:
272: ISC_LIST_PREPEND(mctx->debuglist[size], dl, link);
273: mctx->debuglistcnt++;
274: }
275:
276: static inline void
277: delete_trace_entry(isc_mem_t *mctx, const void *ptr, unsigned int size,
278: const char *file, unsigned int line)
279: {
280: debuglink_t *dl;
281: unsigned int i;
282:
283: if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
284: fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
285: ISC_MSG_DELTRACE,
286: "del %p size %u "
287: "file %s line %u mctx %p\n"),
288: ptr, size, file, line, mctx);
289:
290: if (mctx->debuglist == NULL)
291: return;
292:
293: if (size > mctx->max_size)
294: size = mctx->max_size;
295:
296: dl = ISC_LIST_HEAD(mctx->debuglist[size]);
297: while (dl != NULL) {
298: for (i = 0; i < DEBUGLIST_COUNT; i++) {
299: if (dl->ptr[i] == ptr) {
300: dl->ptr[i] = NULL;
301: dl->size[i] = 0;
302: dl->file[i] = NULL;
303: dl->line[i] = 0;
304:
305: INSIST(dl->count > 0);
306: dl->count--;
307: if (dl->count == 0) {
308: ISC_LIST_UNLINK(mctx->debuglist[size],
309: dl, link);
310: free(dl);
311: }
312: return;
313: }
314: }
315: dl = ISC_LIST_NEXT(dl, link);
316: }
317:
318: /*
319: * If we get here, we didn't find the item on the list. We're
320: * screwed.
321: */
322: INSIST(dl != NULL);
323: }
324: #endif /* ISC_MEM_TRACKLINES */
325:
326: static inline size_t
327: rmsize(size_t size) {
328: /*
329: * round down to ALIGNMENT_SIZE
330: */
331: return (size & (~(ALIGNMENT_SIZE - 1)));
332: }
333:
334: static inline size_t
335: quantize(size_t size) {
336: /*!
337: * Round up the result in order to get a size big
338: * enough to satisfy the request and be aligned on ALIGNMENT_SIZE
339: * byte boundaries.
340: */
341:
342: if (size == 0U)
343: return (ALIGNMENT_SIZE);
344: return ((size + ALIGNMENT_SIZE - 1) & (~(ALIGNMENT_SIZE - 1)));
345: }
346:
347: static inline isc_boolean_t
348: more_basic_blocks(isc_mem_t *ctx) {
349: void *new;
350: unsigned char *curr, *next;
351: unsigned char *first, *last;
352: unsigned char **table;
353: unsigned int table_size;
354: size_t increment;
355: int i;
356:
357: /* Require: we hold the context lock. */
358:
359: /*
360: * Did we hit the quota for this context?
361: */
362: increment = NUM_BASIC_BLOCKS * ctx->mem_target;
363: if (ctx->quota != 0U && ctx->total + increment > ctx->quota)
364: return (ISC_FALSE);
365:
366: INSIST(ctx->basic_table_count <= ctx->basic_table_size);
367: if (ctx->basic_table_count == ctx->basic_table_size) {
368: table_size = ctx->basic_table_size + TABLE_INCREMENT;
369: table = (ctx->memalloc)(ctx->arg,
370: table_size * sizeof(unsigned char *));
371: if (table == NULL) {
372: ctx->memalloc_failures++;
373: return (ISC_FALSE);
374: }
375: if (ctx->basic_table_size != 0) {
376: memcpy(table, ctx->basic_table,
377: ctx->basic_table_size *
378: sizeof(unsigned char *));
379: (ctx->memfree)(ctx->arg, ctx->basic_table);
380: }
381: ctx->basic_table = table;
382: ctx->basic_table_size = table_size;
383: }
384:
385: new = (ctx->memalloc)(ctx->arg, NUM_BASIC_BLOCKS * ctx->mem_target);
386: if (new == NULL) {
387: ctx->memalloc_failures++;
388: return (ISC_FALSE);
389: }
390: ctx->total += increment;
391: ctx->basic_table[ctx->basic_table_count] = new;
392: ctx->basic_table_count++;
393:
394: curr = new;
395: next = curr + ctx->mem_target;
396: for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) {
397: ((element *)curr)->next = (element *)next;
398: curr = next;
399: next += ctx->mem_target;
400: }
401: /*
402: * curr is now pointing at the last block in the
403: * array.
404: */
405: ((element *)curr)->next = NULL;
406: first = new;
407: last = first + NUM_BASIC_BLOCKS * ctx->mem_target - 1;
408: if (first < ctx->lowest || ctx->lowest == NULL)
409: ctx->lowest = first;
410: if (last > ctx->highest)
411: ctx->highest = last;
412: ctx->basic_blocks = new;
413:
414: return (ISC_TRUE);
415: }
416:
417: static inline isc_boolean_t
418: more_frags(isc_mem_t *ctx, size_t new_size) {
419: int i, frags;
420: size_t total_size;
421: void *new;
422: unsigned char *curr, *next;
423:
424: /*!
425: * Try to get more fragments by chopping up a basic block.
426: */
427:
428: if (ctx->basic_blocks == NULL) {
429: if (!more_basic_blocks(ctx)) {
430: /*
431: * We can't get more memory from the OS, or we've
432: * hit the quota for this context.
433: */
434: /*
435: * XXXRTH "At quota" notification here.
436: */
437: return (ISC_FALSE);
438: }
439: }
440:
441: total_size = ctx->mem_target;
442: new = ctx->basic_blocks;
443: ctx->basic_blocks = ctx->basic_blocks->next;
444: frags = total_size / new_size;
445: ctx->stats[new_size].blocks++;
446: ctx->stats[new_size].freefrags += frags;
447: /*
448: * Set up a linked-list of blocks of size
449: * "new_size".
450: */
451: curr = new;
452: next = curr + new_size;
453: total_size -= new_size;
454: for (i = 0; i < (frags - 1); i++) {
455: ((element *)curr)->next = (element *)next;
456: curr = next;
457: next += new_size;
458: total_size -= new_size;
459: }
460: /*
461: * Add the remaining fragment of the basic block to a free list.
462: */
463: total_size = rmsize(total_size);
464: if (total_size > 0U) {
465: ((element *)next)->next = ctx->freelists[total_size];
466: ctx->freelists[total_size] = (element *)next;
467: ctx->stats[total_size].freefrags++;
468: }
469: /*
470: * curr is now pointing at the last block in the
471: * array.
472: */
473: ((element *)curr)->next = NULL;
474: ctx->freelists[new_size] = new;
475:
476: return (ISC_TRUE);
477: }
478:
479: static inline void *
480: mem_getunlocked(isc_mem_t *ctx, size_t size) {
481: size_t new_size = quantize(size);
482: void *ret;
483:
484: if (size >= ctx->max_size || new_size >= ctx->max_size) {
485: /*
486: * memget() was called on something beyond our upper limit.
487: */
488: if (ctx->quota != 0U && ctx->total + size > ctx->quota) {
489: ret = NULL;
490: goto done;
491: }
492: ret = (ctx->memalloc)(ctx->arg, size);
493: if (ret == NULL) {
494: ctx->memalloc_failures++;
495: goto done;
496: }
497: ctx->total += size;
498: ctx->inuse += size;
499: ctx->stats[ctx->max_size].gets++;
500: ctx->stats[ctx->max_size].totalgets++;
501: /*
502: * If we don't set new_size to size, then the
503: * ISC_MEM_FILL code might write over bytes we
504: * don't own.
505: */
506: new_size = size;
507: goto done;
508: }
509:
510: /*
511: * If there are no blocks in the free list for this size, get a chunk
512: * of memory and then break it up into "new_size"-sized blocks, adding
513: * them to the free list.
514: */
515: if (ctx->freelists[new_size] == NULL && !more_frags(ctx, new_size))
516: return (NULL);
517:
518: /*
519: * The free list uses the "rounded-up" size "new_size".
520: */
521: ret = ctx->freelists[new_size];
522: ctx->freelists[new_size] = ctx->freelists[new_size]->next;
523:
524: /*
525: * The stats[] uses the _actual_ "size" requested by the
526: * caller, with the caveat (in the code above) that "size" >= the
527: * max. size (max_size) ends up getting recorded as a call to
528: * max_size.
529: */
530: ctx->stats[size].gets++;
531: ctx->stats[size].totalgets++;
532: ctx->stats[new_size].freefrags--;
533: ctx->inuse += new_size;
534:
535: done:
536:
537: #if ISC_MEM_FILL
538: if (ret != NULL)
539: memset(ret, 0xbe, new_size); /* Mnemonic for "beef". */
540: #endif
541:
542: return (ret);
543: }
544:
545: #if ISC_MEM_FILL && ISC_MEM_CHECKOVERRUN
546: static inline void
547: check_overrun(void *mem, size_t size, size_t new_size) {
548: unsigned char *cp;
549:
550: cp = (unsigned char *)mem;
551: cp += size;
552: while (size < new_size) {
553: INSIST(*cp == 0xbe);
554: cp++;
555: size++;
556: }
557: }
558: #endif
559:
560: static inline void
561: mem_putunlocked(isc_mem_t *ctx, void *mem, size_t size) {
562: size_t new_size = quantize(size);
563:
564: if (size == ctx->max_size || new_size >= ctx->max_size) {
565: /*
566: * memput() called on something beyond our upper limit.
567: */
568: #if ISC_MEM_FILL
569: memset(mem, 0xde, size); /* Mnemonic for "dead". */
570: #endif
571: (ctx->memfree)(ctx->arg, mem);
572: INSIST(ctx->stats[ctx->max_size].gets != 0U);
573: ctx->stats[ctx->max_size].gets--;
574: INSIST(size <= ctx->total);
575: ctx->inuse -= size;
576: ctx->total -= size;
577: return;
578: }
579:
580: #if ISC_MEM_FILL
581: #if ISC_MEM_CHECKOVERRUN
582: check_overrun(mem, size, new_size);
583: #endif
584: memset(mem, 0xde, new_size); /* Mnemonic for "dead". */
585: #endif
586:
587: /*
588: * The free list uses the "rounded-up" size "new_size".
589: */
590: ((element *)mem)->next = ctx->freelists[new_size];
591: ctx->freelists[new_size] = (element *)mem;
592:
593: /*
594: * The stats[] uses the _actual_ "size" requested by the
595: * caller, with the caveat (in the code above) that "size" >= the
596: * max. size (max_size) ends up getting recorded as a call to
597: * max_size.
598: */
599: INSIST(ctx->stats[size].gets != 0U);
600: ctx->stats[size].gets--;
601: ctx->stats[new_size].freefrags++;
602: ctx->inuse -= new_size;
603: }
604:
605: /*!
606: * Perform a malloc, doing memory filling and overrun detection as necessary.
607: */
608: static inline void *
609: mem_get(isc_mem_t *ctx, size_t size) {
610: char *ret;
611:
612: #if ISC_MEM_CHECKOVERRUN
613: size += 1;
614: #endif
615:
616: ret = (ctx->memalloc)(ctx->arg, size);
617: if (ret == NULL)
618: ctx->memalloc_failures++;
619:
620: #if ISC_MEM_FILL
621: if (ret != NULL)
622: memset(ret, 0xbe, size); /* Mnemonic for "beef". */
623: #else
624: # if ISC_MEM_CHECKOVERRUN
625: if (ret != NULL)
626: ret[size-1] = 0xbe;
627: # endif
628: #endif
629:
630: return (ret);
631: }
632:
633: /*!
634: * Perform a free, doing memory filling and overrun detection as necessary.
635: */
636: static inline void
637: mem_put(isc_mem_t *ctx, void *mem, size_t size) {
638: #if ISC_MEM_CHECKOVERRUN
639: INSIST(((unsigned char *)mem)[size] == 0xbe);
640: #endif
641: #if ISC_MEM_FILL
642: memset(mem, 0xde, size); /* Mnemonic for "dead". */
643: #else
644: UNUSED(size);
645: #endif
646: (ctx->memfree)(ctx->arg, mem);
647: }
648:
649: /*!
650: * Update internal counters after a memory get.
651: */
652: static inline void
653: mem_getstats(isc_mem_t *ctx, size_t size) {
654: ctx->total += size;
655: ctx->inuse += size;
656:
657: if (size > ctx->max_size) {
658: ctx->stats[ctx->max_size].gets++;
659: ctx->stats[ctx->max_size].totalgets++;
660: } else {
661: ctx->stats[size].gets++;
662: ctx->stats[size].totalgets++;
663: }
664: }
665:
666: /*!
667: * Update internal counters after a memory put.
668: */
669: static inline void
670: mem_putstats(isc_mem_t *ctx, void *ptr, size_t size) {
671: UNUSED(ptr);
672:
673: INSIST(ctx->inuse >= size);
674: ctx->inuse -= size;
675:
676: if (size > ctx->max_size) {
677: INSIST(ctx->stats[ctx->max_size].gets > 0U);
678: ctx->stats[ctx->max_size].gets--;
679: } else {
680: INSIST(ctx->stats[size].gets > 0U);
681: ctx->stats[size].gets--;
682: }
683: }
684:
685: /*
686: * Private.
687: */
688:
689: static void *
690: default_memalloc(void *arg, size_t size) {
691: UNUSED(arg);
692: if (size == 0U)
693: size = 1;
694: return (malloc(size));
695: }
696:
697: static void
698: default_memfree(void *arg, void *ptr) {
699: UNUSED(arg);
700: free(ptr);
701: }
702:
703: static void
704: initialize_action(void) {
705: RUNTIME_CHECK(isc_mutex_init(&lock) == ISC_R_SUCCESS);
706: ISC_LIST_INIT(contexts);
707: totallost = 0;
708: }
709:
710: /*
711: * Public.
712: */
713:
714: isc_result_t
715: isc_mem_createx(size_t init_max_size, size_t target_size,
716: isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
717: isc_mem_t **ctxp)
718: {
719: return (isc_mem_createx2(init_max_size, target_size, memalloc, memfree,
720: arg, ctxp, ISC_MEMFLAG_DEFAULT));
721:
722: }
723:
724: isc_result_t
725: isc_mem_createx2(size_t init_max_size, size_t target_size,
726: isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
727: isc_mem_t **ctxp, unsigned int flags)
728: {
729: isc_mem_t *ctx;
730: isc_result_t result;
731:
732: REQUIRE(ctxp != NULL && *ctxp == NULL);
733: REQUIRE(memalloc != NULL);
734: REQUIRE(memfree != NULL);
735:
736: INSIST((ALIGNMENT_SIZE & (ALIGNMENT_SIZE - 1)) == 0);
737:
738: RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
739:
740: ctx = (memalloc)(arg, sizeof(*ctx));
741: if (ctx == NULL)
742: return (ISC_R_NOMEMORY);
743:
744: if ((flags & ISC_MEMFLAG_NOLOCK) == 0) {
745: result = isc_mutex_init(&ctx->lock);
746: if (result != ISC_R_SUCCESS) {
747: (memfree)(arg, ctx);
748: return (result);
749: }
750: }
751:
752: if (init_max_size == 0U)
753: ctx->max_size = DEF_MAX_SIZE;
754: else
755: ctx->max_size = init_max_size;
756: ctx->flags = flags;
757: ctx->references = 1;
758: memset(ctx->name, 0, sizeof(ctx->name));
759: ctx->tag = NULL;
760: ctx->quota = 0;
761: ctx->total = 0;
762: ctx->inuse = 0;
763: ctx->maxinuse = 0;
764: ctx->hi_water = 0;
765: ctx->lo_water = 0;
766: ctx->hi_called = ISC_FALSE;
767: ctx->water = NULL;
768: ctx->water_arg = NULL;
769: ctx->magic = MEM_MAGIC;
770: isc_ondestroy_init(&ctx->ondestroy);
771: ctx->memalloc = memalloc;
772: ctx->memfree = memfree;
773: ctx->arg = arg;
774: ctx->stats = NULL;
775: ctx->checkfree = ISC_TRUE;
776: #if ISC_MEM_TRACKLINES
777: ctx->debuglist = NULL;
778: ctx->debuglistcnt = 0;
779: #endif
780: ISC_LIST_INIT(ctx->pools);
781: ctx->poolcnt = 0;
782: ctx->freelists = NULL;
783: ctx->basic_blocks = NULL;
784: ctx->basic_table = NULL;
785: ctx->basic_table_count = 0;
786: ctx->basic_table_size = 0;
787: ctx->lowest = NULL;
788: ctx->highest = NULL;
789:
790: ctx->stats = (memalloc)(arg,
791: (ctx->max_size+1) * sizeof(struct stats));
792: if (ctx->stats == NULL) {
793: result = ISC_R_NOMEMORY;
794: goto error;
795: }
796: memset(ctx->stats, 0, (ctx->max_size + 1) * sizeof(struct stats));
797:
798: if ((flags & ISC_MEMFLAG_INTERNAL) != 0) {
799: if (target_size == 0U)
800: ctx->mem_target = DEF_MEM_TARGET;
801: else
802: ctx->mem_target = target_size;
803: ctx->freelists = (memalloc)(arg, ctx->max_size *
804: sizeof(element *));
805: if (ctx->freelists == NULL) {
806: result = ISC_R_NOMEMORY;
807: goto error;
808: }
809: memset(ctx->freelists, 0,
810: ctx->max_size * sizeof(element *));
811: }
812:
813: #if ISC_MEM_TRACKLINES
814: if ((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0) {
815: unsigned int i;
816:
817: ctx->debuglist = (memalloc)(arg,
818: (ctx->max_size+1) * sizeof(debuglist_t));
819: if (ctx->debuglist == NULL) {
820: result = ISC_R_NOMEMORY;
821: goto error;
822: }
823: for (i = 0; i <= ctx->max_size; i++)
824: ISC_LIST_INIT(ctx->debuglist[i]);
825: }
826: #endif
827:
828: ctx->memalloc_failures = 0;
829:
830: LOCK(&lock);
831: ISC_LIST_INITANDAPPEND(contexts, ctx, link);
832: UNLOCK(&lock);
833:
834: *ctxp = ctx;
835: return (ISC_R_SUCCESS);
836:
837: error:
838: if (ctx != NULL) {
839: if (ctx->stats != NULL)
840: (memfree)(arg, ctx->stats);
841: if (ctx->freelists != NULL)
842: (memfree)(arg, ctx->freelists);
843: #if ISC_MEM_TRACKLINES
844: if (ctx->debuglist != NULL)
845: (ctx->memfree)(ctx->arg, ctx->debuglist);
846: #endif /* ISC_MEM_TRACKLINES */
847: if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
848: DESTROYLOCK(&ctx->lock);
849: (memfree)(arg, ctx);
850: }
851:
852: return (result);
853: }
854:
855: isc_result_t
856: isc_mem_create(size_t init_max_size, size_t target_size,
857: isc_mem_t **ctxp)
858: {
859: return (isc_mem_createx2(init_max_size, target_size,
860: default_memalloc, default_memfree, NULL,
861: ctxp, ISC_MEMFLAG_DEFAULT));
862: }
863:
864: isc_result_t
865: isc_mem_create2(size_t init_max_size, size_t target_size,
866: isc_mem_t **ctxp, unsigned int flags)
867: {
868: return (isc_mem_createx2(init_max_size, target_size,
869: default_memalloc, default_memfree, NULL,
870: ctxp, flags));
871: }
872:
873: static void
874: destroy(isc_mem_t *ctx) {
875: unsigned int i;
876: isc_ondestroy_t ondest;
877:
878: ctx->magic = 0;
879:
880: LOCK(&lock);
881: ISC_LIST_UNLINK(contexts, ctx, link);
882: totallost += ctx->inuse;
883: UNLOCK(&lock);
884:
885: INSIST(ISC_LIST_EMPTY(ctx->pools));
886:
887: #if ISC_MEM_TRACKLINES
888: if (ctx->debuglist != NULL) {
889: if (ctx->checkfree) {
890: for (i = 0; i <= ctx->max_size; i++) {
891: if (!ISC_LIST_EMPTY(ctx->debuglist[i]))
892: print_active(ctx, stderr);
893: INSIST(ISC_LIST_EMPTY(ctx->debuglist[i]));
894: }
895: } else {
896: debuglink_t *dl;
897:
898: for (i = 0; i <= ctx->max_size; i++)
899: for (dl = ISC_LIST_HEAD(ctx->debuglist[i]);
900: dl != NULL;
901: dl = ISC_LIST_HEAD(ctx->debuglist[i])) {
902: ISC_LIST_UNLINK(ctx->debuglist[i],
903: dl, link);
904: free(dl);
905: }
906: }
907: (ctx->memfree)(ctx->arg, ctx->debuglist);
908: }
909: #endif
910: INSIST(ctx->references == 0);
911:
912: if (ctx->checkfree) {
913: for (i = 0; i <= ctx->max_size; i++) {
914: #if ISC_MEM_TRACKLINES
915: if (ctx->stats[i].gets != 0U)
916: print_active(ctx, stderr);
917: #endif
918: INSIST(ctx->stats[i].gets == 0U);
919: }
920: }
921:
922: (ctx->memfree)(ctx->arg, ctx->stats);
923:
924: if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
925: for (i = 0; i < ctx->basic_table_count; i++)
926: (ctx->memfree)(ctx->arg, ctx->basic_table[i]);
927: (ctx->memfree)(ctx->arg, ctx->freelists);
928: if (ctx->basic_table != NULL)
929: (ctx->memfree)(ctx->arg, ctx->basic_table);
930: }
931:
932: ondest = ctx->ondestroy;
933:
934: if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
935: DESTROYLOCK(&ctx->lock);
936: (ctx->memfree)(ctx->arg, ctx);
937:
938: isc_ondestroy_notify(&ondest, ctx);
939: }
940:
941: void
942: isc_mem_attach(isc_mem_t *source, isc_mem_t **targetp) {
943: REQUIRE(VALID_CONTEXT(source));
944: REQUIRE(targetp != NULL && *targetp == NULL);
945:
946: MCTXLOCK(source, &source->lock);
947: source->references++;
948: MCTXUNLOCK(source, &source->lock);
949:
950: *targetp = source;
951: }
952:
953: void
954: isc_mem_detach(isc_mem_t **ctxp) {
955: isc_mem_t *ctx;
956: isc_boolean_t want_destroy = ISC_FALSE;
957:
958: REQUIRE(ctxp != NULL);
959: ctx = *ctxp;
960: REQUIRE(VALID_CONTEXT(ctx));
961:
962: MCTXLOCK(ctx, &ctx->lock);
963: INSIST(ctx->references > 0);
964: ctx->references--;
965: if (ctx->references == 0)
966: want_destroy = ISC_TRUE;
967: MCTXUNLOCK(ctx, &ctx->lock);
968:
969: if (want_destroy)
970: destroy(ctx);
971:
972: *ctxp = NULL;
973: }
974:
975: /*
976: * isc_mem_putanddetach() is the equivalent of:
977: *
978: * mctx = NULL;
979: * isc_mem_attach(ptr->mctx, &mctx);
980: * isc_mem_detach(&ptr->mctx);
981: * isc_mem_put(mctx, ptr, sizeof(*ptr);
982: * isc_mem_detach(&mctx);
983: */
984:
985: void
986: isc__mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) {
987: isc_mem_t *ctx;
988: isc_boolean_t want_destroy = ISC_FALSE;
989: size_info *si;
990: size_t oldsize;
991:
992: REQUIRE(ctxp != NULL);
993: ctx = *ctxp;
994: REQUIRE(VALID_CONTEXT(ctx));
995: REQUIRE(ptr != NULL);
996:
997: /*
998: * Must be before mem_putunlocked() as ctxp is usually within
999: * [ptr..ptr+size).
1000: */
1001: *ctxp = NULL;
1002:
1003: if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) {
1004: if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) {
1005: si = &(((size_info *)ptr)[-1]);
1006: oldsize = si->u.size - ALIGNMENT_SIZE;
1007: if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
1008: oldsize -= ALIGNMENT_SIZE;
1009: INSIST(oldsize == size);
1010: }
1011: isc__mem_free(ctx, ptr FLARG_PASS);
1012:
1013: MCTXLOCK(ctx, &ctx->lock);
1014: ctx->references--;
1015: if (ctx->references == 0)
1016: want_destroy = ISC_TRUE;
1017: MCTXUNLOCK(ctx, &ctx->lock);
1018: if (want_destroy)
1019: destroy(ctx);
1020:
1021: return;
1022: }
1023:
1024: if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1025: MCTXLOCK(ctx, &ctx->lock);
1026: mem_putunlocked(ctx, ptr, size);
1027: } else {
1028: mem_put(ctx, ptr, size);
1029: MCTXLOCK(ctx, &ctx->lock);
1030: mem_putstats(ctx, ptr, size);
1031: }
1032:
1033: DELETE_TRACE(ctx, ptr, size, file, line);
1034: INSIST(ctx->references > 0);
1035: ctx->references--;
1036: if (ctx->references == 0)
1037: want_destroy = ISC_TRUE;
1038:
1039: MCTXUNLOCK(ctx, &ctx->lock);
1040:
1041: if (want_destroy)
1042: destroy(ctx);
1043: }
1044:
1045: void
1046: isc_mem_destroy(isc_mem_t **ctxp) {
1047: isc_mem_t *ctx;
1048:
1049: /*
1050: * This routine provides legacy support for callers who use mctxs
1051: * without attaching/detaching.
1052: */
1053:
1054: REQUIRE(ctxp != NULL);
1055: ctx = *ctxp;
1056: REQUIRE(VALID_CONTEXT(ctx));
1057:
1058: MCTXLOCK(ctx, &ctx->lock);
1059: #if ISC_MEM_TRACKLINES
1060: if (ctx->references != 1)
1061: print_active(ctx, stderr);
1062: #endif
1063: REQUIRE(ctx->references == 1);
1064: ctx->references--;
1065: MCTXUNLOCK(ctx, &ctx->lock);
1066:
1067: destroy(ctx);
1068:
1069: *ctxp = NULL;
1070: }
1071:
1072: isc_result_t
1073: isc_mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event) {
1074: isc_result_t res;
1075:
1076: MCTXLOCK(ctx, &ctx->lock);
1077: res = isc_ondestroy_register(&ctx->ondestroy, task, event);
1078: MCTXUNLOCK(ctx, &ctx->lock);
1079:
1080: return (res);
1081: }
1082:
1083:
1084: void *
1085: isc__mem_get(isc_mem_t *ctx, size_t size FLARG) {
1086: void *ptr;
1087: isc_boolean_t call_water = ISC_FALSE;
1088:
1089: REQUIRE(VALID_CONTEXT(ctx));
1090:
1091: if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0)
1092: return (isc__mem_allocate(ctx, size FLARG_PASS));
1093:
1094: if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1095: MCTXLOCK(ctx, &ctx->lock);
1096: ptr = mem_getunlocked(ctx, size);
1097: } else {
1098: ptr = mem_get(ctx, size);
1099: MCTXLOCK(ctx, &ctx->lock);
1100: if (ptr != NULL)
1101: mem_getstats(ctx, size);
1102: }
1103:
1104: ADD_TRACE(ctx, ptr, size, file, line);
1105: if (ctx->hi_water != 0U && !ctx->hi_called &&
1106: ctx->inuse > ctx->hi_water) {
1107: call_water = ISC_TRUE;
1108: }
1109: if (ctx->inuse > ctx->maxinuse) {
1110: ctx->maxinuse = ctx->inuse;
1111: if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1112: (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
1113: fprintf(stderr, "maxinuse = %lu\n",
1114: (unsigned long)ctx->inuse);
1115: }
1116: MCTXUNLOCK(ctx, &ctx->lock);
1117:
1118: if (call_water)
1119: (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
1120:
1121: return (ptr);
1122: }
1123:
1124: void
1125: isc__mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG)
1126: {
1127: isc_boolean_t call_water = ISC_FALSE;
1128: size_info *si;
1129: size_t oldsize;
1130:
1131: REQUIRE(VALID_CONTEXT(ctx));
1132: REQUIRE(ptr != NULL);
1133:
1134: if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) {
1135: if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) {
1136: si = &(((size_info *)ptr)[-1]);
1137: oldsize = si->u.size - ALIGNMENT_SIZE;
1138: if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
1139: oldsize -= ALIGNMENT_SIZE;
1140: INSIST(oldsize == size);
1141: }
1142: isc__mem_free(ctx, ptr FLARG_PASS);
1143: return;
1144: }
1145:
1146: if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1147: MCTXLOCK(ctx, &ctx->lock);
1148: mem_putunlocked(ctx, ptr, size);
1149: } else {
1150: mem_put(ctx, ptr, size);
1151: MCTXLOCK(ctx, &ctx->lock);
1152: mem_putstats(ctx, ptr, size);
1153: }
1154:
1155: DELETE_TRACE(ctx, ptr, size, file, line);
1156:
1157: /*
1158: * The check against ctx->lo_water == 0 is for the condition
1159: * when the context was pushed over hi_water but then had
1160: * isc_mem_setwater() called with 0 for hi_water and lo_water.
1161: */
1162: if (ctx->hi_called &&
1163: (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1164: if (ctx->water != NULL)
1165: call_water = ISC_TRUE;
1166: }
1167: MCTXUNLOCK(ctx, &ctx->lock);
1168:
1169: if (call_water)
1170: (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
1171: }
1172:
1173: void
1174: isc_mem_waterack(isc_mem_t *ctx, int flag) {
1175: REQUIRE(VALID_CONTEXT(ctx));
1176:
1177: MCTXLOCK(ctx, &ctx->lock);
1178: if (flag == ISC_MEM_LOWATER)
1179: ctx->hi_called = ISC_FALSE;
1180: else if (flag == ISC_MEM_HIWATER)
1181: ctx->hi_called = ISC_TRUE;
1182: MCTXUNLOCK(ctx, &ctx->lock);
1183: }
1184:
1185: #if ISC_MEM_TRACKLINES
1186: static void
1187: print_active(isc_mem_t *mctx, FILE *out) {
1188: if (mctx->debuglist != NULL) {
1189: debuglink_t *dl;
1190: unsigned int i, j;
1191: const char *format;
1192: isc_boolean_t found;
1193:
1194: fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1195: ISC_MSG_DUMPALLOC,
1196: "Dump of all outstanding "
1197: "memory allocations:\n"));
1198: found = ISC_FALSE;
1199: format = isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1200: ISC_MSG_PTRFILELINE,
1201: "\tptr %p size %u file %s line %u\n");
1202: for (i = 0; i <= mctx->max_size; i++) {
1203: dl = ISC_LIST_HEAD(mctx->debuglist[i]);
1204:
1205: if (dl != NULL)
1206: found = ISC_TRUE;
1207:
1208: while (dl != NULL) {
1209: for (j = 0; j < DEBUGLIST_COUNT; j++)
1210: if (dl->ptr[j] != NULL)
1211: fprintf(out, format,
1212: dl->ptr[j],
1213: dl->size[j],
1214: dl->file[j],
1215: dl->line[j]);
1216: dl = ISC_LIST_NEXT(dl, link);
1217: }
1218: }
1219: if (!found)
1220: fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1221: ISC_MSG_NONE, "\tNone.\n"));
1222: }
1223: }
1224: #endif
1225:
1226: /*
1227: * Print the stats[] on the stream "out" with suitable formatting.
1228: */
1229: void
1230: isc_mem_stats(isc_mem_t *ctx, FILE *out) {
1231: size_t i;
1232: const struct stats *s;
1233: const isc_mempool_t *pool;
1234:
1235: REQUIRE(VALID_CONTEXT(ctx));
1236: MCTXLOCK(ctx, &ctx->lock);
1237:
1238: for (i = 0; i <= ctx->max_size; i++) {
1239: s = &ctx->stats[i];
1240:
1241: if (s->totalgets == 0U && s->gets == 0U)
1242: continue;
1243: fprintf(out, "%s%5lu: %11lu gets, %11lu rem",
1244: (i == ctx->max_size) ? ">=" : " ",
1245: (unsigned long) i, s->totalgets, s->gets);
1246: if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0 &&
1247: (s->blocks != 0U || s->freefrags != 0U))
1248: fprintf(out, " (%lu bl, %lu ff)",
1249: s->blocks, s->freefrags);
1250: fputc('\n', out);
1251: }
1252:
1253: /*
1254: * Note that since a pool can be locked now, these stats might be
1255: * somewhat off if the pool is in active use at the time the stats
1256: * are dumped. The link fields are protected by the isc_mem_t's
1257: * lock, however, so walking this list and extracting integers from
1258: * stats fields is always safe.
1259: */
1260: pool = ISC_LIST_HEAD(ctx->pools);
1261: if (pool != NULL) {
1262: fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1263: ISC_MSG_POOLSTATS,
1264: "[Pool statistics]\n"));
1265: fprintf(out, "%15s %10s %10s %10s %10s %10s %10s %10s %1s\n",
1266: isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1267: ISC_MSG_POOLNAME, "name"),
1268: isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1269: ISC_MSG_POOLSIZE, "size"),
1270: isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1271: ISC_MSG_POOLMAXALLOC, "maxalloc"),
1272: isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1273: ISC_MSG_POOLALLOCATED, "allocated"),
1274: isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1275: ISC_MSG_POOLFREECOUNT, "freecount"),
1276: isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1277: ISC_MSG_POOLFREEMAX, "freemax"),
1278: isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1279: ISC_MSG_POOLFILLCOUNT, "fillcount"),
1280: isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1281: ISC_MSG_POOLGETS, "gets"),
1282: "L");
1283: }
1284: while (pool != NULL) {
1285: fprintf(out, "%15s %10lu %10u %10u %10u %10u %10u %10u %s\n",
1286: pool->name, (unsigned long) pool->size, pool->maxalloc,
1287: pool->allocated, pool->freecount, pool->freemax,
1288: pool->fillcount, pool->gets,
1289: (pool->lock == NULL ? "N" : "Y"));
1290: pool = ISC_LIST_NEXT(pool, link);
1291: }
1292:
1293: #if ISC_MEM_TRACKLINES
1294: print_active(ctx, out);
1295: #endif
1296:
1297: MCTXUNLOCK(ctx, &ctx->lock);
1298: }
1299:
1300: /*
1301: * Replacements for malloc() and free() -- they implicitly remember the
1302: * size of the object allocated (with some additional overhead).
1303: */
1304:
1305: static void *
1306: isc__mem_allocateunlocked(isc_mem_t *ctx, size_t size) {
1307: size_info *si;
1308:
1309: size += ALIGNMENT_SIZE;
1310: if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
1311: size += ALIGNMENT_SIZE;
1312:
1313: if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0)
1314: si = mem_getunlocked(ctx, size);
1315: else
1316: si = mem_get(ctx, size);
1317:
1318: if (si == NULL)
1319: return (NULL);
1320: if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
1321: si->u.ctx = ctx;
1322: si++;
1323: }
1324: si->u.size = size;
1325: return (&si[1]);
1326: }
1327:
1328: void *
1329: isc__mem_allocate(isc_mem_t *ctx, size_t size FLARG) {
1330: size_info *si;
1331: isc_boolean_t call_water = ISC_FALSE;
1332:
1333: REQUIRE(VALID_CONTEXT(ctx));
1334:
1335: if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1336: MCTXLOCK(ctx, &ctx->lock);
1337: si = isc__mem_allocateunlocked(ctx, size);
1338: } else {
1339: si = isc__mem_allocateunlocked(ctx, size);
1340: MCTXLOCK(ctx, &ctx->lock);
1341: if (si != NULL)
1342: mem_getstats(ctx, si[-1].u.size);
1343: }
1344:
1345: #if ISC_MEM_TRACKLINES
1346: ADD_TRACE(ctx, si, si[-1].u.size, file, line);
1347: #endif
1348: if (ctx->hi_water != 0U && !ctx->hi_called &&
1349: ctx->inuse > ctx->hi_water) {
1350: ctx->hi_called = ISC_TRUE;
1351: call_water = ISC_TRUE;
1352: }
1353: if (ctx->inuse > ctx->maxinuse) {
1354: ctx->maxinuse = ctx->inuse;
1355: if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1356: (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
1357: fprintf(stderr, "maxinuse = %lu\n",
1358: (unsigned long)ctx->inuse);
1359: }
1360: MCTXUNLOCK(ctx, &ctx->lock);
1361:
1362: if (call_water)
1363: (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
1364:
1365: return (si);
1366: }
1367:
1368: void *
1369: isc__mem_reallocate(isc_mem_t *ctx, void *ptr, size_t size FLARG) {
1370: void *new_ptr = NULL;
1371: size_t oldsize, copysize;
1372:
1373: REQUIRE(VALID_CONTEXT(ctx));
1374:
1375: /*
1376: * This function emulates the realloc(3) standard library function:
1377: * - if size > 0, allocate new memory; and if ptr is non NULL, copy
1378: * as much of the old contents to the new buffer and free the old one.
1379: * Note that when allocation fails the original pointer is intact;
1380: * the caller must free it.
1381: * - if size is 0 and ptr is non NULL, simply free the given ptr.
1382: * - this function returns:
1383: * pointer to the newly allocated memory, or
1384: * NULL if allocation fails or doesn't happen.
1385: */
1386: if (size > 0U) {
1387: new_ptr = isc__mem_allocate(ctx, size FLARG_PASS);
1388: if (new_ptr != NULL && ptr != NULL) {
1389: oldsize = (((size_info *)ptr)[-1]).u.size;
1390: INSIST(oldsize >= ALIGNMENT_SIZE);
1391: oldsize -= ALIGNMENT_SIZE;
1392: copysize = oldsize > size ? size : oldsize;
1393: memcpy(new_ptr, ptr, copysize);
1394: isc__mem_free(ctx, ptr FLARG_PASS);
1395: }
1396: } else if (ptr != NULL)
1397: isc__mem_free(ctx, ptr FLARG_PASS);
1398:
1399: return (new_ptr);
1400: }
1401:
1402: void
1403: isc__mem_free(isc_mem_t *ctx, void *ptr FLARG) {
1404: size_info *si;
1405: size_t size;
1406: isc_boolean_t call_water= ISC_FALSE;
1407:
1408: REQUIRE(VALID_CONTEXT(ctx));
1409: REQUIRE(ptr != NULL);
1410:
1411: if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
1412: si = &(((size_info *)ptr)[-2]);
1413: REQUIRE(si->u.ctx == ctx);
1414: size = si[1].u.size;
1415: } else {
1416: si = &(((size_info *)ptr)[-1]);
1417: size = si->u.size;
1418: }
1419:
1420: if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1421: MCTXLOCK(ctx, &ctx->lock);
1422: mem_putunlocked(ctx, si, size);
1423: } else {
1424: mem_put(ctx, si, size);
1425: MCTXLOCK(ctx, &ctx->lock);
1426: mem_putstats(ctx, si, size);
1427: }
1428:
1429: DELETE_TRACE(ctx, ptr, size, file, line);
1430:
1431: /*
1432: * The check against ctx->lo_water == 0 is for the condition
1433: * when the context was pushed over hi_water but then had
1434: * isc_mem_setwater() called with 0 for hi_water and lo_water.
1435: */
1436: if (ctx->hi_called &&
1437: (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1438: ctx->hi_called = ISC_FALSE;
1439:
1440: if (ctx->water != NULL)
1441: call_water = ISC_TRUE;
1442: }
1443: MCTXUNLOCK(ctx, &ctx->lock);
1444:
1445: if (call_water)
1446: (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
1447: }
1448:
1449:
1450: /*
1451: * Other useful things.
1452: */
1453:
1454: char *
1455: isc__mem_strdup(isc_mem_t *mctx, const char *s FLARG) {
1456: size_t len;
1457: char *ns;
1458:
1459: REQUIRE(VALID_CONTEXT(mctx));
1460: REQUIRE(s != NULL);
1461:
1462: len = strlen(s);
1463:
1464: ns = isc__mem_allocate(mctx, len + 1 FLARG_PASS);
1465:
1466: if (ns != NULL)
1467: strncpy(ns, s, len + 1);
1468:
1469: return (ns);
1470: }
1471:
1472: void
1473: isc_mem_setdestroycheck(isc_mem_t *ctx, isc_boolean_t flag) {
1474: REQUIRE(VALID_CONTEXT(ctx));
1475: MCTXLOCK(ctx, &ctx->lock);
1476:
1477: ctx->checkfree = flag;
1478:
1479: MCTXUNLOCK(ctx, &ctx->lock);
1480: }
1481:
1482: /*
1483: * Quotas
1484: */
1485:
1486: void
1487: isc_mem_setquota(isc_mem_t *ctx, size_t quota) {
1488: REQUIRE(VALID_CONTEXT(ctx));
1489: MCTXLOCK(ctx, &ctx->lock);
1490:
1491: ctx->quota = quota;
1492:
1493: MCTXUNLOCK(ctx, &ctx->lock);
1494: }
1495:
1496: size_t
1497: isc_mem_getquota(isc_mem_t *ctx) {
1498: size_t quota;
1499:
1500: REQUIRE(VALID_CONTEXT(ctx));
1501: MCTXLOCK(ctx, &ctx->lock);
1502:
1503: quota = ctx->quota;
1504:
1505: MCTXUNLOCK(ctx, &ctx->lock);
1506:
1507: return (quota);
1508: }
1509:
1510: size_t
1511: isc_mem_inuse(isc_mem_t *ctx) {
1512: size_t inuse;
1513:
1514: REQUIRE(VALID_CONTEXT(ctx));
1515: MCTXLOCK(ctx, &ctx->lock);
1516:
1517: inuse = ctx->inuse;
1518:
1519: MCTXUNLOCK(ctx, &ctx->lock);
1520:
1521: return (inuse);
1522: }
1523:
1524: void
1525: isc_mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg,
1526: size_t hiwater, size_t lowater)
1527: {
1528: isc_boolean_t callwater = ISC_FALSE;
1529: isc_mem_water_t oldwater;
1530: void *oldwater_arg;
1531:
1532: REQUIRE(VALID_CONTEXT(ctx));
1533: REQUIRE(hiwater >= lowater);
1534:
1535: MCTXLOCK(ctx, &ctx->lock);
1536: oldwater = ctx->water;
1537: oldwater_arg = ctx->water_arg;
1538: if (water == NULL) {
1539: callwater = ctx->hi_called;
1540: ctx->water = NULL;
1541: ctx->water_arg = NULL;
1542: ctx->hi_water = 0;
1543: ctx->lo_water = 0;
1544: ctx->hi_called = ISC_FALSE;
1545: } else {
1546: if (ctx->hi_called &&
1547: (ctx->water != water || ctx->water_arg != water_arg ||
1548: ctx->inuse < lowater || lowater == 0U))
1549: callwater = ISC_TRUE;
1550: ctx->water = water;
1551: ctx->water_arg = water_arg;
1552: ctx->hi_water = hiwater;
1553: ctx->lo_water = lowater;
1554: ctx->hi_called = ISC_FALSE;
1555: }
1556: MCTXUNLOCK(ctx, &ctx->lock);
1557:
1558: if (callwater && oldwater != NULL)
1559: (oldwater)(oldwater_arg, ISC_MEM_LOWATER);
1560: }
1561:
1562: void
1563: isc_mem_setname(isc_mem_t *ctx, const char *name, void *tag) {
1564: REQUIRE(VALID_CONTEXT(ctx));
1565:
1566: LOCK(&ctx->lock);
1567: memset(ctx->name, 0, sizeof(ctx->name));
1568: strncpy(ctx->name, name, sizeof(ctx->name) - 1);
1569: ctx->tag = tag;
1570: UNLOCK(&ctx->lock);
1571: }
1572:
1573: const char *
1574: isc_mem_getname(isc_mem_t *ctx) {
1575: REQUIRE(VALID_CONTEXT(ctx));
1576:
1577: return (ctx->name);
1578: }
1579:
1580: void *
1581: isc_mem_gettag(isc_mem_t *ctx) {
1582: REQUIRE(VALID_CONTEXT(ctx));
1583:
1584: return (ctx->tag);
1585: }
1586:
1587: /*
1588: * Memory pool stuff
1589: */
1590:
1591: isc_result_t
1592: isc_mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp) {
1593: isc_mempool_t *mpctx;
1594:
1595: REQUIRE(VALID_CONTEXT(mctx));
1596: REQUIRE(size > 0U);
1597: REQUIRE(mpctxp != NULL && *mpctxp == NULL);
1598:
1599: /*
1600: * Allocate space for this pool, initialize values, and if all works
1601: * well, attach to the memory context.
1602: */
1603: mpctx = isc_mem_get(mctx, sizeof(isc_mempool_t));
1604: if (mpctx == NULL)
1605: return (ISC_R_NOMEMORY);
1606:
1607: mpctx->magic = MEMPOOL_MAGIC;
1608: mpctx->lock = NULL;
1609: mpctx->mctx = mctx;
1610: mpctx->size = size;
1611: mpctx->maxalloc = UINT_MAX;
1612: mpctx->allocated = 0;
1613: mpctx->freecount = 0;
1614: mpctx->freemax = 1;
1615: mpctx->fillcount = 1;
1616: mpctx->gets = 0;
1617: #if ISC_MEMPOOL_NAMES
1618: mpctx->name[0] = 0;
1619: #endif
1620: mpctx->items = NULL;
1621:
1622: *mpctxp = mpctx;
1623:
1624: MCTXLOCK(mctx, &mctx->lock);
1625: ISC_LIST_INITANDAPPEND(mctx->pools, mpctx, link);
1626: mctx->poolcnt++;
1627: MCTXUNLOCK(mctx, &mctx->lock);
1628:
1629: return (ISC_R_SUCCESS);
1630: }
1631:
1632: void
1633: isc_mempool_setname(isc_mempool_t *mpctx, const char *name) {
1634: REQUIRE(name != NULL);
1635:
1636: #if ISC_MEMPOOL_NAMES
1637: if (mpctx->lock != NULL)
1638: LOCK(mpctx->lock);
1639:
1640: strncpy(mpctx->name, name, sizeof(mpctx->name) - 1);
1641: mpctx->name[sizeof(mpctx->name) - 1] = '\0';
1642:
1643: if (mpctx->lock != NULL)
1644: UNLOCK(mpctx->lock);
1645: #else
1646: UNUSED(mpctx);
1647: UNUSED(name);
1648: #endif
1649: }
1650:
1651: void
1652: isc_mempool_destroy(isc_mempool_t **mpctxp) {
1653: isc_mempool_t *mpctx;
1654: isc_mem_t *mctx;
1655: isc_mutex_t *lock;
1656: element *item;
1657:
1658: REQUIRE(mpctxp != NULL);
1659: mpctx = *mpctxp;
1660: REQUIRE(VALID_MEMPOOL(mpctx));
1661: #if ISC_MEMPOOL_NAMES
1662: if (mpctx->allocated > 0)
1663: UNEXPECTED_ERROR(__FILE__, __LINE__,
1664: "isc_mempool_destroy(): mempool %s "
1665: "leaked memory",
1666: mpctx->name);
1667: #endif
1668: REQUIRE(mpctx->allocated == 0);
1669:
1670: mctx = mpctx->mctx;
1671:
1672: lock = mpctx->lock;
1673:
1674: if (lock != NULL)
1675: LOCK(lock);
1676:
1677: /*
1678: * Return any items on the free list
1679: */
1680: MCTXLOCK(mctx, &mctx->lock);
1681: while (mpctx->items != NULL) {
1682: INSIST(mpctx->freecount > 0);
1683: mpctx->freecount--;
1684: item = mpctx->items;
1685: mpctx->items = item->next;
1686:
1687: if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1688: mem_putunlocked(mctx, item, mpctx->size);
1689: } else {
1690: mem_put(mctx, item, mpctx->size);
1691: mem_putstats(mctx, item, mpctx->size);
1692: }
1693: }
1694: MCTXUNLOCK(mctx, &mctx->lock);
1695:
1696: /*
1697: * Remove our linked list entry from the memory context.
1698: */
1699: MCTXLOCK(mctx, &mctx->lock);
1700: ISC_LIST_UNLINK(mctx->pools, mpctx, link);
1701: mctx->poolcnt--;
1702: MCTXUNLOCK(mctx, &mctx->lock);
1703:
1704: mpctx->magic = 0;
1705:
1706: isc_mem_put(mpctx->mctx, mpctx, sizeof(isc_mempool_t));
1707:
1708: if (lock != NULL)
1709: UNLOCK(lock);
1710:
1711: *mpctxp = NULL;
1712: }
1713:
1714: void
1715: isc_mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock) {
1716: REQUIRE(VALID_MEMPOOL(mpctx));
1717: REQUIRE(mpctx->lock == NULL);
1718: REQUIRE(lock != NULL);
1719:
1720: mpctx->lock = lock;
1721: }
1722:
1723: void *
1724: isc__mempool_get(isc_mempool_t *mpctx FLARG) {
1725: element *item;
1726: isc_mem_t *mctx;
1727: unsigned int i;
1728:
1729: REQUIRE(VALID_MEMPOOL(mpctx));
1730:
1731: mctx = mpctx->mctx;
1732:
1733: if (mpctx->lock != NULL)
1734: LOCK(mpctx->lock);
1735:
1736: /*
1737: * Don't let the caller go over quota
1738: */
1739: if (mpctx->allocated >= mpctx->maxalloc) {
1740: item = NULL;
1741: goto out;
1742: }
1743:
1744: /*
1745: * if we have a free list item, return the first here
1746: */
1747: item = mpctx->items;
1748: if (item != NULL) {
1749: mpctx->items = item->next;
1750: INSIST(mpctx->freecount > 0);
1751: mpctx->freecount--;
1752: mpctx->gets++;
1753: mpctx->allocated++;
1754: goto out;
1755: }
1756:
1757: /*
1758: * We need to dip into the well. Lock the memory context here and
1759: * fill up our free list.
1760: */
1761: MCTXLOCK(mctx, &mctx->lock);
1762: for (i = 0; i < mpctx->fillcount; i++) {
1763: if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1764: item = mem_getunlocked(mctx, mpctx->size);
1765: } else {
1766: item = mem_get(mctx, mpctx->size);
1767: if (item != NULL)
1768: mem_getstats(mctx, mpctx->size);
1769: }
1770: if (item == NULL)
1771: break;
1772: item->next = mpctx->items;
1773: mpctx->items = item;
1774: mpctx->freecount++;
1775: }
1776: MCTXUNLOCK(mctx, &mctx->lock);
1777:
1778: /*
1779: * If we didn't get any items, return NULL.
1780: */
1781: item = mpctx->items;
1782: if (item == NULL)
1783: goto out;
1784:
1785: mpctx->items = item->next;
1786: mpctx->freecount--;
1787: mpctx->gets++;
1788: mpctx->allocated++;
1789:
1790: out:
1791: if (mpctx->lock != NULL)
1792: UNLOCK(mpctx->lock);
1793:
1794: #if ISC_MEM_TRACKLINES
1795: if (item != NULL) {
1796: MCTXLOCK(mctx, &mctx->lock);
1797: ADD_TRACE(mctx, item, mpctx->size, file, line);
1798: MCTXUNLOCK(mctx, &mctx->lock);
1799: }
1800: #endif /* ISC_MEM_TRACKLINES */
1801:
1802: return (item);
1803: }
1804:
1805: void
1806: isc__mempool_put(isc_mempool_t *mpctx, void *mem FLARG) {
1807: isc_mem_t *mctx;
1808: element *item;
1809:
1810: REQUIRE(VALID_MEMPOOL(mpctx));
1811: REQUIRE(mem != NULL);
1812:
1813: mctx = mpctx->mctx;
1814:
1815: if (mpctx->lock != NULL)
1816: LOCK(mpctx->lock);
1817:
1818: INSIST(mpctx->allocated > 0);
1819: mpctx->allocated--;
1820:
1821: #if ISC_MEM_TRACKLINES
1822: MCTXLOCK(mctx, &mctx->lock);
1823: DELETE_TRACE(mctx, mem, mpctx->size, file, line);
1824: MCTXUNLOCK(mctx, &mctx->lock);
1825: #endif /* ISC_MEM_TRACKLINES */
1826:
1827: /*
1828: * If our free list is full, return this to the mctx directly.
1829: */
1830: if (mpctx->freecount >= mpctx->freemax) {
1831: if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1832: MCTXLOCK(mctx, &mctx->lock);
1833: mem_putunlocked(mctx, mem, mpctx->size);
1834: MCTXUNLOCK(mctx, &mctx->lock);
1835: } else {
1836: mem_put(mctx, mem, mpctx->size);
1837: MCTXLOCK(mctx, &mctx->lock);
1838: mem_putstats(mctx, mem, mpctx->size);
1839: MCTXUNLOCK(mctx, &mctx->lock);
1840: }
1841: if (mpctx->lock != NULL)
1842: UNLOCK(mpctx->lock);
1843: return;
1844: }
1845:
1846: /*
1847: * Otherwise, attach it to our free list and bump the counter.
1848: */
1849: mpctx->freecount++;
1850: item = (element *)mem;
1851: item->next = mpctx->items;
1852: mpctx->items = item;
1853:
1854: if (mpctx->lock != NULL)
1855: UNLOCK(mpctx->lock);
1856: }
1857:
1858: /*
1859: * Quotas
1860: */
1861:
1862: void
1863: isc_mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit) {
1864: REQUIRE(VALID_MEMPOOL(mpctx));
1865:
1866: if (mpctx->lock != NULL)
1867: LOCK(mpctx->lock);
1868:
1869: mpctx->freemax = limit;
1870:
1871: if (mpctx->lock != NULL)
1872: UNLOCK(mpctx->lock);
1873: }
1874:
1875: unsigned int
1876: isc_mempool_getfreemax(isc_mempool_t *mpctx) {
1877: unsigned int freemax;
1878:
1879: REQUIRE(VALID_MEMPOOL(mpctx));
1880:
1881: if (mpctx->lock != NULL)
1882: LOCK(mpctx->lock);
1883:
1884: freemax = mpctx->freemax;
1885:
1886: if (mpctx->lock != NULL)
1887: UNLOCK(mpctx->lock);
1888:
1889: return (freemax);
1890: }
1891:
1892: unsigned int
1893: isc_mempool_getfreecount(isc_mempool_t *mpctx) {
1894: unsigned int freecount;
1895:
1896: REQUIRE(VALID_MEMPOOL(mpctx));
1897:
1898: if (mpctx->lock != NULL)
1899: LOCK(mpctx->lock);
1900:
1901: freecount = mpctx->freecount;
1902:
1903: if (mpctx->lock != NULL)
1904: UNLOCK(mpctx->lock);
1905:
1906: return (freecount);
1907: }
1908:
1909: void
1910: isc_mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit) {
1911: REQUIRE(limit > 0);
1912:
1913: REQUIRE(VALID_MEMPOOL(mpctx));
1914:
1915: if (mpctx->lock != NULL)
1916: LOCK(mpctx->lock);
1917:
1918: mpctx->maxalloc = limit;
1919:
1920: if (mpctx->lock != NULL)
1921: UNLOCK(mpctx->lock);
1922: }
1923:
1924: unsigned int
1925: isc_mempool_getmaxalloc(isc_mempool_t *mpctx) {
1926: unsigned int maxalloc;
1927:
1928: REQUIRE(VALID_MEMPOOL(mpctx));
1929:
1930: if (mpctx->lock != NULL)
1931: LOCK(mpctx->lock);
1932:
1933: maxalloc = mpctx->maxalloc;
1934:
1935: if (mpctx->lock != NULL)
1936: UNLOCK(mpctx->lock);
1937:
1938: return (maxalloc);
1939: }
1940:
1941: unsigned int
1942: isc_mempool_getallocated(isc_mempool_t *mpctx) {
1943: unsigned int allocated;
1944:
1945: REQUIRE(VALID_MEMPOOL(mpctx));
1946:
1947: if (mpctx->lock != NULL)
1948: LOCK(mpctx->lock);
1949:
1950: allocated = mpctx->allocated;
1951:
1952: if (mpctx->lock != NULL)
1953: UNLOCK(mpctx->lock);
1954:
1955: return (allocated);
1956: }
1957:
1958: void
1959: isc_mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit) {
1960: REQUIRE(limit > 0);
1961: REQUIRE(VALID_MEMPOOL(mpctx));
1962:
1963: if (mpctx->lock != NULL)
1964: LOCK(mpctx->lock);
1965:
1966: mpctx->fillcount = limit;
1967:
1968: if (mpctx->lock != NULL)
1969: UNLOCK(mpctx->lock);
1970: }
1971:
1972: unsigned int
1973: isc_mempool_getfillcount(isc_mempool_t *mpctx) {
1974: unsigned int fillcount;
1975:
1976: REQUIRE(VALID_MEMPOOL(mpctx));
1977:
1978: if (mpctx->lock != NULL)
1979: LOCK(mpctx->lock);
1980:
1981: fillcount = mpctx->fillcount;
1982:
1983: if (mpctx->lock != NULL)
1984: UNLOCK(mpctx->lock);
1985:
1986: return (fillcount);
1987: }
1988:
1989: void
1990: isc_mem_printactive(isc_mem_t *ctx, FILE *file) {
1991:
1992: REQUIRE(VALID_CONTEXT(ctx));
1993: REQUIRE(file != NULL);
1994:
1995: #if !ISC_MEM_TRACKLINES
1996: UNUSED(ctx);
1997: UNUSED(file);
1998: #else
1999: print_active(ctx, file);
2000: #endif
2001: }
2002:
2003: void
2004: isc_mem_printallactive(FILE *file) {
2005: #if !ISC_MEM_TRACKLINES
2006: UNUSED(file);
2007: #else
2008: isc_mem_t *ctx;
2009:
2010: RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2011:
2012: LOCK(&lock);
2013: for (ctx = ISC_LIST_HEAD(contexts);
2014: ctx != NULL;
2015: ctx = ISC_LIST_NEXT(ctx, link)) {
2016: fprintf(file, "context: %p\n", ctx);
2017: print_active(ctx, file);
2018: }
2019: UNLOCK(&lock);
2020: #endif
2021: }
2022:
2023: void
2024: isc_mem_checkdestroyed(FILE *file) {
2025:
2026: RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2027:
2028: LOCK(&lock);
2029: if (!ISC_LIST_EMPTY(contexts)) {
2030: #if ISC_MEM_TRACKLINES
2031: isc_mem_t *ctx;
2032:
2033: for (ctx = ISC_LIST_HEAD(contexts);
2034: ctx != NULL;
2035: ctx = ISC_LIST_NEXT(ctx, link)) {
2036: fprintf(file, "context: %p\n", ctx);
2037: print_active(ctx, file);
2038: }
2039: fflush(file);
2040: #endif
2041: INSIST(0);
2042: }
2043: UNLOCK(&lock);
2044: }
2045:
2046: unsigned int
2047: isc_mem_references(isc_mem_t *ctx) {
2048: unsigned int references;
2049: REQUIRE(VALID_CONTEXT(ctx));
2050:
2051: MCTXLOCK(ctx, &ctx->lock);
2052: references = ctx->references;
2053: MCTXUNLOCK(ctx, &ctx->lock);
2054:
2055: return (references);
2056: }
2057:
2058: #ifdef HAVE_LIBXML2
2059:
2060: typedef struct summarystat {
2061: isc_uint64_t total;
2062: isc_uint64_t inuse;
2063: isc_uint64_t blocksize;
2064: isc_uint64_t contextsize;
2065: } summarystat_t;
2066:
2067: static void
2068: renderctx(isc_mem_t *ctx, summarystat_t *summary, xmlTextWriterPtr writer) {
2069: REQUIRE(VALID_CONTEXT(ctx));
2070:
2071: xmlTextWriterStartElement(writer, ISC_XMLCHAR "context");
2072:
2073: xmlTextWriterStartElement(writer, ISC_XMLCHAR "id");
2074: xmlTextWriterWriteFormatString(writer, "%p", ctx);
2075: xmlTextWriterEndElement(writer); /* id */
2076:
2077: if (ctx->name[0] != 0) {
2078: xmlTextWriterStartElement(writer, ISC_XMLCHAR "name");
2079: xmlTextWriterWriteFormatString(writer, "%s", ctx->name);
2080: xmlTextWriterEndElement(writer); /* name */
2081: }
2082:
2083: REQUIRE(VALID_CONTEXT(ctx));
2084: MCTXLOCK(ctx, &ctx->lock);
2085:
2086: summary->contextsize += sizeof(*ctx) +
2087: (ctx->max_size + 1) * sizeof(struct stats) +
2088: ctx->max_size * sizeof(element *) +
2089: ctx->basic_table_count * sizeof(char *);
2090: #if ISC_MEM_TRACKLINES
2091: if (ctx->debuglist != NULL) {
2092: summary->contextsize +=
2093: (ctx->max_size + 1) * sizeof(debuglist_t) +
2094: ctx->debuglistcnt * sizeof(debuglink_t);
2095: }
2096: #endif
2097: xmlTextWriterStartElement(writer, ISC_XMLCHAR "references");
2098: xmlTextWriterWriteFormatString(writer, "%d", ctx->references);
2099: xmlTextWriterEndElement(writer); /* references */
2100:
2101: summary->total += ctx->total;
2102: xmlTextWriterStartElement(writer, ISC_XMLCHAR "total");
2103: xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2104: (isc_uint64_t)ctx->total);
2105: xmlTextWriterEndElement(writer); /* total */
2106:
2107: summary->inuse += ctx->inuse;
2108: xmlTextWriterStartElement(writer, ISC_XMLCHAR "inuse");
2109: xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2110: (isc_uint64_t)ctx->inuse);
2111: xmlTextWriterEndElement(writer); /* inuse */
2112:
2113: xmlTextWriterStartElement(writer, ISC_XMLCHAR "maxinuse");
2114: xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2115: (isc_uint64_t)ctx->maxinuse);
2116: xmlTextWriterEndElement(writer); /* maxinuse */
2117:
2118: xmlTextWriterStartElement(writer, ISC_XMLCHAR "blocksize");
2119: if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
2120: summary->blocksize += ctx->basic_table_count *
2121: NUM_BASIC_BLOCKS * ctx->mem_target;
2122: xmlTextWriterWriteFormatString(writer,
2123: "%" ISC_PRINT_QUADFORMAT "u",
2124: (isc_uint64_t)
2125: ctx->basic_table_count *
2126: NUM_BASIC_BLOCKS *
2127: ctx->mem_target);
2128: } else
2129: xmlTextWriterWriteFormatString(writer, "%s", "-");
2130: xmlTextWriterEndElement(writer); /* blocksize */
2131:
2132: xmlTextWriterStartElement(writer, ISC_XMLCHAR "pools");
2133: xmlTextWriterWriteFormatString(writer, "%u", ctx->poolcnt);
2134: xmlTextWriterEndElement(writer); /* pools */
2135: summary->contextsize += ctx->poolcnt * sizeof(isc_mempool_t);
2136:
2137: xmlTextWriterStartElement(writer, ISC_XMLCHAR "hiwater");
2138: xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2139: (isc_uint64_t)ctx->hi_water);
2140: xmlTextWriterEndElement(writer); /* hiwater */
2141:
2142: xmlTextWriterStartElement(writer, ISC_XMLCHAR "lowater");
2143: xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2144: (isc_uint64_t)ctx->lo_water);
2145: xmlTextWriterEndElement(writer); /* lowater */
2146:
2147: MCTXUNLOCK(ctx, &ctx->lock);
2148:
2149: xmlTextWriterEndElement(writer); /* context */
2150: }
2151:
2152: void
2153: isc_mem_renderxml(xmlTextWriterPtr writer) {
2154: isc_mem_t *ctx;
2155: summarystat_t summary;
2156: isc_uint64_t lost;
2157:
2158: memset(&summary, 0, sizeof(summary));
2159:
2160: xmlTextWriterStartElement(writer, ISC_XMLCHAR "contexts");
2161:
2162: RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2163:
2164: LOCK(&lock);
2165: lost = totallost;
2166: for (ctx = ISC_LIST_HEAD(contexts);
2167: ctx != NULL;
2168: ctx = ISC_LIST_NEXT(ctx, link)) {
2169: renderctx(ctx, &summary, writer);
2170: }
2171: UNLOCK(&lock);
2172:
2173: xmlTextWriterEndElement(writer); /* contexts */
2174:
2175: xmlTextWriterStartElement(writer, ISC_XMLCHAR "summary");
2176:
2177: xmlTextWriterStartElement(writer, ISC_XMLCHAR "TotalUse");
2178: xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2179: summary.total);
2180: xmlTextWriterEndElement(writer); /* TotalUse */
2181:
2182: xmlTextWriterStartElement(writer, ISC_XMLCHAR "InUse");
2183: xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2184: summary.inuse);
2185: xmlTextWriterEndElement(writer); /* InUse */
2186:
2187: xmlTextWriterStartElement(writer, ISC_XMLCHAR "BlockSize");
2188: xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2189: summary.blocksize);
2190: xmlTextWriterEndElement(writer); /* BlockSize */
2191:
2192: xmlTextWriterStartElement(writer, ISC_XMLCHAR "ContextSize");
2193: xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2194: summary.contextsize);
2195: xmlTextWriterEndElement(writer); /* ContextSize */
2196:
2197: xmlTextWriterStartElement(writer, ISC_XMLCHAR "Lost");
2198: xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2199: lost);
2200: xmlTextWriterEndElement(writer); /* Lost */
2201:
2202: xmlTextWriterEndElement(writer); /* summary */
2203: }
2204:
2205: #endif /* HAVE_LIBXML2 */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>