2 * Copyright (C) 2004-2010 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.
18 /* $Id: mem.c,v 1.145.120.4.24.2 2010/08/12 23:46:25 tbox Exp $ */
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 #if ISC_MEM_TRACKLINES
64 typedef struct debuglink debuglink_t;
66 ISC_LINK(debuglink_t) link;
67 const void *ptr[DEBUGLIST_COUNT];
68 unsigned int size[DEBUGLIST_COUNT];
69 const char *file[DEBUGLIST_COUNT];
70 unsigned int line[DEBUGLIST_COUNT];
74 #define FLARG_PASS , file, line
75 #define FLARG , const char *file, int line
81 typedef struct element element;
88 * This structure must be ALIGNMENT_SIZE bytes.
93 char bytes[ALIGNMENT_SIZE];
99 unsigned long totalgets;
100 unsigned long blocks;
101 unsigned long freefrags;
104 #define MEM_MAGIC ISC_MAGIC('M', 'e', 'm', 'C')
105 #define VALID_CONTEXT(c) ISC_MAGIC_VALID(c, MEM_MAGIC)
107 #if ISC_MEM_TRACKLINES
108 typedef ISC_LIST(debuglink_t) debuglist_t;
111 /* List of all active memory contexts. */
113 static ISC_LIST(isc_mem_t) contexts;
114 static isc_once_t once = ISC_ONCE_INIT;
115 static isc_mutex_t lock;
118 * Total size of lost memory due to a bug of external library.
119 * Locked by the global lock.
121 static isc_uint64_t totallost;
125 isc_ondestroy_t ondestroy;
128 isc_memalloc_t memalloc;
129 isc_memfree_t memfree;
132 isc_boolean_t checkfree;
133 struct stats * stats;
134 unsigned int references;
143 isc_boolean_t hi_called;
144 isc_boolean_t is_overmem;
145 isc_mem_water_t water;
147 ISC_LIST(isc_mempool_t) pools;
148 unsigned int poolcnt;
150 /* ISC_MEMFLAG_INTERNAL */
152 element ** freelists;
153 element * basic_blocks;
154 unsigned char ** basic_table;
155 unsigned int basic_table_count;
156 unsigned int basic_table_size;
157 unsigned char * lowest;
158 unsigned char * highest;
160 #if ISC_MEM_TRACKLINES
161 debuglist_t * debuglist;
162 unsigned int debuglistcnt;
165 unsigned int memalloc_failures;
166 ISC_LINK(isc_mem_t) link;
169 #define MEMPOOL_MAGIC ISC_MAGIC('M', 'E', 'M', 'p')
170 #define VALID_MEMPOOL(c) ISC_MAGIC_VALID(c, MEMPOOL_MAGIC)
173 /* always unlocked */
174 unsigned int magic; /*%< magic number */
175 isc_mutex_t *lock; /*%< optional lock */
176 isc_mem_t *mctx; /*%< our memory context */
177 /*%< locked via the memory context's lock */
178 ISC_LINK(isc_mempool_t) link; /*%< next pool in this mem context */
179 /*%< optionally locked from here down */
180 element *items; /*%< low water item list */
181 size_t size; /*%< size of each item on this pool */
182 unsigned int maxalloc; /*%< max number of items allowed */
183 unsigned int allocated; /*%< # of items currently given out */
184 unsigned int freecount; /*%< # of items on reserved list */
185 unsigned int freemax; /*%< # of items allowed on free list */
186 unsigned int fillcount; /*%< # of items to fetch on each fill */
188 unsigned int gets; /*%< # of requests to this pool */
189 /*%< Debugging only. */
190 #if ISC_MEMPOOL_NAMES
191 char name[16]; /*%< printed name in stats reports */
196 * Private Inline-able.
199 #if ! ISC_MEM_TRACKLINES
200 #define ADD_TRACE(a, b, c, d, e)
201 #define DELETE_TRACE(a, b, c, d, e)
203 #define ADD_TRACE(a, b, c, d, e) \
205 if ((isc_mem_debugging & (ISC_MEM_DEBUGTRACE | \
206 ISC_MEM_DEBUGRECORD)) != 0 && \
208 add_trace_entry(a, b, c, d, e); \
210 #define DELETE_TRACE(a, b, c, d, e) delete_trace_entry(a, b, c, d, e)
213 print_active(isc_mem_t *ctx, FILE *out);
216 * mctx must be locked.
219 add_trace_entry(isc_mem_t *mctx, const void *ptr, unsigned int size
225 if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
226 fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
229 "file %s line %u mctx %p\n"),
230 ptr, size, file, line, mctx);
232 if (mctx->debuglist == NULL)
235 if (size > mctx->max_size)
236 size = mctx->max_size;
238 dl = ISC_LIST_HEAD(mctx->debuglist[size]);
240 if (dl->count == DEBUGLIST_COUNT)
242 for (i = 0; i < DEBUGLIST_COUNT; i++) {
243 if (dl->ptr[i] == NULL) {
253 dl = ISC_LIST_NEXT(dl, link);
256 dl = malloc(sizeof(debuglink_t));
259 ISC_LINK_INIT(dl, link);
260 for (i = 1; i < DEBUGLIST_COUNT; i++) {
273 ISC_LIST_PREPEND(mctx->debuglist[size], dl, link);
274 mctx->debuglistcnt++;
278 delete_trace_entry(isc_mem_t *mctx, const void *ptr, unsigned int size,
279 const char *file, unsigned int line)
284 if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
285 fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
288 "file %s line %u mctx %p\n"),
289 ptr, size, file, line, mctx);
291 if (mctx->debuglist == NULL)
294 if (size > mctx->max_size)
295 size = mctx->max_size;
297 dl = ISC_LIST_HEAD(mctx->debuglist[size]);
299 for (i = 0; i < DEBUGLIST_COUNT; i++) {
300 if (dl->ptr[i] == ptr) {
306 INSIST(dl->count > 0);
308 if (dl->count == 0) {
309 ISC_LIST_UNLINK(mctx->debuglist[size],
316 dl = ISC_LIST_NEXT(dl, link);
320 * If we get here, we didn't find the item on the list. We're
325 #endif /* ISC_MEM_TRACKLINES */
328 rmsize(size_t size) {
330 * round down to ALIGNMENT_SIZE
332 return (size & (~(ALIGNMENT_SIZE - 1)));
336 quantize(size_t size) {
338 * Round up the result in order to get a size big
339 * enough to satisfy the request and be aligned on ALIGNMENT_SIZE
344 return (ALIGNMENT_SIZE);
345 return ((size + ALIGNMENT_SIZE - 1) & (~(ALIGNMENT_SIZE - 1)));
348 static inline isc_boolean_t
349 more_basic_blocks(isc_mem_t *ctx) {
351 unsigned char *curr, *next;
352 unsigned char *first, *last;
353 unsigned char **table;
354 unsigned int table_size;
358 /* Require: we hold the context lock. */
361 * Did we hit the quota for this context?
363 increment = NUM_BASIC_BLOCKS * ctx->mem_target;
364 if (ctx->quota != 0U && ctx->total + increment > ctx->quota)
367 INSIST(ctx->basic_table_count <= ctx->basic_table_size);
368 if (ctx->basic_table_count == ctx->basic_table_size) {
369 table_size = ctx->basic_table_size + TABLE_INCREMENT;
370 table = (ctx->memalloc)(ctx->arg,
371 table_size * sizeof(unsigned char *));
373 ctx->memalloc_failures++;
376 if (ctx->basic_table_size != 0) {
377 memcpy(table, ctx->basic_table,
378 ctx->basic_table_size *
379 sizeof(unsigned char *));
380 (ctx->memfree)(ctx->arg, ctx->basic_table);
382 ctx->basic_table = table;
383 ctx->basic_table_size = table_size;
386 new = (ctx->memalloc)(ctx->arg, NUM_BASIC_BLOCKS * ctx->mem_target);
388 ctx->memalloc_failures++;
391 ctx->total += increment;
392 ctx->basic_table[ctx->basic_table_count] = new;
393 ctx->basic_table_count++;
396 next = curr + ctx->mem_target;
397 for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) {
398 ((element *)curr)->next = (element *)next;
400 next += ctx->mem_target;
403 * curr is now pointing at the last block in the
406 ((element *)curr)->next = NULL;
408 last = first + NUM_BASIC_BLOCKS * ctx->mem_target - 1;
409 if (first < ctx->lowest || ctx->lowest == NULL)
411 if (last > ctx->highest)
413 ctx->basic_blocks = new;
418 static inline isc_boolean_t
419 more_frags(isc_mem_t *ctx, size_t new_size) {
423 unsigned char *curr, *next;
426 * Try to get more fragments by chopping up a basic block.
429 if (ctx->basic_blocks == NULL) {
430 if (!more_basic_blocks(ctx)) {
432 * We can't get more memory from the OS, or we've
433 * hit the quota for this context.
436 * XXXRTH "At quota" notification here.
442 total_size = ctx->mem_target;
443 new = ctx->basic_blocks;
444 ctx->basic_blocks = ctx->basic_blocks->next;
445 frags = total_size / new_size;
446 ctx->stats[new_size].blocks++;
447 ctx->stats[new_size].freefrags += frags;
449 * Set up a linked-list of blocks of size
453 next = curr + new_size;
454 total_size -= new_size;
455 for (i = 0; i < (frags - 1); i++) {
456 ((element *)curr)->next = (element *)next;
459 total_size -= new_size;
462 * Add the remaining fragment of the basic block to a free list.
464 total_size = rmsize(total_size);
465 if (total_size > 0U) {
466 ((element *)next)->next = ctx->freelists[total_size];
467 ctx->freelists[total_size] = (element *)next;
468 ctx->stats[total_size].freefrags++;
471 * curr is now pointing at the last block in the
474 ((element *)curr)->next = NULL;
475 ctx->freelists[new_size] = new;
481 mem_getunlocked(isc_mem_t *ctx, size_t size) {
482 size_t new_size = quantize(size);
485 if (size >= ctx->max_size || new_size >= ctx->max_size) {
487 * memget() was called on something beyond our upper limit.
489 if (ctx->quota != 0U && ctx->total + size > ctx->quota) {
493 ret = (ctx->memalloc)(ctx->arg, size);
495 ctx->memalloc_failures++;
500 ctx->stats[ctx->max_size].gets++;
501 ctx->stats[ctx->max_size].totalgets++;
503 * If we don't set new_size to size, then the
504 * ISC_MEM_FILL code might write over bytes we
512 * If there are no blocks in the free list for this size, get a chunk
513 * of memory and then break it up into "new_size"-sized blocks, adding
514 * them to the free list.
516 if (ctx->freelists[new_size] == NULL && !more_frags(ctx, new_size))
520 * The free list uses the "rounded-up" size "new_size".
522 ret = ctx->freelists[new_size];
523 ctx->freelists[new_size] = ctx->freelists[new_size]->next;
526 * The stats[] uses the _actual_ "size" requested by the
527 * caller, with the caveat (in the code above) that "size" >= the
528 * max. size (max_size) ends up getting recorded as a call to
531 ctx->stats[size].gets++;
532 ctx->stats[size].totalgets++;
533 ctx->stats[new_size].freefrags--;
534 ctx->inuse += new_size;
540 memset(ret, 0xbe, new_size); /* Mnemonic for "beef". */
546 #if ISC_MEM_FILL && ISC_MEM_CHECKOVERRUN
548 check_overrun(void *mem, size_t size, size_t new_size) {
551 cp = (unsigned char *)mem;
553 while (size < new_size) {
562 mem_putunlocked(isc_mem_t *ctx, void *mem, size_t size) {
563 size_t new_size = quantize(size);
565 if (size == ctx->max_size || new_size >= ctx->max_size) {
567 * memput() called on something beyond our upper limit.
570 memset(mem, 0xde, size); /* Mnemonic for "dead". */
572 (ctx->memfree)(ctx->arg, mem);
573 INSIST(ctx->stats[ctx->max_size].gets != 0U);
574 ctx->stats[ctx->max_size].gets--;
575 INSIST(size <= ctx->total);
582 #if ISC_MEM_CHECKOVERRUN
583 check_overrun(mem, size, new_size);
585 memset(mem, 0xde, new_size); /* Mnemonic for "dead". */
589 * The free list uses the "rounded-up" size "new_size".
591 ((element *)mem)->next = ctx->freelists[new_size];
592 ctx->freelists[new_size] = (element *)mem;
595 * The stats[] uses the _actual_ "size" requested by the
596 * caller, with the caveat (in the code above) that "size" >= the
597 * max. size (max_size) ends up getting recorded as a call to
600 INSIST(ctx->stats[size].gets != 0U);
601 ctx->stats[size].gets--;
602 ctx->stats[new_size].freefrags++;
603 ctx->inuse -= new_size;
607 * Perform a malloc, doing memory filling and overrun detection as necessary.
610 mem_get(isc_mem_t *ctx, size_t size) {
613 #if ISC_MEM_CHECKOVERRUN
617 ret = (ctx->memalloc)(ctx->arg, size);
619 ctx->memalloc_failures++;
623 memset(ret, 0xbe, size); /* Mnemonic for "beef". */
625 # if ISC_MEM_CHECKOVERRUN
635 * Perform a free, doing memory filling and overrun detection as necessary.
638 mem_put(isc_mem_t *ctx, void *mem, size_t size) {
639 #if ISC_MEM_CHECKOVERRUN
640 INSIST(((unsigned char *)mem)[size] == 0xbe);
643 memset(mem, 0xde, size); /* Mnemonic for "dead". */
647 (ctx->memfree)(ctx->arg, mem);
651 * Update internal counters after a memory get.
654 mem_getstats(isc_mem_t *ctx, size_t size) {
658 if (size > ctx->max_size) {
659 ctx->stats[ctx->max_size].gets++;
660 ctx->stats[ctx->max_size].totalgets++;
662 ctx->stats[size].gets++;
663 ctx->stats[size].totalgets++;
668 * Update internal counters after a memory put.
671 mem_putstats(isc_mem_t *ctx, void *ptr, size_t size) {
674 INSIST(ctx->inuse >= size);
677 if (size > ctx->max_size) {
678 INSIST(ctx->stats[ctx->max_size].gets > 0U);
679 ctx->stats[ctx->max_size].gets--;
681 INSIST(ctx->stats[size].gets > 0U);
682 ctx->stats[size].gets--;
691 default_memalloc(void *arg, size_t size) {
695 return (malloc(size));
699 default_memfree(void *arg, void *ptr) {
705 initialize_action(void) {
706 RUNTIME_CHECK(isc_mutex_init(&lock) == ISC_R_SUCCESS);
707 ISC_LIST_INIT(contexts);
716 isc_mem_createx(size_t init_max_size, size_t target_size,
717 isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
720 return (isc_mem_createx2(init_max_size, target_size, memalloc, memfree,
721 arg, ctxp, ISC_MEMFLAG_DEFAULT));
726 isc_mem_createx2(size_t init_max_size, size_t target_size,
727 isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
728 isc_mem_t **ctxp, unsigned int flags)
733 REQUIRE(ctxp != NULL && *ctxp == NULL);
734 REQUIRE(memalloc != NULL);
735 REQUIRE(memfree != NULL);
737 INSIST((ALIGNMENT_SIZE & (ALIGNMENT_SIZE - 1)) == 0);
739 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
741 ctx = (memalloc)(arg, sizeof(*ctx));
743 return (ISC_R_NOMEMORY);
745 if ((flags & ISC_MEMFLAG_NOLOCK) == 0) {
746 result = isc_mutex_init(&ctx->lock);
747 if (result != ISC_R_SUCCESS) {
753 if (init_max_size == 0U)
754 ctx->max_size = DEF_MAX_SIZE;
756 ctx->max_size = init_max_size;
759 memset(ctx->name, 0, sizeof(ctx->name));
767 ctx->hi_called = ISC_FALSE;
768 ctx->is_overmem = ISC_FALSE;
770 ctx->water_arg = NULL;
771 ctx->magic = MEM_MAGIC;
772 isc_ondestroy_init(&ctx->ondestroy);
773 ctx->memalloc = memalloc;
774 ctx->memfree = memfree;
777 ctx->checkfree = ISC_TRUE;
778 #if ISC_MEM_TRACKLINES
779 ctx->debuglist = NULL;
780 ctx->debuglistcnt = 0;
782 ISC_LIST_INIT(ctx->pools);
784 ctx->freelists = NULL;
785 ctx->basic_blocks = NULL;
786 ctx->basic_table = NULL;
787 ctx->basic_table_count = 0;
788 ctx->basic_table_size = 0;
792 ctx->stats = (memalloc)(arg,
793 (ctx->max_size+1) * sizeof(struct stats));
794 if (ctx->stats == NULL) {
795 result = ISC_R_NOMEMORY;
798 memset(ctx->stats, 0, (ctx->max_size + 1) * sizeof(struct stats));
800 if ((flags & ISC_MEMFLAG_INTERNAL) != 0) {
801 if (target_size == 0U)
802 ctx->mem_target = DEF_MEM_TARGET;
804 ctx->mem_target = target_size;
805 ctx->freelists = (memalloc)(arg, ctx->max_size *
807 if (ctx->freelists == NULL) {
808 result = ISC_R_NOMEMORY;
811 memset(ctx->freelists, 0,
812 ctx->max_size * sizeof(element *));
815 #if ISC_MEM_TRACKLINES
816 if ((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0) {
819 ctx->debuglist = (memalloc)(arg,
820 (ctx->max_size+1) * sizeof(debuglist_t));
821 if (ctx->debuglist == NULL) {
822 result = ISC_R_NOMEMORY;
825 for (i = 0; i <= ctx->max_size; i++)
826 ISC_LIST_INIT(ctx->debuglist[i]);
830 ctx->memalloc_failures = 0;
833 ISC_LIST_INITANDAPPEND(contexts, ctx, link);
837 return (ISC_R_SUCCESS);
841 if (ctx->stats != NULL)
842 (memfree)(arg, ctx->stats);
843 if (ctx->freelists != NULL)
844 (memfree)(arg, ctx->freelists);
845 #if ISC_MEM_TRACKLINES
846 if (ctx->debuglist != NULL)
847 (ctx->memfree)(ctx->arg, ctx->debuglist);
848 #endif /* ISC_MEM_TRACKLINES */
849 if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
850 DESTROYLOCK(&ctx->lock);
858 isc_mem_create(size_t init_max_size, size_t target_size,
861 return (isc_mem_createx2(init_max_size, target_size,
862 default_memalloc, default_memfree, NULL,
863 ctxp, ISC_MEMFLAG_DEFAULT));
867 isc_mem_create2(size_t init_max_size, size_t target_size,
868 isc_mem_t **ctxp, unsigned int flags)
870 return (isc_mem_createx2(init_max_size, target_size,
871 default_memalloc, default_memfree, NULL,
876 destroy(isc_mem_t *ctx) {
878 isc_ondestroy_t ondest;
883 ISC_LIST_UNLINK(contexts, ctx, link);
884 totallost += ctx->inuse;
887 INSIST(ISC_LIST_EMPTY(ctx->pools));
889 #if ISC_MEM_TRACKLINES
890 if (ctx->debuglist != NULL) {
891 if (ctx->checkfree) {
892 for (i = 0; i <= ctx->max_size; i++) {
893 if (!ISC_LIST_EMPTY(ctx->debuglist[i]))
894 print_active(ctx, stderr);
895 INSIST(ISC_LIST_EMPTY(ctx->debuglist[i]));
900 for (i = 0; i <= ctx->max_size; i++)
901 for (dl = ISC_LIST_HEAD(ctx->debuglist[i]);
903 dl = ISC_LIST_HEAD(ctx->debuglist[i])) {
904 ISC_LIST_UNLINK(ctx->debuglist[i],
909 (ctx->memfree)(ctx->arg, ctx->debuglist);
912 INSIST(ctx->references == 0);
914 if (ctx->checkfree) {
915 for (i = 0; i <= ctx->max_size; i++) {
916 #if ISC_MEM_TRACKLINES
917 if (ctx->stats[i].gets != 0U)
918 print_active(ctx, stderr);
920 INSIST(ctx->stats[i].gets == 0U);
924 (ctx->memfree)(ctx->arg, ctx->stats);
926 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
927 for (i = 0; i < ctx->basic_table_count; i++)
928 (ctx->memfree)(ctx->arg, ctx->basic_table[i]);
929 (ctx->memfree)(ctx->arg, ctx->freelists);
930 if (ctx->basic_table != NULL)
931 (ctx->memfree)(ctx->arg, ctx->basic_table);
934 ondest = ctx->ondestroy;
936 if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
937 DESTROYLOCK(&ctx->lock);
938 (ctx->memfree)(ctx->arg, ctx);
940 isc_ondestroy_notify(&ondest, ctx);
944 isc_mem_attach(isc_mem_t *source, isc_mem_t **targetp) {
945 REQUIRE(VALID_CONTEXT(source));
946 REQUIRE(targetp != NULL && *targetp == NULL);
948 MCTXLOCK(source, &source->lock);
949 source->references++;
950 MCTXUNLOCK(source, &source->lock);
956 isc_mem_detach(isc_mem_t **ctxp) {
958 isc_boolean_t want_destroy = ISC_FALSE;
960 REQUIRE(ctxp != NULL);
962 REQUIRE(VALID_CONTEXT(ctx));
964 MCTXLOCK(ctx, &ctx->lock);
965 INSIST(ctx->references > 0);
967 if (ctx->references == 0)
968 want_destroy = ISC_TRUE;
969 MCTXUNLOCK(ctx, &ctx->lock);
978 * isc_mem_putanddetach() is the equivalent of:
981 * isc_mem_attach(ptr->mctx, &mctx);
982 * isc_mem_detach(&ptr->mctx);
983 * isc_mem_put(mctx, ptr, sizeof(*ptr);
984 * isc_mem_detach(&mctx);
988 isc__mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) {
990 isc_boolean_t want_destroy = ISC_FALSE;
994 REQUIRE(ctxp != NULL);
996 REQUIRE(VALID_CONTEXT(ctx));
997 REQUIRE(ptr != NULL);
1000 * Must be before mem_putunlocked() as ctxp is usually within
1005 if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) {
1006 if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) {
1007 si = &(((size_info *)ptr)[-1]);
1008 oldsize = si->u.size - ALIGNMENT_SIZE;
1009 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
1010 oldsize -= ALIGNMENT_SIZE;
1011 INSIST(oldsize == size);
1013 isc__mem_free(ctx, ptr FLARG_PASS);
1015 MCTXLOCK(ctx, &ctx->lock);
1017 if (ctx->references == 0)
1018 want_destroy = ISC_TRUE;
1019 MCTXUNLOCK(ctx, &ctx->lock);
1026 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1027 MCTXLOCK(ctx, &ctx->lock);
1028 mem_putunlocked(ctx, ptr, size);
1030 mem_put(ctx, ptr, size);
1031 MCTXLOCK(ctx, &ctx->lock);
1032 mem_putstats(ctx, ptr, size);
1035 DELETE_TRACE(ctx, ptr, size, file, line);
1036 INSIST(ctx->references > 0);
1038 if (ctx->references == 0)
1039 want_destroy = ISC_TRUE;
1041 MCTXUNLOCK(ctx, &ctx->lock);
1048 isc_mem_destroy(isc_mem_t **ctxp) {
1052 * This routine provides legacy support for callers who use mctxs
1053 * without attaching/detaching.
1056 REQUIRE(ctxp != NULL);
1058 REQUIRE(VALID_CONTEXT(ctx));
1060 MCTXLOCK(ctx, &ctx->lock);
1061 #if ISC_MEM_TRACKLINES
1062 if (ctx->references != 1)
1063 print_active(ctx, stderr);
1065 REQUIRE(ctx->references == 1);
1067 MCTXUNLOCK(ctx, &ctx->lock);
1075 isc_mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event) {
1078 MCTXLOCK(ctx, &ctx->lock);
1079 res = isc_ondestroy_register(&ctx->ondestroy, task, event);
1080 MCTXUNLOCK(ctx, &ctx->lock);
1087 isc__mem_get(isc_mem_t *ctx, size_t size FLARG) {
1089 isc_boolean_t call_water = ISC_FALSE;
1091 REQUIRE(VALID_CONTEXT(ctx));
1093 if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0)
1094 return (isc__mem_allocate(ctx, size FLARG_PASS));
1096 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1097 MCTXLOCK(ctx, &ctx->lock);
1098 ptr = mem_getunlocked(ctx, size);
1100 ptr = mem_get(ctx, size);
1101 MCTXLOCK(ctx, &ctx->lock);
1103 mem_getstats(ctx, size);
1106 ADD_TRACE(ctx, ptr, size, file, line);
1107 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1109 ctx->is_overmem = ISC_TRUE;
1111 if (ctx->hi_water != 0U && !ctx->hi_called &&
1112 ctx->inuse > ctx->hi_water) {
1113 call_water = ISC_TRUE;
1115 if (ctx->inuse > ctx->maxinuse) {
1116 ctx->maxinuse = ctx->inuse;
1117 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1118 (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
1119 fprintf(stderr, "maxinuse = %lu\n",
1120 (unsigned long)ctx->inuse);
1122 MCTXUNLOCK(ctx, &ctx->lock);
1125 (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
1131 isc__mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG)
1133 isc_boolean_t call_water = ISC_FALSE;
1137 REQUIRE(VALID_CONTEXT(ctx));
1138 REQUIRE(ptr != NULL);
1140 if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) {
1141 if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) {
1142 si = &(((size_info *)ptr)[-1]);
1143 oldsize = si->u.size - ALIGNMENT_SIZE;
1144 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
1145 oldsize -= ALIGNMENT_SIZE;
1146 INSIST(oldsize == size);
1148 isc__mem_free(ctx, ptr FLARG_PASS);
1152 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1153 MCTXLOCK(ctx, &ctx->lock);
1154 mem_putunlocked(ctx, ptr, size);
1156 mem_put(ctx, ptr, size);
1157 MCTXLOCK(ctx, &ctx->lock);
1158 mem_putstats(ctx, ptr, size);
1161 DELETE_TRACE(ctx, ptr, size, file, line);
1164 * The check against ctx->lo_water == 0 is for the condition
1165 * when the context was pushed over hi_water but then had
1166 * isc_mem_setwater() called with 0 for hi_water and lo_water.
1168 if (ctx->is_overmem &&
1169 (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1170 ctx->is_overmem = ISC_FALSE;
1172 if (ctx->hi_called &&
1173 (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1174 if (ctx->water != NULL)
1175 call_water = ISC_TRUE;
1177 MCTXUNLOCK(ctx, &ctx->lock);
1180 (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
1184 isc_mem_waterack(isc_mem_t *ctx, int flag) {
1185 REQUIRE(VALID_CONTEXT(ctx));
1187 MCTXLOCK(ctx, &ctx->lock);
1188 if (flag == ISC_MEM_LOWATER)
1189 ctx->hi_called = ISC_FALSE;
1190 else if (flag == ISC_MEM_HIWATER)
1191 ctx->hi_called = ISC_TRUE;
1192 MCTXUNLOCK(ctx, &ctx->lock);
1195 #if ISC_MEM_TRACKLINES
1197 print_active(isc_mem_t *mctx, FILE *out) {
1198 if (mctx->debuglist != NULL) {
1202 isc_boolean_t found;
1204 fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1206 "Dump of all outstanding "
1207 "memory allocations:\n"));
1209 format = isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1210 ISC_MSG_PTRFILELINE,
1211 "\tptr %p size %u file %s line %u\n");
1212 for (i = 0; i <= mctx->max_size; i++) {
1213 dl = ISC_LIST_HEAD(mctx->debuglist[i]);
1218 while (dl != NULL) {
1219 for (j = 0; j < DEBUGLIST_COUNT; j++)
1220 if (dl->ptr[j] != NULL)
1221 fprintf(out, format,
1226 dl = ISC_LIST_NEXT(dl, link);
1230 fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1231 ISC_MSG_NONE, "\tNone.\n"));
1237 * Print the stats[] on the stream "out" with suitable formatting.
1240 isc_mem_stats(isc_mem_t *ctx, FILE *out) {
1242 const struct stats *s;
1243 const isc_mempool_t *pool;
1245 REQUIRE(VALID_CONTEXT(ctx));
1246 MCTXLOCK(ctx, &ctx->lock);
1248 for (i = 0; i <= ctx->max_size; i++) {
1251 if (s->totalgets == 0U && s->gets == 0U)
1253 fprintf(out, "%s%5lu: %11lu gets, %11lu rem",
1254 (i == ctx->max_size) ? ">=" : " ",
1255 (unsigned long) i, s->totalgets, s->gets);
1256 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0 &&
1257 (s->blocks != 0U || s->freefrags != 0U))
1258 fprintf(out, " (%lu bl, %lu ff)",
1259 s->blocks, s->freefrags);
1264 * Note that since a pool can be locked now, these stats might be
1265 * somewhat off if the pool is in active use at the time the stats
1266 * are dumped. The link fields are protected by the isc_mem_t's
1267 * lock, however, so walking this list and extracting integers from
1268 * stats fields is always safe.
1270 pool = ISC_LIST_HEAD(ctx->pools);
1272 fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1274 "[Pool statistics]\n"));
1275 fprintf(out, "%15s %10s %10s %10s %10s %10s %10s %10s %1s\n",
1276 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1277 ISC_MSG_POOLNAME, "name"),
1278 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1279 ISC_MSG_POOLSIZE, "size"),
1280 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1281 ISC_MSG_POOLMAXALLOC, "maxalloc"),
1282 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1283 ISC_MSG_POOLALLOCATED, "allocated"),
1284 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1285 ISC_MSG_POOLFREECOUNT, "freecount"),
1286 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1287 ISC_MSG_POOLFREEMAX, "freemax"),
1288 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1289 ISC_MSG_POOLFILLCOUNT, "fillcount"),
1290 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1291 ISC_MSG_POOLGETS, "gets"),
1294 while (pool != NULL) {
1295 fprintf(out, "%15s %10lu %10u %10u %10u %10u %10u %10u %s\n",
1296 pool->name, (unsigned long) pool->size, pool->maxalloc,
1297 pool->allocated, pool->freecount, pool->freemax,
1298 pool->fillcount, pool->gets,
1299 (pool->lock == NULL ? "N" : "Y"));
1300 pool = ISC_LIST_NEXT(pool, link);
1303 #if ISC_MEM_TRACKLINES
1304 print_active(ctx, out);
1307 MCTXUNLOCK(ctx, &ctx->lock);
1311 * Replacements for malloc() and free() -- they implicitly remember the
1312 * size of the object allocated (with some additional overhead).
1316 isc__mem_allocateunlocked(isc_mem_t *ctx, size_t size) {
1319 size += ALIGNMENT_SIZE;
1320 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
1321 size += ALIGNMENT_SIZE;
1323 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0)
1324 si = mem_getunlocked(ctx, size);
1326 si = mem_get(ctx, size);
1330 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
1339 isc__mem_allocate(isc_mem_t *ctx, size_t size FLARG) {
1341 isc_boolean_t call_water = ISC_FALSE;
1343 REQUIRE(VALID_CONTEXT(ctx));
1345 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1346 MCTXLOCK(ctx, &ctx->lock);
1347 si = isc__mem_allocateunlocked(ctx, size);
1349 si = isc__mem_allocateunlocked(ctx, size);
1350 MCTXLOCK(ctx, &ctx->lock);
1352 mem_getstats(ctx, si[-1].u.size);
1355 #if ISC_MEM_TRACKLINES
1356 ADD_TRACE(ctx, si, si[-1].u.size, file, line);
1358 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1360 ctx->is_overmem = ISC_TRUE;
1363 if (ctx->hi_water != 0U && !ctx->hi_called &&
1364 ctx->inuse > ctx->hi_water) {
1365 ctx->hi_called = ISC_TRUE;
1366 call_water = ISC_TRUE;
1368 if (ctx->inuse > ctx->maxinuse) {
1369 ctx->maxinuse = ctx->inuse;
1370 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1371 (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
1372 fprintf(stderr, "maxinuse = %lu\n",
1373 (unsigned long)ctx->inuse);
1375 MCTXUNLOCK(ctx, &ctx->lock);
1378 (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
1384 isc__mem_reallocate(isc_mem_t *ctx, void *ptr, size_t size FLARG) {
1385 void *new_ptr = NULL;
1386 size_t oldsize, copysize;
1388 REQUIRE(VALID_CONTEXT(ctx));
1391 * This function emulates the realloc(3) standard library function:
1392 * - if size > 0, allocate new memory; and if ptr is non NULL, copy
1393 * as much of the old contents to the new buffer and free the old one.
1394 * Note that when allocation fails the original pointer is intact;
1395 * the caller must free it.
1396 * - if size is 0 and ptr is non NULL, simply free the given ptr.
1397 * - this function returns:
1398 * pointer to the newly allocated memory, or
1399 * NULL if allocation fails or doesn't happen.
1402 new_ptr = isc__mem_allocate(ctx, size FLARG_PASS);
1403 if (new_ptr != NULL && ptr != NULL) {
1404 oldsize = (((size_info *)ptr)[-1]).u.size;
1405 INSIST(oldsize >= ALIGNMENT_SIZE);
1406 oldsize -= ALIGNMENT_SIZE;
1407 copysize = oldsize > size ? size : oldsize;
1408 memcpy(new_ptr, ptr, copysize);
1409 isc__mem_free(ctx, ptr FLARG_PASS);
1411 } else if (ptr != NULL)
1412 isc__mem_free(ctx, ptr FLARG_PASS);
1418 isc__mem_free(isc_mem_t *ctx, void *ptr FLARG) {
1421 isc_boolean_t call_water= ISC_FALSE;
1423 REQUIRE(VALID_CONTEXT(ctx));
1424 REQUIRE(ptr != NULL);
1426 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
1427 si = &(((size_info *)ptr)[-2]);
1428 REQUIRE(si->u.ctx == ctx);
1429 size = si[1].u.size;
1431 si = &(((size_info *)ptr)[-1]);
1435 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1436 MCTXLOCK(ctx, &ctx->lock);
1437 mem_putunlocked(ctx, si, size);
1439 mem_put(ctx, si, size);
1440 MCTXLOCK(ctx, &ctx->lock);
1441 mem_putstats(ctx, si, size);
1444 DELETE_TRACE(ctx, ptr, size, file, line);
1447 * The check against ctx->lo_water == 0 is for the condition
1448 * when the context was pushed over hi_water but then had
1449 * isc_mem_setwater() called with 0 for hi_water and lo_water.
1451 if (ctx->is_overmem &&
1452 (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1453 ctx->is_overmem = ISC_FALSE;
1456 if (ctx->hi_called &&
1457 (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1458 ctx->hi_called = ISC_FALSE;
1460 if (ctx->water != NULL)
1461 call_water = ISC_TRUE;
1463 MCTXUNLOCK(ctx, &ctx->lock);
1466 (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
1471 * Other useful things.
1475 isc__mem_strdup(isc_mem_t *mctx, const char *s FLARG) {
1479 REQUIRE(VALID_CONTEXT(mctx));
1484 ns = isc__mem_allocate(mctx, len + 1 FLARG_PASS);
1487 strncpy(ns, s, len + 1);
1493 isc_mem_setdestroycheck(isc_mem_t *ctx, isc_boolean_t flag) {
1494 REQUIRE(VALID_CONTEXT(ctx));
1495 MCTXLOCK(ctx, &ctx->lock);
1497 ctx->checkfree = flag;
1499 MCTXUNLOCK(ctx, &ctx->lock);
1507 isc_mem_setquota(isc_mem_t *ctx, size_t quota) {
1508 REQUIRE(VALID_CONTEXT(ctx));
1509 MCTXLOCK(ctx, &ctx->lock);
1513 MCTXUNLOCK(ctx, &ctx->lock);
1517 isc_mem_getquota(isc_mem_t *ctx) {
1520 REQUIRE(VALID_CONTEXT(ctx));
1521 MCTXLOCK(ctx, &ctx->lock);
1525 MCTXUNLOCK(ctx, &ctx->lock);
1531 isc_mem_inuse(isc_mem_t *ctx) {
1534 REQUIRE(VALID_CONTEXT(ctx));
1535 MCTXLOCK(ctx, &ctx->lock);
1539 MCTXUNLOCK(ctx, &ctx->lock);
1545 isc_mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg,
1546 size_t hiwater, size_t lowater)
1548 isc_boolean_t callwater = ISC_FALSE;
1549 isc_mem_water_t oldwater;
1552 REQUIRE(VALID_CONTEXT(ctx));
1553 REQUIRE(hiwater >= lowater);
1555 MCTXLOCK(ctx, &ctx->lock);
1556 oldwater = ctx->water;
1557 oldwater_arg = ctx->water_arg;
1558 if (water == NULL) {
1559 callwater = ctx->hi_called;
1561 ctx->water_arg = NULL;
1564 ctx->hi_called = ISC_FALSE;
1566 if (ctx->hi_called &&
1567 (ctx->water != water || ctx->water_arg != water_arg ||
1568 ctx->inuse < lowater || lowater == 0U))
1569 callwater = ISC_TRUE;
1571 ctx->water_arg = water_arg;
1572 ctx->hi_water = hiwater;
1573 ctx->lo_water = lowater;
1574 ctx->hi_called = ISC_FALSE;
1576 MCTXUNLOCK(ctx, &ctx->lock);
1578 if (callwater && oldwater != NULL)
1579 (oldwater)(oldwater_arg, ISC_MEM_LOWATER);
1583 isc_mem_isovermem(isc_mem_t *ctx) {
1584 REQUIRE(VALID_CONTEXT(ctx));
1587 * We don't bother to lock the context because 100% accuracy isn't
1588 * necessary (and even if we locked the context the returned value
1589 * could be different from the actual state when it's used anyway)
1591 return (ctx->is_overmem);
1595 isc_mem_setname(isc_mem_t *ctx, const char *name, void *tag) {
1596 REQUIRE(VALID_CONTEXT(ctx));
1599 memset(ctx->name, 0, sizeof(ctx->name));
1600 strncpy(ctx->name, name, sizeof(ctx->name) - 1);
1606 isc_mem_getname(isc_mem_t *ctx) {
1607 REQUIRE(VALID_CONTEXT(ctx));
1613 isc_mem_gettag(isc_mem_t *ctx) {
1614 REQUIRE(VALID_CONTEXT(ctx));
1624 isc_mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp) {
1625 isc_mempool_t *mpctx;
1627 REQUIRE(VALID_CONTEXT(mctx));
1629 REQUIRE(mpctxp != NULL && *mpctxp == NULL);
1632 * Allocate space for this pool, initialize values, and if all works
1633 * well, attach to the memory context.
1635 mpctx = isc_mem_get(mctx, sizeof(isc_mempool_t));
1637 return (ISC_R_NOMEMORY);
1639 mpctx->magic = MEMPOOL_MAGIC;
1643 mpctx->maxalloc = UINT_MAX;
1644 mpctx->allocated = 0;
1645 mpctx->freecount = 0;
1647 mpctx->fillcount = 1;
1649 #if ISC_MEMPOOL_NAMES
1652 mpctx->items = NULL;
1656 MCTXLOCK(mctx, &mctx->lock);
1657 ISC_LIST_INITANDAPPEND(mctx->pools, mpctx, link);
1659 MCTXUNLOCK(mctx, &mctx->lock);
1661 return (ISC_R_SUCCESS);
1665 isc_mempool_setname(isc_mempool_t *mpctx, const char *name) {
1666 REQUIRE(name != NULL);
1668 #if ISC_MEMPOOL_NAMES
1669 if (mpctx->lock != NULL)
1672 strncpy(mpctx->name, name, sizeof(mpctx->name) - 1);
1673 mpctx->name[sizeof(mpctx->name) - 1] = '\0';
1675 if (mpctx->lock != NULL)
1676 UNLOCK(mpctx->lock);
1684 isc_mempool_destroy(isc_mempool_t **mpctxp) {
1685 isc_mempool_t *mpctx;
1690 REQUIRE(mpctxp != NULL);
1692 REQUIRE(VALID_MEMPOOL(mpctx));
1693 #if ISC_MEMPOOL_NAMES
1694 if (mpctx->allocated > 0)
1695 UNEXPECTED_ERROR(__FILE__, __LINE__,
1696 "isc_mempool_destroy(): mempool %s "
1700 REQUIRE(mpctx->allocated == 0);
1710 * Return any items on the free list
1712 MCTXLOCK(mctx, &mctx->lock);
1713 while (mpctx->items != NULL) {
1714 INSIST(mpctx->freecount > 0);
1716 item = mpctx->items;
1717 mpctx->items = item->next;
1719 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1720 mem_putunlocked(mctx, item, mpctx->size);
1722 mem_put(mctx, item, mpctx->size);
1723 mem_putstats(mctx, item, mpctx->size);
1726 MCTXUNLOCK(mctx, &mctx->lock);
1729 * Remove our linked list entry from the memory context.
1731 MCTXLOCK(mctx, &mctx->lock);
1732 ISC_LIST_UNLINK(mctx->pools, mpctx, link);
1734 MCTXUNLOCK(mctx, &mctx->lock);
1738 isc_mem_put(mpctx->mctx, mpctx, sizeof(isc_mempool_t));
1747 isc_mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock) {
1748 REQUIRE(VALID_MEMPOOL(mpctx));
1749 REQUIRE(mpctx->lock == NULL);
1750 REQUIRE(lock != NULL);
1756 isc__mempool_get(isc_mempool_t *mpctx FLARG) {
1761 REQUIRE(VALID_MEMPOOL(mpctx));
1765 if (mpctx->lock != NULL)
1769 * Don't let the caller go over quota
1771 if (mpctx->allocated >= mpctx->maxalloc) {
1777 * if we have a free list item, return the first here
1779 item = mpctx->items;
1781 mpctx->items = item->next;
1782 INSIST(mpctx->freecount > 0);
1790 * We need to dip into the well. Lock the memory context here and
1791 * fill up our free list.
1793 MCTXLOCK(mctx, &mctx->lock);
1794 for (i = 0; i < mpctx->fillcount; i++) {
1795 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1796 item = mem_getunlocked(mctx, mpctx->size);
1798 item = mem_get(mctx, mpctx->size);
1800 mem_getstats(mctx, mpctx->size);
1804 item->next = mpctx->items;
1805 mpctx->items = item;
1808 MCTXUNLOCK(mctx, &mctx->lock);
1811 * If we didn't get any items, return NULL.
1813 item = mpctx->items;
1817 mpctx->items = item->next;
1823 if (mpctx->lock != NULL)
1824 UNLOCK(mpctx->lock);
1826 #if ISC_MEM_TRACKLINES
1828 MCTXLOCK(mctx, &mctx->lock);
1829 ADD_TRACE(mctx, item, mpctx->size, file, line);
1830 MCTXUNLOCK(mctx, &mctx->lock);
1832 #endif /* ISC_MEM_TRACKLINES */
1838 isc__mempool_put(isc_mempool_t *mpctx, void *mem FLARG) {
1842 REQUIRE(VALID_MEMPOOL(mpctx));
1843 REQUIRE(mem != NULL);
1847 if (mpctx->lock != NULL)
1850 INSIST(mpctx->allocated > 0);
1853 #if ISC_MEM_TRACKLINES
1854 MCTXLOCK(mctx, &mctx->lock);
1855 DELETE_TRACE(mctx, mem, mpctx->size, file, line);
1856 MCTXUNLOCK(mctx, &mctx->lock);
1857 #endif /* ISC_MEM_TRACKLINES */
1860 * If our free list is full, return this to the mctx directly.
1862 if (mpctx->freecount >= mpctx->freemax) {
1863 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1864 MCTXLOCK(mctx, &mctx->lock);
1865 mem_putunlocked(mctx, mem, mpctx->size);
1866 MCTXUNLOCK(mctx, &mctx->lock);
1868 mem_put(mctx, mem, mpctx->size);
1869 MCTXLOCK(mctx, &mctx->lock);
1870 mem_putstats(mctx, mem, mpctx->size);
1871 MCTXUNLOCK(mctx, &mctx->lock);
1873 if (mpctx->lock != NULL)
1874 UNLOCK(mpctx->lock);
1879 * Otherwise, attach it to our free list and bump the counter.
1882 item = (element *)mem;
1883 item->next = mpctx->items;
1884 mpctx->items = item;
1886 if (mpctx->lock != NULL)
1887 UNLOCK(mpctx->lock);
1895 isc_mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit) {
1896 REQUIRE(VALID_MEMPOOL(mpctx));
1898 if (mpctx->lock != NULL)
1901 mpctx->freemax = limit;
1903 if (mpctx->lock != NULL)
1904 UNLOCK(mpctx->lock);
1908 isc_mempool_getfreemax(isc_mempool_t *mpctx) {
1909 unsigned int freemax;
1911 REQUIRE(VALID_MEMPOOL(mpctx));
1913 if (mpctx->lock != NULL)
1916 freemax = mpctx->freemax;
1918 if (mpctx->lock != NULL)
1919 UNLOCK(mpctx->lock);
1925 isc_mempool_getfreecount(isc_mempool_t *mpctx) {
1926 unsigned int freecount;
1928 REQUIRE(VALID_MEMPOOL(mpctx));
1930 if (mpctx->lock != NULL)
1933 freecount = mpctx->freecount;
1935 if (mpctx->lock != NULL)
1936 UNLOCK(mpctx->lock);
1942 isc_mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit) {
1945 REQUIRE(VALID_MEMPOOL(mpctx));
1947 if (mpctx->lock != NULL)
1950 mpctx->maxalloc = limit;
1952 if (mpctx->lock != NULL)
1953 UNLOCK(mpctx->lock);
1957 isc_mempool_getmaxalloc(isc_mempool_t *mpctx) {
1958 unsigned int maxalloc;
1960 REQUIRE(VALID_MEMPOOL(mpctx));
1962 if (mpctx->lock != NULL)
1965 maxalloc = mpctx->maxalloc;
1967 if (mpctx->lock != NULL)
1968 UNLOCK(mpctx->lock);
1974 isc_mempool_getallocated(isc_mempool_t *mpctx) {
1975 unsigned int allocated;
1977 REQUIRE(VALID_MEMPOOL(mpctx));
1979 if (mpctx->lock != NULL)
1982 allocated = mpctx->allocated;
1984 if (mpctx->lock != NULL)
1985 UNLOCK(mpctx->lock);
1991 isc_mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit) {
1993 REQUIRE(VALID_MEMPOOL(mpctx));
1995 if (mpctx->lock != NULL)
1998 mpctx->fillcount = limit;
2000 if (mpctx->lock != NULL)
2001 UNLOCK(mpctx->lock);
2005 isc_mempool_getfillcount(isc_mempool_t *mpctx) {
2006 unsigned int fillcount;
2008 REQUIRE(VALID_MEMPOOL(mpctx));
2010 if (mpctx->lock != NULL)
2013 fillcount = mpctx->fillcount;
2015 if (mpctx->lock != NULL)
2016 UNLOCK(mpctx->lock);
2022 isc_mem_printactive(isc_mem_t *ctx, FILE *file) {
2024 REQUIRE(VALID_CONTEXT(ctx));
2025 REQUIRE(file != NULL);
2027 #if !ISC_MEM_TRACKLINES
2031 print_active(ctx, file);
2036 isc_mem_printallactive(FILE *file) {
2037 #if !ISC_MEM_TRACKLINES
2042 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2045 for (ctx = ISC_LIST_HEAD(contexts);
2047 ctx = ISC_LIST_NEXT(ctx, link)) {
2048 fprintf(file, "context: %p\n", ctx);
2049 print_active(ctx, file);
2056 isc_mem_checkdestroyed(FILE *file) {
2058 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2061 if (!ISC_LIST_EMPTY(contexts)) {
2062 #if ISC_MEM_TRACKLINES
2065 for (ctx = ISC_LIST_HEAD(contexts);
2067 ctx = ISC_LIST_NEXT(ctx, link)) {
2068 fprintf(file, "context: %p\n", ctx);
2069 print_active(ctx, file);
2079 isc_mem_references(isc_mem_t *ctx) {
2080 unsigned int references;
2081 REQUIRE(VALID_CONTEXT(ctx));
2083 MCTXLOCK(ctx, &ctx->lock);
2084 references = ctx->references;
2085 MCTXUNLOCK(ctx, &ctx->lock);
2087 return (references);
2092 typedef struct summarystat {
2095 isc_uint64_t blocksize;
2096 isc_uint64_t contextsize;
2100 renderctx(isc_mem_t *ctx, summarystat_t *summary, xmlTextWriterPtr writer) {
2101 REQUIRE(VALID_CONTEXT(ctx));
2103 xmlTextWriterStartElement(writer, ISC_XMLCHAR "context");
2105 xmlTextWriterStartElement(writer, ISC_XMLCHAR "id");
2106 xmlTextWriterWriteFormatString(writer, "%p", ctx);
2107 xmlTextWriterEndElement(writer); /* id */
2109 if (ctx->name[0] != 0) {
2110 xmlTextWriterStartElement(writer, ISC_XMLCHAR "name");
2111 xmlTextWriterWriteFormatString(writer, "%s", ctx->name);
2112 xmlTextWriterEndElement(writer); /* name */
2115 REQUIRE(VALID_CONTEXT(ctx));
2116 MCTXLOCK(ctx, &ctx->lock);
2118 summary->contextsize += sizeof(*ctx) +
2119 (ctx->max_size + 1) * sizeof(struct stats) +
2120 ctx->max_size * sizeof(element *) +
2121 ctx->basic_table_count * sizeof(char *);
2122 #if ISC_MEM_TRACKLINES
2123 if (ctx->debuglist != NULL) {
2124 summary->contextsize +=
2125 (ctx->max_size + 1) * sizeof(debuglist_t) +
2126 ctx->debuglistcnt * sizeof(debuglink_t);
2129 xmlTextWriterStartElement(writer, ISC_XMLCHAR "references");
2130 xmlTextWriterWriteFormatString(writer, "%d", ctx->references);
2131 xmlTextWriterEndElement(writer); /* references */
2133 summary->total += ctx->total;
2134 xmlTextWriterStartElement(writer, ISC_XMLCHAR "total");
2135 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2136 (isc_uint64_t)ctx->total);
2137 xmlTextWriterEndElement(writer); /* total */
2139 summary->inuse += ctx->inuse;
2140 xmlTextWriterStartElement(writer, ISC_XMLCHAR "inuse");
2141 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2142 (isc_uint64_t)ctx->inuse);
2143 xmlTextWriterEndElement(writer); /* inuse */
2145 xmlTextWriterStartElement(writer, ISC_XMLCHAR "maxinuse");
2146 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2147 (isc_uint64_t)ctx->maxinuse);
2148 xmlTextWriterEndElement(writer); /* maxinuse */
2150 xmlTextWriterStartElement(writer, ISC_XMLCHAR "blocksize");
2151 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
2152 summary->blocksize += ctx->basic_table_count *
2153 NUM_BASIC_BLOCKS * ctx->mem_target;
2154 xmlTextWriterWriteFormatString(writer,
2155 "%" ISC_PRINT_QUADFORMAT "u",
2157 ctx->basic_table_count *
2161 xmlTextWriterWriteFormatString(writer, "%s", "-");
2162 xmlTextWriterEndElement(writer); /* blocksize */
2164 xmlTextWriterStartElement(writer, ISC_XMLCHAR "pools");
2165 xmlTextWriterWriteFormatString(writer, "%u", ctx->poolcnt);
2166 xmlTextWriterEndElement(writer); /* pools */
2167 summary->contextsize += ctx->poolcnt * sizeof(isc_mempool_t);
2169 xmlTextWriterStartElement(writer, ISC_XMLCHAR "hiwater");
2170 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2171 (isc_uint64_t)ctx->hi_water);
2172 xmlTextWriterEndElement(writer); /* hiwater */
2174 xmlTextWriterStartElement(writer, ISC_XMLCHAR "lowater");
2175 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2176 (isc_uint64_t)ctx->lo_water);
2177 xmlTextWriterEndElement(writer); /* lowater */
2179 MCTXUNLOCK(ctx, &ctx->lock);
2181 xmlTextWriterEndElement(writer); /* context */
2185 isc_mem_renderxml(xmlTextWriterPtr writer) {
2187 summarystat_t summary;
2190 memset(&summary, 0, sizeof(summary));
2192 xmlTextWriterStartElement(writer, ISC_XMLCHAR "contexts");
2194 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2198 for (ctx = ISC_LIST_HEAD(contexts);
2200 ctx = ISC_LIST_NEXT(ctx, link)) {
2201 renderctx(ctx, &summary, writer);
2205 xmlTextWriterEndElement(writer); /* contexts */
2207 xmlTextWriterStartElement(writer, ISC_XMLCHAR "summary");
2209 xmlTextWriterStartElement(writer, ISC_XMLCHAR "TotalUse");
2210 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2212 xmlTextWriterEndElement(writer); /* TotalUse */
2214 xmlTextWriterStartElement(writer, ISC_XMLCHAR "InUse");
2215 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2217 xmlTextWriterEndElement(writer); /* InUse */
2219 xmlTextWriterStartElement(writer, ISC_XMLCHAR "BlockSize");
2220 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2222 xmlTextWriterEndElement(writer); /* BlockSize */
2224 xmlTextWriterStartElement(writer, ISC_XMLCHAR "ContextSize");
2225 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2226 summary.contextsize);
2227 xmlTextWriterEndElement(writer); /* ContextSize */
2229 xmlTextWriterStartElement(writer, ISC_XMLCHAR "Lost");
2230 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2232 xmlTextWriterEndElement(writer); /* Lost */
2234 xmlTextWriterEndElement(writer); /* summary */
2237 #endif /* HAVE_LIBXML2 */