2 * Copyright (C) 2004-2010, 2012-2015 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1997-2003 Internet Software Consortium.
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.
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.
28 #include <isc/magic.h>
32 #include <isc/ondestroy.h>
33 #include <isc/string.h>
34 #include <isc/mutex.h>
35 #include <isc/print.h>
39 #define MCTXLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) LOCK(l)
40 #define MCTXUNLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) UNLOCK(l)
42 #ifndef ISC_MEM_DEBUGGING
43 #define ISC_MEM_DEBUGGING 0
45 LIBISC_EXTERNAL_DATA unsigned int isc_mem_debugging = ISC_MEM_DEBUGGING;
46 LIBISC_EXTERNAL_DATA unsigned int isc_mem_defaultflags = ISC_MEMFLAG_DEFAULT;
52 #define DEF_MAX_SIZE 1100
53 #define DEF_MEM_TARGET 4096
54 #define ALIGNMENT_SIZE 8U /*%< must be a power of 2 */
55 #define NUM_BASIC_BLOCKS 64 /*%< must be > 1 */
56 #define TABLE_INCREMENT 1024
57 #define DEBUGLIST_COUNT 1024
62 typedef struct isc__mem isc__mem_t;
63 typedef struct isc__mempool isc__mempool_t;
65 #if ISC_MEM_TRACKLINES
66 typedef struct debuglink debuglink_t;
68 ISC_LINK(debuglink_t) link;
69 const void *ptr[DEBUGLIST_COUNT];
70 size_t size[DEBUGLIST_COUNT];
71 const char *file[DEBUGLIST_COUNT];
72 unsigned int line[DEBUGLIST_COUNT];
76 #define FLARG_PASS , file, line
77 #define FLARG , const char *file, unsigned int line
83 typedef struct element element;
90 * This structure must be ALIGNMENT_SIZE bytes.
95 char bytes[ALIGNMENT_SIZE];
101 unsigned long totalgets;
102 unsigned long blocks;
103 unsigned long freefrags;
106 #define MEM_MAGIC ISC_MAGIC('M', 'e', 'm', 'C')
107 #define VALID_CONTEXT(c) ISC_MAGIC_VALID(c, MEM_MAGIC)
109 #if ISC_MEM_TRACKLINES
110 typedef ISC_LIST(debuglink_t) debuglist_t;
113 /* List of all active memory contexts. */
115 static ISC_LIST(isc__mem_t) contexts;
116 static isc_once_t once = ISC_ONCE_INIT;
117 static isc_mutex_t contextslock;
118 static isc_mutex_t createlock;
121 * Total size of lost memory due to a bug of external library.
122 * Locked by the global lock.
124 static isc_uint64_t totallost;
128 isc_ondestroy_t ondestroy;
131 isc_memalloc_t memalloc;
132 isc_memfree_t memfree;
135 isc_boolean_t checkfree;
136 struct stats * stats;
137 unsigned int references;
146 isc_boolean_t hi_called;
147 isc_boolean_t is_overmem;
148 isc_mem_water_t water;
150 ISC_LIST(isc__mempool_t) pools;
151 unsigned int poolcnt;
153 /* ISC_MEMFLAG_INTERNAL */
155 element ** freelists;
156 element * basic_blocks;
157 unsigned char ** basic_table;
158 unsigned int basic_table_count;
159 unsigned int basic_table_size;
160 unsigned char * lowest;
161 unsigned char * highest;
163 #if ISC_MEM_TRACKLINES
164 debuglist_t * debuglist;
165 unsigned int debuglistcnt;
168 unsigned int memalloc_failures;
169 ISC_LINK(isc__mem_t) link;
172 #define MEMPOOL_MAGIC ISC_MAGIC('M', 'E', 'M', 'p')
173 #define VALID_MEMPOOL(c) ISC_MAGIC_VALID(c, MEMPOOL_MAGIC)
175 struct isc__mempool {
176 /* always unlocked */
177 isc_mempool_t common; /*%< common header of mempool's */
178 isc_mutex_t *lock; /*%< optional lock */
179 isc__mem_t *mctx; /*%< our memory context */
180 /*%< locked via the memory context's lock */
181 ISC_LINK(isc__mempool_t) link; /*%< next pool in this mem context */
182 /*%< optionally locked from here down */
183 element *items; /*%< low water item list */
184 size_t size; /*%< size of each item on this pool */
185 unsigned int maxalloc; /*%< max number of items allowed */
186 unsigned int allocated; /*%< # of items currently given out */
187 unsigned int freecount; /*%< # of items on reserved list */
188 unsigned int freemax; /*%< # of items allowed on free list */
189 unsigned int fillcount; /*%< # of items to fetch on each fill */
191 unsigned int gets; /*%< # of requests to this pool */
192 /*%< Debugging only. */
193 #if ISC_MEMPOOL_NAMES
194 char name[16]; /*%< printed name in stats reports */
199 * Private Inline-able.
202 #if ! ISC_MEM_TRACKLINES
203 #define ADD_TRACE(a, b, c, d, e)
204 #define DELETE_TRACE(a, b, c, d, e)
205 #define ISC_MEMFUNC_SCOPE
207 #define ADD_TRACE(a, b, c, d, e) \
209 if ((isc_mem_debugging & (ISC_MEM_DEBUGTRACE | \
210 ISC_MEM_DEBUGRECORD)) != 0 && \
212 add_trace_entry(a, b, c, d, e); \
214 #define DELETE_TRACE(a, b, c, d, e) delete_trace_entry(a, b, c, d, e)
217 print_active(isc__mem_t *ctx, FILE *out);
219 #endif /* ISC_MEM_TRACKLINES */
222 * The following can be either static or public, depending on build environment.
226 #define ISC_MEMFUNC_SCOPE
228 #define ISC_MEMFUNC_SCOPE static
231 ISC_MEMFUNC_SCOPE isc_result_t
232 isc__mem_createx(size_t init_max_size, size_t target_size,
233 isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
235 ISC_MEMFUNC_SCOPE isc_result_t
236 isc__mem_createx2(size_t init_max_size, size_t target_size,
237 isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
238 isc_mem_t **ctxp, unsigned int flags);
239 ISC_MEMFUNC_SCOPE isc_result_t
240 isc__mem_create(size_t init_max_size, size_t target_size, isc_mem_t **ctxp);
241 ISC_MEMFUNC_SCOPE isc_result_t
242 isc__mem_create2(size_t init_max_size, size_t target_size,
243 isc_mem_t **ctxp, unsigned int flags);
244 ISC_MEMFUNC_SCOPE void
245 isc__mem_attach(isc_mem_t *source, isc_mem_t **targetp);
246 ISC_MEMFUNC_SCOPE void
247 isc__mem_detach(isc_mem_t **ctxp);
248 ISC_MEMFUNC_SCOPE void
249 isc___mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG);
250 ISC_MEMFUNC_SCOPE void
251 isc__mem_destroy(isc_mem_t **ctxp);
252 ISC_MEMFUNC_SCOPE isc_result_t
253 isc__mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event);
254 ISC_MEMFUNC_SCOPE void *
255 isc___mem_get(isc_mem_t *ctx, size_t size FLARG);
256 ISC_MEMFUNC_SCOPE void
257 isc___mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG);
258 ISC_MEMFUNC_SCOPE void
259 isc__mem_stats(isc_mem_t *ctx, FILE *out);
260 ISC_MEMFUNC_SCOPE void *
261 isc___mem_allocate(isc_mem_t *ctx, size_t size FLARG);
262 ISC_MEMFUNC_SCOPE void *
263 isc___mem_reallocate(isc_mem_t *ctx, void *ptr, size_t size FLARG);
264 ISC_MEMFUNC_SCOPE void
265 isc___mem_free(isc_mem_t *ctx, void *ptr FLARG);
266 ISC_MEMFUNC_SCOPE char *
267 isc___mem_strdup(isc_mem_t *mctx, const char *s FLARG);
268 ISC_MEMFUNC_SCOPE void
269 isc__mem_setdestroycheck(isc_mem_t *ctx, isc_boolean_t flag);
270 ISC_MEMFUNC_SCOPE void
271 isc__mem_setquota(isc_mem_t *ctx, size_t quota);
272 ISC_MEMFUNC_SCOPE size_t
273 isc__mem_getquota(isc_mem_t *ctx);
274 ISC_MEMFUNC_SCOPE size_t
275 isc__mem_inuse(isc_mem_t *ctx);
276 ISC_MEMFUNC_SCOPE isc_boolean_t
277 isc__mem_isovermem(isc_mem_t *ctx);
278 ISC_MEMFUNC_SCOPE void
279 isc__mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg,
280 size_t hiwater, size_t lowater);
281 ISC_MEMFUNC_SCOPE void
282 isc__mem_waterack(isc_mem_t *ctx0, int flag);
283 ISC_MEMFUNC_SCOPE void
284 isc__mem_setname(isc_mem_t *ctx, const char *name, void *tag);
285 ISC_MEMFUNC_SCOPE const char *
286 isc__mem_getname(isc_mem_t *ctx);
287 ISC_MEMFUNC_SCOPE void *
288 isc__mem_gettag(isc_mem_t *ctx);
289 ISC_MEMFUNC_SCOPE isc_result_t
290 isc__mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp);
291 ISC_MEMFUNC_SCOPE void
292 isc__mempool_setname(isc_mempool_t *mpctx, const char *name);
293 ISC_MEMFUNC_SCOPE void
294 isc__mempool_destroy(isc_mempool_t **mpctxp);
295 ISC_MEMFUNC_SCOPE void
296 isc__mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock);
297 ISC_MEMFUNC_SCOPE void *
298 isc___mempool_get(isc_mempool_t *mpctx FLARG);
299 ISC_MEMFUNC_SCOPE void
300 isc___mempool_put(isc_mempool_t *mpctx, void *mem FLARG);
301 ISC_MEMFUNC_SCOPE void
302 isc__mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit);
303 ISC_MEMFUNC_SCOPE unsigned int
304 isc__mempool_getfreemax(isc_mempool_t *mpctx);
305 ISC_MEMFUNC_SCOPE unsigned int
306 isc__mempool_getfreecount(isc_mempool_t *mpctx);
307 ISC_MEMFUNC_SCOPE void
308 isc__mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit);
309 ISC_MEMFUNC_SCOPE unsigned int
310 isc__mempool_getmaxalloc(isc_mempool_t *mpctx);
311 ISC_MEMFUNC_SCOPE unsigned int
312 isc__mempool_getallocated(isc_mempool_t *mpctx);
313 ISC_MEMFUNC_SCOPE void
314 isc__mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit);
315 ISC_MEMFUNC_SCOPE unsigned int
316 isc__mempool_getfillcount(isc_mempool_t *mpctx);
318 ISC_MEMFUNC_SCOPE void
319 isc__mem_printactive(isc_mem_t *ctx0, FILE *file);
320 ISC_MEMFUNC_SCOPE void
321 isc__mem_printallactive(FILE *file);
322 ISC_MEMFUNC_SCOPE void
323 isc__mem_checkdestroyed(FILE *file);
324 ISC_MEMFUNC_SCOPE unsigned int
325 isc__mem_references(isc_mem_t *ctx0);
328 static struct isc__memmethods {
329 isc_memmethods_t methods;
332 * The following are defined just for avoiding unused static functions.
335 void *createx, *create, *create2, *ondestroy, *stats,
336 *setquota, *getquota, *setname, *getname, *gettag;
345 isc___mem_putanddetach,
347 isc___mem_reallocate,
350 isc__mem_setdestroycheck,
359 (void *)isc__mem_createx, (void *)isc__mem_create,
360 (void *)isc__mem_create2, (void *)isc__mem_ondestroy,
361 (void *)isc__mem_stats, (void *)isc__mem_setquota,
362 (void *)isc__mem_getquota, (void *)isc__mem_setname,
363 (void *)isc__mem_getname, (void *)isc__mem_gettag
367 static struct isc__mempoolmethods {
368 isc_mempoolmethods_t methods;
371 * The following are defined just for avoiding unused static functions.
374 void *getfreemax, *getfreecount, *getmaxalloc, *getfillcount;
378 isc__mempool_destroy,
381 isc__mempool_getallocated,
382 isc__mempool_setmaxalloc,
383 isc__mempool_setfreemax,
384 isc__mempool_setname,
385 isc__mempool_associatelock,
386 isc__mempool_setfillcount
390 (void *)isc__mempool_getfreemax, (void *)isc__mempool_getfreecount,
391 (void *)isc__mempool_getmaxalloc, (void *)isc__mempool_getfillcount
395 #if ISC_MEM_TRACKLINES
397 * mctx must be locked.
400 add_trace_entry(isc__mem_t *mctx, const void *ptr, size_t size FLARG) {
403 size_t mysize = size;
405 if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
406 fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
409 "file %s line %u mctx %p\n"),
410 ptr, size, file, line, mctx);
412 if (mctx->debuglist == NULL)
415 if (mysize > mctx->max_size)
416 mysize = mctx->max_size;
418 dl = ISC_LIST_HEAD(mctx->debuglist[mysize]);
420 if (dl->count == DEBUGLIST_COUNT)
422 for (i = 0; i < DEBUGLIST_COUNT; i++) {
423 if (dl->ptr[i] == NULL) {
433 dl = ISC_LIST_NEXT(dl, link);
436 dl = malloc(sizeof(debuglink_t));
439 ISC_LINK_INIT(dl, link);
440 for (i = 1; i < DEBUGLIST_COUNT; i++) {
453 ISC_LIST_PREPEND(mctx->debuglist[mysize], dl, link);
454 mctx->debuglistcnt++;
458 delete_trace_entry(isc__mem_t *mctx, const void *ptr, size_t size,
459 const char *file, unsigned int line)
464 if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
465 fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
468 "file %s line %u mctx %p\n"),
469 ptr, size, file, line, mctx);
471 if (mctx->debuglist == NULL)
474 if (size > mctx->max_size)
475 size = mctx->max_size;
477 dl = ISC_LIST_HEAD(mctx->debuglist[size]);
479 for (i = 0; i < DEBUGLIST_COUNT; i++) {
480 if (dl->ptr[i] == ptr) {
486 INSIST(dl->count > 0);
488 if (dl->count == 0) {
489 ISC_LIST_UNLINK(mctx->debuglist[size],
496 dl = ISC_LIST_NEXT(dl, link);
500 * If we get here, we didn't find the item on the list. We're
505 #endif /* ISC_MEM_TRACKLINES */
508 rmsize(size_t size) {
510 * round down to ALIGNMENT_SIZE
512 return (size & (~(ALIGNMENT_SIZE - 1)));
516 quantize(size_t size) {
518 * Round up the result in order to get a size big
519 * enough to satisfy the request and be aligned on ALIGNMENT_SIZE
524 return (ALIGNMENT_SIZE);
525 return ((size + ALIGNMENT_SIZE - 1) & (~(ALIGNMENT_SIZE - 1)));
528 static inline isc_boolean_t
529 more_basic_blocks(isc__mem_t *ctx) {
531 unsigned char *curr, *next;
532 unsigned char *first, *last;
533 unsigned char **table;
534 unsigned int table_size;
538 /* Require: we hold the context lock. */
541 * Did we hit the quota for this context?
543 increment = NUM_BASIC_BLOCKS * ctx->mem_target;
544 if (ctx->quota != 0U && ctx->total + increment > ctx->quota)
547 INSIST(ctx->basic_table_count <= ctx->basic_table_size);
548 if (ctx->basic_table_count == ctx->basic_table_size) {
549 table_size = ctx->basic_table_size + TABLE_INCREMENT;
550 table = (ctx->memalloc)(ctx->arg,
551 table_size * sizeof(unsigned char *));
553 ctx->memalloc_failures++;
556 if (ctx->basic_table_size != 0) {
557 memmove(table, ctx->basic_table,
558 ctx->basic_table_size *
559 sizeof(unsigned char *));
560 (ctx->memfree)(ctx->arg, ctx->basic_table);
562 ctx->basic_table = table;
563 ctx->basic_table_size = table_size;
566 new = (ctx->memalloc)(ctx->arg, NUM_BASIC_BLOCKS * ctx->mem_target);
568 ctx->memalloc_failures++;
571 ctx->total += increment;
572 ctx->basic_table[ctx->basic_table_count] = new;
573 ctx->basic_table_count++;
576 next = curr + ctx->mem_target;
577 for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) {
578 ((element *)curr)->next = (element *)next;
580 next += ctx->mem_target;
583 * curr is now pointing at the last block in the
586 ((element *)curr)->next = NULL;
588 last = first + NUM_BASIC_BLOCKS * ctx->mem_target - 1;
589 if (first < ctx->lowest || ctx->lowest == NULL)
591 if (last > ctx->highest)
593 ctx->basic_blocks = new;
598 static inline isc_boolean_t
599 more_frags(isc__mem_t *ctx, size_t new_size) {
603 unsigned char *curr, *next;
606 * Try to get more fragments by chopping up a basic block.
609 if (ctx->basic_blocks == NULL) {
610 if (!more_basic_blocks(ctx)) {
612 * We can't get more memory from the OS, or we've
613 * hit the quota for this context.
616 * XXXRTH "At quota" notification here.
622 total_size = ctx->mem_target;
623 new = ctx->basic_blocks;
624 ctx->basic_blocks = ctx->basic_blocks->next;
625 frags = (int)(total_size / new_size);
626 ctx->stats[new_size].blocks++;
627 ctx->stats[new_size].freefrags += frags;
629 * Set up a linked-list of blocks of size
633 next = curr + new_size;
634 total_size -= new_size;
635 for (i = 0; i < (frags - 1); i++) {
636 ((element *)curr)->next = (element *)next;
639 total_size -= new_size;
642 * Add the remaining fragment of the basic block to a free list.
644 total_size = rmsize(total_size);
645 if (total_size > 0U) {
646 ((element *)next)->next = ctx->freelists[total_size];
647 ctx->freelists[total_size] = (element *)next;
648 ctx->stats[total_size].freefrags++;
651 * curr is now pointing at the last block in the
654 ((element *)curr)->next = NULL;
655 ctx->freelists[new_size] = new;
661 mem_getunlocked(isc__mem_t *ctx, size_t size) {
662 size_t new_size = quantize(size);
665 if (new_size >= ctx->max_size) {
667 * memget() was called on something beyond our upper limit.
669 if (ctx->quota != 0U && ctx->total + size > ctx->quota) {
673 ret = (ctx->memalloc)(ctx->arg, size);
675 ctx->memalloc_failures++;
680 ctx->stats[ctx->max_size].gets++;
681 ctx->stats[ctx->max_size].totalgets++;
683 * If we don't set new_size to size, then the
684 * ISC_MEM_FILL code might write over bytes we
692 * If there are no blocks in the free list for this size, get a chunk
693 * of memory and then break it up into "new_size"-sized blocks, adding
694 * them to the free list.
696 if (ctx->freelists[new_size] == NULL && !more_frags(ctx, new_size))
700 * The free list uses the "rounded-up" size "new_size".
702 ret = ctx->freelists[new_size];
703 ctx->freelists[new_size] = ctx->freelists[new_size]->next;
706 * The stats[] uses the _actual_ "size" requested by the
707 * caller, with the caveat (in the code above) that "size" >= the
708 * max. size (max_size) ends up getting recorded as a call to
711 ctx->stats[size].gets++;
712 ctx->stats[size].totalgets++;
713 ctx->stats[new_size].freefrags--;
714 ctx->inuse += new_size;
720 memset(ret, 0xbe, new_size); /* Mnemonic for "beef". */
726 #if ISC_MEM_FILL && ISC_MEM_CHECKOVERRUN
728 check_overrun(void *mem, size_t size, size_t new_size) {
731 cp = (unsigned char *)mem;
733 while (size < new_size) {
742 mem_putunlocked(isc__mem_t *ctx, void *mem, size_t size) {
743 size_t new_size = quantize(size);
745 if (new_size >= ctx->max_size) {
747 * memput() called on something beyond our upper limit.
750 memset(mem, 0xde, size); /* Mnemonic for "dead". */
752 (ctx->memfree)(ctx->arg, mem);
753 INSIST(ctx->stats[ctx->max_size].gets != 0U);
754 ctx->stats[ctx->max_size].gets--;
755 INSIST(size <= ctx->inuse);
761 #if ISC_MEM_CHECKOVERRUN
762 check_overrun(mem, size, new_size);
764 memset(mem, 0xde, new_size); /* Mnemonic for "dead". */
768 * The free list uses the "rounded-up" size "new_size".
770 ((element *)mem)->next = ctx->freelists[new_size];
771 ctx->freelists[new_size] = (element *)mem;
774 * The stats[] uses the _actual_ "size" requested by the
775 * caller, with the caveat (in the code above) that "size" >= the
776 * max. size (max_size) ends up getting recorded as a call to
779 INSIST(ctx->stats[size].gets != 0U);
780 ctx->stats[size].gets--;
781 ctx->stats[new_size].freefrags++;
782 ctx->inuse -= new_size;
786 * Perform a malloc, doing memory filling and overrun detection as necessary.
789 mem_get(isc__mem_t *ctx, size_t size) {
792 #if ISC_MEM_CHECKOVERRUN
796 ret = (ctx->memalloc)(ctx->arg, size);
798 ctx->memalloc_failures++;
802 memset(ret, 0xbe, size); /* Mnemonic for "beef". */
804 # if ISC_MEM_CHECKOVERRUN
814 * Perform a free, doing memory filling and overrun detection as necessary.
817 mem_put(isc__mem_t *ctx, void *mem, size_t size) {
818 #if ISC_MEM_CHECKOVERRUN
819 INSIST(((unsigned char *)mem)[size] == 0xbe);
822 memset(mem, 0xde, size); /* Mnemonic for "dead". */
826 (ctx->memfree)(ctx->arg, mem);
830 * Update internal counters after a memory get.
833 mem_getstats(isc__mem_t *ctx, size_t size) {
837 if (size > ctx->max_size) {
838 ctx->stats[ctx->max_size].gets++;
839 ctx->stats[ctx->max_size].totalgets++;
841 ctx->stats[size].gets++;
842 ctx->stats[size].totalgets++;
847 * Update internal counters after a memory put.
850 mem_putstats(isc__mem_t *ctx, void *ptr, size_t size) {
853 INSIST(ctx->inuse >= size);
856 if (size > ctx->max_size) {
857 INSIST(ctx->stats[ctx->max_size].gets > 0U);
858 ctx->stats[ctx->max_size].gets--;
860 INSIST(ctx->stats[size].gets > 0U);
861 ctx->stats[size].gets--;
870 default_memalloc(void *arg, size_t size) {
874 return (malloc(size));
878 default_memfree(void *arg, void *ptr) {
884 initialize_action(void) {
885 RUNTIME_CHECK(isc_mutex_init(&createlock) == ISC_R_SUCCESS);
886 RUNTIME_CHECK(isc_mutex_init(&contextslock) == ISC_R_SUCCESS);
887 ISC_LIST_INIT(contexts);
895 ISC_MEMFUNC_SCOPE isc_result_t
896 isc__mem_createx(size_t init_max_size, size_t target_size,
897 isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
900 return (isc__mem_createx2(init_max_size, target_size, memalloc, memfree,
901 arg, ctxp, isc_mem_defaultflags));
905 ISC_MEMFUNC_SCOPE isc_result_t
906 isc__mem_createx2(size_t init_max_size, size_t target_size,
907 isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
908 isc_mem_t **ctxp, unsigned int flags)
913 REQUIRE(ctxp != NULL && *ctxp == NULL);
914 REQUIRE(memalloc != NULL);
915 REQUIRE(memfree != NULL);
917 INSIST((ALIGNMENT_SIZE & (ALIGNMENT_SIZE - 1)) == 0);
919 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
921 ctx = (memalloc)(arg, sizeof(*ctx));
923 return (ISC_R_NOMEMORY);
925 if ((flags & ISC_MEMFLAG_NOLOCK) == 0) {
926 result = isc_mutex_init(&ctx->lock);
927 if (result != ISC_R_SUCCESS) {
933 if (init_max_size == 0U)
934 ctx->max_size = DEF_MAX_SIZE;
936 ctx->max_size = init_max_size;
939 memset(ctx->name, 0, sizeof(ctx->name));
947 ctx->hi_called = ISC_FALSE;
948 ctx->is_overmem = ISC_FALSE;
950 ctx->water_arg = NULL;
951 ctx->common.impmagic = MEM_MAGIC;
952 ctx->common.magic = ISCAPI_MCTX_MAGIC;
953 ctx->common.methods = (isc_memmethods_t *)&memmethods;
954 isc_ondestroy_init(&ctx->ondestroy);
955 ctx->memalloc = memalloc;
956 ctx->memfree = memfree;
959 ctx->checkfree = ISC_TRUE;
960 #if ISC_MEM_TRACKLINES
961 ctx->debuglist = NULL;
962 ctx->debuglistcnt = 0;
964 ISC_LIST_INIT(ctx->pools);
966 ctx->freelists = NULL;
967 ctx->basic_blocks = NULL;
968 ctx->basic_table = NULL;
969 ctx->basic_table_count = 0;
970 ctx->basic_table_size = 0;
974 ctx->stats = (memalloc)(arg,
975 (ctx->max_size+1) * sizeof(struct stats));
976 if (ctx->stats == NULL) {
977 result = ISC_R_NOMEMORY;
980 memset(ctx->stats, 0, (ctx->max_size + 1) * sizeof(struct stats));
982 if ((flags & ISC_MEMFLAG_INTERNAL) != 0) {
983 if (target_size == 0U)
984 ctx->mem_target = DEF_MEM_TARGET;
986 ctx->mem_target = target_size;
987 ctx->freelists = (memalloc)(arg, ctx->max_size *
989 if (ctx->freelists == NULL) {
990 result = ISC_R_NOMEMORY;
993 memset(ctx->freelists, 0,
994 ctx->max_size * sizeof(element *));
997 #if ISC_MEM_TRACKLINES
998 if ((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0) {
1001 ctx->debuglist = (memalloc)(arg,
1002 (ctx->max_size+1) * sizeof(debuglist_t));
1003 if (ctx->debuglist == NULL) {
1004 result = ISC_R_NOMEMORY;
1007 for (i = 0; i <= ctx->max_size; i++)
1008 ISC_LIST_INIT(ctx->debuglist[i]);
1012 ctx->memalloc_failures = 0;
1014 LOCK(&contextslock);
1015 ISC_LIST_INITANDAPPEND(contexts, ctx, link);
1016 UNLOCK(&contextslock);
1018 *ctxp = (isc_mem_t *)ctx;
1019 return (ISC_R_SUCCESS);
1023 if (ctx->stats != NULL)
1024 (memfree)(arg, ctx->stats);
1025 if (ctx->freelists != NULL)
1026 (memfree)(arg, ctx->freelists);
1027 #if ISC_MEM_TRACKLINES
1028 if (ctx->debuglist != NULL)
1029 (ctx->memfree)(ctx->arg, ctx->debuglist);
1030 #endif /* ISC_MEM_TRACKLINES */
1031 if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
1032 DESTROYLOCK(&ctx->lock);
1033 (memfree)(arg, ctx);
1039 ISC_MEMFUNC_SCOPE isc_result_t
1040 isc__mem_create(size_t init_max_size, size_t target_size, isc_mem_t **ctxp) {
1041 return (isc__mem_createx2(init_max_size, target_size,
1042 default_memalloc, default_memfree, NULL,
1043 ctxp, isc_mem_defaultflags));
1046 ISC_MEMFUNC_SCOPE isc_result_t
1047 isc__mem_create2(size_t init_max_size, size_t target_size,
1048 isc_mem_t **ctxp, unsigned int flags)
1050 return (isc__mem_createx2(init_max_size, target_size,
1051 default_memalloc, default_memfree, NULL,
1056 destroy(isc__mem_t *ctx) {
1058 isc_ondestroy_t ondest;
1060 LOCK(&contextslock);
1061 ISC_LIST_UNLINK(contexts, ctx, link);
1062 totallost += ctx->inuse;
1063 UNLOCK(&contextslock);
1065 ctx->common.impmagic = 0;
1066 ctx->common.magic = 0;
1068 INSIST(ISC_LIST_EMPTY(ctx->pools));
1070 #if ISC_MEM_TRACKLINES
1071 if (ctx->debuglist != NULL) {
1072 if (ctx->checkfree) {
1073 for (i = 0; i <= ctx->max_size; i++) {
1074 if (!ISC_LIST_EMPTY(ctx->debuglist[i]))
1075 print_active(ctx, stderr);
1076 INSIST(ISC_LIST_EMPTY(ctx->debuglist[i]));
1081 for (i = 0; i <= ctx->max_size; i++)
1082 for (dl = ISC_LIST_HEAD(ctx->debuglist[i]);
1084 dl = ISC_LIST_HEAD(ctx->debuglist[i])) {
1085 ISC_LIST_UNLINK(ctx->debuglist[i],
1090 (ctx->memfree)(ctx->arg, ctx->debuglist);
1093 INSIST(ctx->references == 0);
1095 if (ctx->checkfree) {
1096 for (i = 0; i <= ctx->max_size; i++) {
1097 if (ctx->stats[i].gets != 0U) {
1099 "Failing assertion due to probable "
1100 "leaked memory in context %p (\"%s\") "
1101 "(stats[%u].gets == %lu).\n",
1102 ctx, ctx->name, i, ctx->stats[i].gets);
1103 #if ISC_MEM_TRACKLINES
1104 print_active(ctx, stderr);
1106 INSIST(ctx->stats[i].gets == 0U);
1111 (ctx->memfree)(ctx->arg, ctx->stats);
1113 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1114 for (i = 0; i < ctx->basic_table_count; i++)
1115 (ctx->memfree)(ctx->arg, ctx->basic_table[i]);
1116 (ctx->memfree)(ctx->arg, ctx->freelists);
1117 if (ctx->basic_table != NULL)
1118 (ctx->memfree)(ctx->arg, ctx->basic_table);
1121 ondest = ctx->ondestroy;
1123 if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
1124 DESTROYLOCK(&ctx->lock);
1125 (ctx->memfree)(ctx->arg, ctx);
1127 isc_ondestroy_notify(&ondest, ctx);
1130 ISC_MEMFUNC_SCOPE void
1131 isc__mem_attach(isc_mem_t *source0, isc_mem_t **targetp) {
1132 isc__mem_t *source = (isc__mem_t *)source0;
1134 REQUIRE(VALID_CONTEXT(source));
1135 REQUIRE(targetp != NULL && *targetp == NULL);
1137 MCTXLOCK(source, &source->lock);
1138 source->references++;
1139 MCTXUNLOCK(source, &source->lock);
1141 *targetp = (isc_mem_t *)source;
1144 ISC_MEMFUNC_SCOPE void
1145 isc__mem_detach(isc_mem_t **ctxp) {
1147 isc_boolean_t want_destroy = ISC_FALSE;
1149 REQUIRE(ctxp != NULL);
1150 ctx = (isc__mem_t *)*ctxp;
1151 REQUIRE(VALID_CONTEXT(ctx));
1153 MCTXLOCK(ctx, &ctx->lock);
1154 INSIST(ctx->references > 0);
1156 if (ctx->references == 0)
1157 want_destroy = ISC_TRUE;
1158 MCTXUNLOCK(ctx, &ctx->lock);
1167 * isc_mem_putanddetach() is the equivalent of:
1170 * isc_mem_attach(ptr->mctx, &mctx);
1171 * isc_mem_detach(&ptr->mctx);
1172 * isc_mem_put(mctx, ptr, sizeof(*ptr);
1173 * isc_mem_detach(&mctx);
1176 ISC_MEMFUNC_SCOPE void
1177 isc___mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) {
1179 isc_boolean_t want_destroy = ISC_FALSE;
1183 REQUIRE(ctxp != NULL);
1184 ctx = (isc__mem_t *)*ctxp;
1185 REQUIRE(VALID_CONTEXT(ctx));
1186 REQUIRE(ptr != NULL);
1189 * Must be before mem_putunlocked() as ctxp is usually within
1194 if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) {
1195 if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) {
1196 si = &(((size_info *)ptr)[-1]);
1197 oldsize = si->u.size - ALIGNMENT_SIZE;
1198 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
1199 oldsize -= ALIGNMENT_SIZE;
1200 INSIST(oldsize == size);
1202 isc__mem_free((isc_mem_t *)ctx, ptr FLARG_PASS);
1204 MCTXLOCK(ctx, &ctx->lock);
1206 if (ctx->references == 0)
1207 want_destroy = ISC_TRUE;
1208 MCTXUNLOCK(ctx, &ctx->lock);
1215 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1216 MCTXLOCK(ctx, &ctx->lock);
1217 mem_putunlocked(ctx, ptr, size);
1219 mem_put(ctx, ptr, size);
1220 MCTXLOCK(ctx, &ctx->lock);
1221 mem_putstats(ctx, ptr, size);
1224 DELETE_TRACE(ctx, ptr, size, file, line);
1225 INSIST(ctx->references > 0);
1227 if (ctx->references == 0)
1228 want_destroy = ISC_TRUE;
1230 MCTXUNLOCK(ctx, &ctx->lock);
1236 ISC_MEMFUNC_SCOPE void
1237 isc__mem_destroy(isc_mem_t **ctxp) {
1241 * This routine provides legacy support for callers who use mctxs
1242 * without attaching/detaching.
1245 REQUIRE(ctxp != NULL);
1246 ctx = (isc__mem_t *)*ctxp;
1247 REQUIRE(VALID_CONTEXT(ctx));
1249 MCTXLOCK(ctx, &ctx->lock);
1250 #if ISC_MEM_TRACKLINES
1251 if (ctx->references != 1)
1252 print_active(ctx, stderr);
1254 REQUIRE(ctx->references == 1);
1256 MCTXUNLOCK(ctx, &ctx->lock);
1263 ISC_MEMFUNC_SCOPE isc_result_t
1264 isc__mem_ondestroy(isc_mem_t *ctx0, isc_task_t *task, isc_event_t **event) {
1265 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1268 MCTXLOCK(ctx, &ctx->lock);
1269 res = isc_ondestroy_register(&ctx->ondestroy, task, event);
1270 MCTXUNLOCK(ctx, &ctx->lock);
1275 ISC_MEMFUNC_SCOPE void *
1276 isc___mem_get(isc_mem_t *ctx0, size_t size FLARG) {
1277 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1279 isc_boolean_t call_water = ISC_FALSE;
1281 REQUIRE(VALID_CONTEXT(ctx));
1283 if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0)
1284 return (isc__mem_allocate(ctx0, size FLARG_PASS));
1286 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1287 MCTXLOCK(ctx, &ctx->lock);
1288 ptr = mem_getunlocked(ctx, size);
1290 ptr = mem_get(ctx, size);
1291 MCTXLOCK(ctx, &ctx->lock);
1293 mem_getstats(ctx, size);
1296 ADD_TRACE(ctx, ptr, size, file, line);
1297 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water) {
1298 ctx->is_overmem = ISC_TRUE;
1299 if (!ctx->hi_called)
1300 call_water = ISC_TRUE;
1302 if (ctx->inuse > ctx->maxinuse) {
1303 ctx->maxinuse = ctx->inuse;
1304 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1305 (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
1306 fprintf(stderr, "maxinuse = %lu\n",
1307 (unsigned long)ctx->inuse);
1309 MCTXUNLOCK(ctx, &ctx->lock);
1311 if (call_water && (ctx->water != NULL))
1312 (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
1317 ISC_MEMFUNC_SCOPE void
1318 isc___mem_put(isc_mem_t *ctx0, void *ptr, size_t size FLARG) {
1319 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1320 isc_boolean_t call_water = ISC_FALSE;
1324 REQUIRE(VALID_CONTEXT(ctx));
1325 REQUIRE(ptr != NULL);
1327 if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) {
1328 if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) {
1329 si = &(((size_info *)ptr)[-1]);
1330 oldsize = si->u.size - ALIGNMENT_SIZE;
1331 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
1332 oldsize -= ALIGNMENT_SIZE;
1333 INSIST(oldsize == size);
1335 isc__mem_free((isc_mem_t *)ctx, ptr FLARG_PASS);
1339 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1340 MCTXLOCK(ctx, &ctx->lock);
1341 mem_putunlocked(ctx, ptr, size);
1343 mem_put(ctx, ptr, size);
1344 MCTXLOCK(ctx, &ctx->lock);
1345 mem_putstats(ctx, ptr, size);
1348 DELETE_TRACE(ctx, ptr, size, file, line);
1351 * The check against ctx->lo_water == 0 is for the condition
1352 * when the context was pushed over hi_water but then had
1353 * isc_mem_setwater() called with 0 for hi_water and lo_water.
1355 if ((ctx->inuse < ctx->lo_water) || (ctx->lo_water == 0U)) {
1356 ctx->is_overmem = ISC_FALSE;
1358 call_water = ISC_TRUE;
1361 MCTXUNLOCK(ctx, &ctx->lock);
1363 if (call_water && (ctx->water != NULL))
1364 (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
1367 ISC_MEMFUNC_SCOPE void
1368 isc__mem_waterack(isc_mem_t *ctx0, int flag) {
1369 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1371 REQUIRE(VALID_CONTEXT(ctx));
1373 MCTXLOCK(ctx, &ctx->lock);
1374 if (flag == ISC_MEM_LOWATER)
1375 ctx->hi_called = ISC_FALSE;
1376 else if (flag == ISC_MEM_HIWATER)
1377 ctx->hi_called = ISC_TRUE;
1378 MCTXUNLOCK(ctx, &ctx->lock);
1381 #if ISC_MEM_TRACKLINES
1383 print_active(isc__mem_t *mctx, FILE *out) {
1384 if (mctx->debuglist != NULL) {
1388 isc_boolean_t found;
1390 fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1392 "Dump of all outstanding "
1393 "memory allocations:\n"));
1395 format = isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1396 ISC_MSG_PTRFILELINE,
1397 "\tptr %p size %u file %s line %u\n");
1398 for (i = 0; i <= mctx->max_size; i++) {
1399 dl = ISC_LIST_HEAD(mctx->debuglist[i]);
1404 while (dl != NULL) {
1405 for (j = 0; j < DEBUGLIST_COUNT; j++)
1406 if (dl->ptr[j] != NULL)
1407 fprintf(out, format,
1412 dl = ISC_LIST_NEXT(dl, link);
1416 fputs(isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1417 ISC_MSG_NONE, "\tNone.\n"), out);
1423 * Print the stats[] on the stream "out" with suitable formatting.
1425 ISC_MEMFUNC_SCOPE void
1426 isc__mem_stats(isc_mem_t *ctx0, FILE *out) {
1427 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1429 const struct stats *s;
1430 const isc__mempool_t *pool;
1432 REQUIRE(VALID_CONTEXT(ctx));
1433 MCTXLOCK(ctx, &ctx->lock);
1435 for (i = 0; i <= ctx->max_size; i++) {
1438 if (s->totalgets == 0U && s->gets == 0U)
1440 fprintf(out, "%s%5lu: %11lu gets, %11lu rem",
1441 (i == ctx->max_size) ? ">=" : " ",
1442 (unsigned long) i, s->totalgets, s->gets);
1443 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0 &&
1444 (s->blocks != 0U || s->freefrags != 0U))
1445 fprintf(out, " (%lu bl, %lu ff)",
1446 s->blocks, s->freefrags);
1451 * Note that since a pool can be locked now, these stats might be
1452 * somewhat off if the pool is in active use at the time the stats
1453 * are dumped. The link fields are protected by the isc_mem_t's
1454 * lock, however, so walking this list and extracting integers from
1455 * stats fields is always safe.
1457 pool = ISC_LIST_HEAD(ctx->pools);
1459 fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1461 "[Pool statistics]\n"));
1462 fprintf(out, "%15s %10s %10s %10s %10s %10s %10s %10s %1s\n",
1463 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1464 ISC_MSG_POOLNAME, "name"),
1465 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1466 ISC_MSG_POOLSIZE, "size"),
1467 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1468 ISC_MSG_POOLMAXALLOC, "maxalloc"),
1469 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1470 ISC_MSG_POOLALLOCATED, "allocated"),
1471 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1472 ISC_MSG_POOLFREECOUNT, "freecount"),
1473 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1474 ISC_MSG_POOLFREEMAX, "freemax"),
1475 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1476 ISC_MSG_POOLFILLCOUNT, "fillcount"),
1477 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1478 ISC_MSG_POOLGETS, "gets"),
1481 while (pool != NULL) {
1482 fprintf(out, "%15s %10lu %10u %10u %10u %10u %10u %10u %s\n",
1483 #if ISC_MEMPOOL_NAMES
1488 (unsigned long) pool->size, pool->maxalloc,
1489 pool->allocated, pool->freecount, pool->freemax,
1490 pool->fillcount, pool->gets,
1491 (pool->lock == NULL ? "N" : "Y"));
1492 pool = ISC_LIST_NEXT(pool, link);
1495 #if ISC_MEM_TRACKLINES
1496 print_active(ctx, out);
1499 MCTXUNLOCK(ctx, &ctx->lock);
1503 * Replacements for malloc() and free() -- they implicitly remember the
1504 * size of the object allocated (with some additional overhead).
1508 isc__mem_allocateunlocked(isc_mem_t *ctx0, size_t size) {
1509 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1512 size += ALIGNMENT_SIZE;
1513 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
1514 size += ALIGNMENT_SIZE;
1516 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0)
1517 si = mem_getunlocked(ctx, size);
1519 si = mem_get(ctx, size);
1523 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
1531 ISC_MEMFUNC_SCOPE void *
1532 isc___mem_allocate(isc_mem_t *ctx0, size_t size FLARG) {
1533 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1535 isc_boolean_t call_water = ISC_FALSE;
1537 REQUIRE(VALID_CONTEXT(ctx));
1539 MCTXLOCK(ctx, &ctx->lock);
1540 si = isc__mem_allocateunlocked((isc_mem_t *)ctx, size);
1541 if (((ctx->flags & ISC_MEMFLAG_INTERNAL) == 0) && (si != NULL))
1542 mem_getstats(ctx, si[-1].u.size);
1544 #if ISC_MEM_TRACKLINES
1545 ADD_TRACE(ctx, si, si[-1].u.size, file, line);
1547 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1549 ctx->is_overmem = ISC_TRUE;
1552 if (ctx->hi_water != 0U && !ctx->hi_called &&
1553 ctx->inuse > ctx->hi_water) {
1554 ctx->hi_called = ISC_TRUE;
1555 call_water = ISC_TRUE;
1557 if (ctx->inuse > ctx->maxinuse) {
1558 ctx->maxinuse = ctx->inuse;
1559 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1560 (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
1561 fprintf(stderr, "maxinuse = %lu\n",
1562 (unsigned long)ctx->inuse);
1564 MCTXUNLOCK(ctx, &ctx->lock);
1567 (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
1572 ISC_MEMFUNC_SCOPE void *
1573 isc___mem_reallocate(isc_mem_t *ctx0, void *ptr, size_t size FLARG) {
1574 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1575 void *new_ptr = NULL;
1576 size_t oldsize, copysize;
1578 REQUIRE(VALID_CONTEXT(ctx));
1581 * This function emulates the realloc(3) standard library function:
1582 * - if size > 0, allocate new memory; and if ptr is non NULL, copy
1583 * as much of the old contents to the new buffer and free the old one.
1584 * Note that when allocation fails the original pointer is intact;
1585 * the caller must free it.
1586 * - if size is 0 and ptr is non NULL, simply free the given ptr.
1587 * - this function returns:
1588 * pointer to the newly allocated memory, or
1589 * NULL if allocation fails or doesn't happen.
1592 new_ptr = isc__mem_allocate(ctx0, size FLARG_PASS);
1593 if (new_ptr != NULL && ptr != NULL) {
1594 oldsize = (((size_info *)ptr)[-1]).u.size;
1595 INSIST(oldsize >= ALIGNMENT_SIZE);
1596 oldsize -= ALIGNMENT_SIZE;
1597 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
1598 INSIST(oldsize >= ALIGNMENT_SIZE);
1599 oldsize -= ALIGNMENT_SIZE;
1601 copysize = (oldsize > size) ? size : oldsize;
1602 memmove(new_ptr, ptr, copysize);
1603 isc__mem_free(ctx0, ptr FLARG_PASS);
1605 } else if (ptr != NULL)
1606 isc__mem_free(ctx0, ptr FLARG_PASS);
1611 ISC_MEMFUNC_SCOPE void
1612 isc___mem_free(isc_mem_t *ctx0, void *ptr FLARG) {
1613 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1616 isc_boolean_t call_water= ISC_FALSE;
1618 REQUIRE(VALID_CONTEXT(ctx));
1619 REQUIRE(ptr != NULL);
1621 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
1622 si = &(((size_info *)ptr)[-2]);
1623 REQUIRE(si->u.ctx == ctx);
1624 size = si[1].u.size;
1626 si = &(((size_info *)ptr)[-1]);
1630 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1631 MCTXLOCK(ctx, &ctx->lock);
1632 mem_putunlocked(ctx, si, size);
1634 mem_put(ctx, si, size);
1635 MCTXLOCK(ctx, &ctx->lock);
1636 mem_putstats(ctx, si, size);
1639 DELETE_TRACE(ctx, ptr, size, file, line);
1642 * The check against ctx->lo_water == 0 is for the condition
1643 * when the context was pushed over hi_water but then had
1644 * isc_mem_setwater() called with 0 for hi_water and lo_water.
1646 if (ctx->is_overmem &&
1647 (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1648 ctx->is_overmem = ISC_FALSE;
1651 if (ctx->hi_called &&
1652 (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1653 ctx->hi_called = ISC_FALSE;
1655 if (ctx->water != NULL)
1656 call_water = ISC_TRUE;
1658 MCTXUNLOCK(ctx, &ctx->lock);
1661 (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
1666 * Other useful things.
1669 ISC_MEMFUNC_SCOPE char *
1670 isc___mem_strdup(isc_mem_t *mctx0, const char *s FLARG) {
1671 isc__mem_t *mctx = (isc__mem_t *)mctx0;
1675 REQUIRE(VALID_CONTEXT(mctx));
1680 ns = isc___mem_allocate((isc_mem_t *)mctx, len + 1 FLARG_PASS);
1683 strncpy(ns, s, len + 1);
1688 ISC_MEMFUNC_SCOPE void
1689 isc__mem_setdestroycheck(isc_mem_t *ctx0, isc_boolean_t flag) {
1690 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1692 REQUIRE(VALID_CONTEXT(ctx));
1693 MCTXLOCK(ctx, &ctx->lock);
1695 ctx->checkfree = flag;
1697 MCTXUNLOCK(ctx, &ctx->lock);
1704 ISC_MEMFUNC_SCOPE void
1705 isc__mem_setquota(isc_mem_t *ctx0, size_t quota) {
1706 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1708 REQUIRE(VALID_CONTEXT(ctx));
1709 MCTXLOCK(ctx, &ctx->lock);
1713 MCTXUNLOCK(ctx, &ctx->lock);
1716 ISC_MEMFUNC_SCOPE size_t
1717 isc__mem_getquota(isc_mem_t *ctx0) {
1718 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1721 REQUIRE(VALID_CONTEXT(ctx));
1722 MCTXLOCK(ctx, &ctx->lock);
1726 MCTXUNLOCK(ctx, &ctx->lock);
1731 ISC_MEMFUNC_SCOPE size_t
1732 isc__mem_inuse(isc_mem_t *ctx0) {
1733 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1736 REQUIRE(VALID_CONTEXT(ctx));
1737 MCTXLOCK(ctx, &ctx->lock);
1741 MCTXUNLOCK(ctx, &ctx->lock);
1746 ISC_MEMFUNC_SCOPE void
1747 isc__mem_setwater(isc_mem_t *ctx0, isc_mem_water_t water, void *water_arg,
1748 size_t hiwater, size_t lowater)
1750 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1751 isc_boolean_t callwater = ISC_FALSE;
1752 isc_mem_water_t oldwater;
1755 REQUIRE(VALID_CONTEXT(ctx));
1756 REQUIRE(hiwater >= lowater);
1758 MCTXLOCK(ctx, &ctx->lock);
1759 oldwater = ctx->water;
1760 oldwater_arg = ctx->water_arg;
1761 if (water == NULL) {
1762 callwater = ctx->hi_called;
1764 ctx->water_arg = NULL;
1768 if (ctx->hi_called &&
1769 (ctx->water != water || ctx->water_arg != water_arg ||
1770 ctx->inuse < lowater || lowater == 0U))
1771 callwater = ISC_TRUE;
1773 ctx->water_arg = water_arg;
1774 ctx->hi_water = hiwater;
1775 ctx->lo_water = lowater;
1777 MCTXUNLOCK(ctx, &ctx->lock);
1779 if (callwater && oldwater != NULL)
1780 (oldwater)(oldwater_arg, ISC_MEM_LOWATER);
1783 ISC_MEMFUNC_SCOPE isc_boolean_t
1784 isc__mem_isovermem(isc_mem_t *ctx0) {
1785 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1787 REQUIRE(VALID_CONTEXT(ctx));
1790 * We don't bother to lock the context because 100% accuracy isn't
1791 * necessary (and even if we locked the context the returned value
1792 * could be different from the actual state when it's used anyway)
1794 return (ctx->is_overmem);
1797 ISC_MEMFUNC_SCOPE void
1798 isc__mem_setname(isc_mem_t *ctx0, const char *name, void *tag) {
1799 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1801 REQUIRE(VALID_CONTEXT(ctx));
1804 memset(ctx->name, 0, sizeof(ctx->name));
1805 strncpy(ctx->name, name, sizeof(ctx->name) - 1);
1810 ISC_MEMFUNC_SCOPE const char *
1811 isc__mem_getname(isc_mem_t *ctx0) {
1812 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1814 REQUIRE(VALID_CONTEXT(ctx));
1819 ISC_MEMFUNC_SCOPE void *
1820 isc__mem_gettag(isc_mem_t *ctx0) {
1821 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1823 REQUIRE(VALID_CONTEXT(ctx));
1832 ISC_MEMFUNC_SCOPE isc_result_t
1833 isc__mempool_create(isc_mem_t *mctx0, size_t size, isc_mempool_t **mpctxp) {
1834 isc__mem_t *mctx = (isc__mem_t *)mctx0;
1835 isc__mempool_t *mpctx;
1837 REQUIRE(VALID_CONTEXT(mctx));
1839 REQUIRE(mpctxp != NULL && *mpctxp == NULL);
1842 * Allocate space for this pool, initialize values, and if all works
1843 * well, attach to the memory context.
1845 mpctx = isc_mem_get((isc_mem_t *)mctx, sizeof(isc__mempool_t));
1847 return (ISC_R_NOMEMORY);
1849 mpctx->common.methods = (isc_mempoolmethods_t *)&mempoolmethods;
1850 mpctx->common.impmagic = MEMPOOL_MAGIC;
1851 mpctx->common.magic = ISCAPI_MPOOL_MAGIC;
1855 mpctx->maxalloc = UINT_MAX;
1856 mpctx->allocated = 0;
1857 mpctx->freecount = 0;
1859 mpctx->fillcount = 1;
1861 #if ISC_MEMPOOL_NAMES
1864 mpctx->items = NULL;
1866 *mpctxp = (isc_mempool_t *)mpctx;
1868 MCTXLOCK(mctx, &mctx->lock);
1869 ISC_LIST_INITANDAPPEND(mctx->pools, mpctx, link);
1871 MCTXUNLOCK(mctx, &mctx->lock);
1873 return (ISC_R_SUCCESS);
1876 ISC_MEMFUNC_SCOPE void
1877 isc__mempool_setname(isc_mempool_t *mpctx0, const char *name) {
1878 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
1880 REQUIRE(name != NULL);
1881 REQUIRE(VALID_MEMPOOL(mpctx));
1883 #if ISC_MEMPOOL_NAMES
1884 if (mpctx->lock != NULL)
1887 strncpy(mpctx->name, name, sizeof(mpctx->name) - 1);
1888 mpctx->name[sizeof(mpctx->name) - 1] = '\0';
1890 if (mpctx->lock != NULL)
1891 UNLOCK(mpctx->lock);
1898 ISC_MEMFUNC_SCOPE void
1899 isc__mempool_destroy(isc_mempool_t **mpctxp) {
1900 isc__mempool_t *mpctx;
1905 REQUIRE(mpctxp != NULL);
1906 mpctx = (isc__mempool_t *)*mpctxp;
1907 REQUIRE(VALID_MEMPOOL(mpctx));
1908 #if ISC_MEMPOOL_NAMES
1909 if (mpctx->allocated > 0)
1910 UNEXPECTED_ERROR(__FILE__, __LINE__,
1911 "isc__mempool_destroy(): mempool %s "
1915 REQUIRE(mpctx->allocated == 0);
1925 * Return any items on the free list
1927 MCTXLOCK(mctx, &mctx->lock);
1928 while (mpctx->items != NULL) {
1929 INSIST(mpctx->freecount > 0);
1931 item = mpctx->items;
1932 mpctx->items = item->next;
1934 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1935 mem_putunlocked(mctx, item, mpctx->size);
1937 mem_put(mctx, item, mpctx->size);
1938 mem_putstats(mctx, item, mpctx->size);
1941 MCTXUNLOCK(mctx, &mctx->lock);
1944 * Remove our linked list entry from the memory context.
1946 MCTXLOCK(mctx, &mctx->lock);
1947 ISC_LIST_UNLINK(mctx->pools, mpctx, link);
1949 MCTXUNLOCK(mctx, &mctx->lock);
1951 mpctx->common.impmagic = 0;
1952 mpctx->common.magic = 0;
1954 isc_mem_put((isc_mem_t *)mpctx->mctx, mpctx, sizeof(isc__mempool_t));
1962 ISC_MEMFUNC_SCOPE void
1963 isc__mempool_associatelock(isc_mempool_t *mpctx0, isc_mutex_t *lock) {
1964 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
1966 REQUIRE(VALID_MEMPOOL(mpctx));
1967 REQUIRE(mpctx->lock == NULL);
1968 REQUIRE(lock != NULL);
1973 ISC_MEMFUNC_SCOPE void *
1974 isc___mempool_get(isc_mempool_t *mpctx0 FLARG) {
1975 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
1980 REQUIRE(VALID_MEMPOOL(mpctx));
1984 if (mpctx->lock != NULL)
1988 * Don't let the caller go over quota
1990 if (mpctx->allocated >= mpctx->maxalloc) {
1996 * if we have a free list item, return the first here
1998 item = mpctx->items;
2000 mpctx->items = item->next;
2001 INSIST(mpctx->freecount > 0);
2009 * We need to dip into the well. Lock the memory context here and
2010 * fill up our free list.
2012 MCTXLOCK(mctx, &mctx->lock);
2013 for (i = 0; i < mpctx->fillcount; i++) {
2014 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
2015 item = mem_getunlocked(mctx, mpctx->size);
2017 item = mem_get(mctx, mpctx->size);
2019 mem_getstats(mctx, mpctx->size);
2023 item->next = mpctx->items;
2024 mpctx->items = item;
2027 MCTXUNLOCK(mctx, &mctx->lock);
2030 * If we didn't get any items, return NULL.
2032 item = mpctx->items;
2036 mpctx->items = item->next;
2042 if (mpctx->lock != NULL)
2043 UNLOCK(mpctx->lock);
2045 #if ISC_MEM_TRACKLINES
2047 MCTXLOCK(mctx, &mctx->lock);
2048 ADD_TRACE(mctx, item, mpctx->size, file, line);
2049 MCTXUNLOCK(mctx, &mctx->lock);
2051 #endif /* ISC_MEM_TRACKLINES */
2056 ISC_MEMFUNC_SCOPE void
2057 isc___mempool_put(isc_mempool_t *mpctx0, void *mem FLARG) {
2058 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2062 REQUIRE(VALID_MEMPOOL(mpctx));
2063 REQUIRE(mem != NULL);
2067 if (mpctx->lock != NULL)
2070 INSIST(mpctx->allocated > 0);
2073 #if ISC_MEM_TRACKLINES
2074 MCTXLOCK(mctx, &mctx->lock);
2075 DELETE_TRACE(mctx, mem, mpctx->size, file, line);
2076 MCTXUNLOCK(mctx, &mctx->lock);
2077 #endif /* ISC_MEM_TRACKLINES */
2080 * If our free list is full, return this to the mctx directly.
2082 if (mpctx->freecount >= mpctx->freemax) {
2083 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
2084 MCTXLOCK(mctx, &mctx->lock);
2085 mem_putunlocked(mctx, mem, mpctx->size);
2086 MCTXUNLOCK(mctx, &mctx->lock);
2088 mem_put(mctx, mem, mpctx->size);
2089 MCTXLOCK(mctx, &mctx->lock);
2090 mem_putstats(mctx, mem, mpctx->size);
2091 MCTXUNLOCK(mctx, &mctx->lock);
2093 if (mpctx->lock != NULL)
2094 UNLOCK(mpctx->lock);
2099 * Otherwise, attach it to our free list and bump the counter.
2102 item = (element *)mem;
2103 item->next = mpctx->items;
2104 mpctx->items = item;
2106 if (mpctx->lock != NULL)
2107 UNLOCK(mpctx->lock);
2114 ISC_MEMFUNC_SCOPE void
2115 isc__mempool_setfreemax(isc_mempool_t *mpctx0, unsigned int limit) {
2116 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2118 REQUIRE(VALID_MEMPOOL(mpctx));
2120 if (mpctx->lock != NULL)
2123 mpctx->freemax = limit;
2125 if (mpctx->lock != NULL)
2126 UNLOCK(mpctx->lock);
2129 ISC_MEMFUNC_SCOPE unsigned int
2130 isc__mempool_getfreemax(isc_mempool_t *mpctx0) {
2131 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2132 unsigned int freemax;
2134 REQUIRE(VALID_MEMPOOL(mpctx));
2136 if (mpctx->lock != NULL)
2139 freemax = mpctx->freemax;
2141 if (mpctx->lock != NULL)
2142 UNLOCK(mpctx->lock);
2147 ISC_MEMFUNC_SCOPE unsigned int
2148 isc__mempool_getfreecount(isc_mempool_t *mpctx0) {
2149 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2150 unsigned int freecount;
2152 REQUIRE(VALID_MEMPOOL(mpctx));
2154 if (mpctx->lock != NULL)
2157 freecount = mpctx->freecount;
2159 if (mpctx->lock != NULL)
2160 UNLOCK(mpctx->lock);
2165 ISC_MEMFUNC_SCOPE void
2166 isc__mempool_setmaxalloc(isc_mempool_t *mpctx0, unsigned int limit) {
2167 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2171 REQUIRE(VALID_MEMPOOL(mpctx));
2173 if (mpctx->lock != NULL)
2176 mpctx->maxalloc = limit;
2178 if (mpctx->lock != NULL)
2179 UNLOCK(mpctx->lock);
2182 ISC_MEMFUNC_SCOPE unsigned int
2183 isc__mempool_getmaxalloc(isc_mempool_t *mpctx0) {
2184 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2185 unsigned int maxalloc;
2187 REQUIRE(VALID_MEMPOOL(mpctx));
2189 if (mpctx->lock != NULL)
2192 maxalloc = mpctx->maxalloc;
2194 if (mpctx->lock != NULL)
2195 UNLOCK(mpctx->lock);
2200 ISC_MEMFUNC_SCOPE unsigned int
2201 isc__mempool_getallocated(isc_mempool_t *mpctx0) {
2202 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2203 unsigned int allocated;
2205 REQUIRE(VALID_MEMPOOL(mpctx));
2207 if (mpctx->lock != NULL)
2210 allocated = mpctx->allocated;
2212 if (mpctx->lock != NULL)
2213 UNLOCK(mpctx->lock);
2218 ISC_MEMFUNC_SCOPE void
2219 isc__mempool_setfillcount(isc_mempool_t *mpctx0, unsigned int limit) {
2220 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2223 REQUIRE(VALID_MEMPOOL(mpctx));
2225 if (mpctx->lock != NULL)
2228 mpctx->fillcount = limit;
2230 if (mpctx->lock != NULL)
2231 UNLOCK(mpctx->lock);
2234 ISC_MEMFUNC_SCOPE unsigned int
2235 isc__mempool_getfillcount(isc_mempool_t *mpctx0) {
2236 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2238 unsigned int fillcount;
2240 REQUIRE(VALID_MEMPOOL(mpctx));
2242 if (mpctx->lock != NULL)
2245 fillcount = mpctx->fillcount;
2247 if (mpctx->lock != NULL)
2248 UNLOCK(mpctx->lock);
2253 #ifdef USE_MEMIMPREGISTER
2255 isc__mem_register(void) {
2256 return (isc_mem_register(isc__mem_create2));
2261 ISC_MEMFUNC_SCOPE void
2262 isc__mem_printactive(isc_mem_t *ctx0, FILE *file) {
2263 #if ISC_MEM_TRACKLINES
2264 isc__mem_t *ctx = (isc__mem_t *)ctx0;
2266 REQUIRE(VALID_CONTEXT(ctx));
2267 REQUIRE(file != NULL);
2269 print_active(ctx, file);
2276 ISC_MEMFUNC_SCOPE void
2277 isc__mem_printallactive(FILE *file) {
2278 #if !ISC_MEM_TRACKLINES
2283 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2285 LOCK(&contextslock);
2286 for (ctx = ISC_LIST_HEAD(contexts);
2288 ctx = ISC_LIST_NEXT(ctx, link)) {
2289 fprintf(file, "context: %p\n", ctx);
2290 print_active(ctx, file);
2292 UNLOCK(&contextslock);
2296 ISC_MEMFUNC_SCOPE void
2297 isc__mem_checkdestroyed(FILE *file) {
2298 #if !ISC_MEM_TRACKLINES
2302 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2304 LOCK(&contextslock);
2305 if (!ISC_LIST_EMPTY(contexts)) {
2306 #if ISC_MEM_TRACKLINES
2309 for (ctx = ISC_LIST_HEAD(contexts);
2311 ctx = ISC_LIST_NEXT(ctx, link)) {
2312 fprintf(file, "context: %p\n", ctx);
2313 print_active(ctx, file);
2319 UNLOCK(&contextslock);
2322 ISC_MEMFUNC_SCOPE unsigned int
2323 isc_mem_references(isc_mem_t *ctx0) {
2324 isc__mem_t *ctx = (isc__mem_t *)ctx0;
2325 unsigned int references;
2327 REQUIRE(VALID_CONTEXT(ctx));
2329 MCTXLOCK(ctx, &ctx->lock);
2330 references = ctx->references;
2331 MCTXUNLOCK(ctx, &ctx->lock);
2333 return (references);
2338 typedef struct summarystat {
2341 isc_uint64_t blocksize;
2342 isc_uint64_t contextsize;
2345 #define TRY0(a) do { xmlrc = (a); if (xmlrc < 0) goto error; } while(0)
2347 renderctx(isc__mem_t *ctx, summarystat_t *summary, xmlTextWriterPtr writer) {
2350 REQUIRE(VALID_CONTEXT(ctx));
2352 MCTXLOCK(ctx, &ctx->lock);
2354 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "context"));
2356 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "id"));
2357 TRY0(xmlTextWriterWriteFormatString(writer, "%p", ctx));
2358 TRY0(xmlTextWriterEndElement(writer)); /* id */
2360 if (ctx->name[0] != 0) {
2361 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"));
2362 TRY0(xmlTextWriterWriteFormatString(writer, "%s", ctx->name));
2363 TRY0(xmlTextWriterEndElement(writer)); /* name */
2366 summary->contextsize += sizeof(*ctx) +
2367 (ctx->max_size + 1) * sizeof(struct stats) +
2368 ctx->max_size * sizeof(element *) +
2369 ctx->basic_table_count * sizeof(char *);
2370 #if ISC_MEM_TRACKLINES
2371 if (ctx->debuglist != NULL) {
2372 summary->contextsize +=
2373 (ctx->max_size + 1) * sizeof(debuglist_t) +
2374 ctx->debuglistcnt * sizeof(debuglink_t);
2377 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "references"));
2378 TRY0(xmlTextWriterWriteFormatString(writer, "%d", ctx->references));
2379 TRY0(xmlTextWriterEndElement(writer)); /* references */
2381 summary->total += ctx->total;
2382 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "total"));
2383 TRY0(xmlTextWriterWriteFormatString(writer,
2384 "%" ISC_PRINT_QUADFORMAT "u",
2385 (isc_uint64_t)ctx->total));
2386 TRY0(xmlTextWriterEndElement(writer)); /* total */
2388 summary->inuse += ctx->inuse;
2389 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "inuse"));
2390 TRY0(xmlTextWriterWriteFormatString(writer,
2391 "%" ISC_PRINT_QUADFORMAT "u",
2392 (isc_uint64_t)ctx->inuse));
2393 TRY0(xmlTextWriterEndElement(writer)); /* inuse */
2395 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "maxinuse"));
2396 TRY0(xmlTextWriterWriteFormatString(writer,
2397 "%" ISC_PRINT_QUADFORMAT "u",
2398 (isc_uint64_t)ctx->maxinuse));
2399 TRY0(xmlTextWriterEndElement(writer)); /* maxinuse */
2401 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "blocksize"));
2402 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
2403 summary->blocksize += ctx->basic_table_count *
2404 NUM_BASIC_BLOCKS * ctx->mem_target;
2405 TRY0(xmlTextWriterWriteFormatString(writer,
2406 "%" ISC_PRINT_QUADFORMAT "u",
2408 ctx->basic_table_count *
2412 TRY0(xmlTextWriterWriteFormatString(writer, "%s", "-"));
2413 TRY0(xmlTextWriterEndElement(writer)); /* blocksize */
2415 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "pools"));
2416 TRY0(xmlTextWriterWriteFormatString(writer, "%u", ctx->poolcnt));
2417 TRY0(xmlTextWriterEndElement(writer)); /* pools */
2418 summary->contextsize += ctx->poolcnt * sizeof(isc_mempool_t);
2420 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "hiwater"));
2421 TRY0(xmlTextWriterWriteFormatString(writer,
2422 "%" ISC_PRINT_QUADFORMAT "u",
2423 (isc_uint64_t)ctx->hi_water));
2424 TRY0(xmlTextWriterEndElement(writer)); /* hiwater */
2426 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "lowater"));
2427 TRY0(xmlTextWriterWriteFormatString(writer,
2428 "%" ISC_PRINT_QUADFORMAT "u",
2429 (isc_uint64_t)ctx->lo_water));
2430 TRY0(xmlTextWriterEndElement(writer)); /* lowater */
2432 TRY0(xmlTextWriterEndElement(writer)); /* context */
2435 MCTXUNLOCK(ctx, &ctx->lock);
2441 isc_mem_renderxml(xmlTextWriterPtr writer) {
2443 summarystat_t summary;
2447 memset(&summary, 0, sizeof(summary));
2449 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "contexts"));
2451 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2453 LOCK(&contextslock);
2455 for (ctx = ISC_LIST_HEAD(contexts);
2457 ctx = ISC_LIST_NEXT(ctx, link)) {
2458 xmlrc = renderctx(ctx, &summary, writer);
2460 UNLOCK(&contextslock);
2464 UNLOCK(&contextslock);
2466 TRY0(xmlTextWriterEndElement(writer)); /* contexts */
2468 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "summary"));
2470 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "TotalUse"));
2471 TRY0(xmlTextWriterWriteFormatString(writer,
2472 "%" ISC_PRINT_QUADFORMAT "u",
2474 TRY0(xmlTextWriterEndElement(writer)); /* TotalUse */
2476 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "InUse"));
2477 TRY0(xmlTextWriterWriteFormatString(writer,
2478 "%" ISC_PRINT_QUADFORMAT "u",
2480 TRY0(xmlTextWriterEndElement(writer)); /* InUse */
2482 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "BlockSize"));
2483 TRY0(xmlTextWriterWriteFormatString(writer,
2484 "%" ISC_PRINT_QUADFORMAT "u",
2485 summary.blocksize));
2486 TRY0(xmlTextWriterEndElement(writer)); /* BlockSize */
2488 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "ContextSize"));
2489 TRY0(xmlTextWriterWriteFormatString(writer,
2490 "%" ISC_PRINT_QUADFORMAT "u",
2491 summary.contextsize));
2492 TRY0(xmlTextWriterEndElement(writer)); /* ContextSize */
2494 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "Lost"));
2495 TRY0(xmlTextWriterWriteFormatString(writer,
2496 "%" ISC_PRINT_QUADFORMAT "u",
2498 TRY0(xmlTextWriterEndElement(writer)); /* Lost */
2500 TRY0(xmlTextWriterEndElement(writer)); /* summary */
2505 #endif /* HAVE_LIBXML2 */