2 * Copyright (C) 2004-2010, 2012-2014 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.
30 #include <isc/magic.h>
34 #include <isc/ondestroy.h>
35 #include <isc/string.h>
36 #include <isc/mutex.h>
37 #include <isc/print.h>
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)
44 #ifndef ISC_MEM_DEBUGGING
45 #define ISC_MEM_DEBUGGING 0
47 LIBISC_EXTERNAL_DATA unsigned int isc_mem_debugging = ISC_MEM_DEBUGGING;
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
63 typedef struct isc__mem isc__mem_t;
64 typedef struct isc__mempool isc__mempool_t;
66 #if ISC_MEM_TRACKLINES
67 typedef struct debuglink debuglink_t;
69 ISC_LINK(debuglink_t) link;
70 const void *ptr[DEBUGLIST_COUNT];
71 size_t size[DEBUGLIST_COUNT];
72 const char *file[DEBUGLIST_COUNT];
73 unsigned int line[DEBUGLIST_COUNT];
77 #define FLARG_PASS , file, line
78 #define FLARG , const char *file, unsigned int line
84 typedef struct element element;
91 * This structure must be ALIGNMENT_SIZE bytes.
96 char bytes[ALIGNMENT_SIZE];
102 unsigned long totalgets;
103 unsigned long blocks;
104 unsigned long freefrags;
107 #define MEM_MAGIC ISC_MAGIC('M', 'e', 'm', 'C')
108 #define VALID_CONTEXT(c) ISC_MAGIC_VALID(c, MEM_MAGIC)
110 #if ISC_MEM_TRACKLINES
111 typedef ISC_LIST(debuglink_t) debuglist_t;
114 /* List of all active memory contexts. */
116 static ISC_LIST(isc__mem_t) contexts;
117 static isc_once_t once = ISC_ONCE_INIT;
118 static isc_mutex_t lock;
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);
220 * The following can be either static or public, depending on build environment.
224 #define ISC_MEMFUNC_SCOPE
226 #define ISC_MEMFUNC_SCOPE static
229 ISC_MEMFUNC_SCOPE isc_result_t
230 isc__mem_createx(size_t init_max_size, size_t target_size,
231 isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
233 ISC_MEMFUNC_SCOPE isc_result_t
234 isc__mem_createx2(size_t init_max_size, size_t target_size,
235 isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
236 isc_mem_t **ctxp, unsigned int flags);
237 ISC_MEMFUNC_SCOPE isc_result_t
238 isc__mem_create(size_t init_max_size, size_t target_size, isc_mem_t **ctxp);
239 ISC_MEMFUNC_SCOPE isc_result_t
240 isc__mem_create2(size_t init_max_size, size_t target_size,
241 isc_mem_t **ctxp, unsigned int flags);
242 ISC_MEMFUNC_SCOPE void
243 isc__mem_attach(isc_mem_t *source, isc_mem_t **targetp);
244 ISC_MEMFUNC_SCOPE void
245 isc__mem_detach(isc_mem_t **ctxp);
246 ISC_MEMFUNC_SCOPE void
247 isc___mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG);
248 ISC_MEMFUNC_SCOPE void
249 isc__mem_destroy(isc_mem_t **ctxp);
250 ISC_MEMFUNC_SCOPE isc_result_t
251 isc__mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event);
252 ISC_MEMFUNC_SCOPE void *
253 isc___mem_get(isc_mem_t *ctx, size_t size FLARG);
254 ISC_MEMFUNC_SCOPE void
255 isc___mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG);
256 ISC_MEMFUNC_SCOPE void
257 isc__mem_stats(isc_mem_t *ctx, FILE *out);
258 ISC_MEMFUNC_SCOPE void *
259 isc___mem_allocate(isc_mem_t *ctx, size_t size FLARG);
260 ISC_MEMFUNC_SCOPE void *
261 isc___mem_reallocate(isc_mem_t *ctx, void *ptr, size_t size FLARG);
262 ISC_MEMFUNC_SCOPE void
263 isc___mem_free(isc_mem_t *ctx, void *ptr FLARG);
264 ISC_MEMFUNC_SCOPE char *
265 isc___mem_strdup(isc_mem_t *mctx, const char *s FLARG);
266 ISC_MEMFUNC_SCOPE void
267 isc__mem_setdestroycheck(isc_mem_t *ctx, isc_boolean_t flag);
268 ISC_MEMFUNC_SCOPE void
269 isc__mem_setquota(isc_mem_t *ctx, size_t quota);
270 ISC_MEMFUNC_SCOPE size_t
271 isc__mem_getquota(isc_mem_t *ctx);
272 ISC_MEMFUNC_SCOPE size_t
273 isc__mem_inuse(isc_mem_t *ctx);
274 ISC_MEMFUNC_SCOPE isc_boolean_t
275 isc__mem_isovermem(isc_mem_t *ctx);
276 ISC_MEMFUNC_SCOPE void
277 isc__mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg,
278 size_t hiwater, size_t lowater);
279 ISC_MEMFUNC_SCOPE void
280 isc__mem_waterack(isc_mem_t *ctx0, int flag);
281 ISC_MEMFUNC_SCOPE void
282 isc__mem_setname(isc_mem_t *ctx, const char *name, void *tag);
283 ISC_MEMFUNC_SCOPE const char *
284 isc__mem_getname(isc_mem_t *ctx);
285 ISC_MEMFUNC_SCOPE void *
286 isc__mem_gettag(isc_mem_t *ctx);
287 ISC_MEMFUNC_SCOPE isc_result_t
288 isc__mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp);
289 ISC_MEMFUNC_SCOPE void
290 isc__mempool_setname(isc_mempool_t *mpctx, const char *name);
291 ISC_MEMFUNC_SCOPE void
292 isc__mempool_destroy(isc_mempool_t **mpctxp);
293 ISC_MEMFUNC_SCOPE void
294 isc__mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock);
295 ISC_MEMFUNC_SCOPE void *
296 isc___mempool_get(isc_mempool_t *mpctx FLARG);
297 ISC_MEMFUNC_SCOPE void
298 isc___mempool_put(isc_mempool_t *mpctx, void *mem FLARG);
299 ISC_MEMFUNC_SCOPE void
300 isc__mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit);
301 ISC_MEMFUNC_SCOPE unsigned int
302 isc__mempool_getfreemax(isc_mempool_t *mpctx);
303 ISC_MEMFUNC_SCOPE unsigned int
304 isc__mempool_getfreecount(isc_mempool_t *mpctx);
305 ISC_MEMFUNC_SCOPE void
306 isc__mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit);
307 ISC_MEMFUNC_SCOPE unsigned int
308 isc__mempool_getmaxalloc(isc_mempool_t *mpctx);
309 ISC_MEMFUNC_SCOPE unsigned int
310 isc__mempool_getallocated(isc_mempool_t *mpctx);
311 ISC_MEMFUNC_SCOPE void
312 isc__mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit);
313 ISC_MEMFUNC_SCOPE unsigned int
314 isc__mempool_getfillcount(isc_mempool_t *mpctx);
316 ISC_MEMFUNC_SCOPE void
317 isc__mem_printactive(isc_mem_t *ctx0, FILE *file);
318 ISC_MEMFUNC_SCOPE void
319 isc__mem_printallactive(FILE *file);
320 ISC_MEMFUNC_SCOPE void
321 isc__mem_checkdestroyed(FILE *file);
322 ISC_MEMFUNC_SCOPE unsigned int
323 isc__mem_references(isc_mem_t *ctx0);
325 #endif /* ISC_MEM_TRACKLINES */
327 static struct isc__memmethods {
328 isc_memmethods_t methods;
331 * The following are defined just for avoiding unused static functions.
334 void *createx, *create, *create2, *ondestroy, *stats,
335 *setquota, *getquota, *setname, *getname, *gettag;
344 isc___mem_putanddetach,
346 isc___mem_reallocate,
349 isc__mem_setdestroycheck,
358 (void *)isc__mem_createx, (void *)isc__mem_create,
359 (void *)isc__mem_create2, (void *)isc__mem_ondestroy,
360 (void *)isc__mem_stats, (void *)isc__mem_setquota,
361 (void *)isc__mem_getquota, (void *)isc__mem_setname,
362 (void *)isc__mem_getname, (void *)isc__mem_gettag
366 static struct isc__mempoolmethods {
367 isc_mempoolmethods_t methods;
370 * The following are defined just for avoiding unused static functions.
373 void *getfreemax, *getfreecount, *getmaxalloc, *getfillcount;
377 isc__mempool_destroy,
380 isc__mempool_getallocated,
381 isc__mempool_setmaxalloc,
382 isc__mempool_setfreemax,
383 isc__mempool_setname,
384 isc__mempool_associatelock,
385 isc__mempool_setfillcount
389 (void *)isc__mempool_getfreemax, (void *)isc__mempool_getfreecount,
390 (void *)isc__mempool_getmaxalloc, (void *)isc__mempool_getfillcount
394 #if ISC_MEM_TRACKLINES
396 * mctx must be locked.
399 add_trace_entry(isc__mem_t *mctx, const void *ptr, size_t size FLARG) {
402 size_t mysize = size;
404 if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
405 fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
408 "file %s line %u mctx %p\n"),
409 ptr, size, file, line, mctx);
411 if (mctx->debuglist == NULL)
414 if (mysize > mctx->max_size)
415 mysize = mctx->max_size;
417 dl = ISC_LIST_HEAD(mctx->debuglist[mysize]);
419 if (dl->count == DEBUGLIST_COUNT)
421 for (i = 0; i < DEBUGLIST_COUNT; i++) {
422 if (dl->ptr[i] == NULL) {
432 dl = ISC_LIST_NEXT(dl, link);
435 dl = malloc(sizeof(debuglink_t));
438 ISC_LINK_INIT(dl, link);
439 for (i = 1; i < DEBUGLIST_COUNT; i++) {
452 ISC_LIST_PREPEND(mctx->debuglist[mysize], dl, link);
453 mctx->debuglistcnt++;
457 delete_trace_entry(isc__mem_t *mctx, const void *ptr, size_t size,
458 const char *file, unsigned int line)
463 if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
464 fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
467 "file %s line %u mctx %p\n"),
468 ptr, size, file, line, mctx);
470 if (mctx->debuglist == NULL)
473 if (size > mctx->max_size)
474 size = mctx->max_size;
476 dl = ISC_LIST_HEAD(mctx->debuglist[size]);
478 for (i = 0; i < DEBUGLIST_COUNT; i++) {
479 if (dl->ptr[i] == ptr) {
485 INSIST(dl->count > 0);
487 if (dl->count == 0) {
488 ISC_LIST_UNLINK(mctx->debuglist[size],
495 dl = ISC_LIST_NEXT(dl, link);
499 * If we get here, we didn't find the item on the list. We're
504 #endif /* ISC_MEM_TRACKLINES */
507 rmsize(size_t size) {
509 * round down to ALIGNMENT_SIZE
511 return (size & (~(ALIGNMENT_SIZE - 1)));
515 quantize(size_t size) {
517 * Round up the result in order to get a size big
518 * enough to satisfy the request and be aligned on ALIGNMENT_SIZE
523 return (ALIGNMENT_SIZE);
524 return ((size + ALIGNMENT_SIZE - 1) & (~(ALIGNMENT_SIZE - 1)));
527 static inline isc_boolean_t
528 more_basic_blocks(isc__mem_t *ctx) {
530 unsigned char *curr, *next;
531 unsigned char *first, *last;
532 unsigned char **table;
533 unsigned int table_size;
537 /* Require: we hold the context lock. */
540 * Did we hit the quota for this context?
542 increment = NUM_BASIC_BLOCKS * ctx->mem_target;
543 if (ctx->quota != 0U && ctx->total + increment > ctx->quota)
546 INSIST(ctx->basic_table_count <= ctx->basic_table_size);
547 if (ctx->basic_table_count == ctx->basic_table_size) {
548 table_size = ctx->basic_table_size + TABLE_INCREMENT;
549 table = (ctx->memalloc)(ctx->arg,
550 table_size * sizeof(unsigned char *));
552 ctx->memalloc_failures++;
555 if (ctx->basic_table_size != 0) {
556 memmove(table, ctx->basic_table,
557 ctx->basic_table_size *
558 sizeof(unsigned char *));
559 (ctx->memfree)(ctx->arg, ctx->basic_table);
561 ctx->basic_table = table;
562 ctx->basic_table_size = table_size;
565 new = (ctx->memalloc)(ctx->arg, NUM_BASIC_BLOCKS * ctx->mem_target);
567 ctx->memalloc_failures++;
570 ctx->total += increment;
571 ctx->basic_table[ctx->basic_table_count] = new;
572 ctx->basic_table_count++;
575 next = curr + ctx->mem_target;
576 for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) {
577 ((element *)curr)->next = (element *)next;
579 next += ctx->mem_target;
582 * curr is now pointing at the last block in the
585 ((element *)curr)->next = NULL;
587 last = first + NUM_BASIC_BLOCKS * ctx->mem_target - 1;
588 if (first < ctx->lowest || ctx->lowest == NULL)
590 if (last > ctx->highest)
592 ctx->basic_blocks = new;
597 static inline isc_boolean_t
598 more_frags(isc__mem_t *ctx, size_t new_size) {
602 unsigned char *curr, *next;
605 * Try to get more fragments by chopping up a basic block.
608 if (ctx->basic_blocks == NULL) {
609 if (!more_basic_blocks(ctx)) {
611 * We can't get more memory from the OS, or we've
612 * hit the quota for this context.
615 * XXXRTH "At quota" notification here.
621 total_size = ctx->mem_target;
622 new = ctx->basic_blocks;
623 ctx->basic_blocks = ctx->basic_blocks->next;
624 frags = (int)(total_size / new_size);
625 ctx->stats[new_size].blocks++;
626 ctx->stats[new_size].freefrags += frags;
628 * Set up a linked-list of blocks of size
632 next = curr + new_size;
633 total_size -= new_size;
634 for (i = 0; i < (frags - 1); i++) {
635 ((element *)curr)->next = (element *)next;
638 total_size -= new_size;
641 * Add the remaining fragment of the basic block to a free list.
643 total_size = rmsize(total_size);
644 if (total_size > 0U) {
645 ((element *)next)->next = ctx->freelists[total_size];
646 ctx->freelists[total_size] = (element *)next;
647 ctx->stats[total_size].freefrags++;
650 * curr is now pointing at the last block in the
653 ((element *)curr)->next = NULL;
654 ctx->freelists[new_size] = new;
660 mem_getunlocked(isc__mem_t *ctx, size_t size) {
661 size_t new_size = quantize(size);
664 if (size >= ctx->max_size || new_size >= ctx->max_size) {
666 * memget() was called on something beyond our upper limit.
668 if (ctx->quota != 0U && ctx->total + size > ctx->quota) {
672 ret = (ctx->memalloc)(ctx->arg, size);
674 ctx->memalloc_failures++;
679 ctx->stats[ctx->max_size].gets++;
680 ctx->stats[ctx->max_size].totalgets++;
682 * If we don't set new_size to size, then the
683 * ISC_MEM_FILL code might write over bytes we
691 * If there are no blocks in the free list for this size, get a chunk
692 * of memory and then break it up into "new_size"-sized blocks, adding
693 * them to the free list.
695 if (ctx->freelists[new_size] == NULL && !more_frags(ctx, new_size))
699 * The free list uses the "rounded-up" size "new_size".
701 ret = ctx->freelists[new_size];
702 ctx->freelists[new_size] = ctx->freelists[new_size]->next;
705 * The stats[] uses the _actual_ "size" requested by the
706 * caller, with the caveat (in the code above) that "size" >= the
707 * max. size (max_size) ends up getting recorded as a call to
710 ctx->stats[size].gets++;
711 ctx->stats[size].totalgets++;
712 ctx->stats[new_size].freefrags--;
713 ctx->inuse += new_size;
719 memset(ret, 0xbe, new_size); /* Mnemonic for "beef". */
725 #if ISC_MEM_FILL && ISC_MEM_CHECKOVERRUN
727 check_overrun(void *mem, size_t size, size_t new_size) {
730 cp = (unsigned char *)mem;
732 while (size < new_size) {
741 mem_putunlocked(isc__mem_t *ctx, void *mem, size_t size) {
742 size_t new_size = quantize(size);
744 if (size == ctx->max_size || new_size >= ctx->max_size) {
746 * memput() called on something beyond our upper limit.
749 memset(mem, 0xde, size); /* Mnemonic for "dead". */
751 (ctx->memfree)(ctx->arg, mem);
752 INSIST(ctx->stats[ctx->max_size].gets != 0U);
753 ctx->stats[ctx->max_size].gets--;
754 INSIST(size <= ctx->total);
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(&lock) == ISC_R_SUCCESS);
886 ISC_LIST_INIT(contexts);
894 ISC_MEMFUNC_SCOPE isc_result_t
895 isc__mem_createx(size_t init_max_size, size_t target_size,
896 isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
899 return (isc__mem_createx2(init_max_size, target_size, memalloc, memfree,
900 arg, ctxp, ISC_MEMFLAG_DEFAULT));
904 ISC_MEMFUNC_SCOPE isc_result_t
905 isc__mem_createx2(size_t init_max_size, size_t target_size,
906 isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
907 isc_mem_t **ctxp, unsigned int flags)
912 REQUIRE(ctxp != NULL && *ctxp == NULL);
913 REQUIRE(memalloc != NULL);
914 REQUIRE(memfree != NULL);
916 INSIST((ALIGNMENT_SIZE & (ALIGNMENT_SIZE - 1)) == 0);
918 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
920 ctx = (memalloc)(arg, sizeof(*ctx));
922 return (ISC_R_NOMEMORY);
924 if ((flags & ISC_MEMFLAG_NOLOCK) == 0) {
925 result = isc_mutex_init(&ctx->lock);
926 if (result != ISC_R_SUCCESS) {
932 if (init_max_size == 0U)
933 ctx->max_size = DEF_MAX_SIZE;
935 ctx->max_size = init_max_size;
938 memset(ctx->name, 0, sizeof(ctx->name));
946 ctx->hi_called = ISC_FALSE;
947 ctx->is_overmem = ISC_FALSE;
949 ctx->water_arg = NULL;
950 ctx->common.impmagic = MEM_MAGIC;
951 ctx->common.magic = ISCAPI_MCTX_MAGIC;
952 ctx->common.methods = (isc_memmethods_t *)&memmethods;
953 isc_ondestroy_init(&ctx->ondestroy);
954 ctx->memalloc = memalloc;
955 ctx->memfree = memfree;
958 ctx->checkfree = ISC_TRUE;
959 #if ISC_MEM_TRACKLINES
960 ctx->debuglist = NULL;
961 ctx->debuglistcnt = 0;
963 ISC_LIST_INIT(ctx->pools);
965 ctx->freelists = NULL;
966 ctx->basic_blocks = NULL;
967 ctx->basic_table = NULL;
968 ctx->basic_table_count = 0;
969 ctx->basic_table_size = 0;
973 ctx->stats = (memalloc)(arg,
974 (ctx->max_size+1) * sizeof(struct stats));
975 if (ctx->stats == NULL) {
976 result = ISC_R_NOMEMORY;
979 memset(ctx->stats, 0, (ctx->max_size + 1) * sizeof(struct stats));
981 if ((flags & ISC_MEMFLAG_INTERNAL) != 0) {
982 if (target_size == 0U)
983 ctx->mem_target = DEF_MEM_TARGET;
985 ctx->mem_target = target_size;
986 ctx->freelists = (memalloc)(arg, ctx->max_size *
988 if (ctx->freelists == NULL) {
989 result = ISC_R_NOMEMORY;
992 memset(ctx->freelists, 0,
993 ctx->max_size * sizeof(element *));
996 #if ISC_MEM_TRACKLINES
997 if ((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0) {
1000 ctx->debuglist = (memalloc)(arg,
1001 (ctx->max_size+1) * sizeof(debuglist_t));
1002 if (ctx->debuglist == NULL) {
1003 result = ISC_R_NOMEMORY;
1006 for (i = 0; i <= ctx->max_size; i++)
1007 ISC_LIST_INIT(ctx->debuglist[i]);
1011 ctx->memalloc_failures = 0;
1014 ISC_LIST_INITANDAPPEND(contexts, ctx, link);
1017 *ctxp = (isc_mem_t *)ctx;
1018 return (ISC_R_SUCCESS);
1022 if (ctx->stats != NULL)
1023 (memfree)(arg, ctx->stats);
1024 if (ctx->freelists != NULL)
1025 (memfree)(arg, ctx->freelists);
1026 #if ISC_MEM_TRACKLINES
1027 if (ctx->debuglist != NULL)
1028 (ctx->memfree)(ctx->arg, ctx->debuglist);
1029 #endif /* ISC_MEM_TRACKLINES */
1030 if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
1031 DESTROYLOCK(&ctx->lock);
1032 (memfree)(arg, ctx);
1038 ISC_MEMFUNC_SCOPE isc_result_t
1039 isc__mem_create(size_t init_max_size, size_t target_size, isc_mem_t **ctxp) {
1040 return (isc__mem_createx2(init_max_size, target_size,
1041 default_memalloc, default_memfree, NULL,
1042 ctxp, ISC_MEMFLAG_DEFAULT));
1045 ISC_MEMFUNC_SCOPE isc_result_t
1046 isc__mem_create2(size_t init_max_size, size_t target_size,
1047 isc_mem_t **ctxp, unsigned int flags)
1049 return (isc__mem_createx2(init_max_size, target_size,
1050 default_memalloc, default_memfree, NULL,
1055 destroy(isc__mem_t *ctx) {
1057 isc_ondestroy_t ondest;
1060 ISC_LIST_UNLINK(contexts, ctx, link);
1061 totallost += ctx->inuse;
1064 ctx->common.impmagic = 0;
1065 ctx->common.magic = 0;
1067 INSIST(ISC_LIST_EMPTY(ctx->pools));
1069 #if ISC_MEM_TRACKLINES
1070 if (ctx->debuglist != NULL) {
1071 if (ctx->checkfree) {
1072 for (i = 0; i <= ctx->max_size; i++) {
1073 if (!ISC_LIST_EMPTY(ctx->debuglist[i]))
1074 print_active(ctx, stderr);
1075 INSIST(ISC_LIST_EMPTY(ctx->debuglist[i]));
1080 for (i = 0; i <= ctx->max_size; i++)
1081 for (dl = ISC_LIST_HEAD(ctx->debuglist[i]);
1083 dl = ISC_LIST_HEAD(ctx->debuglist[i])) {
1084 ISC_LIST_UNLINK(ctx->debuglist[i],
1089 (ctx->memfree)(ctx->arg, ctx->debuglist);
1092 INSIST(ctx->references == 0);
1094 if (ctx->checkfree) {
1095 for (i = 0; i <= ctx->max_size; i++) {
1096 #if ISC_MEM_TRACKLINES
1097 if (ctx->stats[i].gets != 0U)
1098 print_active(ctx, stderr);
1100 INSIST(ctx->stats[i].gets == 0U);
1104 (ctx->memfree)(ctx->arg, ctx->stats);
1106 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1107 for (i = 0; i < ctx->basic_table_count; i++)
1108 (ctx->memfree)(ctx->arg, ctx->basic_table[i]);
1109 (ctx->memfree)(ctx->arg, ctx->freelists);
1110 if (ctx->basic_table != NULL)
1111 (ctx->memfree)(ctx->arg, ctx->basic_table);
1114 ondest = ctx->ondestroy;
1116 if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
1117 DESTROYLOCK(&ctx->lock);
1118 (ctx->memfree)(ctx->arg, ctx);
1120 isc_ondestroy_notify(&ondest, ctx);
1123 ISC_MEMFUNC_SCOPE void
1124 isc__mem_attach(isc_mem_t *source0, isc_mem_t **targetp) {
1125 isc__mem_t *source = (isc__mem_t *)source0;
1127 REQUIRE(VALID_CONTEXT(source));
1128 REQUIRE(targetp != NULL && *targetp == NULL);
1130 MCTXLOCK(source, &source->lock);
1131 source->references++;
1132 MCTXUNLOCK(source, &source->lock);
1134 *targetp = (isc_mem_t *)source;
1137 ISC_MEMFUNC_SCOPE void
1138 isc__mem_detach(isc_mem_t **ctxp) {
1140 isc_boolean_t want_destroy = ISC_FALSE;
1142 REQUIRE(ctxp != NULL);
1143 ctx = (isc__mem_t *)*ctxp;
1144 REQUIRE(VALID_CONTEXT(ctx));
1146 MCTXLOCK(ctx, &ctx->lock);
1147 INSIST(ctx->references > 0);
1149 if (ctx->references == 0)
1150 want_destroy = ISC_TRUE;
1151 MCTXUNLOCK(ctx, &ctx->lock);
1160 * isc_mem_putanddetach() is the equivalent of:
1163 * isc_mem_attach(ptr->mctx, &mctx);
1164 * isc_mem_detach(&ptr->mctx);
1165 * isc_mem_put(mctx, ptr, sizeof(*ptr);
1166 * isc_mem_detach(&mctx);
1169 ISC_MEMFUNC_SCOPE void
1170 isc___mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) {
1172 isc_boolean_t want_destroy = ISC_FALSE;
1176 REQUIRE(ctxp != NULL);
1177 ctx = (isc__mem_t *)*ctxp;
1178 REQUIRE(VALID_CONTEXT(ctx));
1179 REQUIRE(ptr != NULL);
1182 * Must be before mem_putunlocked() as ctxp is usually within
1187 if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) {
1188 if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) {
1189 si = &(((size_info *)ptr)[-1]);
1190 oldsize = si->u.size - ALIGNMENT_SIZE;
1191 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
1192 oldsize -= ALIGNMENT_SIZE;
1193 INSIST(oldsize == size);
1195 isc__mem_free((isc_mem_t *)ctx, ptr FLARG_PASS);
1197 MCTXLOCK(ctx, &ctx->lock);
1199 if (ctx->references == 0)
1200 want_destroy = ISC_TRUE;
1201 MCTXUNLOCK(ctx, &ctx->lock);
1208 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1209 MCTXLOCK(ctx, &ctx->lock);
1210 mem_putunlocked(ctx, ptr, size);
1212 mem_put(ctx, ptr, size);
1213 MCTXLOCK(ctx, &ctx->lock);
1214 mem_putstats(ctx, ptr, size);
1217 DELETE_TRACE(ctx, ptr, size, file, line);
1218 INSIST(ctx->references > 0);
1220 if (ctx->references == 0)
1221 want_destroy = ISC_TRUE;
1223 MCTXUNLOCK(ctx, &ctx->lock);
1229 ISC_MEMFUNC_SCOPE void
1230 isc__mem_destroy(isc_mem_t **ctxp) {
1234 * This routine provides legacy support for callers who use mctxs
1235 * without attaching/detaching.
1238 REQUIRE(ctxp != NULL);
1239 ctx = (isc__mem_t *)*ctxp;
1240 REQUIRE(VALID_CONTEXT(ctx));
1242 MCTXLOCK(ctx, &ctx->lock);
1243 #if ISC_MEM_TRACKLINES
1244 if (ctx->references != 1)
1245 print_active(ctx, stderr);
1247 REQUIRE(ctx->references == 1);
1249 MCTXUNLOCK(ctx, &ctx->lock);
1256 ISC_MEMFUNC_SCOPE isc_result_t
1257 isc__mem_ondestroy(isc_mem_t *ctx0, isc_task_t *task, isc_event_t **event) {
1258 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1261 MCTXLOCK(ctx, &ctx->lock);
1262 res = isc_ondestroy_register(&ctx->ondestroy, task, event);
1263 MCTXUNLOCK(ctx, &ctx->lock);
1268 ISC_MEMFUNC_SCOPE void *
1269 isc___mem_get(isc_mem_t *ctx0, size_t size FLARG) {
1270 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1272 isc_boolean_t call_water = ISC_FALSE;
1274 REQUIRE(VALID_CONTEXT(ctx));
1276 if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0)
1277 return (isc__mem_allocate(ctx0, size FLARG_PASS));
1279 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1280 MCTXLOCK(ctx, &ctx->lock);
1281 ptr = mem_getunlocked(ctx, size);
1283 ptr = mem_get(ctx, size);
1284 MCTXLOCK(ctx, &ctx->lock);
1286 mem_getstats(ctx, size);
1289 ADD_TRACE(ctx, ptr, size, file, line);
1290 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1292 ctx->is_overmem = ISC_TRUE;
1294 if (ctx->hi_water != 0U && !ctx->hi_called &&
1295 ctx->inuse > ctx->hi_water) {
1296 call_water = ISC_TRUE;
1298 if (ctx->inuse > ctx->maxinuse) {
1299 ctx->maxinuse = ctx->inuse;
1300 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1301 (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
1302 fprintf(stderr, "maxinuse = %lu\n",
1303 (unsigned long)ctx->inuse);
1305 MCTXUNLOCK(ctx, &ctx->lock);
1308 (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
1313 ISC_MEMFUNC_SCOPE void
1314 isc___mem_put(isc_mem_t *ctx0, void *ptr, size_t size FLARG) {
1315 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1316 isc_boolean_t call_water = ISC_FALSE;
1320 REQUIRE(VALID_CONTEXT(ctx));
1321 REQUIRE(ptr != NULL);
1323 if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) {
1324 if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) {
1325 si = &(((size_info *)ptr)[-1]);
1326 oldsize = si->u.size - ALIGNMENT_SIZE;
1327 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
1328 oldsize -= ALIGNMENT_SIZE;
1329 INSIST(oldsize == size);
1331 isc__mem_free((isc_mem_t *)ctx, ptr FLARG_PASS);
1335 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1336 MCTXLOCK(ctx, &ctx->lock);
1337 mem_putunlocked(ctx, ptr, size);
1339 mem_put(ctx, ptr, size);
1340 MCTXLOCK(ctx, &ctx->lock);
1341 mem_putstats(ctx, ptr, size);
1344 DELETE_TRACE(ctx, ptr, size, file, line);
1347 * The check against ctx->lo_water == 0 is for the condition
1348 * when the context was pushed over hi_water but then had
1349 * isc_mem_setwater() called with 0 for hi_water and lo_water.
1351 if (ctx->is_overmem &&
1352 (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1353 ctx->is_overmem = ISC_FALSE;
1355 if (ctx->hi_called &&
1356 (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1357 if (ctx->water != NULL)
1358 call_water = ISC_TRUE;
1360 MCTXUNLOCK(ctx, &ctx->lock);
1363 (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
1366 ISC_MEMFUNC_SCOPE void
1367 isc__mem_waterack(isc_mem_t *ctx0, int flag) {
1368 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1370 REQUIRE(VALID_CONTEXT(ctx));
1372 MCTXLOCK(ctx, &ctx->lock);
1373 if (flag == ISC_MEM_LOWATER)
1374 ctx->hi_called = ISC_FALSE;
1375 else if (flag == ISC_MEM_HIWATER)
1376 ctx->hi_called = ISC_TRUE;
1377 MCTXUNLOCK(ctx, &ctx->lock);
1380 #if ISC_MEM_TRACKLINES
1382 print_active(isc__mem_t *mctx, FILE *out) {
1383 if (mctx->debuglist != NULL) {
1387 isc_boolean_t found;
1389 fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1391 "Dump of all outstanding "
1392 "memory allocations:\n"));
1394 format = isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1395 ISC_MSG_PTRFILELINE,
1396 "\tptr %p size %u file %s line %u\n");
1397 for (i = 0; i <= mctx->max_size; i++) {
1398 dl = ISC_LIST_HEAD(mctx->debuglist[i]);
1403 while (dl != NULL) {
1404 for (j = 0; j < DEBUGLIST_COUNT; j++)
1405 if (dl->ptr[j] != NULL)
1406 fprintf(out, format,
1411 dl = ISC_LIST_NEXT(dl, link);
1415 fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1416 ISC_MSG_NONE, "\tNone.\n"));
1422 * Print the stats[] on the stream "out" with suitable formatting.
1424 ISC_MEMFUNC_SCOPE void
1425 isc__mem_stats(isc_mem_t *ctx0, FILE *out) {
1426 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1428 const struct stats *s;
1429 const isc__mempool_t *pool;
1431 REQUIRE(VALID_CONTEXT(ctx));
1432 MCTXLOCK(ctx, &ctx->lock);
1434 for (i = 0; i <= ctx->max_size; i++) {
1437 if (s->totalgets == 0U && s->gets == 0U)
1439 fprintf(out, "%s%5lu: %11lu gets, %11lu rem",
1440 (i == ctx->max_size) ? ">=" : " ",
1441 (unsigned long) i, s->totalgets, s->gets);
1442 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0 &&
1443 (s->blocks != 0U || s->freefrags != 0U))
1444 fprintf(out, " (%lu bl, %lu ff)",
1445 s->blocks, s->freefrags);
1450 * Note that since a pool can be locked now, these stats might be
1451 * somewhat off if the pool is in active use at the time the stats
1452 * are dumped. The link fields are protected by the isc_mem_t's
1453 * lock, however, so walking this list and extracting integers from
1454 * stats fields is always safe.
1456 pool = ISC_LIST_HEAD(ctx->pools);
1458 fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1460 "[Pool statistics]\n"));
1461 fprintf(out, "%15s %10s %10s %10s %10s %10s %10s %10s %1s\n",
1462 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1463 ISC_MSG_POOLNAME, "name"),
1464 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1465 ISC_MSG_POOLSIZE, "size"),
1466 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1467 ISC_MSG_POOLMAXALLOC, "maxalloc"),
1468 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1469 ISC_MSG_POOLALLOCATED, "allocated"),
1470 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1471 ISC_MSG_POOLFREECOUNT, "freecount"),
1472 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1473 ISC_MSG_POOLFREEMAX, "freemax"),
1474 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1475 ISC_MSG_POOLFILLCOUNT, "fillcount"),
1476 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1477 ISC_MSG_POOLGETS, "gets"),
1480 while (pool != NULL) {
1481 fprintf(out, "%15s %10lu %10u %10u %10u %10u %10u %10u %s\n",
1482 #if ISC_MEMPOOL_NAMES
1487 (unsigned long) pool->size, pool->maxalloc,
1488 pool->allocated, pool->freecount, pool->freemax,
1489 pool->fillcount, pool->gets,
1490 (pool->lock == NULL ? "N" : "Y"));
1491 pool = ISC_LIST_NEXT(pool, link);
1494 #if ISC_MEM_TRACKLINES
1495 print_active(ctx, out);
1498 MCTXUNLOCK(ctx, &ctx->lock);
1502 * Replacements for malloc() and free() -- they implicitly remember the
1503 * size of the object allocated (with some additional overhead).
1507 isc__mem_allocateunlocked(isc_mem_t *ctx0, size_t size) {
1508 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1511 size += ALIGNMENT_SIZE;
1512 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
1513 size += ALIGNMENT_SIZE;
1515 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0)
1516 si = mem_getunlocked(ctx, size);
1518 si = mem_get(ctx, size);
1522 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
1530 ISC_MEMFUNC_SCOPE void *
1531 isc___mem_allocate(isc_mem_t *ctx0, size_t size FLARG) {
1532 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1534 isc_boolean_t call_water = ISC_FALSE;
1536 REQUIRE(VALID_CONTEXT(ctx));
1538 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1539 MCTXLOCK(ctx, &ctx->lock);
1540 si = isc__mem_allocateunlocked((isc_mem_t *)ctx, size);
1542 si = isc__mem_allocateunlocked((isc_mem_t *)ctx, size);
1543 MCTXLOCK(ctx, &ctx->lock);
1545 mem_getstats(ctx, si[-1].u.size);
1548 #if ISC_MEM_TRACKLINES
1549 ADD_TRACE(ctx, si, si[-1].u.size, file, line);
1551 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1553 ctx->is_overmem = ISC_TRUE;
1556 if (ctx->hi_water != 0U && !ctx->hi_called &&
1557 ctx->inuse > ctx->hi_water) {
1558 ctx->hi_called = ISC_TRUE;
1559 call_water = ISC_TRUE;
1561 if (ctx->inuse > ctx->maxinuse) {
1562 ctx->maxinuse = ctx->inuse;
1563 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1564 (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
1565 fprintf(stderr, "maxinuse = %lu\n",
1566 (unsigned long)ctx->inuse);
1568 MCTXUNLOCK(ctx, &ctx->lock);
1571 (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
1576 ISC_MEMFUNC_SCOPE void *
1577 isc___mem_reallocate(isc_mem_t *ctx0, void *ptr, size_t size FLARG) {
1578 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1579 void *new_ptr = NULL;
1580 size_t oldsize, copysize;
1582 REQUIRE(VALID_CONTEXT(ctx));
1585 * This function emulates the realloc(3) standard library function:
1586 * - if size > 0, allocate new memory; and if ptr is non NULL, copy
1587 * as much of the old contents to the new buffer and free the old one.
1588 * Note that when allocation fails the original pointer is intact;
1589 * the caller must free it.
1590 * - if size is 0 and ptr is non NULL, simply free the given ptr.
1591 * - this function returns:
1592 * pointer to the newly allocated memory, or
1593 * NULL if allocation fails or doesn't happen.
1596 new_ptr = isc__mem_allocate(ctx0, size FLARG_PASS);
1597 if (new_ptr != NULL && ptr != NULL) {
1598 oldsize = (((size_info *)ptr)[-1]).u.size;
1599 INSIST(oldsize >= ALIGNMENT_SIZE);
1600 oldsize -= ALIGNMENT_SIZE;
1601 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
1602 INSIST(oldsize >= ALIGNMENT_SIZE);
1603 oldsize -= ALIGNMENT_SIZE;
1605 copysize = (oldsize > size) ? size : oldsize;
1606 memmove(new_ptr, ptr, copysize);
1607 isc__mem_free(ctx0, ptr FLARG_PASS);
1609 } else if (ptr != NULL)
1610 isc__mem_free(ctx0, ptr FLARG_PASS);
1615 ISC_MEMFUNC_SCOPE void
1616 isc___mem_free(isc_mem_t *ctx0, void *ptr FLARG) {
1617 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1620 isc_boolean_t call_water= ISC_FALSE;
1622 REQUIRE(VALID_CONTEXT(ctx));
1623 REQUIRE(ptr != NULL);
1625 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
1626 si = &(((size_info *)ptr)[-2]);
1627 REQUIRE(si->u.ctx == ctx);
1628 size = si[1].u.size;
1630 si = &(((size_info *)ptr)[-1]);
1634 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1635 MCTXLOCK(ctx, &ctx->lock);
1636 mem_putunlocked(ctx, si, size);
1638 mem_put(ctx, si, size);
1639 MCTXLOCK(ctx, &ctx->lock);
1640 mem_putstats(ctx, si, size);
1643 DELETE_TRACE(ctx, ptr, size, file, line);
1646 * The check against ctx->lo_water == 0 is for the condition
1647 * when the context was pushed over hi_water but then had
1648 * isc_mem_setwater() called with 0 for hi_water and lo_water.
1650 if (ctx->is_overmem &&
1651 (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1652 ctx->is_overmem = ISC_FALSE;
1655 if (ctx->hi_called &&
1656 (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1657 ctx->hi_called = ISC_FALSE;
1659 if (ctx->water != NULL)
1660 call_water = ISC_TRUE;
1662 MCTXUNLOCK(ctx, &ctx->lock);
1665 (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
1670 * Other useful things.
1673 ISC_MEMFUNC_SCOPE char *
1674 isc___mem_strdup(isc_mem_t *mctx0, const char *s FLARG) {
1675 isc__mem_t *mctx = (isc__mem_t *)mctx0;
1679 REQUIRE(VALID_CONTEXT(mctx));
1684 ns = isc___mem_allocate((isc_mem_t *)mctx, len + 1 FLARG_PASS);
1687 strncpy(ns, s, len + 1);
1692 ISC_MEMFUNC_SCOPE void
1693 isc__mem_setdestroycheck(isc_mem_t *ctx0, isc_boolean_t flag) {
1694 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1696 REQUIRE(VALID_CONTEXT(ctx));
1697 MCTXLOCK(ctx, &ctx->lock);
1699 ctx->checkfree = flag;
1701 MCTXUNLOCK(ctx, &ctx->lock);
1708 ISC_MEMFUNC_SCOPE void
1709 isc__mem_setquota(isc_mem_t *ctx0, size_t quota) {
1710 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1712 REQUIRE(VALID_CONTEXT(ctx));
1713 MCTXLOCK(ctx, &ctx->lock);
1717 MCTXUNLOCK(ctx, &ctx->lock);
1720 ISC_MEMFUNC_SCOPE size_t
1721 isc__mem_getquota(isc_mem_t *ctx0) {
1722 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1725 REQUIRE(VALID_CONTEXT(ctx));
1726 MCTXLOCK(ctx, &ctx->lock);
1730 MCTXUNLOCK(ctx, &ctx->lock);
1735 ISC_MEMFUNC_SCOPE size_t
1736 isc__mem_inuse(isc_mem_t *ctx0) {
1737 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1740 REQUIRE(VALID_CONTEXT(ctx));
1741 MCTXLOCK(ctx, &ctx->lock);
1745 MCTXUNLOCK(ctx, &ctx->lock);
1750 ISC_MEMFUNC_SCOPE void
1751 isc__mem_setwater(isc_mem_t *ctx0, isc_mem_water_t water, void *water_arg,
1752 size_t hiwater, size_t lowater)
1754 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1755 isc_boolean_t callwater = ISC_FALSE;
1756 isc_mem_water_t oldwater;
1759 REQUIRE(VALID_CONTEXT(ctx));
1760 REQUIRE(hiwater >= lowater);
1762 MCTXLOCK(ctx, &ctx->lock);
1763 oldwater = ctx->water;
1764 oldwater_arg = ctx->water_arg;
1765 if (water == NULL) {
1766 callwater = ctx->hi_called;
1768 ctx->water_arg = NULL;
1771 ctx->hi_called = ISC_FALSE;
1773 if (ctx->hi_called &&
1774 (ctx->water != water || ctx->water_arg != water_arg ||
1775 ctx->inuse < lowater || lowater == 0U))
1776 callwater = ISC_TRUE;
1778 ctx->water_arg = water_arg;
1779 ctx->hi_water = hiwater;
1780 ctx->lo_water = lowater;
1781 ctx->hi_called = ISC_FALSE;
1783 MCTXUNLOCK(ctx, &ctx->lock);
1785 if (callwater && oldwater != NULL)
1786 (oldwater)(oldwater_arg, ISC_MEM_LOWATER);
1789 ISC_MEMFUNC_SCOPE isc_boolean_t
1790 isc__mem_isovermem(isc_mem_t *ctx0) {
1791 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1793 REQUIRE(VALID_CONTEXT(ctx));
1796 * We don't bother to lock the context because 100% accuracy isn't
1797 * necessary (and even if we locked the context the returned value
1798 * could be different from the actual state when it's used anyway)
1800 return (ctx->is_overmem);
1803 ISC_MEMFUNC_SCOPE void
1804 isc__mem_setname(isc_mem_t *ctx0, const char *name, void *tag) {
1805 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1807 REQUIRE(VALID_CONTEXT(ctx));
1810 memset(ctx->name, 0, sizeof(ctx->name));
1811 strncpy(ctx->name, name, sizeof(ctx->name) - 1);
1816 ISC_MEMFUNC_SCOPE const char *
1817 isc__mem_getname(isc_mem_t *ctx0) {
1818 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1820 REQUIRE(VALID_CONTEXT(ctx));
1825 ISC_MEMFUNC_SCOPE void *
1826 isc__mem_gettag(isc_mem_t *ctx0) {
1827 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1829 REQUIRE(VALID_CONTEXT(ctx));
1838 ISC_MEMFUNC_SCOPE isc_result_t
1839 isc__mempool_create(isc_mem_t *mctx0, size_t size, isc_mempool_t **mpctxp) {
1840 isc__mem_t *mctx = (isc__mem_t *)mctx0;
1841 isc__mempool_t *mpctx;
1843 REQUIRE(VALID_CONTEXT(mctx));
1845 REQUIRE(mpctxp != NULL && *mpctxp == NULL);
1848 * Allocate space for this pool, initialize values, and if all works
1849 * well, attach to the memory context.
1851 mpctx = isc_mem_get((isc_mem_t *)mctx, sizeof(isc__mempool_t));
1853 return (ISC_R_NOMEMORY);
1855 mpctx->common.methods = (isc_mempoolmethods_t *)&mempoolmethods;
1856 mpctx->common.impmagic = MEMPOOL_MAGIC;
1857 mpctx->common.magic = ISCAPI_MPOOL_MAGIC;
1861 mpctx->maxalloc = UINT_MAX;
1862 mpctx->allocated = 0;
1863 mpctx->freecount = 0;
1865 mpctx->fillcount = 1;
1867 #if ISC_MEMPOOL_NAMES
1870 mpctx->items = NULL;
1872 *mpctxp = (isc_mempool_t *)mpctx;
1874 MCTXLOCK(mctx, &mctx->lock);
1875 ISC_LIST_INITANDAPPEND(mctx->pools, mpctx, link);
1877 MCTXUNLOCK(mctx, &mctx->lock);
1879 return (ISC_R_SUCCESS);
1882 ISC_MEMFUNC_SCOPE void
1883 isc__mempool_setname(isc_mempool_t *mpctx0, const char *name) {
1884 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
1886 REQUIRE(name != NULL);
1887 REQUIRE(VALID_MEMPOOL(mpctx));
1889 #if ISC_MEMPOOL_NAMES
1890 if (mpctx->lock != NULL)
1893 strncpy(mpctx->name, name, sizeof(mpctx->name) - 1);
1894 mpctx->name[sizeof(mpctx->name) - 1] = '\0';
1896 if (mpctx->lock != NULL)
1897 UNLOCK(mpctx->lock);
1904 ISC_MEMFUNC_SCOPE void
1905 isc__mempool_destroy(isc_mempool_t **mpctxp) {
1906 isc__mempool_t *mpctx;
1911 REQUIRE(mpctxp != NULL);
1912 mpctx = (isc__mempool_t *)*mpctxp;
1913 REQUIRE(VALID_MEMPOOL(mpctx));
1914 #if ISC_MEMPOOL_NAMES
1915 if (mpctx->allocated > 0)
1916 UNEXPECTED_ERROR(__FILE__, __LINE__,
1917 "isc__mempool_destroy(): mempool %s "
1921 REQUIRE(mpctx->allocated == 0);
1931 * Return any items on the free list
1933 MCTXLOCK(mctx, &mctx->lock);
1934 while (mpctx->items != NULL) {
1935 INSIST(mpctx->freecount > 0);
1937 item = mpctx->items;
1938 mpctx->items = item->next;
1940 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1941 mem_putunlocked(mctx, item, mpctx->size);
1943 mem_put(mctx, item, mpctx->size);
1944 mem_putstats(mctx, item, mpctx->size);
1947 MCTXUNLOCK(mctx, &mctx->lock);
1950 * Remove our linked list entry from the memory context.
1952 MCTXLOCK(mctx, &mctx->lock);
1953 ISC_LIST_UNLINK(mctx->pools, mpctx, link);
1955 MCTXUNLOCK(mctx, &mctx->lock);
1957 mpctx->common.impmagic = 0;
1958 mpctx->common.magic = 0;
1960 isc_mem_put((isc_mem_t *)mpctx->mctx, mpctx, sizeof(isc__mempool_t));
1968 ISC_MEMFUNC_SCOPE void
1969 isc__mempool_associatelock(isc_mempool_t *mpctx0, isc_mutex_t *lock) {
1970 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
1972 REQUIRE(VALID_MEMPOOL(mpctx));
1973 REQUIRE(mpctx->lock == NULL);
1974 REQUIRE(lock != NULL);
1979 ISC_MEMFUNC_SCOPE void *
1980 isc___mempool_get(isc_mempool_t *mpctx0 FLARG) {
1981 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
1986 REQUIRE(VALID_MEMPOOL(mpctx));
1990 if (mpctx->lock != NULL)
1994 * Don't let the caller go over quota
1996 if (mpctx->allocated >= mpctx->maxalloc) {
2002 * if we have a free list item, return the first here
2004 item = mpctx->items;
2006 mpctx->items = item->next;
2007 INSIST(mpctx->freecount > 0);
2015 * We need to dip into the well. Lock the memory context here and
2016 * fill up our free list.
2018 MCTXLOCK(mctx, &mctx->lock);
2019 for (i = 0; i < mpctx->fillcount; i++) {
2020 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
2021 item = mem_getunlocked(mctx, mpctx->size);
2023 item = mem_get(mctx, mpctx->size);
2025 mem_getstats(mctx, mpctx->size);
2029 item->next = mpctx->items;
2030 mpctx->items = item;
2033 MCTXUNLOCK(mctx, &mctx->lock);
2036 * If we didn't get any items, return NULL.
2038 item = mpctx->items;
2042 mpctx->items = item->next;
2048 if (mpctx->lock != NULL)
2049 UNLOCK(mpctx->lock);
2051 #if ISC_MEM_TRACKLINES
2053 MCTXLOCK(mctx, &mctx->lock);
2054 ADD_TRACE(mctx, item, mpctx->size, file, line);
2055 MCTXUNLOCK(mctx, &mctx->lock);
2057 #endif /* ISC_MEM_TRACKLINES */
2062 ISC_MEMFUNC_SCOPE void
2063 isc___mempool_put(isc_mempool_t *mpctx0, void *mem FLARG) {
2064 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2068 REQUIRE(VALID_MEMPOOL(mpctx));
2069 REQUIRE(mem != NULL);
2073 if (mpctx->lock != NULL)
2076 INSIST(mpctx->allocated > 0);
2079 #if ISC_MEM_TRACKLINES
2080 MCTXLOCK(mctx, &mctx->lock);
2081 DELETE_TRACE(mctx, mem, mpctx->size, file, line);
2082 MCTXUNLOCK(mctx, &mctx->lock);
2083 #endif /* ISC_MEM_TRACKLINES */
2086 * If our free list is full, return this to the mctx directly.
2088 if (mpctx->freecount >= mpctx->freemax) {
2089 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
2090 MCTXLOCK(mctx, &mctx->lock);
2091 mem_putunlocked(mctx, mem, mpctx->size);
2092 MCTXUNLOCK(mctx, &mctx->lock);
2094 mem_put(mctx, mem, mpctx->size);
2095 MCTXLOCK(mctx, &mctx->lock);
2096 mem_putstats(mctx, mem, mpctx->size);
2097 MCTXUNLOCK(mctx, &mctx->lock);
2099 if (mpctx->lock != NULL)
2100 UNLOCK(mpctx->lock);
2105 * Otherwise, attach it to our free list and bump the counter.
2108 item = (element *)mem;
2109 item->next = mpctx->items;
2110 mpctx->items = item;
2112 if (mpctx->lock != NULL)
2113 UNLOCK(mpctx->lock);
2120 ISC_MEMFUNC_SCOPE void
2121 isc__mempool_setfreemax(isc_mempool_t *mpctx0, unsigned int limit) {
2122 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2124 REQUIRE(VALID_MEMPOOL(mpctx));
2126 if (mpctx->lock != NULL)
2129 mpctx->freemax = limit;
2131 if (mpctx->lock != NULL)
2132 UNLOCK(mpctx->lock);
2135 ISC_MEMFUNC_SCOPE unsigned int
2136 isc__mempool_getfreemax(isc_mempool_t *mpctx0) {
2137 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2138 unsigned int freemax;
2140 REQUIRE(VALID_MEMPOOL(mpctx));
2142 if (mpctx->lock != NULL)
2145 freemax = mpctx->freemax;
2147 if (mpctx->lock != NULL)
2148 UNLOCK(mpctx->lock);
2153 ISC_MEMFUNC_SCOPE unsigned int
2154 isc__mempool_getfreecount(isc_mempool_t *mpctx0) {
2155 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2156 unsigned int freecount;
2158 REQUIRE(VALID_MEMPOOL(mpctx));
2160 if (mpctx->lock != NULL)
2163 freecount = mpctx->freecount;
2165 if (mpctx->lock != NULL)
2166 UNLOCK(mpctx->lock);
2171 ISC_MEMFUNC_SCOPE void
2172 isc__mempool_setmaxalloc(isc_mempool_t *mpctx0, unsigned int limit) {
2173 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2177 REQUIRE(VALID_MEMPOOL(mpctx));
2179 if (mpctx->lock != NULL)
2182 mpctx->maxalloc = limit;
2184 if (mpctx->lock != NULL)
2185 UNLOCK(mpctx->lock);
2188 ISC_MEMFUNC_SCOPE unsigned int
2189 isc__mempool_getmaxalloc(isc_mempool_t *mpctx0) {
2190 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2191 unsigned int maxalloc;
2193 REQUIRE(VALID_MEMPOOL(mpctx));
2195 if (mpctx->lock != NULL)
2198 maxalloc = mpctx->maxalloc;
2200 if (mpctx->lock != NULL)
2201 UNLOCK(mpctx->lock);
2206 ISC_MEMFUNC_SCOPE unsigned int
2207 isc__mempool_getallocated(isc_mempool_t *mpctx0) {
2208 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2209 unsigned int allocated;
2211 REQUIRE(VALID_MEMPOOL(mpctx));
2213 if (mpctx->lock != NULL)
2216 allocated = mpctx->allocated;
2218 if (mpctx->lock != NULL)
2219 UNLOCK(mpctx->lock);
2224 ISC_MEMFUNC_SCOPE void
2225 isc__mempool_setfillcount(isc_mempool_t *mpctx0, unsigned int limit) {
2226 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2229 REQUIRE(VALID_MEMPOOL(mpctx));
2231 if (mpctx->lock != NULL)
2234 mpctx->fillcount = limit;
2236 if (mpctx->lock != NULL)
2237 UNLOCK(mpctx->lock);
2240 ISC_MEMFUNC_SCOPE unsigned int
2241 isc__mempool_getfillcount(isc_mempool_t *mpctx0) {
2242 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2244 unsigned int fillcount;
2246 REQUIRE(VALID_MEMPOOL(mpctx));
2248 if (mpctx->lock != NULL)
2251 fillcount = mpctx->fillcount;
2253 if (mpctx->lock != NULL)
2254 UNLOCK(mpctx->lock);
2259 #ifdef USE_MEMIMPREGISTER
2261 isc__mem_register() {
2262 return (isc_mem_register(isc__mem_create2));
2267 ISC_MEMFUNC_SCOPE void
2268 isc__mem_printactive(isc_mem_t *ctx0, FILE *file) {
2269 #if ISC_MEM_TRACKLINES
2270 isc__mem_t *ctx = (isc__mem_t *)ctx0;
2272 REQUIRE(VALID_CONTEXT(ctx));
2273 REQUIRE(file != NULL);
2275 print_active(ctx, file);
2282 ISC_MEMFUNC_SCOPE void
2283 isc__mem_printallactive(FILE *file) {
2284 #if !ISC_MEM_TRACKLINES
2289 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2292 for (ctx = ISC_LIST_HEAD(contexts);
2294 ctx = ISC_LIST_NEXT(ctx, link)) {
2295 fprintf(file, "context: %p\n", ctx);
2296 print_active(ctx, file);
2302 ISC_MEMFUNC_SCOPE void
2303 isc__mem_checkdestroyed(FILE *file) {
2304 #if !ISC_MEM_TRACKLINES
2308 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2311 if (!ISC_LIST_EMPTY(contexts)) {
2312 #if ISC_MEM_TRACKLINES
2315 for (ctx = ISC_LIST_HEAD(contexts);
2317 ctx = ISC_LIST_NEXT(ctx, link)) {
2318 fprintf(file, "context: %p\n", ctx);
2319 print_active(ctx, file);
2328 ISC_MEMFUNC_SCOPE unsigned int
2329 isc_mem_references(isc_mem_t *ctx0) {
2330 isc__mem_t *ctx = (isc__mem_t *)ctx0;
2331 unsigned int references;
2333 REQUIRE(VALID_CONTEXT(ctx));
2335 MCTXLOCK(ctx, &ctx->lock);
2336 references = ctx->references;
2337 MCTXUNLOCK(ctx, &ctx->lock);
2339 return (references);
2344 typedef struct summarystat {
2347 isc_uint64_t blocksize;
2348 isc_uint64_t contextsize;
2351 #define TRY0(a) do { xmlrc = (a); if (xmlrc < 0) goto error; } while(0)
2353 renderctx(isc__mem_t *ctx, summarystat_t *summary, xmlTextWriterPtr writer) {
2356 REQUIRE(VALID_CONTEXT(ctx));
2358 MCTXLOCK(ctx, &ctx->lock);
2360 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "context"));
2362 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "id"));
2363 TRY0(xmlTextWriterWriteFormatString(writer, "%p", ctx));
2364 TRY0(xmlTextWriterEndElement(writer)); /* id */
2366 if (ctx->name[0] != 0) {
2367 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"));
2368 TRY0(xmlTextWriterWriteFormatString(writer, "%s", ctx->name));
2369 TRY0(xmlTextWriterEndElement(writer)); /* name */
2372 summary->contextsize += sizeof(*ctx) +
2373 (ctx->max_size + 1) * sizeof(struct stats) +
2374 ctx->max_size * sizeof(element *) +
2375 ctx->basic_table_count * sizeof(char *);
2376 #if ISC_MEM_TRACKLINES
2377 if (ctx->debuglist != NULL) {
2378 summary->contextsize +=
2379 (ctx->max_size + 1) * sizeof(debuglist_t) +
2380 ctx->debuglistcnt * sizeof(debuglink_t);
2383 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "references"));
2384 TRY0(xmlTextWriterWriteFormatString(writer, "%d", ctx->references));
2385 TRY0(xmlTextWriterEndElement(writer)); /* references */
2387 summary->total += ctx->total;
2388 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "total"));
2389 TRY0(xmlTextWriterWriteFormatString(writer,
2390 "%" ISC_PRINT_QUADFORMAT "u",
2391 (isc_uint64_t)ctx->total));
2392 TRY0(xmlTextWriterEndElement(writer)); /* total */
2394 summary->inuse += ctx->inuse;
2395 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "inuse"));
2396 TRY0(xmlTextWriterWriteFormatString(writer,
2397 "%" ISC_PRINT_QUADFORMAT "u",
2398 (isc_uint64_t)ctx->inuse));
2399 TRY0(xmlTextWriterEndElement(writer)); /* inuse */
2401 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "maxinuse"));
2402 TRY0(xmlTextWriterWriteFormatString(writer,
2403 "%" ISC_PRINT_QUADFORMAT "u",
2404 (isc_uint64_t)ctx->maxinuse));
2405 TRY0(xmlTextWriterEndElement(writer)); /* maxinuse */
2407 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "blocksize"));
2408 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
2409 summary->blocksize += ctx->basic_table_count *
2410 NUM_BASIC_BLOCKS * ctx->mem_target;
2411 TRY0(xmlTextWriterWriteFormatString(writer,
2412 "%" ISC_PRINT_QUADFORMAT "u",
2414 ctx->basic_table_count *
2418 TRY0(xmlTextWriterWriteFormatString(writer, "%s", "-"));
2419 TRY0(xmlTextWriterEndElement(writer)); /* blocksize */
2421 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "pools"));
2422 TRY0(xmlTextWriterWriteFormatString(writer, "%u", ctx->poolcnt));
2423 TRY0(xmlTextWriterEndElement(writer)); /* pools */
2424 summary->contextsize += ctx->poolcnt * sizeof(isc_mempool_t);
2426 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "hiwater"));
2427 TRY0(xmlTextWriterWriteFormatString(writer,
2428 "%" ISC_PRINT_QUADFORMAT "u",
2429 (isc_uint64_t)ctx->hi_water));
2430 TRY0(xmlTextWriterEndElement(writer)); /* hiwater */
2432 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "lowater"));
2433 TRY0(xmlTextWriterWriteFormatString(writer,
2434 "%" ISC_PRINT_QUADFORMAT "u",
2435 (isc_uint64_t)ctx->lo_water));
2436 TRY0(xmlTextWriterEndElement(writer)); /* lowater */
2438 TRY0(xmlTextWriterEndElement(writer)); /* context */
2441 MCTXUNLOCK(ctx, &ctx->lock);
2447 isc_mem_renderxml(xmlTextWriterPtr writer) {
2449 summarystat_t summary;
2453 memset(&summary, 0, sizeof(summary));
2455 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "contexts"));
2457 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2461 for (ctx = ISC_LIST_HEAD(contexts);
2463 ctx = ISC_LIST_NEXT(ctx, link)) {
2464 xmlrc = renderctx(ctx, &summary, writer);
2472 TRY0(xmlTextWriterEndElement(writer)); /* contexts */
2474 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "summary"));
2476 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "TotalUse"));
2477 TRY0(xmlTextWriterWriteFormatString(writer,
2478 "%" ISC_PRINT_QUADFORMAT "u",
2480 TRY0(xmlTextWriterEndElement(writer)); /* TotalUse */
2482 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "InUse"));
2483 TRY0(xmlTextWriterWriteFormatString(writer,
2484 "%" ISC_PRINT_QUADFORMAT "u",
2486 TRY0(xmlTextWriterEndElement(writer)); /* InUse */
2488 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "BlockSize"));
2489 TRY0(xmlTextWriterWriteFormatString(writer,
2490 "%" ISC_PRINT_QUADFORMAT "u",
2491 summary.blocksize));
2492 TRY0(xmlTextWriterEndElement(writer)); /* BlockSize */
2494 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "ContextSize"));
2495 TRY0(xmlTextWriterWriteFormatString(writer,
2496 "%" ISC_PRINT_QUADFORMAT "u",
2497 summary.contextsize));
2498 TRY0(xmlTextWriterEndElement(writer)); /* ContextSize */
2500 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "Lost"));
2501 TRY0(xmlTextWriterWriteFormatString(writer,
2502 "%" ISC_PRINT_QUADFORMAT "u",
2504 TRY0(xmlTextWriterEndElement(writer)); /* Lost */
2506 TRY0(xmlTextWriterEndElement(writer)); /* summary */
2511 #endif /* HAVE_LIBXML2 */