2 * Copyright (C) 2004-2007 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.116.18.18 2007/10/30 23:31:43 marka Exp $ */
30 #include <isc/magic.h>
34 #include <isc/ondestroy.h>
35 #include <isc/string.h>
37 #include <isc/mutex.h>
40 #define MCTXLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) LOCK(l)
41 #define MCTXUNLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) UNLOCK(l)
43 #ifndef ISC_MEM_DEBUGGING
44 #define ISC_MEM_DEBUGGING 0
46 LIBISC_EXTERNAL_DATA unsigned int isc_mem_debugging = ISC_MEM_DEBUGGING;
52 #define DEF_MAX_SIZE 1100
53 #define DEF_MEM_TARGET 4096
54 #define ALIGNMENT_SIZE 8 /*%< must be a power of 2 */
55 #define NUM_BASIC_BLOCKS 64 /*%< must be > 1 */
56 #define TABLE_INCREMENT 1024
57 #define DEBUGLIST_COUNT 1024
62 #if ISC_MEM_TRACKLINES
63 typedef struct debuglink debuglink_t;
65 ISC_LINK(debuglink_t) link;
66 const void *ptr[DEBUGLIST_COUNT];
67 unsigned int size[DEBUGLIST_COUNT];
68 const char *file[DEBUGLIST_COUNT];
69 unsigned int line[DEBUGLIST_COUNT];
73 #define FLARG_PASS , file, line
74 #define FLARG , const char *file, int line
80 typedef struct element element;
87 * This structure must be ALIGNMENT_SIZE bytes.
92 char bytes[ALIGNMENT_SIZE];
98 unsigned long totalgets;
100 unsigned long freefrags;
103 #define MEM_MAGIC ISC_MAGIC('M', 'e', 'm', 'C')
104 #define VALID_CONTEXT(c) ISC_MAGIC_VALID(c, MEM_MAGIC)
106 #if ISC_MEM_TRACKLINES
107 typedef ISC_LIST(debuglink_t) debuglist_t;
110 /* List of all active memory contexts. */
112 static ISC_LIST(isc_mem_t) contexts;
113 static isc_once_t once = ISC_ONCE_INIT;
114 static isc_mutex_t lock;
118 isc_ondestroy_t ondestroy;
121 isc_memalloc_t memalloc;
122 isc_memfree_t memfree;
125 isc_boolean_t checkfree;
126 struct stats * stats;
127 unsigned int references;
134 isc_boolean_t hi_called;
135 isc_mem_water_t water;
137 ISC_LIST(isc_mempool_t) pools;
139 /* ISC_MEMFLAG_INTERNAL */
141 element ** freelists;
142 element * basic_blocks;
143 unsigned char ** basic_table;
144 unsigned int basic_table_count;
145 unsigned int basic_table_size;
146 unsigned char * lowest;
147 unsigned char * highest;
149 #if ISC_MEM_TRACKLINES
150 debuglist_t * debuglist;
153 unsigned int memalloc_failures;
154 ISC_LINK(isc_mem_t) link;
157 #define MEMPOOL_MAGIC ISC_MAGIC('M', 'E', 'M', 'p')
158 #define VALID_MEMPOOL(c) ISC_MAGIC_VALID(c, MEMPOOL_MAGIC)
161 /* always unlocked */
162 unsigned int magic; /*%< magic number */
163 isc_mutex_t *lock; /*%< optional lock */
164 isc_mem_t *mctx; /*%< our memory context */
165 /*%< locked via the memory context's lock */
166 ISC_LINK(isc_mempool_t) link; /*%< next pool in this mem context */
167 /*%< optionally locked from here down */
168 element *items; /*%< low water item list */
169 size_t size; /*%< size of each item on this pool */
170 unsigned int maxalloc; /*%< max number of items allowed */
171 unsigned int allocated; /*%< # of items currently given out */
172 unsigned int freecount; /*%< # of items on reserved list */
173 unsigned int freemax; /*%< # of items allowed on free list */
174 unsigned int fillcount; /*%< # of items to fetch on each fill */
176 unsigned int gets; /*%< # of requests to this pool */
177 /*%< Debugging only. */
178 #if ISC_MEMPOOL_NAMES
179 char name[16]; /*%< printed name in stats reports */
184 * Private Inline-able.
187 #if ! ISC_MEM_TRACKLINES
188 #define ADD_TRACE(a, b, c, d, e)
189 #define DELETE_TRACE(a, b, c, d, e)
191 #define ADD_TRACE(a, b, c, d, e) \
193 if ((isc_mem_debugging & (ISC_MEM_DEBUGTRACE | \
194 ISC_MEM_DEBUGRECORD)) != 0 && \
196 add_trace_entry(a, b, c, d, e); \
198 #define DELETE_TRACE(a, b, c, d, e) delete_trace_entry(a, b, c, d, e)
201 print_active(isc_mem_t *ctx, FILE *out);
204 * mctx must be locked.
207 add_trace_entry(isc_mem_t *mctx, const void *ptr, unsigned int size
213 if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
214 fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
217 "file %s line %u mctx %p\n"),
218 ptr, size, file, line, mctx);
220 if (mctx->debuglist == NULL)
223 if (size > mctx->max_size)
224 size = mctx->max_size;
226 dl = ISC_LIST_HEAD(mctx->debuglist[size]);
228 if (dl->count == DEBUGLIST_COUNT)
230 for (i = 0; i < DEBUGLIST_COUNT; i++) {
231 if (dl->ptr[i] == NULL) {
241 dl = ISC_LIST_NEXT(dl, link);
244 dl = malloc(sizeof(debuglink_t));
247 ISC_LINK_INIT(dl, link);
248 for (i = 1; i < DEBUGLIST_COUNT; i++) {
261 ISC_LIST_PREPEND(mctx->debuglist[size], dl, link);
265 delete_trace_entry(isc_mem_t *mctx, const void *ptr, unsigned int size,
266 const char *file, unsigned int line)
271 if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
272 fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
275 "file %s line %u mctx %p\n"),
276 ptr, size, file, line, mctx);
278 if (mctx->debuglist == NULL)
281 if (size > mctx->max_size)
282 size = mctx->max_size;
284 dl = ISC_LIST_HEAD(mctx->debuglist[size]);
286 for (i = 0; i < DEBUGLIST_COUNT; i++) {
287 if (dl->ptr[i] == ptr) {
293 INSIST(dl->count > 0);
295 if (dl->count == 0) {
296 ISC_LIST_UNLINK(mctx->debuglist[size],
303 dl = ISC_LIST_NEXT(dl, link);
307 * If we get here, we didn't find the item on the list. We're
312 #endif /* ISC_MEM_TRACKLINES */
315 rmsize(size_t size) {
317 * round down to ALIGNMENT_SIZE
319 return (size & (~(ALIGNMENT_SIZE - 1)));
323 quantize(size_t size) {
325 * Round up the result in order to get a size big
326 * enough to satisfy the request and be aligned on ALIGNMENT_SIZE
331 return (ALIGNMENT_SIZE);
332 return ((size + ALIGNMENT_SIZE - 1) & (~(ALIGNMENT_SIZE - 1)));
335 static inline isc_boolean_t
336 more_basic_blocks(isc_mem_t *ctx) {
338 unsigned char *curr, *next;
339 unsigned char *first, *last;
340 unsigned char **table;
341 unsigned int table_size;
345 /* Require: we hold the context lock. */
348 * Did we hit the quota for this context?
350 increment = NUM_BASIC_BLOCKS * ctx->mem_target;
351 if (ctx->quota != 0U && ctx->total + increment > ctx->quota)
354 INSIST(ctx->basic_table_count <= ctx->basic_table_size);
355 if (ctx->basic_table_count == ctx->basic_table_size) {
356 table_size = ctx->basic_table_size + TABLE_INCREMENT;
357 table = (ctx->memalloc)(ctx->arg,
358 table_size * sizeof(unsigned char *));
360 ctx->memalloc_failures++;
363 if (ctx->basic_table_size != 0) {
364 memcpy(table, ctx->basic_table,
365 ctx->basic_table_size *
366 sizeof(unsigned char *));
367 (ctx->memfree)(ctx->arg, ctx->basic_table);
369 ctx->basic_table = table;
370 ctx->basic_table_size = table_size;
373 new = (ctx->memalloc)(ctx->arg, NUM_BASIC_BLOCKS * ctx->mem_target);
375 ctx->memalloc_failures++;
378 ctx->total += increment;
379 ctx->basic_table[ctx->basic_table_count] = new;
380 ctx->basic_table_count++;
383 next = curr + ctx->mem_target;
384 for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) {
385 ((element *)curr)->next = (element *)next;
387 next += ctx->mem_target;
390 * curr is now pointing at the last block in the
393 ((element *)curr)->next = NULL;
395 last = first + NUM_BASIC_BLOCKS * ctx->mem_target - 1;
396 if (first < ctx->lowest || ctx->lowest == NULL)
398 if (last > ctx->highest)
400 ctx->basic_blocks = new;
405 static inline isc_boolean_t
406 more_frags(isc_mem_t *ctx, size_t new_size) {
410 unsigned char *curr, *next;
413 * Try to get more fragments by chopping up a basic block.
416 if (ctx->basic_blocks == NULL) {
417 if (!more_basic_blocks(ctx)) {
419 * We can't get more memory from the OS, or we've
420 * hit the quota for this context.
423 * XXXRTH "At quota" notification here.
429 total_size = ctx->mem_target;
430 new = ctx->basic_blocks;
431 ctx->basic_blocks = ctx->basic_blocks->next;
432 frags = total_size / new_size;
433 ctx->stats[new_size].blocks++;
434 ctx->stats[new_size].freefrags += frags;
436 * Set up a linked-list of blocks of size
440 next = curr + new_size;
441 total_size -= new_size;
442 for (i = 0; i < (frags - 1); i++) {
443 ((element *)curr)->next = (element *)next;
446 total_size -= new_size;
449 * Add the remaining fragment of the basic block to a free list.
451 total_size = rmsize(total_size);
452 if (total_size > 0U) {
453 ((element *)next)->next = ctx->freelists[total_size];
454 ctx->freelists[total_size] = (element *)next;
455 ctx->stats[total_size].freefrags++;
458 * curr is now pointing at the last block in the
461 ((element *)curr)->next = NULL;
462 ctx->freelists[new_size] = new;
468 mem_getunlocked(isc_mem_t *ctx, size_t size) {
469 size_t new_size = quantize(size);
472 if (size >= ctx->max_size || new_size >= ctx->max_size) {
474 * memget() was called on something beyond our upper limit.
476 if (ctx->quota != 0U && ctx->total + size > ctx->quota) {
480 ret = (ctx->memalloc)(ctx->arg, size);
482 ctx->memalloc_failures++;
487 ctx->stats[ctx->max_size].gets++;
488 ctx->stats[ctx->max_size].totalgets++;
490 * If we don't set new_size to size, then the
491 * ISC_MEM_FILL code might write over bytes we
499 * If there are no blocks in the free list for this size, get a chunk
500 * of memory and then break it up into "new_size"-sized blocks, adding
501 * them to the free list.
503 if (ctx->freelists[new_size] == NULL && !more_frags(ctx, new_size))
507 * The free list uses the "rounded-up" size "new_size".
509 ret = ctx->freelists[new_size];
510 ctx->freelists[new_size] = ctx->freelists[new_size]->next;
513 * The stats[] uses the _actual_ "size" requested by the
514 * caller, with the caveat (in the code above) that "size" >= the
515 * max. size (max_size) ends up getting recorded as a call to
518 ctx->stats[size].gets++;
519 ctx->stats[size].totalgets++;
520 ctx->stats[new_size].freefrags--;
521 ctx->inuse += new_size;
527 memset(ret, 0xbe, new_size); /* Mnemonic for "beef". */
533 #if ISC_MEM_FILL && ISC_MEM_CHECKOVERRUN
535 check_overrun(void *mem, size_t size, size_t new_size) {
538 cp = (unsigned char *)mem;
540 while (size < new_size) {
549 mem_putunlocked(isc_mem_t *ctx, void *mem, size_t size) {
550 size_t new_size = quantize(size);
552 if (size == ctx->max_size || new_size >= ctx->max_size) {
554 * memput() called on something beyond our upper limit.
557 memset(mem, 0xde, size); /* Mnemonic for "dead". */
559 (ctx->memfree)(ctx->arg, mem);
560 INSIST(ctx->stats[ctx->max_size].gets != 0U);
561 ctx->stats[ctx->max_size].gets--;
562 INSIST(size <= ctx->total);
569 #if ISC_MEM_CHECKOVERRUN
570 check_overrun(mem, size, new_size);
572 memset(mem, 0xde, new_size); /* Mnemonic for "dead". */
576 * The free list uses the "rounded-up" size "new_size".
578 ((element *)mem)->next = ctx->freelists[new_size];
579 ctx->freelists[new_size] = (element *)mem;
582 * The stats[] uses the _actual_ "size" requested by the
583 * caller, with the caveat (in the code above) that "size" >= the
584 * max. size (max_size) ends up getting recorded as a call to
587 INSIST(ctx->stats[size].gets != 0U);
588 ctx->stats[size].gets--;
589 ctx->stats[new_size].freefrags++;
590 ctx->inuse -= new_size;
594 * Perform a malloc, doing memory filling and overrun detection as necessary.
597 mem_get(isc_mem_t *ctx, size_t size) {
600 #if ISC_MEM_CHECKOVERRUN
604 ret = (ctx->memalloc)(ctx->arg, size);
606 ctx->memalloc_failures++;
610 memset(ret, 0xbe, size); /* Mnemonic for "beef". */
612 # if ISC_MEM_CHECKOVERRUN
622 * Perform a free, doing memory filling and overrun detection as necessary.
625 mem_put(isc_mem_t *ctx, void *mem, size_t size) {
626 #if ISC_MEM_CHECKOVERRUN
627 INSIST(((unsigned char *)mem)[size] == 0xbe);
630 memset(mem, 0xde, size); /* Mnemonic for "dead". */
634 (ctx->memfree)(ctx->arg, mem);
638 * Update internal counters after a memory get.
641 mem_getstats(isc_mem_t *ctx, size_t size) {
645 if (size > ctx->max_size) {
646 ctx->stats[ctx->max_size].gets++;
647 ctx->stats[ctx->max_size].totalgets++;
649 ctx->stats[size].gets++;
650 ctx->stats[size].totalgets++;
655 * Update internal counters after a memory put.
658 mem_putstats(isc_mem_t *ctx, void *ptr, size_t size) {
661 INSIST(ctx->inuse >= size);
664 if (size > ctx->max_size) {
665 INSIST(ctx->stats[ctx->max_size].gets > 0U);
666 ctx->stats[ctx->max_size].gets--;
668 INSIST(ctx->stats[size].gets > 0U);
669 ctx->stats[size].gets--;
678 default_memalloc(void *arg, size_t size) {
682 return (malloc(size));
686 default_memfree(void *arg, void *ptr) {
692 initialize_action(void) {
693 RUNTIME_CHECK(isc_mutex_init(&lock) == ISC_R_SUCCESS);
694 ISC_LIST_INIT(contexts);
702 isc_mem_createx(size_t init_max_size, size_t target_size,
703 isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
706 return (isc_mem_createx2(init_max_size, target_size, memalloc, memfree,
707 arg, ctxp, ISC_MEMFLAG_DEFAULT));
712 isc_mem_createx2(size_t init_max_size, size_t target_size,
713 isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
714 isc_mem_t **ctxp, unsigned int flags)
719 REQUIRE(ctxp != NULL && *ctxp == NULL);
720 REQUIRE(memalloc != NULL);
721 REQUIRE(memfree != NULL);
723 INSIST((ALIGNMENT_SIZE & (ALIGNMENT_SIZE - 1)) == 0);
725 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
727 ctx = (memalloc)(arg, sizeof(*ctx));
729 return (ISC_R_NOMEMORY);
731 if ((flags & ISC_MEMFLAG_NOLOCK) == 0) {
732 result = isc_mutex_init(&ctx->lock);
733 if (result != ISC_R_SUCCESS) {
739 if (init_max_size == 0U)
740 ctx->max_size = DEF_MAX_SIZE;
742 ctx->max_size = init_max_size;
751 ctx->hi_called = ISC_FALSE;
753 ctx->water_arg = NULL;
754 ctx->magic = MEM_MAGIC;
755 isc_ondestroy_init(&ctx->ondestroy);
756 ctx->memalloc = memalloc;
757 ctx->memfree = memfree;
760 ctx->checkfree = ISC_TRUE;
761 #if ISC_MEM_TRACKLINES
762 ctx->debuglist = NULL;
764 ISC_LIST_INIT(ctx->pools);
765 ctx->freelists = NULL;
766 ctx->basic_blocks = NULL;
767 ctx->basic_table = NULL;
768 ctx->basic_table_count = 0;
769 ctx->basic_table_size = 0;
773 ctx->stats = (memalloc)(arg,
774 (ctx->max_size+1) * sizeof(struct stats));
775 if (ctx->stats == NULL) {
776 result = ISC_R_NOMEMORY;
779 memset(ctx->stats, 0, (ctx->max_size + 1) * sizeof(struct stats));
781 if ((flags & ISC_MEMFLAG_INTERNAL) != 0) {
782 if (target_size == 0U)
783 ctx->mem_target = DEF_MEM_TARGET;
785 ctx->mem_target = target_size;
786 ctx->freelists = (memalloc)(arg, ctx->max_size *
788 if (ctx->freelists == NULL) {
789 result = ISC_R_NOMEMORY;
792 memset(ctx->freelists, 0,
793 ctx->max_size * sizeof(element *));
796 #if ISC_MEM_TRACKLINES
797 if ((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0) {
800 ctx->debuglist = (memalloc)(arg,
801 (ctx->max_size+1) * sizeof(debuglist_t));
802 if (ctx->debuglist == NULL) {
803 result = ISC_R_NOMEMORY;
806 for (i = 0; i <= ctx->max_size; i++)
807 ISC_LIST_INIT(ctx->debuglist[i]);
811 ctx->memalloc_failures = 0;
814 ISC_LIST_INITANDAPPEND(contexts, ctx, link);
818 return (ISC_R_SUCCESS);
822 if (ctx->stats != NULL)
823 (memfree)(arg, ctx->stats);
824 if (ctx->freelists != NULL)
825 (memfree)(arg, ctx->freelists);
826 #if ISC_MEM_TRACKLINES
827 if (ctx->debuglist != NULL)
828 (ctx->memfree)(ctx->arg, ctx->debuglist);
829 #endif /* ISC_MEM_TRACKLINES */
830 if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
831 DESTROYLOCK(&ctx->lock);
839 isc_mem_create(size_t init_max_size, size_t target_size,
842 return (isc_mem_createx2(init_max_size, target_size,
843 default_memalloc, default_memfree, NULL,
844 ctxp, ISC_MEMFLAG_DEFAULT));
848 isc_mem_create2(size_t init_max_size, size_t target_size,
849 isc_mem_t **ctxp, unsigned int flags)
851 return (isc_mem_createx2(init_max_size, target_size,
852 default_memalloc, default_memfree, NULL,
857 destroy(isc_mem_t *ctx) {
859 isc_ondestroy_t ondest;
864 ISC_LIST_UNLINK(contexts, ctx, link);
867 INSIST(ISC_LIST_EMPTY(ctx->pools));
869 #if ISC_MEM_TRACKLINES
870 if (ctx->debuglist != NULL) {
871 if (ctx->checkfree) {
872 for (i = 0; i <= ctx->max_size; i++) {
873 if (!ISC_LIST_EMPTY(ctx->debuglist[i]))
874 print_active(ctx, stderr);
875 INSIST(ISC_LIST_EMPTY(ctx->debuglist[i]));
880 for (i = 0; i <= ctx->max_size; i++)
881 for (dl = ISC_LIST_HEAD(ctx->debuglist[i]);
883 dl = ISC_LIST_HEAD(ctx->debuglist[i])) {
884 ISC_LIST_UNLINK(ctx->debuglist[i],
889 (ctx->memfree)(ctx->arg, ctx->debuglist);
892 INSIST(ctx->references == 0);
894 if (ctx->checkfree) {
895 for (i = 0; i <= ctx->max_size; i++) {
896 #if ISC_MEM_TRACKLINES
897 if (ctx->stats[i].gets != 0U)
898 print_active(ctx, stderr);
900 INSIST(ctx->stats[i].gets == 0U);
904 (ctx->memfree)(ctx->arg, ctx->stats);
906 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
907 for (i = 0; i < ctx->basic_table_count; i++)
908 (ctx->memfree)(ctx->arg, ctx->basic_table[i]);
909 (ctx->memfree)(ctx->arg, ctx->freelists);
910 (ctx->memfree)(ctx->arg, ctx->basic_table);
913 ondest = ctx->ondestroy;
915 if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
916 DESTROYLOCK(&ctx->lock);
917 (ctx->memfree)(ctx->arg, ctx);
919 isc_ondestroy_notify(&ondest, ctx);
923 isc_mem_attach(isc_mem_t *source, isc_mem_t **targetp) {
924 REQUIRE(VALID_CONTEXT(source));
925 REQUIRE(targetp != NULL && *targetp == NULL);
927 MCTXLOCK(source, &source->lock);
928 source->references++;
929 MCTXUNLOCK(source, &source->lock);
935 isc_mem_detach(isc_mem_t **ctxp) {
937 isc_boolean_t want_destroy = ISC_FALSE;
939 REQUIRE(ctxp != NULL);
941 REQUIRE(VALID_CONTEXT(ctx));
943 MCTXLOCK(ctx, &ctx->lock);
944 INSIST(ctx->references > 0);
946 if (ctx->references == 0)
947 want_destroy = ISC_TRUE;
948 MCTXUNLOCK(ctx, &ctx->lock);
957 * isc_mem_putanddetach() is the equivalent of:
960 * isc_mem_attach(ptr->mctx, &mctx);
961 * isc_mem_detach(&ptr->mctx);
962 * isc_mem_put(mctx, ptr, sizeof(*ptr);
963 * isc_mem_detach(&mctx);
967 isc__mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) {
969 isc_boolean_t want_destroy = ISC_FALSE;
973 REQUIRE(ctxp != NULL);
975 REQUIRE(VALID_CONTEXT(ctx));
976 REQUIRE(ptr != NULL);
979 * Must be before mem_putunlocked() as ctxp is usually within
984 if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) {
985 if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) {
986 si = &(((size_info *)ptr)[-1]);
987 oldsize = si->u.size - ALIGNMENT_SIZE;
988 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
989 oldsize -= ALIGNMENT_SIZE;
990 INSIST(oldsize == size);
992 isc__mem_free(ctx, ptr FLARG_PASS);
994 MCTXLOCK(ctx, &ctx->lock);
996 if (ctx->references == 0)
997 want_destroy = ISC_TRUE;
998 MCTXUNLOCK(ctx, &ctx->lock);
1005 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1006 MCTXLOCK(ctx, &ctx->lock);
1007 mem_putunlocked(ctx, ptr, size);
1009 mem_put(ctx, ptr, size);
1010 MCTXLOCK(ctx, &ctx->lock);
1011 mem_putstats(ctx, ptr, size);
1014 DELETE_TRACE(ctx, ptr, size, file, line);
1015 INSIST(ctx->references > 0);
1017 if (ctx->references == 0)
1018 want_destroy = ISC_TRUE;
1020 MCTXUNLOCK(ctx, &ctx->lock);
1027 isc_mem_destroy(isc_mem_t **ctxp) {
1031 * This routine provides legacy support for callers who use mctxs
1032 * without attaching/detaching.
1035 REQUIRE(ctxp != NULL);
1037 REQUIRE(VALID_CONTEXT(ctx));
1039 MCTXLOCK(ctx, &ctx->lock);
1040 #if ISC_MEM_TRACKLINES
1041 if (ctx->references != 1)
1042 print_active(ctx, stderr);
1044 REQUIRE(ctx->references == 1);
1046 MCTXUNLOCK(ctx, &ctx->lock);
1054 isc_mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event) {
1057 MCTXLOCK(ctx, &ctx->lock);
1058 res = isc_ondestroy_register(&ctx->ondestroy, task, event);
1059 MCTXUNLOCK(ctx, &ctx->lock);
1066 isc__mem_get(isc_mem_t *ctx, size_t size FLARG) {
1068 isc_boolean_t call_water = ISC_FALSE;
1070 REQUIRE(VALID_CONTEXT(ctx));
1072 if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0)
1073 return (isc__mem_allocate(ctx, size FLARG_PASS));
1075 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1076 MCTXLOCK(ctx, &ctx->lock);
1077 ptr = mem_getunlocked(ctx, size);
1079 ptr = mem_get(ctx, size);
1080 MCTXLOCK(ctx, &ctx->lock);
1082 mem_getstats(ctx, size);
1085 ADD_TRACE(ctx, ptr, size, file, line);
1086 if (ctx->hi_water != 0U && !ctx->hi_called &&
1087 ctx->inuse > ctx->hi_water) {
1088 ctx->hi_called = ISC_TRUE;
1089 call_water = ISC_TRUE;
1091 if (ctx->inuse > ctx->maxinuse) {
1092 ctx->maxinuse = ctx->inuse;
1093 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1094 (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
1095 fprintf(stderr, "maxinuse = %lu\n",
1096 (unsigned long)ctx->inuse);
1098 MCTXUNLOCK(ctx, &ctx->lock);
1101 (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
1107 isc__mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG)
1109 isc_boolean_t call_water = ISC_FALSE;
1113 REQUIRE(VALID_CONTEXT(ctx));
1114 REQUIRE(ptr != NULL);
1116 if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) {
1117 if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) {
1118 si = &(((size_info *)ptr)[-1]);
1119 oldsize = si->u.size - ALIGNMENT_SIZE;
1120 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
1121 oldsize -= ALIGNMENT_SIZE;
1122 INSIST(oldsize == size);
1124 isc__mem_free(ctx, ptr FLARG_PASS);
1128 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1129 MCTXLOCK(ctx, &ctx->lock);
1130 mem_putunlocked(ctx, ptr, size);
1132 mem_put(ctx, ptr, size);
1133 MCTXLOCK(ctx, &ctx->lock);
1134 mem_putstats(ctx, ptr, size);
1137 DELETE_TRACE(ctx, ptr, size, file, line);
1140 * The check against ctx->lo_water == 0 is for the condition
1141 * when the context was pushed over hi_water but then had
1142 * isc_mem_setwater() called with 0 for hi_water and lo_water.
1144 if (ctx->hi_called &&
1145 (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1146 ctx->hi_called = ISC_FALSE;
1148 if (ctx->water != NULL)
1149 call_water = ISC_TRUE;
1151 MCTXUNLOCK(ctx, &ctx->lock);
1154 (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
1157 #if ISC_MEM_TRACKLINES
1159 print_active(isc_mem_t *mctx, FILE *out) {
1160 if (mctx->debuglist != NULL) {
1164 isc_boolean_t found;
1166 fprintf(out, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1168 "Dump of all outstanding "
1169 "memory allocations:\n"));
1171 format = isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1172 ISC_MSG_PTRFILELINE,
1173 "\tptr %p size %u file %s line %u\n");
1174 for (i = 0; i <= mctx->max_size; i++) {
1175 dl = ISC_LIST_HEAD(mctx->debuglist[i]);
1180 while (dl != NULL) {
1181 for (j = 0; j < DEBUGLIST_COUNT; j++)
1182 if (dl->ptr[j] != NULL)
1183 fprintf(out, format,
1188 dl = ISC_LIST_NEXT(dl, link);
1192 fprintf(out, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1193 ISC_MSG_NONE, "\tNone.\n"));
1199 * Print the stats[] on the stream "out" with suitable formatting.
1202 isc_mem_stats(isc_mem_t *ctx, FILE *out) {
1204 const struct stats *s;
1205 const isc_mempool_t *pool;
1207 REQUIRE(VALID_CONTEXT(ctx));
1208 MCTXLOCK(ctx, &ctx->lock);
1210 for (i = 0; i <= ctx->max_size; i++) {
1213 if (s->totalgets == 0U && s->gets == 0U)
1215 fprintf(out, "%s%5lu: %11lu gets, %11lu rem",
1216 (i == ctx->max_size) ? ">=" : " ",
1217 (unsigned long) i, s->totalgets, s->gets);
1218 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0 &&
1219 (s->blocks != 0U || s->freefrags != 0U))
1220 fprintf(out, " (%lu bl, %lu ff)",
1221 s->blocks, s->freefrags);
1226 * Note that since a pool can be locked now, these stats might be
1227 * somewhat off if the pool is in active use at the time the stats
1228 * are dumped. The link fields are protected by the isc_mem_t's
1229 * lock, however, so walking this list and extracting integers from
1230 * stats fields is always safe.
1232 pool = ISC_LIST_HEAD(ctx->pools);
1234 fprintf(out, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1236 "[Pool statistics]\n"));
1237 fprintf(out, "%15s %10s %10s %10s %10s %10s %10s %10s %1s\n",
1238 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1239 ISC_MSG_POOLNAME, "name"),
1240 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1241 ISC_MSG_POOLSIZE, "size"),
1242 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1243 ISC_MSG_POOLMAXALLOC, "maxalloc"),
1244 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1245 ISC_MSG_POOLALLOCATED, "allocated"),
1246 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1247 ISC_MSG_POOLFREECOUNT, "freecount"),
1248 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1249 ISC_MSG_POOLFREEMAX, "freemax"),
1250 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1251 ISC_MSG_POOLFILLCOUNT, "fillcount"),
1252 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1253 ISC_MSG_POOLGETS, "gets"),
1256 while (pool != NULL) {
1257 fprintf(out, "%15s %10lu %10u %10u %10u %10u %10u %10u %s\n",
1258 pool->name, (unsigned long) pool->size, pool->maxalloc,
1259 pool->allocated, pool->freecount, pool->freemax,
1260 pool->fillcount, pool->gets,
1261 (pool->lock == NULL ? "N" : "Y"));
1262 pool = ISC_LIST_NEXT(pool, link);
1265 #if ISC_MEM_TRACKLINES
1266 print_active(ctx, out);
1269 MCTXUNLOCK(ctx, &ctx->lock);
1273 * Replacements for malloc() and free() -- they implicitly remember the
1274 * size of the object allocated (with some additional overhead).
1278 isc__mem_allocateunlocked(isc_mem_t *ctx, size_t size) {
1281 size += ALIGNMENT_SIZE;
1282 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
1283 size += ALIGNMENT_SIZE;
1285 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0)
1286 si = mem_getunlocked(ctx, size);
1288 si = mem_get(ctx, size);
1292 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
1301 isc__mem_allocate(isc_mem_t *ctx, size_t size FLARG) {
1303 isc_boolean_t call_water = ISC_FALSE;
1305 REQUIRE(VALID_CONTEXT(ctx));
1307 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1308 MCTXLOCK(ctx, &ctx->lock);
1309 si = isc__mem_allocateunlocked(ctx, size);
1311 si = isc__mem_allocateunlocked(ctx, size);
1312 MCTXLOCK(ctx, &ctx->lock);
1314 mem_getstats(ctx, si[-1].u.size);
1317 #if ISC_MEM_TRACKLINES
1318 ADD_TRACE(ctx, si, si[-1].u.size, file, line);
1320 if (ctx->hi_water != 0U && !ctx->hi_called &&
1321 ctx->inuse > ctx->hi_water) {
1322 ctx->hi_called = ISC_TRUE;
1323 call_water = ISC_TRUE;
1325 if (ctx->inuse > ctx->maxinuse) {
1326 ctx->maxinuse = ctx->inuse;
1327 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1328 (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
1329 fprintf(stderr, "maxinuse = %lu\n",
1330 (unsigned long)ctx->inuse);
1332 MCTXUNLOCK(ctx, &ctx->lock);
1335 (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
1341 isc__mem_free(isc_mem_t *ctx, void *ptr FLARG) {
1344 isc_boolean_t call_water= ISC_FALSE;
1346 REQUIRE(VALID_CONTEXT(ctx));
1347 REQUIRE(ptr != NULL);
1349 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
1350 si = &(((size_info *)ptr)[-2]);
1351 REQUIRE(si->u.ctx == ctx);
1352 size = si[1].u.size;
1354 si = &(((size_info *)ptr)[-1]);
1358 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1359 MCTXLOCK(ctx, &ctx->lock);
1360 mem_putunlocked(ctx, si, size);
1362 mem_put(ctx, si, size);
1363 MCTXLOCK(ctx, &ctx->lock);
1364 mem_putstats(ctx, si, size);
1367 DELETE_TRACE(ctx, ptr, size, file, line);
1370 * The check against ctx->lo_water == 0 is for the condition
1371 * when the context was pushed over hi_water but then had
1372 * isc_mem_setwater() called with 0 for hi_water and lo_water.
1374 if (ctx->hi_called &&
1375 (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1376 ctx->hi_called = ISC_FALSE;
1378 if (ctx->water != NULL)
1379 call_water = ISC_TRUE;
1381 MCTXUNLOCK(ctx, &ctx->lock);
1384 (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
1389 * Other useful things.
1393 isc__mem_strdup(isc_mem_t *mctx, const char *s FLARG) {
1397 REQUIRE(VALID_CONTEXT(mctx));
1402 ns = isc__mem_allocate(mctx, len + 1 FLARG_PASS);
1405 strncpy(ns, s, len + 1);
1411 isc_mem_setdestroycheck(isc_mem_t *ctx, isc_boolean_t flag) {
1412 REQUIRE(VALID_CONTEXT(ctx));
1413 MCTXLOCK(ctx, &ctx->lock);
1415 ctx->checkfree = flag;
1417 MCTXUNLOCK(ctx, &ctx->lock);
1425 isc_mem_setquota(isc_mem_t *ctx, size_t quota) {
1426 REQUIRE(VALID_CONTEXT(ctx));
1427 MCTXLOCK(ctx, &ctx->lock);
1431 MCTXUNLOCK(ctx, &ctx->lock);
1435 isc_mem_getquota(isc_mem_t *ctx) {
1438 REQUIRE(VALID_CONTEXT(ctx));
1439 MCTXLOCK(ctx, &ctx->lock);
1443 MCTXUNLOCK(ctx, &ctx->lock);
1449 isc_mem_inuse(isc_mem_t *ctx) {
1452 REQUIRE(VALID_CONTEXT(ctx));
1453 MCTXLOCK(ctx, &ctx->lock);
1457 MCTXUNLOCK(ctx, &ctx->lock);
1463 isc_mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg,
1464 size_t hiwater, size_t lowater)
1466 isc_boolean_t callwater = ISC_FALSE;
1467 isc_mem_water_t oldwater;
1470 REQUIRE(VALID_CONTEXT(ctx));
1471 REQUIRE(hiwater >= lowater);
1473 MCTXLOCK(ctx, &ctx->lock);
1474 oldwater = ctx->water;
1475 oldwater_arg = ctx->water_arg;
1476 if (water == NULL) {
1477 callwater = ctx->hi_called;
1479 ctx->water_arg = NULL;
1482 ctx->hi_called = ISC_FALSE;
1484 if (ctx->hi_called &&
1485 (ctx->water != water || ctx->water_arg != water_arg ||
1486 ctx->inuse < lowater || lowater == 0U))
1487 callwater = ISC_TRUE;
1489 ctx->water_arg = water_arg;
1490 ctx->hi_water = hiwater;
1491 ctx->lo_water = lowater;
1492 ctx->hi_called = ISC_FALSE;
1494 MCTXUNLOCK(ctx, &ctx->lock);
1496 if (callwater && oldwater != NULL)
1497 (oldwater)(oldwater_arg, ISC_MEM_LOWATER);
1505 isc_mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp) {
1506 isc_mempool_t *mpctx;
1508 REQUIRE(VALID_CONTEXT(mctx));
1510 REQUIRE(mpctxp != NULL && *mpctxp == NULL);
1513 * Allocate space for this pool, initialize values, and if all works
1514 * well, attach to the memory context.
1516 mpctx = isc_mem_get(mctx, sizeof(isc_mempool_t));
1518 return (ISC_R_NOMEMORY);
1520 mpctx->magic = MEMPOOL_MAGIC;
1524 mpctx->maxalloc = UINT_MAX;
1525 mpctx->allocated = 0;
1526 mpctx->freecount = 0;
1528 mpctx->fillcount = 1;
1530 #if ISC_MEMPOOL_NAMES
1533 mpctx->items = NULL;
1537 MCTXLOCK(mctx, &mctx->lock);
1538 ISC_LIST_INITANDAPPEND(mctx->pools, mpctx, link);
1539 MCTXUNLOCK(mctx, &mctx->lock);
1541 return (ISC_R_SUCCESS);
1545 isc_mempool_setname(isc_mempool_t *mpctx, const char *name) {
1546 REQUIRE(name != NULL);
1548 #if ISC_MEMPOOL_NAMES
1549 if (mpctx->lock != NULL)
1552 strncpy(mpctx->name, name, sizeof(mpctx->name) - 1);
1553 mpctx->name[sizeof(mpctx->name) - 1] = '\0';
1555 if (mpctx->lock != NULL)
1556 UNLOCK(mpctx->lock);
1564 isc_mempool_destroy(isc_mempool_t **mpctxp) {
1565 isc_mempool_t *mpctx;
1570 REQUIRE(mpctxp != NULL);
1572 REQUIRE(VALID_MEMPOOL(mpctx));
1573 #if ISC_MEMPOOL_NAMES
1574 if (mpctx->allocated > 0)
1575 UNEXPECTED_ERROR(__FILE__, __LINE__,
1576 "isc_mempool_destroy(): mempool %s "
1580 REQUIRE(mpctx->allocated == 0);
1590 * Return any items on the free list
1592 MCTXLOCK(mctx, &mctx->lock);
1593 while (mpctx->items != NULL) {
1594 INSIST(mpctx->freecount > 0);
1596 item = mpctx->items;
1597 mpctx->items = item->next;
1599 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1600 mem_putunlocked(mctx, item, mpctx->size);
1602 mem_put(mctx, item, mpctx->size);
1603 mem_putstats(mctx, item, mpctx->size);
1606 MCTXUNLOCK(mctx, &mctx->lock);
1609 * Remove our linked list entry from the memory context.
1611 MCTXLOCK(mctx, &mctx->lock);
1612 ISC_LIST_UNLINK(mctx->pools, mpctx, link);
1613 MCTXUNLOCK(mctx, &mctx->lock);
1617 isc_mem_put(mpctx->mctx, mpctx, sizeof(isc_mempool_t));
1626 isc_mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock) {
1627 REQUIRE(VALID_MEMPOOL(mpctx));
1628 REQUIRE(mpctx->lock == NULL);
1629 REQUIRE(lock != NULL);
1635 isc__mempool_get(isc_mempool_t *mpctx FLARG) {
1640 REQUIRE(VALID_MEMPOOL(mpctx));
1644 if (mpctx->lock != NULL)
1648 * Don't let the caller go over quota
1650 if (mpctx->allocated >= mpctx->maxalloc) {
1656 * if we have a free list item, return the first here
1658 item = mpctx->items;
1660 mpctx->items = item->next;
1661 INSIST(mpctx->freecount > 0);
1669 * We need to dip into the well. Lock the memory context here and
1670 * fill up our free list.
1672 MCTXLOCK(mctx, &mctx->lock);
1673 for (i = 0; i < mpctx->fillcount; i++) {
1674 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1675 item = mem_getunlocked(mctx, mpctx->size);
1677 item = mem_get(mctx, mpctx->size);
1679 mem_getstats(mctx, mpctx->size);
1683 item->next = mpctx->items;
1684 mpctx->items = item;
1687 MCTXUNLOCK(mctx, &mctx->lock);
1690 * If we didn't get any items, return NULL.
1692 item = mpctx->items;
1696 mpctx->items = item->next;
1702 if (mpctx->lock != NULL)
1703 UNLOCK(mpctx->lock);
1705 #if ISC_MEM_TRACKLINES
1707 MCTXLOCK(mctx, &mctx->lock);
1708 ADD_TRACE(mctx, item, mpctx->size, file, line);
1709 MCTXUNLOCK(mctx, &mctx->lock);
1711 #endif /* ISC_MEM_TRACKLINES */
1717 isc__mempool_put(isc_mempool_t *mpctx, void *mem FLARG) {
1721 REQUIRE(VALID_MEMPOOL(mpctx));
1722 REQUIRE(mem != NULL);
1726 if (mpctx->lock != NULL)
1729 INSIST(mpctx->allocated > 0);
1732 #if ISC_MEM_TRACKLINES
1733 MCTXLOCK(mctx, &mctx->lock);
1734 DELETE_TRACE(mctx, mem, mpctx->size, file, line);
1735 MCTXUNLOCK(mctx, &mctx->lock);
1736 #endif /* ISC_MEM_TRACKLINES */
1739 * If our free list is full, return this to the mctx directly.
1741 if (mpctx->freecount >= mpctx->freemax) {
1742 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1743 MCTXLOCK(mctx, &mctx->lock);
1744 mem_putunlocked(mctx, mem, mpctx->size);
1745 MCTXUNLOCK(mctx, &mctx->lock);
1747 mem_put(mctx, mem, mpctx->size);
1748 MCTXLOCK(mctx, &mctx->lock);
1749 mem_putstats(mctx, mem, mpctx->size);
1750 MCTXUNLOCK(mctx, &mctx->lock);
1752 if (mpctx->lock != NULL)
1753 UNLOCK(mpctx->lock);
1758 * Otherwise, attach it to our free list and bump the counter.
1761 item = (element *)mem;
1762 item->next = mpctx->items;
1763 mpctx->items = item;
1765 if (mpctx->lock != NULL)
1766 UNLOCK(mpctx->lock);
1774 isc_mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit) {
1775 REQUIRE(VALID_MEMPOOL(mpctx));
1777 if (mpctx->lock != NULL)
1780 mpctx->freemax = limit;
1782 if (mpctx->lock != NULL)
1783 UNLOCK(mpctx->lock);
1787 isc_mempool_getfreemax(isc_mempool_t *mpctx) {
1788 unsigned int freemax;
1790 REQUIRE(VALID_MEMPOOL(mpctx));
1792 if (mpctx->lock != NULL)
1795 freemax = mpctx->freemax;
1797 if (mpctx->lock != NULL)
1798 UNLOCK(mpctx->lock);
1804 isc_mempool_getfreecount(isc_mempool_t *mpctx) {
1805 unsigned int freecount;
1807 REQUIRE(VALID_MEMPOOL(mpctx));
1809 if (mpctx->lock != NULL)
1812 freecount = mpctx->freecount;
1814 if (mpctx->lock != NULL)
1815 UNLOCK(mpctx->lock);
1821 isc_mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit) {
1824 REQUIRE(VALID_MEMPOOL(mpctx));
1826 if (mpctx->lock != NULL)
1829 mpctx->maxalloc = limit;
1831 if (mpctx->lock != NULL)
1832 UNLOCK(mpctx->lock);
1836 isc_mempool_getmaxalloc(isc_mempool_t *mpctx) {
1837 unsigned int maxalloc;
1839 REQUIRE(VALID_MEMPOOL(mpctx));
1841 if (mpctx->lock != NULL)
1844 maxalloc = mpctx->maxalloc;
1846 if (mpctx->lock != NULL)
1847 UNLOCK(mpctx->lock);
1853 isc_mempool_getallocated(isc_mempool_t *mpctx) {
1854 unsigned int allocated;
1856 REQUIRE(VALID_MEMPOOL(mpctx));
1858 if (mpctx->lock != NULL)
1861 allocated = mpctx->allocated;
1863 if (mpctx->lock != NULL)
1864 UNLOCK(mpctx->lock);
1870 isc_mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit) {
1872 REQUIRE(VALID_MEMPOOL(mpctx));
1874 if (mpctx->lock != NULL)
1877 mpctx->fillcount = limit;
1879 if (mpctx->lock != NULL)
1880 UNLOCK(mpctx->lock);
1884 isc_mempool_getfillcount(isc_mempool_t *mpctx) {
1885 unsigned int fillcount;
1887 REQUIRE(VALID_MEMPOOL(mpctx));
1889 if (mpctx->lock != NULL)
1892 fillcount = mpctx->fillcount;
1894 if (mpctx->lock != NULL)
1895 UNLOCK(mpctx->lock);
1901 isc_mem_printactive(isc_mem_t *ctx, FILE *file) {
1903 REQUIRE(VALID_CONTEXT(ctx));
1904 REQUIRE(file != NULL);
1906 #if !ISC_MEM_TRACKLINES
1910 print_active(ctx, file);
1915 isc_mem_printallactive(FILE *file) {
1916 #if !ISC_MEM_TRACKLINES
1921 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
1924 for (ctx = ISC_LIST_HEAD(contexts);
1926 ctx = ISC_LIST_NEXT(ctx, link)) {
1927 fprintf(file, "context: %p\n", ctx);
1928 print_active(ctx, file);
1935 isc_mem_checkdestroyed(FILE *file) {
1937 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
1940 if (!ISC_LIST_EMPTY(contexts)) {
1941 #if ISC_MEM_TRACKLINES
1944 for (ctx = ISC_LIST_HEAD(contexts);
1946 ctx = ISC_LIST_NEXT(ctx, link)) {
1947 fprintf(file, "context: %p\n", ctx);
1948 print_active(ctx, file);