4 * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1997-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: mem.c,v 1.145.120.4 2009/02/16 03:17:05 marka Exp */
32 #include <isc/magic.h>
36 #include <isc/ondestroy.h>
37 #include <isc/string.h>
38 #include <isc/mutex.h>
39 #include <isc/print.h>
43 #define MCTXLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) LOCK(l)
44 #define MCTXUNLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) UNLOCK(l)
46 #ifndef ISC_MEM_DEBUGGING
47 #define ISC_MEM_DEBUGGING 0
49 LIBISC_EXTERNAL_DATA
unsigned int isc_mem_debugging
= ISC_MEM_DEBUGGING
;
55 #define DEF_MAX_SIZE 1100
56 #define DEF_MEM_TARGET 4096
57 #define ALIGNMENT_SIZE 8U /*%< must be a power of 2 */
58 #define NUM_BASIC_BLOCKS 64 /*%< must be > 1 */
59 #define TABLE_INCREMENT 1024
60 #define DEBUGLIST_COUNT 1024
65 #if ISC_MEM_TRACKLINES
66 typedef struct debuglink debuglink_t
;
68 ISC_LINK(debuglink_t
) link
;
69 const void *ptr
[DEBUGLIST_COUNT
];
70 unsigned int size
[DEBUGLIST_COUNT
];
71 const char *file
[DEBUGLIST_COUNT
];
72 unsigned int line
[DEBUGLIST_COUNT
];
76 #define FLARG_PASS , file, line
77 #define FLARG , const char *file, int line
83 typedef struct element element
;
90 * This structure must be ALIGNMENT_SIZE bytes.
95 char bytes
[ALIGNMENT_SIZE
];
101 unsigned long totalgets
;
102 unsigned long blocks
;
103 unsigned long freefrags
;
106 #define MEM_MAGIC ISC_MAGIC('M', 'e', 'm', 'C')
107 #define VALID_CONTEXT(c) ISC_MAGIC_VALID(c, MEM_MAGIC)
109 #if ISC_MEM_TRACKLINES
110 typedef ISC_LIST(debuglink_t
) debuglist_t
;
113 /* List of all active memory contexts. */
115 static ISC_LIST(isc_mem_t
) contexts
;
116 static isc_once_t once
= ISC_ONCE_INIT
;
117 static isc_mutex_t lock
;
120 * Total size of lost memory due to a bug of external library.
121 * Locked by the global lock.
123 static isc_uint64_t totallost
;
127 isc_ondestroy_t ondestroy
;
130 isc_memalloc_t memalloc
;
131 isc_memfree_t memfree
;
134 isc_boolean_t checkfree
;
135 struct stats
* stats
;
136 unsigned int references
;
145 isc_boolean_t hi_called
;
146 isc_mem_water_t water
;
148 ISC_LIST(isc_mempool_t
) pools
;
149 unsigned int poolcnt
;
151 /* ISC_MEMFLAG_INTERNAL */
153 element
** freelists
;
154 element
* basic_blocks
;
155 unsigned char ** basic_table
;
156 unsigned int basic_table_count
;
157 unsigned int basic_table_size
;
158 unsigned char * lowest
;
159 unsigned char * highest
;
161 #if ISC_MEM_TRACKLINES
162 debuglist_t
* debuglist
;
163 unsigned int debuglistcnt
;
166 unsigned int memalloc_failures
;
167 ISC_LINK(isc_mem_t
) link
;
170 #define MEMPOOL_MAGIC ISC_MAGIC('M', 'E', 'M', 'p')
171 #define VALID_MEMPOOL(c) ISC_MAGIC_VALID(c, MEMPOOL_MAGIC)
174 /* always unlocked */
175 unsigned int magic
; /*%< magic number */
176 isc_mutex_t
*lock
; /*%< optional lock */
177 isc_mem_t
*mctx
; /*%< our memory context */
178 /*%< locked via the memory context's lock */
179 ISC_LINK(isc_mempool_t
) link
; /*%< next pool in this mem context */
180 /*%< optionally locked from here down */
181 element
*items
; /*%< low water item list */
182 size_t size
; /*%< size of each item on this pool */
183 unsigned int maxalloc
; /*%< max number of items allowed */
184 unsigned int allocated
; /*%< # of items currently given out */
185 unsigned int freecount
; /*%< # of items on reserved list */
186 unsigned int freemax
; /*%< # of items allowed on free list */
187 unsigned int fillcount
; /*%< # of items to fetch on each fill */
189 unsigned int gets
; /*%< # of requests to this pool */
190 /*%< Debugging only. */
191 #if ISC_MEMPOOL_NAMES
192 char name
[16]; /*%< printed name in stats reports */
197 * Private Inline-able.
200 #if ! ISC_MEM_TRACKLINES
201 #define ADD_TRACE(a, b, c, d, e)
202 #define DELETE_TRACE(a, b, c, d, e)
204 #define ADD_TRACE(a, b, c, d, e) \
206 if ((isc_mem_debugging & (ISC_MEM_DEBUGTRACE | \
207 ISC_MEM_DEBUGRECORD)) != 0 && \
209 add_trace_entry(a, b, c, d, e); \
211 #define DELETE_TRACE(a, b, c, d, e) delete_trace_entry(a, b, c, d, e)
214 print_active(isc_mem_t
*ctx
, FILE *out
);
217 * mctx must be locked.
220 add_trace_entry(isc_mem_t
*mctx
, const void *ptr
, unsigned int 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 (size
> mctx
->max_size
)
237 size
= mctx
->max_size
;
239 dl
= ISC_LIST_HEAD(mctx
->debuglist
[size
]);
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
[size
], 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
;
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
->hi_called
&&
1108 ctx
->inuse
> ctx
->hi_water
) {
1109 call_water
= ISC_TRUE
;
1111 if (ctx
->inuse
> ctx
->maxinuse
) {
1112 ctx
->maxinuse
= ctx
->inuse
;
1113 if (ctx
->hi_water
!= 0U && ctx
->inuse
> ctx
->hi_water
&&
1114 (isc_mem_debugging
& ISC_MEM_DEBUGUSAGE
) != 0)
1115 fprintf(stderr
, "maxinuse = %lu\n",
1116 (unsigned long)ctx
->inuse
);
1118 MCTXUNLOCK(ctx
, &ctx
->lock
);
1121 (ctx
->water
)(ctx
->water_arg
, ISC_MEM_HIWATER
);
1127 isc__mem_put(isc_mem_t
*ctx
, void *ptr
, size_t size FLARG
)
1129 isc_boolean_t call_water
= ISC_FALSE
;
1133 REQUIRE(VALID_CONTEXT(ctx
));
1134 REQUIRE(ptr
!= NULL
);
1136 if ((isc_mem_debugging
& (ISC_MEM_DEBUGSIZE
|ISC_MEM_DEBUGCTX
)) != 0) {
1137 if ((isc_mem_debugging
& ISC_MEM_DEBUGSIZE
) != 0) {
1138 si
= &(((size_info
*)ptr
)[-1]);
1139 oldsize
= si
->u
.size
- ALIGNMENT_SIZE
;
1140 if ((isc_mem_debugging
& ISC_MEM_DEBUGCTX
) != 0)
1141 oldsize
-= ALIGNMENT_SIZE
;
1142 INSIST(oldsize
== size
);
1144 isc__mem_free(ctx
, ptr FLARG_PASS
);
1148 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
1149 MCTXLOCK(ctx
, &ctx
->lock
);
1150 mem_putunlocked(ctx
, ptr
, size
);
1152 mem_put(ctx
, ptr
, size
);
1153 MCTXLOCK(ctx
, &ctx
->lock
);
1154 mem_putstats(ctx
, ptr
, size
);
1157 DELETE_TRACE(ctx
, ptr
, size
, file
, line
);
1160 * The check against ctx->lo_water == 0 is for the condition
1161 * when the context was pushed over hi_water but then had
1162 * isc_mem_setwater() called with 0 for hi_water and lo_water.
1164 if (ctx
->hi_called
&&
1165 (ctx
->inuse
< ctx
->lo_water
|| ctx
->lo_water
== 0U)) {
1166 if (ctx
->water
!= NULL
)
1167 call_water
= ISC_TRUE
;
1169 MCTXUNLOCK(ctx
, &ctx
->lock
);
1172 (ctx
->water
)(ctx
->water_arg
, ISC_MEM_LOWATER
);
1176 isc_mem_waterack(isc_mem_t
*ctx
, int flag
) {
1177 REQUIRE(VALID_CONTEXT(ctx
));
1179 MCTXLOCK(ctx
, &ctx
->lock
);
1180 if (flag
== ISC_MEM_LOWATER
)
1181 ctx
->hi_called
= ISC_FALSE
;
1182 else if (flag
== ISC_MEM_HIWATER
)
1183 ctx
->hi_called
= ISC_TRUE
;
1184 MCTXUNLOCK(ctx
, &ctx
->lock
);
1187 #if ISC_MEM_TRACKLINES
1189 print_active(isc_mem_t
*mctx
, FILE *out
) {
1190 if (mctx
->debuglist
!= NULL
) {
1194 isc_boolean_t found
;
1196 fprintf(out
, "%s", isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1198 "Dump of all outstanding "
1199 "memory allocations:\n"));
1201 format
= isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1202 ISC_MSG_PTRFILELINE
,
1203 "\tptr %p size %u file %s line %u\n");
1204 for (i
= 0; i
<= mctx
->max_size
; i
++) {
1205 dl
= ISC_LIST_HEAD(mctx
->debuglist
[i
]);
1210 while (dl
!= NULL
) {
1211 for (j
= 0; j
< DEBUGLIST_COUNT
; j
++)
1212 if (dl
->ptr
[j
] != NULL
)
1213 fprintf(out
, format
,
1218 dl
= ISC_LIST_NEXT(dl
, link
);
1222 fprintf(out
, "%s", isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1223 ISC_MSG_NONE
, "\tNone.\n"));
1229 * Print the stats[] on the stream "out" with suitable formatting.
1232 isc_mem_stats(isc_mem_t
*ctx
, FILE *out
) {
1234 const struct stats
*s
;
1235 const isc_mempool_t
*pool
;
1237 REQUIRE(VALID_CONTEXT(ctx
));
1238 MCTXLOCK(ctx
, &ctx
->lock
);
1240 for (i
= 0; i
<= ctx
->max_size
; i
++) {
1243 if (s
->totalgets
== 0U && s
->gets
== 0U)
1245 fprintf(out
, "%s%5lu: %11lu gets, %11lu rem",
1246 (i
== ctx
->max_size
) ? ">=" : " ",
1247 (unsigned long) i
, s
->totalgets
, s
->gets
);
1248 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0 &&
1249 (s
->blocks
!= 0U || s
->freefrags
!= 0U))
1250 fprintf(out
, " (%lu bl, %lu ff)",
1251 s
->blocks
, s
->freefrags
);
1256 * Note that since a pool can be locked now, these stats might be
1257 * somewhat off if the pool is in active use at the time the stats
1258 * are dumped. The link fields are protected by the isc_mem_t's
1259 * lock, however, so walking this list and extracting integers from
1260 * stats fields is always safe.
1262 pool
= ISC_LIST_HEAD(ctx
->pools
);
1264 fprintf(out
, "%s", isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1266 "[Pool statistics]\n"));
1267 fprintf(out
, "%15s %10s %10s %10s %10s %10s %10s %10s %1s\n",
1268 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1269 ISC_MSG_POOLNAME
, "name"),
1270 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1271 ISC_MSG_POOLSIZE
, "size"),
1272 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1273 ISC_MSG_POOLMAXALLOC
, "maxalloc"),
1274 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1275 ISC_MSG_POOLALLOCATED
, "allocated"),
1276 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1277 ISC_MSG_POOLFREECOUNT
, "freecount"),
1278 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1279 ISC_MSG_POOLFREEMAX
, "freemax"),
1280 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1281 ISC_MSG_POOLFILLCOUNT
, "fillcount"),
1282 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1283 ISC_MSG_POOLGETS
, "gets"),
1286 while (pool
!= NULL
) {
1287 fprintf(out
, "%15s %10lu %10u %10u %10u %10u %10u %10u %s\n",
1288 pool
->name
, (unsigned long) pool
->size
, pool
->maxalloc
,
1289 pool
->allocated
, pool
->freecount
, pool
->freemax
,
1290 pool
->fillcount
, pool
->gets
,
1291 (pool
->lock
== NULL
? "N" : "Y"));
1292 pool
= ISC_LIST_NEXT(pool
, link
);
1295 #if ISC_MEM_TRACKLINES
1296 print_active(ctx
, out
);
1299 MCTXUNLOCK(ctx
, &ctx
->lock
);
1303 * Replacements for malloc() and free() -- they implicitly remember the
1304 * size of the object allocated (with some additional overhead).
1308 isc__mem_allocateunlocked(isc_mem_t
*ctx
, size_t size
) {
1311 size
+= ALIGNMENT_SIZE
;
1312 if ((isc_mem_debugging
& ISC_MEM_DEBUGCTX
) != 0)
1313 size
+= ALIGNMENT_SIZE
;
1315 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0)
1316 si
= mem_getunlocked(ctx
, size
);
1318 si
= mem_get(ctx
, size
);
1322 if ((isc_mem_debugging
& ISC_MEM_DEBUGCTX
) != 0) {
1331 isc__mem_allocate(isc_mem_t
*ctx
, size_t size FLARG
) {
1333 isc_boolean_t call_water
= ISC_FALSE
;
1335 REQUIRE(VALID_CONTEXT(ctx
));
1337 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
1338 MCTXLOCK(ctx
, &ctx
->lock
);
1339 si
= isc__mem_allocateunlocked(ctx
, size
);
1341 si
= isc__mem_allocateunlocked(ctx
, size
);
1342 MCTXLOCK(ctx
, &ctx
->lock
);
1344 mem_getstats(ctx
, si
[-1].u
.size
);
1347 #if ISC_MEM_TRACKLINES
1348 ADD_TRACE(ctx
, si
, si
[-1].u
.size
, file
, line
);
1350 if (ctx
->hi_water
!= 0U && !ctx
->hi_called
&&
1351 ctx
->inuse
> ctx
->hi_water
) {
1352 ctx
->hi_called
= ISC_TRUE
;
1353 call_water
= ISC_TRUE
;
1355 if (ctx
->inuse
> ctx
->maxinuse
) {
1356 ctx
->maxinuse
= ctx
->inuse
;
1357 if (ctx
->hi_water
!= 0U && ctx
->inuse
> ctx
->hi_water
&&
1358 (isc_mem_debugging
& ISC_MEM_DEBUGUSAGE
) != 0)
1359 fprintf(stderr
, "maxinuse = %lu\n",
1360 (unsigned long)ctx
->inuse
);
1362 MCTXUNLOCK(ctx
, &ctx
->lock
);
1365 (ctx
->water
)(ctx
->water_arg
, ISC_MEM_HIWATER
);
1371 isc__mem_reallocate(isc_mem_t
*ctx
, void *ptr
, size_t size FLARG
) {
1372 void *new_ptr
= NULL
;
1373 size_t oldsize
, copysize
;
1375 REQUIRE(VALID_CONTEXT(ctx
));
1378 * This function emulates the realloc(3) standard library function:
1379 * - if size > 0, allocate new memory; and if ptr is non NULL, copy
1380 * as much of the old contents to the new buffer and free the old one.
1381 * Note that when allocation fails the original pointer is intact;
1382 * the caller must free it.
1383 * - if size is 0 and ptr is non NULL, simply free the given ptr.
1384 * - this function returns:
1385 * pointer to the newly allocated memory, or
1386 * NULL if allocation fails or doesn't happen.
1389 new_ptr
= isc__mem_allocate(ctx
, size FLARG_PASS
);
1390 if (new_ptr
!= NULL
&& ptr
!= NULL
) {
1391 oldsize
= (((size_info
*)ptr
)[-1]).u
.size
;
1392 INSIST(oldsize
>= ALIGNMENT_SIZE
);
1393 oldsize
-= ALIGNMENT_SIZE
;
1394 copysize
= oldsize
> size
? size
: oldsize
;
1395 memcpy(new_ptr
, ptr
, copysize
);
1396 isc__mem_free(ctx
, ptr FLARG_PASS
);
1398 } else if (ptr
!= NULL
)
1399 isc__mem_free(ctx
, ptr FLARG_PASS
);
1405 isc__mem_free(isc_mem_t
*ctx
, void *ptr FLARG
) {
1408 isc_boolean_t call_water
= ISC_FALSE
;
1410 REQUIRE(VALID_CONTEXT(ctx
));
1411 REQUIRE(ptr
!= NULL
);
1413 if ((isc_mem_debugging
& ISC_MEM_DEBUGCTX
) != 0) {
1414 si
= &(((size_info
*)ptr
)[-2]);
1415 REQUIRE(si
->u
.ctx
== ctx
);
1416 size
= si
[1].u
.size
;
1418 si
= &(((size_info
*)ptr
)[-1]);
1422 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
1423 MCTXLOCK(ctx
, &ctx
->lock
);
1424 mem_putunlocked(ctx
, si
, size
);
1426 mem_put(ctx
, si
, size
);
1427 MCTXLOCK(ctx
, &ctx
->lock
);
1428 mem_putstats(ctx
, si
, size
);
1431 DELETE_TRACE(ctx
, ptr
, size
, file
, line
);
1434 * The check against ctx->lo_water == 0 is for the condition
1435 * when the context was pushed over hi_water but then had
1436 * isc_mem_setwater() called with 0 for hi_water and lo_water.
1438 if (ctx
->hi_called
&&
1439 (ctx
->inuse
< ctx
->lo_water
|| ctx
->lo_water
== 0U)) {
1440 ctx
->hi_called
= ISC_FALSE
;
1442 if (ctx
->water
!= NULL
)
1443 call_water
= ISC_TRUE
;
1445 MCTXUNLOCK(ctx
, &ctx
->lock
);
1448 (ctx
->water
)(ctx
->water_arg
, ISC_MEM_LOWATER
);
1453 * Other useful things.
1457 isc__mem_strdup(isc_mem_t
*mctx
, const char *s FLARG
) {
1461 REQUIRE(VALID_CONTEXT(mctx
));
1466 ns
= isc__mem_allocate(mctx
, len
+ 1 FLARG_PASS
);
1469 strncpy(ns
, s
, len
+ 1);
1475 isc_mem_setdestroycheck(isc_mem_t
*ctx
, isc_boolean_t flag
) {
1476 REQUIRE(VALID_CONTEXT(ctx
));
1477 MCTXLOCK(ctx
, &ctx
->lock
);
1479 ctx
->checkfree
= flag
;
1481 MCTXUNLOCK(ctx
, &ctx
->lock
);
1489 isc_mem_setquota(isc_mem_t
*ctx
, size_t quota
) {
1490 REQUIRE(VALID_CONTEXT(ctx
));
1491 MCTXLOCK(ctx
, &ctx
->lock
);
1495 MCTXUNLOCK(ctx
, &ctx
->lock
);
1499 isc_mem_getquota(isc_mem_t
*ctx
) {
1502 REQUIRE(VALID_CONTEXT(ctx
));
1503 MCTXLOCK(ctx
, &ctx
->lock
);
1507 MCTXUNLOCK(ctx
, &ctx
->lock
);
1513 isc_mem_inuse(isc_mem_t
*ctx
) {
1516 REQUIRE(VALID_CONTEXT(ctx
));
1517 MCTXLOCK(ctx
, &ctx
->lock
);
1521 MCTXUNLOCK(ctx
, &ctx
->lock
);
1527 isc_mem_setwater(isc_mem_t
*ctx
, isc_mem_water_t water
, void *water_arg
,
1528 size_t hiwater
, size_t lowater
)
1530 isc_boolean_t callwater
= ISC_FALSE
;
1531 isc_mem_water_t oldwater
;
1534 REQUIRE(VALID_CONTEXT(ctx
));
1535 REQUIRE(hiwater
>= lowater
);
1537 MCTXLOCK(ctx
, &ctx
->lock
);
1538 oldwater
= ctx
->water
;
1539 oldwater_arg
= ctx
->water_arg
;
1540 if (water
== NULL
) {
1541 callwater
= ctx
->hi_called
;
1543 ctx
->water_arg
= NULL
;
1546 ctx
->hi_called
= ISC_FALSE
;
1548 if (ctx
->hi_called
&&
1549 (ctx
->water
!= water
|| ctx
->water_arg
!= water_arg
||
1550 ctx
->inuse
< lowater
|| lowater
== 0U))
1551 callwater
= ISC_TRUE
;
1553 ctx
->water_arg
= water_arg
;
1554 ctx
->hi_water
= hiwater
;
1555 ctx
->lo_water
= lowater
;
1556 ctx
->hi_called
= ISC_FALSE
;
1558 MCTXUNLOCK(ctx
, &ctx
->lock
);
1560 if (callwater
&& oldwater
!= NULL
)
1561 (oldwater
)(oldwater_arg
, ISC_MEM_LOWATER
);
1565 isc_mem_setname(isc_mem_t
*ctx
, const char *name
, void *tag
) {
1566 REQUIRE(VALID_CONTEXT(ctx
));
1569 memset(ctx
->name
, 0, sizeof(ctx
->name
));
1570 strncpy(ctx
->name
, name
, sizeof(ctx
->name
) - 1);
1576 isc_mem_getname(isc_mem_t
*ctx
) {
1577 REQUIRE(VALID_CONTEXT(ctx
));
1583 isc_mem_gettag(isc_mem_t
*ctx
) {
1584 REQUIRE(VALID_CONTEXT(ctx
));
1594 isc_mempool_create(isc_mem_t
*mctx
, size_t size
, isc_mempool_t
**mpctxp
) {
1595 isc_mempool_t
*mpctx
;
1597 REQUIRE(VALID_CONTEXT(mctx
));
1599 REQUIRE(mpctxp
!= NULL
&& *mpctxp
== NULL
);
1602 * Allocate space for this pool, initialize values, and if all works
1603 * well, attach to the memory context.
1605 mpctx
= isc_mem_get(mctx
, sizeof(isc_mempool_t
));
1607 return (ISC_R_NOMEMORY
);
1609 mpctx
->magic
= MEMPOOL_MAGIC
;
1613 mpctx
->maxalloc
= UINT_MAX
;
1614 mpctx
->allocated
= 0;
1615 mpctx
->freecount
= 0;
1617 mpctx
->fillcount
= 1;
1619 #if ISC_MEMPOOL_NAMES
1622 mpctx
->items
= NULL
;
1626 MCTXLOCK(mctx
, &mctx
->lock
);
1627 ISC_LIST_INITANDAPPEND(mctx
->pools
, mpctx
, link
);
1629 MCTXUNLOCK(mctx
, &mctx
->lock
);
1631 return (ISC_R_SUCCESS
);
1635 isc_mempool_setname(isc_mempool_t
*mpctx
, const char *name
) {
1636 REQUIRE(name
!= NULL
);
1638 #if ISC_MEMPOOL_NAMES
1639 if (mpctx
->lock
!= NULL
)
1642 strncpy(mpctx
->name
, name
, sizeof(mpctx
->name
) - 1);
1643 mpctx
->name
[sizeof(mpctx
->name
) - 1] = '\0';
1645 if (mpctx
->lock
!= NULL
)
1646 UNLOCK(mpctx
->lock
);
1654 isc_mempool_destroy(isc_mempool_t
**mpctxp
) {
1655 isc_mempool_t
*mpctx
;
1660 REQUIRE(mpctxp
!= NULL
);
1662 REQUIRE(VALID_MEMPOOL(mpctx
));
1663 #if ISC_MEMPOOL_NAMES
1664 if (mpctx
->allocated
> 0)
1665 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
1666 "isc_mempool_destroy(): mempool %s "
1670 REQUIRE(mpctx
->allocated
== 0);
1680 * Return any items on the free list
1682 MCTXLOCK(mctx
, &mctx
->lock
);
1683 while (mpctx
->items
!= NULL
) {
1684 INSIST(mpctx
->freecount
> 0);
1686 item
= mpctx
->items
;
1687 mpctx
->items
= item
->next
;
1689 if ((mctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
1690 mem_putunlocked(mctx
, item
, mpctx
->size
);
1692 mem_put(mctx
, item
, mpctx
->size
);
1693 mem_putstats(mctx
, item
, mpctx
->size
);
1696 MCTXUNLOCK(mctx
, &mctx
->lock
);
1699 * Remove our linked list entry from the memory context.
1701 MCTXLOCK(mctx
, &mctx
->lock
);
1702 ISC_LIST_UNLINK(mctx
->pools
, mpctx
, link
);
1704 MCTXUNLOCK(mctx
, &mctx
->lock
);
1708 isc_mem_put(mpctx
->mctx
, mpctx
, sizeof(isc_mempool_t
));
1717 isc_mempool_associatelock(isc_mempool_t
*mpctx
, isc_mutex_t
*lock
) {
1718 REQUIRE(VALID_MEMPOOL(mpctx
));
1719 REQUIRE(mpctx
->lock
== NULL
);
1720 REQUIRE(lock
!= NULL
);
1726 isc__mempool_get(isc_mempool_t
*mpctx FLARG
) {
1731 REQUIRE(VALID_MEMPOOL(mpctx
));
1735 if (mpctx
->lock
!= NULL
)
1739 * Don't let the caller go over quota
1741 if (mpctx
->allocated
>= mpctx
->maxalloc
) {
1747 * if we have a free list item, return the first here
1749 item
= mpctx
->items
;
1751 mpctx
->items
= item
->next
;
1752 INSIST(mpctx
->freecount
> 0);
1760 * We need to dip into the well. Lock the memory context here and
1761 * fill up our free list.
1763 MCTXLOCK(mctx
, &mctx
->lock
);
1764 for (i
= 0; i
< mpctx
->fillcount
; i
++) {
1765 if ((mctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
1766 item
= mem_getunlocked(mctx
, mpctx
->size
);
1768 item
= mem_get(mctx
, mpctx
->size
);
1770 mem_getstats(mctx
, mpctx
->size
);
1774 item
->next
= mpctx
->items
;
1775 mpctx
->items
= item
;
1778 MCTXUNLOCK(mctx
, &mctx
->lock
);
1781 * If we didn't get any items, return NULL.
1783 item
= mpctx
->items
;
1787 mpctx
->items
= item
->next
;
1793 if (mpctx
->lock
!= NULL
)
1794 UNLOCK(mpctx
->lock
);
1796 #if ISC_MEM_TRACKLINES
1798 MCTXLOCK(mctx
, &mctx
->lock
);
1799 ADD_TRACE(mctx
, item
, mpctx
->size
, file
, line
);
1800 MCTXUNLOCK(mctx
, &mctx
->lock
);
1802 #endif /* ISC_MEM_TRACKLINES */
1808 isc__mempool_put(isc_mempool_t
*mpctx
, void *mem FLARG
) {
1812 REQUIRE(VALID_MEMPOOL(mpctx
));
1813 REQUIRE(mem
!= NULL
);
1817 if (mpctx
->lock
!= NULL
)
1820 INSIST(mpctx
->allocated
> 0);
1823 #if ISC_MEM_TRACKLINES
1824 MCTXLOCK(mctx
, &mctx
->lock
);
1825 DELETE_TRACE(mctx
, mem
, mpctx
->size
, file
, line
);
1826 MCTXUNLOCK(mctx
, &mctx
->lock
);
1827 #endif /* ISC_MEM_TRACKLINES */
1830 * If our free list is full, return this to the mctx directly.
1832 if (mpctx
->freecount
>= mpctx
->freemax
) {
1833 if ((mctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
1834 MCTXLOCK(mctx
, &mctx
->lock
);
1835 mem_putunlocked(mctx
, mem
, mpctx
->size
);
1836 MCTXUNLOCK(mctx
, &mctx
->lock
);
1838 mem_put(mctx
, mem
, mpctx
->size
);
1839 MCTXLOCK(mctx
, &mctx
->lock
);
1840 mem_putstats(mctx
, mem
, mpctx
->size
);
1841 MCTXUNLOCK(mctx
, &mctx
->lock
);
1843 if (mpctx
->lock
!= NULL
)
1844 UNLOCK(mpctx
->lock
);
1849 * Otherwise, attach it to our free list and bump the counter.
1852 item
= (element
*)mem
;
1853 item
->next
= mpctx
->items
;
1854 mpctx
->items
= item
;
1856 if (mpctx
->lock
!= NULL
)
1857 UNLOCK(mpctx
->lock
);
1865 isc_mempool_setfreemax(isc_mempool_t
*mpctx
, unsigned int limit
) {
1866 REQUIRE(VALID_MEMPOOL(mpctx
));
1868 if (mpctx
->lock
!= NULL
)
1871 mpctx
->freemax
= limit
;
1873 if (mpctx
->lock
!= NULL
)
1874 UNLOCK(mpctx
->lock
);
1878 isc_mempool_getfreemax(isc_mempool_t
*mpctx
) {
1879 unsigned int freemax
;
1881 REQUIRE(VALID_MEMPOOL(mpctx
));
1883 if (mpctx
->lock
!= NULL
)
1886 freemax
= mpctx
->freemax
;
1888 if (mpctx
->lock
!= NULL
)
1889 UNLOCK(mpctx
->lock
);
1895 isc_mempool_getfreecount(isc_mempool_t
*mpctx
) {
1896 unsigned int freecount
;
1898 REQUIRE(VALID_MEMPOOL(mpctx
));
1900 if (mpctx
->lock
!= NULL
)
1903 freecount
= mpctx
->freecount
;
1905 if (mpctx
->lock
!= NULL
)
1906 UNLOCK(mpctx
->lock
);
1912 isc_mempool_setmaxalloc(isc_mempool_t
*mpctx
, unsigned int limit
) {
1915 REQUIRE(VALID_MEMPOOL(mpctx
));
1917 if (mpctx
->lock
!= NULL
)
1920 mpctx
->maxalloc
= limit
;
1922 if (mpctx
->lock
!= NULL
)
1923 UNLOCK(mpctx
->lock
);
1927 isc_mempool_getmaxalloc(isc_mempool_t
*mpctx
) {
1928 unsigned int maxalloc
;
1930 REQUIRE(VALID_MEMPOOL(mpctx
));
1932 if (mpctx
->lock
!= NULL
)
1935 maxalloc
= mpctx
->maxalloc
;
1937 if (mpctx
->lock
!= NULL
)
1938 UNLOCK(mpctx
->lock
);
1944 isc_mempool_getallocated(isc_mempool_t
*mpctx
) {
1945 unsigned int allocated
;
1947 REQUIRE(VALID_MEMPOOL(mpctx
));
1949 if (mpctx
->lock
!= NULL
)
1952 allocated
= mpctx
->allocated
;
1954 if (mpctx
->lock
!= NULL
)
1955 UNLOCK(mpctx
->lock
);
1961 isc_mempool_setfillcount(isc_mempool_t
*mpctx
, unsigned int limit
) {
1963 REQUIRE(VALID_MEMPOOL(mpctx
));
1965 if (mpctx
->lock
!= NULL
)
1968 mpctx
->fillcount
= limit
;
1970 if (mpctx
->lock
!= NULL
)
1971 UNLOCK(mpctx
->lock
);
1975 isc_mempool_getfillcount(isc_mempool_t
*mpctx
) {
1976 unsigned int fillcount
;
1978 REQUIRE(VALID_MEMPOOL(mpctx
));
1980 if (mpctx
->lock
!= NULL
)
1983 fillcount
= mpctx
->fillcount
;
1985 if (mpctx
->lock
!= NULL
)
1986 UNLOCK(mpctx
->lock
);
1992 isc_mem_printactive(isc_mem_t
*ctx
, FILE *file
) {
1994 REQUIRE(VALID_CONTEXT(ctx
));
1995 REQUIRE(file
!= NULL
);
1997 #if !ISC_MEM_TRACKLINES
2001 print_active(ctx
, file
);
2006 isc_mem_printallactive(FILE *file
) {
2007 #if !ISC_MEM_TRACKLINES
2012 RUNTIME_CHECK(isc_once_do(&once
, initialize_action
) == ISC_R_SUCCESS
);
2015 for (ctx
= ISC_LIST_HEAD(contexts
);
2017 ctx
= ISC_LIST_NEXT(ctx
, link
)) {
2018 fprintf(file
, "context: %p\n", ctx
);
2019 print_active(ctx
, file
);
2026 isc_mem_checkdestroyed(FILE *file
) {
2028 RUNTIME_CHECK(isc_once_do(&once
, initialize_action
) == ISC_R_SUCCESS
);
2031 if (!ISC_LIST_EMPTY(contexts
)) {
2032 #if ISC_MEM_TRACKLINES
2035 for (ctx
= ISC_LIST_HEAD(contexts
);
2037 ctx
= ISC_LIST_NEXT(ctx
, link
)) {
2038 fprintf(file
, "context: %p\n", ctx
);
2039 print_active(ctx
, file
);
2049 isc_mem_references(isc_mem_t
*ctx
) {
2050 unsigned int references
;
2051 REQUIRE(VALID_CONTEXT(ctx
));
2053 MCTXLOCK(ctx
, &ctx
->lock
);
2054 references
= ctx
->references
;
2055 MCTXUNLOCK(ctx
, &ctx
->lock
);
2057 return (references
);
2062 typedef struct summarystat
{
2065 isc_uint64_t blocksize
;
2066 isc_uint64_t contextsize
;
2070 renderctx(isc_mem_t
*ctx
, summarystat_t
*summary
, xmlTextWriterPtr writer
) {
2071 REQUIRE(VALID_CONTEXT(ctx
));
2073 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"context");
2075 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"id");
2076 xmlTextWriterWriteFormatString(writer
, "%p", ctx
);
2077 xmlTextWriterEndElement(writer
); /* id */
2079 if (ctx
->name
[0] != 0) {
2080 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"name");
2081 xmlTextWriterWriteFormatString(writer
, "%s", ctx
->name
);
2082 xmlTextWriterEndElement(writer
); /* name */
2085 REQUIRE(VALID_CONTEXT(ctx
));
2086 MCTXLOCK(ctx
, &ctx
->lock
);
2088 summary
->contextsize
+= sizeof(*ctx
) +
2089 (ctx
->max_size
+ 1) * sizeof(struct stats
) +
2090 ctx
->max_size
* sizeof(element
*) +
2091 ctx
->basic_table_count
* sizeof(char *);
2092 #if ISC_MEM_TRACKLINES
2093 if (ctx
->debuglist
!= NULL
) {
2094 summary
->contextsize
+=
2095 (ctx
->max_size
+ 1) * sizeof(debuglist_t
) +
2096 ctx
->debuglistcnt
* sizeof(debuglink_t
);
2099 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"references");
2100 xmlTextWriterWriteFormatString(writer
, "%d", ctx
->references
);
2101 xmlTextWriterEndElement(writer
); /* references */
2103 summary
->total
+= ctx
->total
;
2104 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"total");
2105 xmlTextWriterWriteFormatString(writer
, "%" ISC_PRINT_QUADFORMAT
"u",
2106 (isc_uint64_t
)ctx
->total
);
2107 xmlTextWriterEndElement(writer
); /* total */
2109 summary
->inuse
+= ctx
->inuse
;
2110 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"inuse");
2111 xmlTextWriterWriteFormatString(writer
, "%" ISC_PRINT_QUADFORMAT
"u",
2112 (isc_uint64_t
)ctx
->inuse
);
2113 xmlTextWriterEndElement(writer
); /* inuse */
2115 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"maxinuse");
2116 xmlTextWriterWriteFormatString(writer
, "%" ISC_PRINT_QUADFORMAT
"u",
2117 (isc_uint64_t
)ctx
->maxinuse
);
2118 xmlTextWriterEndElement(writer
); /* maxinuse */
2120 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"blocksize");
2121 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
2122 summary
->blocksize
+= ctx
->basic_table_count
*
2123 NUM_BASIC_BLOCKS
* ctx
->mem_target
;
2124 xmlTextWriterWriteFormatString(writer
,
2125 "%" ISC_PRINT_QUADFORMAT
"u",
2127 ctx
->basic_table_count
*
2131 xmlTextWriterWriteFormatString(writer
, "%s", "-");
2132 xmlTextWriterEndElement(writer
); /* blocksize */
2134 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"pools");
2135 xmlTextWriterWriteFormatString(writer
, "%u", ctx
->poolcnt
);
2136 xmlTextWriterEndElement(writer
); /* pools */
2137 summary
->contextsize
+= ctx
->poolcnt
* sizeof(isc_mempool_t
);
2139 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"hiwater");
2140 xmlTextWriterWriteFormatString(writer
, "%" ISC_PRINT_QUADFORMAT
"u",
2141 (isc_uint64_t
)ctx
->hi_water
);
2142 xmlTextWriterEndElement(writer
); /* hiwater */
2144 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"lowater");
2145 xmlTextWriterWriteFormatString(writer
, "%" ISC_PRINT_QUADFORMAT
"u",
2146 (isc_uint64_t
)ctx
->lo_water
);
2147 xmlTextWriterEndElement(writer
); /* lowater */
2149 MCTXUNLOCK(ctx
, &ctx
->lock
);
2151 xmlTextWriterEndElement(writer
); /* context */
2155 isc_mem_renderxml(xmlTextWriterPtr writer
) {
2157 summarystat_t summary
;
2160 memset(&summary
, 0, sizeof(summary
));
2162 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"contexts");
2164 RUNTIME_CHECK(isc_once_do(&once
, initialize_action
) == ISC_R_SUCCESS
);
2168 for (ctx
= ISC_LIST_HEAD(contexts
);
2170 ctx
= ISC_LIST_NEXT(ctx
, link
)) {
2171 renderctx(ctx
, &summary
, writer
);
2175 xmlTextWriterEndElement(writer
); /* contexts */
2177 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"summary");
2179 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"TotalUse");
2180 xmlTextWriterWriteFormatString(writer
, "%" ISC_PRINT_QUADFORMAT
"u",
2182 xmlTextWriterEndElement(writer
); /* TotalUse */
2184 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"InUse");
2185 xmlTextWriterWriteFormatString(writer
, "%" ISC_PRINT_QUADFORMAT
"u",
2187 xmlTextWriterEndElement(writer
); /* InUse */
2189 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"BlockSize");
2190 xmlTextWriterWriteFormatString(writer
, "%" ISC_PRINT_QUADFORMAT
"u",
2192 xmlTextWriterEndElement(writer
); /* BlockSize */
2194 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"ContextSize");
2195 xmlTextWriterWriteFormatString(writer
, "%" ISC_PRINT_QUADFORMAT
"u",
2196 summary
.contextsize
);
2197 xmlTextWriterEndElement(writer
); /* ContextSize */
2199 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"Lost");
2200 xmlTextWriterWriteFormatString(writer
, "%" ISC_PRINT_QUADFORMAT
"u",
2202 xmlTextWriterEndElement(writer
); /* Lost */
2204 xmlTextWriterEndElement(writer
); /* summary */
2207 #endif /* HAVE_LIBXML2 */