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.9 2010-08-11 23:45:49 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, unsigned 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
224 unsigned int mysize = size;
226 if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
227 fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
230 "file %s line %u mctx %p\n"),
231 ptr, size, file, line, mctx);
233 if (mctx->debuglist == NULL)
236 if (mysize > mctx->max_size)
237 mysize = mctx->max_size;
239 dl = ISC_LIST_HEAD(mctx->debuglist[mysize]);
241 if (dl->count == DEBUGLIST_COUNT)
243 for (i = 0; i < DEBUGLIST_COUNT; i++) {
244 if (dl->ptr[i] == NULL) {
254 dl = ISC_LIST_NEXT(dl, link);
257 dl = malloc(sizeof(debuglink_t));
260 ISC_LINK_INIT(dl, link);
261 for (i = 1; i < DEBUGLIST_COUNT; i++) {
274 ISC_LIST_PREPEND(mctx->debuglist[mysize], dl, link);
275 mctx->debuglistcnt++;
279 delete_trace_entry(isc_mem_t *mctx, const void *ptr, unsigned int size,
280 const char *file, unsigned int line)
285 if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
286 fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
289 "file %s line %u mctx %p\n"),
290 ptr, size, file, line, mctx);
292 if (mctx->debuglist == NULL)
295 if (size > mctx->max_size)
296 size = mctx->max_size;
298 dl = ISC_LIST_HEAD(mctx->debuglist[size]);
300 for (i = 0; i < DEBUGLIST_COUNT; i++) {
301 if (dl->ptr[i] == ptr) {
307 INSIST(dl->count > 0);
309 if (dl->count == 0) {
310 ISC_LIST_UNLINK(mctx->debuglist[size],
317 dl = ISC_LIST_NEXT(dl, link);
321 * If we get here, we didn't find the item on the list. We're
326 #endif /* ISC_MEM_TRACKLINES */
329 rmsize(size_t size) {
331 * round down to ALIGNMENT_SIZE
333 return (size & (~(ALIGNMENT_SIZE - 1)));
337 quantize(size_t size) {
339 * Round up the result in order to get a size big
340 * enough to satisfy the request and be aligned on ALIGNMENT_SIZE
345 return (ALIGNMENT_SIZE);
346 return ((size + ALIGNMENT_SIZE - 1) & (~(ALIGNMENT_SIZE - 1)));
349 static inline isc_boolean_t
350 more_basic_blocks(isc_mem_t *ctx) {
352 unsigned char *curr, *next;
353 unsigned char *first, *last;
354 unsigned char **table;
355 unsigned int table_size;
359 /* Require: we hold the context lock. */
362 * Did we hit the quota for this context?
364 increment = NUM_BASIC_BLOCKS * ctx->mem_target;
365 if (ctx->quota != 0U && ctx->total + increment > ctx->quota)
368 INSIST(ctx->basic_table_count <= ctx->basic_table_size);
369 if (ctx->basic_table_count == ctx->basic_table_size) {
370 table_size = ctx->basic_table_size + TABLE_INCREMENT;
371 table = (ctx->memalloc)(ctx->arg,
372 table_size * sizeof(unsigned char *));
374 ctx->memalloc_failures++;
377 if (ctx->basic_table_size != 0) {
378 memcpy(table, ctx->basic_table,
379 ctx->basic_table_size *
380 sizeof(unsigned char *));
381 (ctx->memfree)(ctx->arg, ctx->basic_table);
383 ctx->basic_table = table;
384 ctx->basic_table_size = table_size;
387 new = (ctx->memalloc)(ctx->arg, NUM_BASIC_BLOCKS * ctx->mem_target);
389 ctx->memalloc_failures++;
392 ctx->total += increment;
393 ctx->basic_table[ctx->basic_table_count] = new;
394 ctx->basic_table_count++;
397 next = curr + ctx->mem_target;
398 for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) {
399 ((element *)curr)->next = (element *)next;
401 next += ctx->mem_target;
404 * curr is now pointing at the last block in the
407 ((element *)curr)->next = NULL;
409 last = first + NUM_BASIC_BLOCKS * ctx->mem_target - 1;
410 if (first < ctx->lowest || ctx->lowest == NULL)
412 if (last > ctx->highest)
414 ctx->basic_blocks = new;
419 static inline isc_boolean_t
420 more_frags(isc_mem_t *ctx, size_t new_size) {
424 unsigned char *curr, *next;
427 * Try to get more fragments by chopping up a basic block.
430 if (ctx->basic_blocks == NULL) {
431 if (!more_basic_blocks(ctx)) {
433 * We can't get more memory from the OS, or we've
434 * hit the quota for this context.
437 * XXXRTH "At quota" notification here.
443 total_size = ctx->mem_target;
444 new = ctx->basic_blocks;
445 ctx->basic_blocks = ctx->basic_blocks->next;
446 frags = total_size / new_size;
447 ctx->stats[new_size].blocks++;
448 ctx->stats[new_size].freefrags += frags;
450 * Set up a linked-list of blocks of size
454 next = curr + new_size;
455 total_size -= new_size;
456 for (i = 0; i < (frags - 1); i++) {
457 ((element *)curr)->next = (element *)next;
460 total_size -= new_size;
463 * Add the remaining fragment of the basic block to a free list.
465 total_size = rmsize(total_size);
466 if (total_size > 0U) {
467 ((element *)next)->next = ctx->freelists[total_size];
468 ctx->freelists[total_size] = (element *)next;
469 ctx->stats[total_size].freefrags++;
472 * curr is now pointing at the last block in the
475 ((element *)curr)->next = NULL;
476 ctx->freelists[new_size] = new;
482 mem_getunlocked(isc_mem_t *ctx, size_t size) {
483 size_t new_size = quantize(size);
486 if (size >= ctx->max_size || new_size >= ctx->max_size) {
488 * memget() was called on something beyond our upper limit.
490 if (ctx->quota != 0U && ctx->total + size > ctx->quota) {
494 ret = (ctx->memalloc)(ctx->arg, size);
496 ctx->memalloc_failures++;
501 ctx->stats[ctx->max_size].gets++;
502 ctx->stats[ctx->max_size].totalgets++;
504 * If we don't set new_size to size, then the
505 * ISC_MEM_FILL code might write over bytes we
513 * If there are no blocks in the free list for this size, get a chunk
514 * of memory and then break it up into "new_size"-sized blocks, adding
515 * them to the free list.
517 if (ctx->freelists[new_size] == NULL && !more_frags(ctx, new_size))
521 * The free list uses the "rounded-up" size "new_size".
523 ret = ctx->freelists[new_size];
524 ctx->freelists[new_size] = ctx->freelists[new_size]->next;
527 * The stats[] uses the _actual_ "size" requested by the
528 * caller, with the caveat (in the code above) that "size" >= the
529 * max. size (max_size) ends up getting recorded as a call to
532 ctx->stats[size].gets++;
533 ctx->stats[size].totalgets++;
534 ctx->stats[new_size].freefrags--;
535 ctx->inuse += new_size;
541 memset(ret, 0xbe, new_size); /* Mnemonic for "beef". */
547 #if ISC_MEM_FILL && ISC_MEM_CHECKOVERRUN
549 check_overrun(void *mem, size_t size, size_t new_size) {
552 cp = (unsigned char *)mem;
554 while (size < new_size) {
563 mem_putunlocked(isc_mem_t *ctx, void *mem, size_t size) {
564 size_t new_size = quantize(size);
566 if (size == ctx->max_size || new_size >= ctx->max_size) {
568 * memput() called on something beyond our upper limit.
571 memset(mem, 0xde, size); /* Mnemonic for "dead". */
573 (ctx->memfree)(ctx->arg, mem);
574 INSIST(ctx->stats[ctx->max_size].gets != 0U);
575 ctx->stats[ctx->max_size].gets--;
576 INSIST(size <= ctx->total);
583 #if ISC_MEM_CHECKOVERRUN
584 check_overrun(mem, size, new_size);
586 memset(mem, 0xde, new_size); /* Mnemonic for "dead". */
590 * The free list uses the "rounded-up" size "new_size".
592 ((element *)mem)->next = ctx->freelists[new_size];
593 ctx->freelists[new_size] = (element *)mem;
596 * The stats[] uses the _actual_ "size" requested by the
597 * caller, with the caveat (in the code above) that "size" >= the
598 * max. size (max_size) ends up getting recorded as a call to
601 INSIST(ctx->stats[size].gets != 0U);
602 ctx->stats[size].gets--;
603 ctx->stats[new_size].freefrags++;
604 ctx->inuse -= new_size;
608 * Perform a malloc, doing memory filling and overrun detection as necessary.
611 mem_get(isc_mem_t *ctx, size_t size) {
614 #if ISC_MEM_CHECKOVERRUN
618 ret = (ctx->memalloc)(ctx->arg, size);
620 ctx->memalloc_failures++;
624 memset(ret, 0xbe, size); /* Mnemonic for "beef". */
626 # if ISC_MEM_CHECKOVERRUN
636 * Perform a free, doing memory filling and overrun detection as necessary.
639 mem_put(isc_mem_t *ctx, void *mem, size_t size) {
640 #if ISC_MEM_CHECKOVERRUN
641 INSIST(((unsigned char *)mem)[size] == 0xbe);
644 memset(mem, 0xde, size); /* Mnemonic for "dead". */
648 (ctx->memfree)(ctx->arg, mem);
652 * Update internal counters after a memory get.
655 mem_getstats(isc_mem_t *ctx, size_t size) {
659 if (size > ctx->max_size) {
660 ctx->stats[ctx->max_size].gets++;
661 ctx->stats[ctx->max_size].totalgets++;
663 ctx->stats[size].gets++;
664 ctx->stats[size].totalgets++;
669 * Update internal counters after a memory put.
672 mem_putstats(isc_mem_t *ctx, void *ptr, size_t size) {
675 INSIST(ctx->inuse >= size);
678 if (size > ctx->max_size) {
679 INSIST(ctx->stats[ctx->max_size].gets > 0U);
680 ctx->stats[ctx->max_size].gets--;
682 INSIST(ctx->stats[size].gets > 0U);
683 ctx->stats[size].gets--;
692 default_memalloc(void *arg, size_t size) {
696 return (malloc(size));
700 default_memfree(void *arg, void *ptr) {
706 initialize_action(void) {
707 RUNTIME_CHECK(isc_mutex_init(&lock) == ISC_R_SUCCESS);
708 ISC_LIST_INIT(contexts);
717 isc_mem_createx(size_t init_max_size, size_t target_size,
718 isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
721 return (isc_mem_createx2(init_max_size, target_size, memalloc, memfree,
722 arg, ctxp, ISC_MEMFLAG_DEFAULT));
727 isc_mem_createx2(size_t init_max_size, size_t target_size,
728 isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
729 isc_mem_t **ctxp, unsigned int flags)
734 REQUIRE(ctxp != NULL && *ctxp == NULL);
735 REQUIRE(memalloc != NULL);
736 REQUIRE(memfree != NULL);
738 INSIST((ALIGNMENT_SIZE & (ALIGNMENT_SIZE - 1)) == 0);
740 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
742 ctx = (memalloc)(arg, sizeof(*ctx));
744 return (ISC_R_NOMEMORY);
746 if ((flags & ISC_MEMFLAG_NOLOCK) == 0) {
747 result = isc_mutex_init(&ctx->lock);
748 if (result != ISC_R_SUCCESS) {
754 if (init_max_size == 0U)
755 ctx->max_size = DEF_MAX_SIZE;
757 ctx->max_size = init_max_size;
760 memset(ctx->name, 0, sizeof(ctx->name));
768 ctx->hi_called = ISC_FALSE;
769 ctx->is_overmem = ISC_FALSE;
771 ctx->water_arg = NULL;
772 ctx->magic = MEM_MAGIC;
773 isc_ondestroy_init(&ctx->ondestroy);
774 ctx->memalloc = memalloc;
775 ctx->memfree = memfree;
778 ctx->checkfree = ISC_TRUE;
779 #if ISC_MEM_TRACKLINES
780 ctx->debuglist = NULL;
781 ctx->debuglistcnt = 0;
783 ISC_LIST_INIT(ctx->pools);
785 ctx->freelists = NULL;
786 ctx->basic_blocks = NULL;
787 ctx->basic_table = NULL;
788 ctx->basic_table_count = 0;
789 ctx->basic_table_size = 0;
793 ctx->stats = (memalloc)(arg,
794 (ctx->max_size+1) * sizeof(struct stats));
795 if (ctx->stats == NULL) {
796 result = ISC_R_NOMEMORY;
799 memset(ctx->stats, 0, (ctx->max_size + 1) * sizeof(struct stats));
801 if ((flags & ISC_MEMFLAG_INTERNAL) != 0) {
802 if (target_size == 0U)
803 ctx->mem_target = DEF_MEM_TARGET;
805 ctx->mem_target = target_size;
806 ctx->freelists = (memalloc)(arg, ctx->max_size *
808 if (ctx->freelists == NULL) {
809 result = ISC_R_NOMEMORY;
812 memset(ctx->freelists, 0,
813 ctx->max_size * sizeof(element *));
816 #if ISC_MEM_TRACKLINES
817 if ((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0) {
820 ctx->debuglist = (memalloc)(arg,
821 (ctx->max_size+1) * sizeof(debuglist_t));
822 if (ctx->debuglist == NULL) {
823 result = ISC_R_NOMEMORY;
826 for (i = 0; i <= ctx->max_size; i++)
827 ISC_LIST_INIT(ctx->debuglist[i]);
831 ctx->memalloc_failures = 0;
834 ISC_LIST_INITANDAPPEND(contexts, ctx, link);
838 return (ISC_R_SUCCESS);
842 if (ctx->stats != NULL)
843 (memfree)(arg, ctx->stats);
844 if (ctx->freelists != NULL)
845 (memfree)(arg, ctx->freelists);
846 #if ISC_MEM_TRACKLINES
847 if (ctx->debuglist != NULL)
848 (ctx->memfree)(ctx->arg, ctx->debuglist);
849 #endif /* ISC_MEM_TRACKLINES */
850 if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
851 DESTROYLOCK(&ctx->lock);
859 isc_mem_create(size_t init_max_size, size_t target_size,
862 return (isc_mem_createx2(init_max_size, target_size,
863 default_memalloc, default_memfree, NULL,
864 ctxp, ISC_MEMFLAG_DEFAULT));
868 isc_mem_create2(size_t init_max_size, size_t target_size,
869 isc_mem_t **ctxp, unsigned int flags)
871 return (isc_mem_createx2(init_max_size, target_size,
872 default_memalloc, default_memfree, NULL,
877 destroy(isc_mem_t *ctx) {
879 isc_ondestroy_t ondest;
882 ISC_LIST_UNLINK(contexts, ctx, link);
883 totallost += ctx->inuse;
888 INSIST(ISC_LIST_EMPTY(ctx->pools));
890 #if ISC_MEM_TRACKLINES
891 if (ctx->debuglist != NULL) {
892 if (ctx->checkfree) {
893 for (i = 0; i <= ctx->max_size; i++) {
894 if (!ISC_LIST_EMPTY(ctx->debuglist[i]))
895 print_active(ctx, stderr);
896 INSIST(ISC_LIST_EMPTY(ctx->debuglist[i]));
901 for (i = 0; i <= ctx->max_size; i++)
902 for (dl = ISC_LIST_HEAD(ctx->debuglist[i]);
904 dl = ISC_LIST_HEAD(ctx->debuglist[i])) {
905 ISC_LIST_UNLINK(ctx->debuglist[i],
910 (ctx->memfree)(ctx->arg, ctx->debuglist);
913 INSIST(ctx->references == 0);
915 if (ctx->checkfree) {
916 for (i = 0; i <= ctx->max_size; i++) {
917 #if ISC_MEM_TRACKLINES
918 if (ctx->stats[i].gets != 0U)
919 print_active(ctx, stderr);
921 INSIST(ctx->stats[i].gets == 0U);
925 (ctx->memfree)(ctx->arg, ctx->stats);
927 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
928 for (i = 0; i < ctx->basic_table_count; i++)
929 (ctx->memfree)(ctx->arg, ctx->basic_table[i]);
930 (ctx->memfree)(ctx->arg, ctx->freelists);
931 if (ctx->basic_table != NULL)
932 (ctx->memfree)(ctx->arg, ctx->basic_table);
935 ondest = ctx->ondestroy;
937 if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
938 DESTROYLOCK(&ctx->lock);
939 (ctx->memfree)(ctx->arg, ctx);
941 isc_ondestroy_notify(&ondest, ctx);
945 isc_mem_attach(isc_mem_t *source, isc_mem_t **targetp) {
946 REQUIRE(VALID_CONTEXT(source));
947 REQUIRE(targetp != NULL && *targetp == NULL);
949 MCTXLOCK(source, &source->lock);
950 source->references++;
951 MCTXUNLOCK(source, &source->lock);
957 isc_mem_detach(isc_mem_t **ctxp) {
959 isc_boolean_t want_destroy = ISC_FALSE;
961 REQUIRE(ctxp != NULL);
963 REQUIRE(VALID_CONTEXT(ctx));
965 MCTXLOCK(ctx, &ctx->lock);
966 INSIST(ctx->references > 0);
968 if (ctx->references == 0)
969 want_destroy = ISC_TRUE;
970 MCTXUNLOCK(ctx, &ctx->lock);
979 * isc_mem_putanddetach() is the equivalent of:
982 * isc_mem_attach(ptr->mctx, &mctx);
983 * isc_mem_detach(&ptr->mctx);
984 * isc_mem_put(mctx, ptr, sizeof(*ptr);
985 * isc_mem_detach(&mctx);
989 isc__mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) {
991 isc_boolean_t want_destroy = ISC_FALSE;
995 REQUIRE(ctxp != NULL);
997 REQUIRE(VALID_CONTEXT(ctx));
998 REQUIRE(ptr != NULL);
1001 * Must be before mem_putunlocked() as ctxp is usually within
1006 if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) {
1007 if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) {
1008 si = &(((size_info *)ptr)[-1]);
1009 oldsize = si->u.size - ALIGNMENT_SIZE;
1010 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
1011 oldsize -= ALIGNMENT_SIZE;
1012 INSIST(oldsize == size);
1014 isc__mem_free(ctx, ptr FLARG_PASS);
1016 MCTXLOCK(ctx, &ctx->lock);
1018 if (ctx->references == 0)
1019 want_destroy = ISC_TRUE;
1020 MCTXUNLOCK(ctx, &ctx->lock);
1027 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1028 MCTXLOCK(ctx, &ctx->lock);
1029 mem_putunlocked(ctx, ptr, size);
1031 mem_put(ctx, ptr, size);
1032 MCTXLOCK(ctx, &ctx->lock);
1033 mem_putstats(ctx, ptr, size);
1036 DELETE_TRACE(ctx, ptr, size, file, line);
1037 INSIST(ctx->references > 0);
1039 if (ctx->references == 0)
1040 want_destroy = ISC_TRUE;
1042 MCTXUNLOCK(ctx, &ctx->lock);
1049 isc_mem_destroy(isc_mem_t **ctxp) {
1053 * This routine provides legacy support for callers who use mctxs
1054 * without attaching/detaching.
1057 REQUIRE(ctxp != NULL);
1059 REQUIRE(VALID_CONTEXT(ctx));
1061 MCTXLOCK(ctx, &ctx->lock);
1062 #if ISC_MEM_TRACKLINES
1063 if (ctx->references != 1)
1064 print_active(ctx, stderr);
1066 REQUIRE(ctx->references == 1);
1068 MCTXUNLOCK(ctx, &ctx->lock);
1076 isc_mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event) {
1079 MCTXLOCK(ctx, &ctx->lock);
1080 res = isc_ondestroy_register(&ctx->ondestroy, task, event);
1081 MCTXUNLOCK(ctx, &ctx->lock);
1088 isc__mem_get(isc_mem_t *ctx, size_t size FLARG) {
1090 isc_boolean_t call_water = ISC_FALSE;
1092 REQUIRE(VALID_CONTEXT(ctx));
1094 if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0)
1095 return (isc__mem_allocate(ctx, size FLARG_PASS));
1097 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1098 MCTXLOCK(ctx, &ctx->lock);
1099 ptr = mem_getunlocked(ctx, size);
1101 ptr = mem_get(ctx, size);
1102 MCTXLOCK(ctx, &ctx->lock);
1104 mem_getstats(ctx, size);
1107 ADD_TRACE(ctx, ptr, size, file, line);
1108 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1110 ctx->is_overmem = ISC_TRUE;
1112 if (ctx->hi_water != 0U && !ctx->hi_called &&
1113 ctx->inuse > ctx->hi_water) {
1114 call_water = ISC_TRUE;
1116 if (ctx->inuse > ctx->maxinuse) {
1117 ctx->maxinuse = ctx->inuse;
1118 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1119 (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
1120 fprintf(stderr, "maxinuse = %lu\n",
1121 (unsigned long)ctx->inuse);
1123 MCTXUNLOCK(ctx, &ctx->lock);
1126 (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
1132 isc__mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG)
1134 isc_boolean_t call_water = ISC_FALSE;
1138 REQUIRE(VALID_CONTEXT(ctx));
1139 REQUIRE(ptr != NULL);
1141 if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) {
1142 if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) {
1143 si = &(((size_info *)ptr)[-1]);
1144 oldsize = si->u.size - ALIGNMENT_SIZE;
1145 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
1146 oldsize -= ALIGNMENT_SIZE;
1147 INSIST(oldsize == size);
1149 isc__mem_free(ctx, ptr FLARG_PASS);
1153 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1154 MCTXLOCK(ctx, &ctx->lock);
1155 mem_putunlocked(ctx, ptr, size);
1157 mem_put(ctx, ptr, size);
1158 MCTXLOCK(ctx, &ctx->lock);
1159 mem_putstats(ctx, ptr, size);
1162 DELETE_TRACE(ctx, ptr, size, file, line);
1165 * The check against ctx->lo_water == 0 is for the condition
1166 * when the context was pushed over hi_water but then had
1167 * isc_mem_setwater() called with 0 for hi_water and lo_water.
1169 if (ctx->is_overmem &&
1170 (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1171 ctx->is_overmem = ISC_FALSE;
1173 if (ctx->hi_called &&
1174 (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1175 if (ctx->water != NULL)
1176 call_water = ISC_TRUE;
1178 MCTXUNLOCK(ctx, &ctx->lock);
1181 (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
1185 isc_mem_waterack(isc_mem_t *ctx, int flag) {
1186 REQUIRE(VALID_CONTEXT(ctx));
1188 MCTXLOCK(ctx, &ctx->lock);
1189 if (flag == ISC_MEM_LOWATER)
1190 ctx->hi_called = ISC_FALSE;
1191 else if (flag == ISC_MEM_HIWATER)
1192 ctx->hi_called = ISC_TRUE;
1193 MCTXUNLOCK(ctx, &ctx->lock);
1196 #if ISC_MEM_TRACKLINES
1198 print_active(isc_mem_t *mctx, FILE *out) {
1199 if (mctx->debuglist != NULL) {
1203 isc_boolean_t found;
1205 fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1207 "Dump of all outstanding "
1208 "memory allocations:\n"));
1210 format = isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1211 ISC_MSG_PTRFILELINE,
1212 "\tptr %p size %u file %s line %u\n");
1213 for (i = 0; i <= mctx->max_size; i++) {
1214 dl = ISC_LIST_HEAD(mctx->debuglist[i]);
1219 while (dl != NULL) {
1220 for (j = 0; j < DEBUGLIST_COUNT; j++)
1221 if (dl->ptr[j] != NULL)
1222 fprintf(out, format,
1227 dl = ISC_LIST_NEXT(dl, link);
1231 fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1232 ISC_MSG_NONE, "\tNone.\n"));
1238 * Print the stats[] on the stream "out" with suitable formatting.
1241 isc_mem_stats(isc_mem_t *ctx, FILE *out) {
1243 const struct stats *s;
1244 const isc_mempool_t *pool;
1246 REQUIRE(VALID_CONTEXT(ctx));
1247 MCTXLOCK(ctx, &ctx->lock);
1249 for (i = 0; i <= ctx->max_size; i++) {
1252 if (s->totalgets == 0U && s->gets == 0U)
1254 fprintf(out, "%s%5lu: %11lu gets, %11lu rem",
1255 (i == ctx->max_size) ? ">=" : " ",
1256 (unsigned long) i, s->totalgets, s->gets);
1257 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0 &&
1258 (s->blocks != 0U || s->freefrags != 0U))
1259 fprintf(out, " (%lu bl, %lu ff)",
1260 s->blocks, s->freefrags);
1265 * Note that since a pool can be locked now, these stats might be
1266 * somewhat off if the pool is in active use at the time the stats
1267 * are dumped. The link fields are protected by the isc_mem_t's
1268 * lock, however, so walking this list and extracting integers from
1269 * stats fields is always safe.
1271 pool = ISC_LIST_HEAD(ctx->pools);
1273 fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1275 "[Pool statistics]\n"));
1276 fprintf(out, "%15s %10s %10s %10s %10s %10s %10s %10s %1s\n",
1277 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1278 ISC_MSG_POOLNAME, "name"),
1279 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1280 ISC_MSG_POOLSIZE, "size"),
1281 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1282 ISC_MSG_POOLMAXALLOC, "maxalloc"),
1283 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1284 ISC_MSG_POOLALLOCATED, "allocated"),
1285 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1286 ISC_MSG_POOLFREECOUNT, "freecount"),
1287 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1288 ISC_MSG_POOLFREEMAX, "freemax"),
1289 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1290 ISC_MSG_POOLFILLCOUNT, "fillcount"),
1291 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1292 ISC_MSG_POOLGETS, "gets"),
1295 while (pool != NULL) {
1296 fprintf(out, "%15s %10lu %10u %10u %10u %10u %10u %10u %s\n",
1297 pool->name, (unsigned long) pool->size, pool->maxalloc,
1298 pool->allocated, pool->freecount, pool->freemax,
1299 pool->fillcount, pool->gets,
1300 (pool->lock == NULL ? "N" : "Y"));
1301 pool = ISC_LIST_NEXT(pool, link);
1304 #if ISC_MEM_TRACKLINES
1305 print_active(ctx, out);
1308 MCTXUNLOCK(ctx, &ctx->lock);
1312 * Replacements for malloc() and free() -- they implicitly remember the
1313 * size of the object allocated (with some additional overhead).
1317 isc__mem_allocateunlocked(isc_mem_t *ctx, size_t size) {
1320 size += ALIGNMENT_SIZE;
1321 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
1322 size += ALIGNMENT_SIZE;
1324 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0)
1325 si = mem_getunlocked(ctx, size);
1327 si = mem_get(ctx, size);
1331 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
1340 isc__mem_allocate(isc_mem_t *ctx, size_t size FLARG) {
1342 isc_boolean_t call_water = ISC_FALSE;
1344 REQUIRE(VALID_CONTEXT(ctx));
1346 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1347 MCTXLOCK(ctx, &ctx->lock);
1348 si = isc__mem_allocateunlocked(ctx, size);
1350 si = isc__mem_allocateunlocked(ctx, size);
1351 MCTXLOCK(ctx, &ctx->lock);
1353 mem_getstats(ctx, si[-1].u.size);
1356 #if ISC_MEM_TRACKLINES
1357 ADD_TRACE(ctx, si, si[-1].u.size, file, line);
1359 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1361 ctx->is_overmem = ISC_TRUE;
1364 if (ctx->hi_water != 0U && !ctx->hi_called &&
1365 ctx->inuse > ctx->hi_water) {
1366 ctx->hi_called = ISC_TRUE;
1367 call_water = ISC_TRUE;
1369 if (ctx->inuse > ctx->maxinuse) {
1370 ctx->maxinuse = ctx->inuse;
1371 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1372 (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
1373 fprintf(stderr, "maxinuse = %lu\n",
1374 (unsigned long)ctx->inuse);
1376 MCTXUNLOCK(ctx, &ctx->lock);
1379 (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
1385 isc__mem_reallocate(isc_mem_t *ctx, void *ptr, size_t size FLARG) {
1386 void *new_ptr = NULL;
1387 size_t oldsize, copysize;
1389 REQUIRE(VALID_CONTEXT(ctx));
1392 * This function emulates the realloc(3) standard library function:
1393 * - if size > 0, allocate new memory; and if ptr is non NULL, copy
1394 * as much of the old contents to the new buffer and free the old one.
1395 * Note that when allocation fails the original pointer is intact;
1396 * the caller must free it.
1397 * - if size is 0 and ptr is non NULL, simply free the given ptr.
1398 * - this function returns:
1399 * pointer to the newly allocated memory, or
1400 * NULL if allocation fails or doesn't happen.
1403 new_ptr = isc__mem_allocate(ctx, size FLARG_PASS);
1404 if (new_ptr != NULL && ptr != NULL) {
1405 oldsize = (((size_info *)ptr)[-1]).u.size;
1406 INSIST(oldsize >= ALIGNMENT_SIZE);
1407 oldsize -= ALIGNMENT_SIZE;
1408 copysize = oldsize > size ? size : oldsize;
1409 memcpy(new_ptr, ptr, copysize);
1410 isc__mem_free(ctx, ptr FLARG_PASS);
1412 } else if (ptr != NULL)
1413 isc__mem_free(ctx, ptr FLARG_PASS);
1419 isc__mem_free(isc_mem_t *ctx, void *ptr FLARG) {
1422 isc_boolean_t call_water= ISC_FALSE;
1424 REQUIRE(VALID_CONTEXT(ctx));
1425 REQUIRE(ptr != NULL);
1427 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
1428 si = &(((size_info *)ptr)[-2]);
1429 REQUIRE(si->u.ctx == ctx);
1430 size = si[1].u.size;
1432 si = &(((size_info *)ptr)[-1]);
1436 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1437 MCTXLOCK(ctx, &ctx->lock);
1438 mem_putunlocked(ctx, si, size);
1440 mem_put(ctx, si, size);
1441 MCTXLOCK(ctx, &ctx->lock);
1442 mem_putstats(ctx, si, size);
1445 DELETE_TRACE(ctx, ptr, size, file, line);
1448 * The check against ctx->lo_water == 0 is for the condition
1449 * when the context was pushed over hi_water but then had
1450 * isc_mem_setwater() called with 0 for hi_water and lo_water.
1452 if (ctx->is_overmem &&
1453 (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1454 ctx->is_overmem = ISC_FALSE;
1457 if (ctx->hi_called &&
1458 (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1459 ctx->hi_called = ISC_FALSE;
1461 if (ctx->water != NULL)
1462 call_water = ISC_TRUE;
1464 MCTXUNLOCK(ctx, &ctx->lock);
1467 (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
1472 * Other useful things.
1476 isc__mem_strdup(isc_mem_t *mctx, const char *s FLARG) {
1480 REQUIRE(VALID_CONTEXT(mctx));
1485 ns = isc__mem_allocate(mctx, len + 1 FLARG_PASS);
1488 strncpy(ns, s, len + 1);
1494 isc_mem_setdestroycheck(isc_mem_t *ctx, isc_boolean_t flag) {
1495 REQUIRE(VALID_CONTEXT(ctx));
1496 MCTXLOCK(ctx, &ctx->lock);
1498 ctx->checkfree = flag;
1500 MCTXUNLOCK(ctx, &ctx->lock);
1508 isc_mem_setquota(isc_mem_t *ctx, size_t quota) {
1509 REQUIRE(VALID_CONTEXT(ctx));
1510 MCTXLOCK(ctx, &ctx->lock);
1514 MCTXUNLOCK(ctx, &ctx->lock);
1518 isc_mem_getquota(isc_mem_t *ctx) {
1521 REQUIRE(VALID_CONTEXT(ctx));
1522 MCTXLOCK(ctx, &ctx->lock);
1526 MCTXUNLOCK(ctx, &ctx->lock);
1532 isc_mem_inuse(isc_mem_t *ctx) {
1535 REQUIRE(VALID_CONTEXT(ctx));
1536 MCTXLOCK(ctx, &ctx->lock);
1540 MCTXUNLOCK(ctx, &ctx->lock);
1546 isc_mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg,
1547 size_t hiwater, size_t lowater)
1549 isc_boolean_t callwater = ISC_FALSE;
1550 isc_mem_water_t oldwater;
1553 REQUIRE(VALID_CONTEXT(ctx));
1554 REQUIRE(hiwater >= lowater);
1556 MCTXLOCK(ctx, &ctx->lock);
1557 oldwater = ctx->water;
1558 oldwater_arg = ctx->water_arg;
1559 if (water == NULL) {
1560 callwater = ctx->hi_called;
1562 ctx->water_arg = NULL;
1565 ctx->hi_called = ISC_FALSE;
1567 if (ctx->hi_called &&
1568 (ctx->water != water || ctx->water_arg != water_arg ||
1569 ctx->inuse < lowater || lowater == 0U))
1570 callwater = ISC_TRUE;
1572 ctx->water_arg = water_arg;
1573 ctx->hi_water = hiwater;
1574 ctx->lo_water = lowater;
1575 ctx->hi_called = ISC_FALSE;
1577 MCTXUNLOCK(ctx, &ctx->lock);
1579 if (callwater && oldwater != NULL)
1580 (oldwater)(oldwater_arg, ISC_MEM_LOWATER);
1584 isc_mem_isovermem(isc_mem_t *ctx) {
1585 REQUIRE(VALID_CONTEXT(ctx));
1588 * We don't bother to lock the context because 100% accuracy isn't
1589 * necessary (and even if we locked the context the returned value
1590 * could be different from the actual state when it's used anyway)
1592 return (ctx->is_overmem);
1596 isc_mem_setname(isc_mem_t *ctx, const char *name, void *tag) {
1597 REQUIRE(VALID_CONTEXT(ctx));
1600 memset(ctx->name, 0, sizeof(ctx->name));
1601 strncpy(ctx->name, name, sizeof(ctx->name) - 1);
1607 isc_mem_getname(isc_mem_t *ctx) {
1608 REQUIRE(VALID_CONTEXT(ctx));
1614 isc_mem_gettag(isc_mem_t *ctx) {
1615 REQUIRE(VALID_CONTEXT(ctx));
1625 isc_mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp) {
1626 isc_mempool_t *mpctx;
1628 REQUIRE(VALID_CONTEXT(mctx));
1630 REQUIRE(mpctxp != NULL && *mpctxp == NULL);
1633 * Allocate space for this pool, initialize values, and if all works
1634 * well, attach to the memory context.
1636 mpctx = isc_mem_get(mctx, sizeof(isc_mempool_t));
1638 return (ISC_R_NOMEMORY);
1640 mpctx->magic = MEMPOOL_MAGIC;
1644 mpctx->maxalloc = UINT_MAX;
1645 mpctx->allocated = 0;
1646 mpctx->freecount = 0;
1648 mpctx->fillcount = 1;
1650 #if ISC_MEMPOOL_NAMES
1653 mpctx->items = NULL;
1657 MCTXLOCK(mctx, &mctx->lock);
1658 ISC_LIST_INITANDAPPEND(mctx->pools, mpctx, link);
1660 MCTXUNLOCK(mctx, &mctx->lock);
1662 return (ISC_R_SUCCESS);
1666 isc_mempool_setname(isc_mempool_t *mpctx, const char *name) {
1667 REQUIRE(name != NULL);
1669 #if ISC_MEMPOOL_NAMES
1670 if (mpctx->lock != NULL)
1673 strncpy(mpctx->name, name, sizeof(mpctx->name) - 1);
1674 mpctx->name[sizeof(mpctx->name) - 1] = '\0';
1676 if (mpctx->lock != NULL)
1677 UNLOCK(mpctx->lock);
1685 isc_mempool_destroy(isc_mempool_t **mpctxp) {
1686 isc_mempool_t *mpctx;
1691 REQUIRE(mpctxp != NULL);
1693 REQUIRE(VALID_MEMPOOL(mpctx));
1694 #if ISC_MEMPOOL_NAMES
1695 if (mpctx->allocated > 0)
1696 UNEXPECTED_ERROR(__FILE__, __LINE__,
1697 "isc_mempool_destroy(): mempool %s "
1701 REQUIRE(mpctx->allocated == 0);
1711 * Return any items on the free list
1713 MCTXLOCK(mctx, &mctx->lock);
1714 while (mpctx->items != NULL) {
1715 INSIST(mpctx->freecount > 0);
1717 item = mpctx->items;
1718 mpctx->items = item->next;
1720 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1721 mem_putunlocked(mctx, item, mpctx->size);
1723 mem_put(mctx, item, mpctx->size);
1724 mem_putstats(mctx, item, mpctx->size);
1727 MCTXUNLOCK(mctx, &mctx->lock);
1730 * Remove our linked list entry from the memory context.
1732 MCTXLOCK(mctx, &mctx->lock);
1733 ISC_LIST_UNLINK(mctx->pools, mpctx, link);
1735 MCTXUNLOCK(mctx, &mctx->lock);
1739 isc_mem_put(mpctx->mctx, mpctx, sizeof(isc_mempool_t));
1748 isc_mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock) {
1749 REQUIRE(VALID_MEMPOOL(mpctx));
1750 REQUIRE(mpctx->lock == NULL);
1751 REQUIRE(lock != NULL);
1757 isc__mempool_get(isc_mempool_t *mpctx FLARG) {
1762 REQUIRE(VALID_MEMPOOL(mpctx));
1766 if (mpctx->lock != NULL)
1770 * Don't let the caller go over quota
1772 if (mpctx->allocated >= mpctx->maxalloc) {
1778 * if we have a free list item, return the first here
1780 item = mpctx->items;
1782 mpctx->items = item->next;
1783 INSIST(mpctx->freecount > 0);
1791 * We need to dip into the well. Lock the memory context here and
1792 * fill up our free list.
1794 MCTXLOCK(mctx, &mctx->lock);
1795 for (i = 0; i < mpctx->fillcount; i++) {
1796 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1797 item = mem_getunlocked(mctx, mpctx->size);
1799 item = mem_get(mctx, mpctx->size);
1801 mem_getstats(mctx, mpctx->size);
1805 item->next = mpctx->items;
1806 mpctx->items = item;
1809 MCTXUNLOCK(mctx, &mctx->lock);
1812 * If we didn't get any items, return NULL.
1814 item = mpctx->items;
1818 mpctx->items = item->next;
1824 if (mpctx->lock != NULL)
1825 UNLOCK(mpctx->lock);
1827 #if ISC_MEM_TRACKLINES
1829 MCTXLOCK(mctx, &mctx->lock);
1830 ADD_TRACE(mctx, item, mpctx->size, file, line);
1831 MCTXUNLOCK(mctx, &mctx->lock);
1833 #endif /* ISC_MEM_TRACKLINES */
1839 isc__mempool_put(isc_mempool_t *mpctx, void *mem FLARG) {
1843 REQUIRE(VALID_MEMPOOL(mpctx));
1844 REQUIRE(mem != NULL);
1848 if (mpctx->lock != NULL)
1851 INSIST(mpctx->allocated > 0);
1854 #if ISC_MEM_TRACKLINES
1855 MCTXLOCK(mctx, &mctx->lock);
1856 DELETE_TRACE(mctx, mem, mpctx->size, file, line);
1857 MCTXUNLOCK(mctx, &mctx->lock);
1858 #endif /* ISC_MEM_TRACKLINES */
1861 * If our free list is full, return this to the mctx directly.
1863 if (mpctx->freecount >= mpctx->freemax) {
1864 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1865 MCTXLOCK(mctx, &mctx->lock);
1866 mem_putunlocked(mctx, mem, mpctx->size);
1867 MCTXUNLOCK(mctx, &mctx->lock);
1869 mem_put(mctx, mem, mpctx->size);
1870 MCTXLOCK(mctx, &mctx->lock);
1871 mem_putstats(mctx, mem, mpctx->size);
1872 MCTXUNLOCK(mctx, &mctx->lock);
1874 if (mpctx->lock != NULL)
1875 UNLOCK(mpctx->lock);
1880 * Otherwise, attach it to our free list and bump the counter.
1883 item = (element *)mem;
1884 item->next = mpctx->items;
1885 mpctx->items = item;
1887 if (mpctx->lock != NULL)
1888 UNLOCK(mpctx->lock);
1896 isc_mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit) {
1897 REQUIRE(VALID_MEMPOOL(mpctx));
1899 if (mpctx->lock != NULL)
1902 mpctx->freemax = limit;
1904 if (mpctx->lock != NULL)
1905 UNLOCK(mpctx->lock);
1909 isc_mempool_getfreemax(isc_mempool_t *mpctx) {
1910 unsigned int freemax;
1912 REQUIRE(VALID_MEMPOOL(mpctx));
1914 if (mpctx->lock != NULL)
1917 freemax = mpctx->freemax;
1919 if (mpctx->lock != NULL)
1920 UNLOCK(mpctx->lock);
1926 isc_mempool_getfreecount(isc_mempool_t *mpctx) {
1927 unsigned int freecount;
1929 REQUIRE(VALID_MEMPOOL(mpctx));
1931 if (mpctx->lock != NULL)
1934 freecount = mpctx->freecount;
1936 if (mpctx->lock != NULL)
1937 UNLOCK(mpctx->lock);
1943 isc_mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit) {
1946 REQUIRE(VALID_MEMPOOL(mpctx));
1948 if (mpctx->lock != NULL)
1951 mpctx->maxalloc = limit;
1953 if (mpctx->lock != NULL)
1954 UNLOCK(mpctx->lock);
1958 isc_mempool_getmaxalloc(isc_mempool_t *mpctx) {
1959 unsigned int maxalloc;
1961 REQUIRE(VALID_MEMPOOL(mpctx));
1963 if (mpctx->lock != NULL)
1966 maxalloc = mpctx->maxalloc;
1968 if (mpctx->lock != NULL)
1969 UNLOCK(mpctx->lock);
1975 isc_mempool_getallocated(isc_mempool_t *mpctx) {
1976 unsigned int allocated;
1978 REQUIRE(VALID_MEMPOOL(mpctx));
1980 if (mpctx->lock != NULL)
1983 allocated = mpctx->allocated;
1985 if (mpctx->lock != NULL)
1986 UNLOCK(mpctx->lock);
1992 isc_mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit) {
1994 REQUIRE(VALID_MEMPOOL(mpctx));
1996 if (mpctx->lock != NULL)
1999 mpctx->fillcount = limit;
2001 if (mpctx->lock != NULL)
2002 UNLOCK(mpctx->lock);
2006 isc_mempool_getfillcount(isc_mempool_t *mpctx) {
2007 unsigned int fillcount;
2009 REQUIRE(VALID_MEMPOOL(mpctx));
2011 if (mpctx->lock != NULL)
2014 fillcount = mpctx->fillcount;
2016 if (mpctx->lock != NULL)
2017 UNLOCK(mpctx->lock);
2023 isc_mem_printactive(isc_mem_t *ctx, FILE *file) {
2025 REQUIRE(VALID_CONTEXT(ctx));
2026 REQUIRE(file != NULL);
2028 #if !ISC_MEM_TRACKLINES
2032 print_active(ctx, file);
2037 isc_mem_printallactive(FILE *file) {
2038 #if !ISC_MEM_TRACKLINES
2043 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2046 for (ctx = ISC_LIST_HEAD(contexts);
2048 ctx = ISC_LIST_NEXT(ctx, link)) {
2049 fprintf(file, "context: %p\n", ctx);
2050 print_active(ctx, file);
2057 isc_mem_checkdestroyed(FILE *file) {
2059 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2062 if (!ISC_LIST_EMPTY(contexts)) {
2063 #if ISC_MEM_TRACKLINES
2066 for (ctx = ISC_LIST_HEAD(contexts);
2068 ctx = ISC_LIST_NEXT(ctx, link)) {
2069 fprintf(file, "context: %p\n", ctx);
2070 print_active(ctx, file);
2080 isc_mem_references(isc_mem_t *ctx) {
2081 unsigned int references;
2082 REQUIRE(VALID_CONTEXT(ctx));
2084 MCTXLOCK(ctx, &ctx->lock);
2085 references = ctx->references;
2086 MCTXUNLOCK(ctx, &ctx->lock);
2088 return (references);
2093 typedef struct summarystat {
2096 isc_uint64_t blocksize;
2097 isc_uint64_t contextsize;
2101 renderctx(isc_mem_t *ctx, summarystat_t *summary, xmlTextWriterPtr writer) {
2102 REQUIRE(VALID_CONTEXT(ctx));
2104 xmlTextWriterStartElement(writer, ISC_XMLCHAR "context");
2106 xmlTextWriterStartElement(writer, ISC_XMLCHAR "id");
2107 xmlTextWriterWriteFormatString(writer, "%p", ctx);
2108 xmlTextWriterEndElement(writer); /* id */
2110 if (ctx->name[0] != 0) {
2111 xmlTextWriterStartElement(writer, ISC_XMLCHAR "name");
2112 xmlTextWriterWriteFormatString(writer, "%s", ctx->name);
2113 xmlTextWriterEndElement(writer); /* name */
2116 REQUIRE(VALID_CONTEXT(ctx));
2117 MCTXLOCK(ctx, &ctx->lock);
2119 summary->contextsize += sizeof(*ctx) +
2120 (ctx->max_size + 1) * sizeof(struct stats) +
2121 ctx->max_size * sizeof(element *) +
2122 ctx->basic_table_count * sizeof(char *);
2123 #if ISC_MEM_TRACKLINES
2124 if (ctx->debuglist != NULL) {
2125 summary->contextsize +=
2126 (ctx->max_size + 1) * sizeof(debuglist_t) +
2127 ctx->debuglistcnt * sizeof(debuglink_t);
2130 xmlTextWriterStartElement(writer, ISC_XMLCHAR "references");
2131 xmlTextWriterWriteFormatString(writer, "%d", ctx->references);
2132 xmlTextWriterEndElement(writer); /* references */
2134 summary->total += ctx->total;
2135 xmlTextWriterStartElement(writer, ISC_XMLCHAR "total");
2136 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2137 (isc_uint64_t)ctx->total);
2138 xmlTextWriterEndElement(writer); /* total */
2140 summary->inuse += ctx->inuse;
2141 xmlTextWriterStartElement(writer, ISC_XMLCHAR "inuse");
2142 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2143 (isc_uint64_t)ctx->inuse);
2144 xmlTextWriterEndElement(writer); /* inuse */
2146 xmlTextWriterStartElement(writer, ISC_XMLCHAR "maxinuse");
2147 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2148 (isc_uint64_t)ctx->maxinuse);
2149 xmlTextWriterEndElement(writer); /* maxinuse */
2151 xmlTextWriterStartElement(writer, ISC_XMLCHAR "blocksize");
2152 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
2153 summary->blocksize += ctx->basic_table_count *
2154 NUM_BASIC_BLOCKS * ctx->mem_target;
2155 xmlTextWriterWriteFormatString(writer,
2156 "%" ISC_PRINT_QUADFORMAT "u",
2158 ctx->basic_table_count *
2162 xmlTextWriterWriteFormatString(writer, "%s", "-");
2163 xmlTextWriterEndElement(writer); /* blocksize */
2165 xmlTextWriterStartElement(writer, ISC_XMLCHAR "pools");
2166 xmlTextWriterWriteFormatString(writer, "%u", ctx->poolcnt);
2167 xmlTextWriterEndElement(writer); /* pools */
2168 summary->contextsize += ctx->poolcnt * sizeof(isc_mempool_t);
2170 xmlTextWriterStartElement(writer, ISC_XMLCHAR "hiwater");
2171 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2172 (isc_uint64_t)ctx->hi_water);
2173 xmlTextWriterEndElement(writer); /* hiwater */
2175 xmlTextWriterStartElement(writer, ISC_XMLCHAR "lowater");
2176 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2177 (isc_uint64_t)ctx->lo_water);
2178 xmlTextWriterEndElement(writer); /* lowater */
2180 MCTXUNLOCK(ctx, &ctx->lock);
2182 xmlTextWriterEndElement(writer); /* context */
2186 isc_mem_renderxml(xmlTextWriterPtr writer) {
2188 summarystat_t summary;
2191 memset(&summary, 0, sizeof(summary));
2193 xmlTextWriterStartElement(writer, ISC_XMLCHAR "contexts");
2195 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2199 for (ctx = ISC_LIST_HEAD(contexts);
2201 ctx = ISC_LIST_NEXT(ctx, link)) {
2202 renderctx(ctx, &summary, writer);
2206 xmlTextWriterEndElement(writer); /* contexts */
2208 xmlTextWriterStartElement(writer, ISC_XMLCHAR "summary");
2210 xmlTextWriterStartElement(writer, ISC_XMLCHAR "TotalUse");
2211 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2213 xmlTextWriterEndElement(writer); /* TotalUse */
2215 xmlTextWriterStartElement(writer, ISC_XMLCHAR "InUse");
2216 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2218 xmlTextWriterEndElement(writer); /* InUse */
2220 xmlTextWriterStartElement(writer, ISC_XMLCHAR "BlockSize");
2221 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2223 xmlTextWriterEndElement(writer); /* BlockSize */
2225 xmlTextWriterStartElement(writer, ISC_XMLCHAR "ContextSize");
2226 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2227 summary.contextsize);
2228 xmlTextWriterEndElement(writer); /* ContextSize */
2230 xmlTextWriterStartElement(writer, ISC_XMLCHAR "Lost");
2231 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2233 xmlTextWriterEndElement(writer); /* Lost */
2235 xmlTextWriterEndElement(writer); /* summary */
2238 #endif /* HAVE_LIBXML2 */