2 * Copyright (C) 2004-2009 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.137.16.8 2009/02/16 03:17:29 marka Exp $ */
30 #include <isc/magic.h>
34 #include <isc/ondestroy.h>
35 #include <isc/string.h>
36 #include <isc/mutex.h>
37 #include <isc/print.h>
41 #define MCTXLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) LOCK(l)
42 #define MCTXUNLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) UNLOCK(l)
44 #ifndef ISC_MEM_DEBUGGING
45 #define ISC_MEM_DEBUGGING 0
47 LIBISC_EXTERNAL_DATA
unsigned int isc_mem_debugging
= ISC_MEM_DEBUGGING
;
53 #define DEF_MAX_SIZE 1100
54 #define DEF_MEM_TARGET 4096
55 #define ALIGNMENT_SIZE 8U /*%< must be a power of 2 */
56 #define NUM_BASIC_BLOCKS 64 /*%< must be > 1 */
57 #define TABLE_INCREMENT 1024
58 #define DEBUGLIST_COUNT 1024
63 #if ISC_MEM_TRACKLINES
64 typedef struct debuglink debuglink_t
;
66 ISC_LINK(debuglink_t
) link
;
67 const void *ptr
[DEBUGLIST_COUNT
];
68 unsigned int size
[DEBUGLIST_COUNT
];
69 const char *file
[DEBUGLIST_COUNT
];
70 unsigned int line
[DEBUGLIST_COUNT
];
74 #define FLARG_PASS , file, line
75 #define FLARG , const char *file, int line
81 typedef struct element element
;
88 * This structure must be ALIGNMENT_SIZE bytes.
93 char bytes
[ALIGNMENT_SIZE
];
99 unsigned long totalgets
;
100 unsigned long blocks
;
101 unsigned long freefrags
;
104 #define MEM_MAGIC ISC_MAGIC('M', 'e', 'm', 'C')
105 #define VALID_CONTEXT(c) ISC_MAGIC_VALID(c, MEM_MAGIC)
107 #if ISC_MEM_TRACKLINES
108 typedef ISC_LIST(debuglink_t
) debuglist_t
;
111 /* List of all active memory contexts. */
113 static ISC_LIST(isc_mem_t
) contexts
;
114 static isc_once_t once
= ISC_ONCE_INIT
;
115 static isc_mutex_t lock
;
118 * Total size of lost memory due to a bug of external library.
119 * Locked by the global lock.
121 static isc_uint64_t totallost
;
125 isc_ondestroy_t ondestroy
;
128 isc_memalloc_t memalloc
;
129 isc_memfree_t memfree
;
132 isc_boolean_t checkfree
;
133 struct stats
* stats
;
134 unsigned int references
;
143 isc_boolean_t hi_called
;
144 isc_mem_water_t water
;
146 ISC_LIST(isc_mempool_t
) pools
;
147 unsigned int poolcnt
;
149 /* ISC_MEMFLAG_INTERNAL */
151 element
** freelists
;
152 element
* basic_blocks
;
153 unsigned char ** basic_table
;
154 unsigned int basic_table_count
;
155 unsigned int basic_table_size
;
156 unsigned char * lowest
;
157 unsigned char * highest
;
159 #if ISC_MEM_TRACKLINES
160 debuglist_t
* debuglist
;
161 unsigned int debuglistcnt
;
164 unsigned int memalloc_failures
;
165 ISC_LINK(isc_mem_t
) link
;
168 #define MEMPOOL_MAGIC ISC_MAGIC('M', 'E', 'M', 'p')
169 #define VALID_MEMPOOL(c) ISC_MAGIC_VALID(c, MEMPOOL_MAGIC)
172 /* always unlocked */
173 unsigned int magic
; /*%< magic number */
174 isc_mutex_t
*lock
; /*%< optional lock */
175 isc_mem_t
*mctx
; /*%< our memory context */
176 /*%< locked via the memory context's lock */
177 ISC_LINK(isc_mempool_t
) link
; /*%< next pool in this mem context */
178 /*%< optionally locked from here down */
179 element
*items
; /*%< low water item list */
180 size_t size
; /*%< size of each item on this pool */
181 unsigned int maxalloc
; /*%< max number of items allowed */
182 unsigned int allocated
; /*%< # of items currently given out */
183 unsigned int freecount
; /*%< # of items on reserved list */
184 unsigned int freemax
; /*%< # of items allowed on free list */
185 unsigned int fillcount
; /*%< # of items to fetch on each fill */
187 unsigned int gets
; /*%< # of requests to this pool */
188 /*%< Debugging only. */
189 #if ISC_MEMPOOL_NAMES
190 char name
[16]; /*%< printed name in stats reports */
195 * Private Inline-able.
198 #if ! ISC_MEM_TRACKLINES
199 #define ADD_TRACE(a, b, c, d, e)
200 #define DELETE_TRACE(a, b, c, d, e)
202 #define ADD_TRACE(a, b, c, d, e) \
204 if ((isc_mem_debugging & (ISC_MEM_DEBUGTRACE | \
205 ISC_MEM_DEBUGRECORD)) != 0 && \
207 add_trace_entry(a, b, c, d, e); \
209 #define DELETE_TRACE(a, b, c, d, e) delete_trace_entry(a, b, c, d, e)
212 print_active(isc_mem_t
*ctx
, FILE *out
);
215 * mctx must be locked.
218 add_trace_entry(isc_mem_t
*mctx
, const void *ptr
, unsigned int size
224 if ((isc_mem_debugging
& ISC_MEM_DEBUGTRACE
) != 0)
225 fprintf(stderr
, isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
228 "file %s line %u mctx %p\n"),
229 ptr
, size
, file
, line
, mctx
);
231 if (mctx
->debuglist
== NULL
)
234 if (size
> mctx
->max_size
)
235 size
= mctx
->max_size
;
237 dl
= ISC_LIST_HEAD(mctx
->debuglist
[size
]);
239 if (dl
->count
== DEBUGLIST_COUNT
)
241 for (i
= 0; i
< DEBUGLIST_COUNT
; i
++) {
242 if (dl
->ptr
[i
] == NULL
) {
252 dl
= ISC_LIST_NEXT(dl
, link
);
255 dl
= malloc(sizeof(debuglink_t
));
258 ISC_LINK_INIT(dl
, link
);
259 for (i
= 1; i
< DEBUGLIST_COUNT
; i
++) {
272 ISC_LIST_PREPEND(mctx
->debuglist
[size
], dl
, link
);
273 mctx
->debuglistcnt
++;
277 delete_trace_entry(isc_mem_t
*mctx
, const void *ptr
, unsigned int size
,
278 const char *file
, unsigned int line
)
283 if ((isc_mem_debugging
& ISC_MEM_DEBUGTRACE
) != 0)
284 fprintf(stderr
, isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
287 "file %s line %u mctx %p\n"),
288 ptr
, size
, file
, line
, mctx
);
290 if (mctx
->debuglist
== NULL
)
293 if (size
> mctx
->max_size
)
294 size
= mctx
->max_size
;
296 dl
= ISC_LIST_HEAD(mctx
->debuglist
[size
]);
298 for (i
= 0; i
< DEBUGLIST_COUNT
; i
++) {
299 if (dl
->ptr
[i
] == ptr
) {
305 INSIST(dl
->count
> 0);
307 if (dl
->count
== 0) {
308 ISC_LIST_UNLINK(mctx
->debuglist
[size
],
315 dl
= ISC_LIST_NEXT(dl
, link
);
319 * If we get here, we didn't find the item on the list. We're
324 #endif /* ISC_MEM_TRACKLINES */
327 rmsize(size_t size
) {
329 * round down to ALIGNMENT_SIZE
331 return (size
& (~(ALIGNMENT_SIZE
- 1)));
335 quantize(size_t size
) {
337 * Round up the result in order to get a size big
338 * enough to satisfy the request and be aligned on ALIGNMENT_SIZE
343 return (ALIGNMENT_SIZE
);
344 return ((size
+ ALIGNMENT_SIZE
- 1) & (~(ALIGNMENT_SIZE
- 1)));
347 static inline isc_boolean_t
348 more_basic_blocks(isc_mem_t
*ctx
) {
350 unsigned char *curr
, *next
;
351 unsigned char *first
, *last
;
352 unsigned char **table
;
353 unsigned int table_size
;
357 /* Require: we hold the context lock. */
360 * Did we hit the quota for this context?
362 increment
= NUM_BASIC_BLOCKS
* ctx
->mem_target
;
363 if (ctx
->quota
!= 0U && ctx
->total
+ increment
> ctx
->quota
)
366 INSIST(ctx
->basic_table_count
<= ctx
->basic_table_size
);
367 if (ctx
->basic_table_count
== ctx
->basic_table_size
) {
368 table_size
= ctx
->basic_table_size
+ TABLE_INCREMENT
;
369 table
= (ctx
->memalloc
)(ctx
->arg
,
370 table_size
* sizeof(unsigned char *));
372 ctx
->memalloc_failures
++;
375 if (ctx
->basic_table_size
!= 0) {
376 memcpy(table
, ctx
->basic_table
,
377 ctx
->basic_table_size
*
378 sizeof(unsigned char *));
379 (ctx
->memfree
)(ctx
->arg
, ctx
->basic_table
);
381 ctx
->basic_table
= table
;
382 ctx
->basic_table_size
= table_size
;
385 new = (ctx
->memalloc
)(ctx
->arg
, NUM_BASIC_BLOCKS
* ctx
->mem_target
);
387 ctx
->memalloc_failures
++;
390 ctx
->total
+= increment
;
391 ctx
->basic_table
[ctx
->basic_table_count
] = new;
392 ctx
->basic_table_count
++;
395 next
= curr
+ ctx
->mem_target
;
396 for (i
= 0; i
< (NUM_BASIC_BLOCKS
- 1); i
++) {
397 ((element
*)curr
)->next
= (element
*)next
;
399 next
+= ctx
->mem_target
;
402 * curr is now pointing at the last block in the
405 ((element
*)curr
)->next
= NULL
;
407 last
= first
+ NUM_BASIC_BLOCKS
* ctx
->mem_target
- 1;
408 if (first
< ctx
->lowest
|| ctx
->lowest
== NULL
)
410 if (last
> ctx
->highest
)
412 ctx
->basic_blocks
= new;
417 static inline isc_boolean_t
418 more_frags(isc_mem_t
*ctx
, size_t new_size
) {
422 unsigned char *curr
, *next
;
425 * Try to get more fragments by chopping up a basic block.
428 if (ctx
->basic_blocks
== NULL
) {
429 if (!more_basic_blocks(ctx
)) {
431 * We can't get more memory from the OS, or we've
432 * hit the quota for this context.
435 * XXXRTH "At quota" notification here.
441 total_size
= ctx
->mem_target
;
442 new = ctx
->basic_blocks
;
443 ctx
->basic_blocks
= ctx
->basic_blocks
->next
;
444 frags
= total_size
/ new_size
;
445 ctx
->stats
[new_size
].blocks
++;
446 ctx
->stats
[new_size
].freefrags
+= frags
;
448 * Set up a linked-list of blocks of size
452 next
= curr
+ new_size
;
453 total_size
-= new_size
;
454 for (i
= 0; i
< (frags
- 1); i
++) {
455 ((element
*)curr
)->next
= (element
*)next
;
458 total_size
-= new_size
;
461 * Add the remaining fragment of the basic block to a free list.
463 total_size
= rmsize(total_size
);
464 if (total_size
> 0U) {
465 ((element
*)next
)->next
= ctx
->freelists
[total_size
];
466 ctx
->freelists
[total_size
] = (element
*)next
;
467 ctx
->stats
[total_size
].freefrags
++;
470 * curr is now pointing at the last block in the
473 ((element
*)curr
)->next
= NULL
;
474 ctx
->freelists
[new_size
] = new;
480 mem_getunlocked(isc_mem_t
*ctx
, size_t size
) {
481 size_t new_size
= quantize(size
);
484 if (size
>= ctx
->max_size
|| new_size
>= ctx
->max_size
) {
486 * memget() was called on something beyond our upper limit.
488 if (ctx
->quota
!= 0U && ctx
->total
+ size
> ctx
->quota
) {
492 ret
= (ctx
->memalloc
)(ctx
->arg
, size
);
494 ctx
->memalloc_failures
++;
499 ctx
->stats
[ctx
->max_size
].gets
++;
500 ctx
->stats
[ctx
->max_size
].totalgets
++;
502 * If we don't set new_size to size, then the
503 * ISC_MEM_FILL code might write over bytes we
511 * If there are no blocks in the free list for this size, get a chunk
512 * of memory and then break it up into "new_size"-sized blocks, adding
513 * them to the free list.
515 if (ctx
->freelists
[new_size
] == NULL
&& !more_frags(ctx
, new_size
))
519 * The free list uses the "rounded-up" size "new_size".
521 ret
= ctx
->freelists
[new_size
];
522 ctx
->freelists
[new_size
] = ctx
->freelists
[new_size
]->next
;
525 * The stats[] uses the _actual_ "size" requested by the
526 * caller, with the caveat (in the code above) that "size" >= the
527 * max. size (max_size) ends up getting recorded as a call to
530 ctx
->stats
[size
].gets
++;
531 ctx
->stats
[size
].totalgets
++;
532 ctx
->stats
[new_size
].freefrags
--;
533 ctx
->inuse
+= new_size
;
539 memset(ret
, 0xbe, new_size
); /* Mnemonic for "beef". */
545 #if ISC_MEM_FILL && ISC_MEM_CHECKOVERRUN
547 check_overrun(void *mem
, size_t size
, size_t new_size
) {
550 cp
= (unsigned char *)mem
;
552 while (size
< new_size
) {
561 mem_putunlocked(isc_mem_t
*ctx
, void *mem
, size_t size
) {
562 size_t new_size
= quantize(size
);
564 if (size
== ctx
->max_size
|| new_size
>= ctx
->max_size
) {
566 * memput() called on something beyond our upper limit.
569 memset(mem
, 0xde, size
); /* Mnemonic for "dead". */
571 (ctx
->memfree
)(ctx
->arg
, mem
);
572 INSIST(ctx
->stats
[ctx
->max_size
].gets
!= 0U);
573 ctx
->stats
[ctx
->max_size
].gets
--;
574 INSIST(size
<= ctx
->total
);
581 #if ISC_MEM_CHECKOVERRUN
582 check_overrun(mem
, size
, new_size
);
584 memset(mem
, 0xde, new_size
); /* Mnemonic for "dead". */
588 * The free list uses the "rounded-up" size "new_size".
590 ((element
*)mem
)->next
= ctx
->freelists
[new_size
];
591 ctx
->freelists
[new_size
] = (element
*)mem
;
594 * The stats[] uses the _actual_ "size" requested by the
595 * caller, with the caveat (in the code above) that "size" >= the
596 * max. size (max_size) ends up getting recorded as a call to
599 INSIST(ctx
->stats
[size
].gets
!= 0U);
600 ctx
->stats
[size
].gets
--;
601 ctx
->stats
[new_size
].freefrags
++;
602 ctx
->inuse
-= new_size
;
606 * Perform a malloc, doing memory filling and overrun detection as necessary.
609 mem_get(isc_mem_t
*ctx
, size_t size
) {
612 #if ISC_MEM_CHECKOVERRUN
616 ret
= (ctx
->memalloc
)(ctx
->arg
, size
);
618 ctx
->memalloc_failures
++;
622 memset(ret
, 0xbe, size
); /* Mnemonic for "beef". */
624 # if ISC_MEM_CHECKOVERRUN
634 * Perform a free, doing memory filling and overrun detection as necessary.
637 mem_put(isc_mem_t
*ctx
, void *mem
, size_t size
) {
638 #if ISC_MEM_CHECKOVERRUN
639 INSIST(((unsigned char *)mem
)[size
] == 0xbe);
642 memset(mem
, 0xde, size
); /* Mnemonic for "dead". */
646 (ctx
->memfree
)(ctx
->arg
, mem
);
650 * Update internal counters after a memory get.
653 mem_getstats(isc_mem_t
*ctx
, size_t size
) {
657 if (size
> ctx
->max_size
) {
658 ctx
->stats
[ctx
->max_size
].gets
++;
659 ctx
->stats
[ctx
->max_size
].totalgets
++;
661 ctx
->stats
[size
].gets
++;
662 ctx
->stats
[size
].totalgets
++;
667 * Update internal counters after a memory put.
670 mem_putstats(isc_mem_t
*ctx
, void *ptr
, size_t size
) {
673 INSIST(ctx
->inuse
>= size
);
676 if (size
> ctx
->max_size
) {
677 INSIST(ctx
->stats
[ctx
->max_size
].gets
> 0U);
678 ctx
->stats
[ctx
->max_size
].gets
--;
680 INSIST(ctx
->stats
[size
].gets
> 0U);
681 ctx
->stats
[size
].gets
--;
690 default_memalloc(void *arg
, size_t size
) {
694 return (malloc(size
));
698 default_memfree(void *arg
, void *ptr
) {
704 initialize_action(void) {
705 RUNTIME_CHECK(isc_mutex_init(&lock
) == ISC_R_SUCCESS
);
706 ISC_LIST_INIT(contexts
);
715 isc_mem_createx(size_t init_max_size
, size_t target_size
,
716 isc_memalloc_t memalloc
, isc_memfree_t memfree
, void *arg
,
719 return (isc_mem_createx2(init_max_size
, target_size
, memalloc
, memfree
,
720 arg
, ctxp
, ISC_MEMFLAG_DEFAULT
));
725 isc_mem_createx2(size_t init_max_size
, size_t target_size
,
726 isc_memalloc_t memalloc
, isc_memfree_t memfree
, void *arg
,
727 isc_mem_t
**ctxp
, unsigned int flags
)
732 REQUIRE(ctxp
!= NULL
&& *ctxp
== NULL
);
733 REQUIRE(memalloc
!= NULL
);
734 REQUIRE(memfree
!= NULL
);
736 INSIST((ALIGNMENT_SIZE
& (ALIGNMENT_SIZE
- 1)) == 0);
738 RUNTIME_CHECK(isc_once_do(&once
, initialize_action
) == ISC_R_SUCCESS
);
740 ctx
= (memalloc
)(arg
, sizeof(*ctx
));
742 return (ISC_R_NOMEMORY
);
744 if ((flags
& ISC_MEMFLAG_NOLOCK
) == 0) {
745 result
= isc_mutex_init(&ctx
->lock
);
746 if (result
!= ISC_R_SUCCESS
) {
752 if (init_max_size
== 0U)
753 ctx
->max_size
= DEF_MAX_SIZE
;
755 ctx
->max_size
= init_max_size
;
758 memset(ctx
->name
, 0, sizeof(ctx
->name
));
766 ctx
->hi_called
= ISC_FALSE
;
768 ctx
->water_arg
= NULL
;
769 ctx
->magic
= MEM_MAGIC
;
770 isc_ondestroy_init(&ctx
->ondestroy
);
771 ctx
->memalloc
= memalloc
;
772 ctx
->memfree
= memfree
;
775 ctx
->checkfree
= ISC_TRUE
;
776 #if ISC_MEM_TRACKLINES
777 ctx
->debuglist
= NULL
;
778 ctx
->debuglistcnt
= 0;
780 ISC_LIST_INIT(ctx
->pools
);
782 ctx
->freelists
= NULL
;
783 ctx
->basic_blocks
= NULL
;
784 ctx
->basic_table
= NULL
;
785 ctx
->basic_table_count
= 0;
786 ctx
->basic_table_size
= 0;
790 ctx
->stats
= (memalloc
)(arg
,
791 (ctx
->max_size
+1) * sizeof(struct stats
));
792 if (ctx
->stats
== NULL
) {
793 result
= ISC_R_NOMEMORY
;
796 memset(ctx
->stats
, 0, (ctx
->max_size
+ 1) * sizeof(struct stats
));
798 if ((flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
799 if (target_size
== 0U)
800 ctx
->mem_target
= DEF_MEM_TARGET
;
802 ctx
->mem_target
= target_size
;
803 ctx
->freelists
= (memalloc
)(arg
, ctx
->max_size
*
805 if (ctx
->freelists
== NULL
) {
806 result
= ISC_R_NOMEMORY
;
809 memset(ctx
->freelists
, 0,
810 ctx
->max_size
* sizeof(element
*));
813 #if ISC_MEM_TRACKLINES
814 if ((isc_mem_debugging
& ISC_MEM_DEBUGRECORD
) != 0) {
817 ctx
->debuglist
= (memalloc
)(arg
,
818 (ctx
->max_size
+1) * sizeof(debuglist_t
));
819 if (ctx
->debuglist
== NULL
) {
820 result
= ISC_R_NOMEMORY
;
823 for (i
= 0; i
<= ctx
->max_size
; i
++)
824 ISC_LIST_INIT(ctx
->debuglist
[i
]);
828 ctx
->memalloc_failures
= 0;
831 ISC_LIST_INITANDAPPEND(contexts
, ctx
, link
);
835 return (ISC_R_SUCCESS
);
839 if (ctx
->stats
!= NULL
)
840 (memfree
)(arg
, ctx
->stats
);
841 if (ctx
->freelists
!= NULL
)
842 (memfree
)(arg
, ctx
->freelists
);
843 #if ISC_MEM_TRACKLINES
844 if (ctx
->debuglist
!= NULL
)
845 (ctx
->memfree
)(ctx
->arg
, ctx
->debuglist
);
846 #endif /* ISC_MEM_TRACKLINES */
847 if ((ctx
->flags
& ISC_MEMFLAG_NOLOCK
) == 0)
848 DESTROYLOCK(&ctx
->lock
);
856 isc_mem_create(size_t init_max_size
, size_t target_size
,
859 return (isc_mem_createx2(init_max_size
, target_size
,
860 default_memalloc
, default_memfree
, NULL
,
861 ctxp
, ISC_MEMFLAG_DEFAULT
));
865 isc_mem_create2(size_t init_max_size
, size_t target_size
,
866 isc_mem_t
**ctxp
, unsigned int flags
)
868 return (isc_mem_createx2(init_max_size
, target_size
,
869 default_memalloc
, default_memfree
, NULL
,
874 destroy(isc_mem_t
*ctx
) {
876 isc_ondestroy_t ondest
;
881 ISC_LIST_UNLINK(contexts
, ctx
, link
);
882 totallost
+= ctx
->inuse
;
885 INSIST(ISC_LIST_EMPTY(ctx
->pools
));
887 #if ISC_MEM_TRACKLINES
888 if (ctx
->debuglist
!= NULL
) {
889 if (ctx
->checkfree
) {
890 for (i
= 0; i
<= ctx
->max_size
; i
++) {
891 if (!ISC_LIST_EMPTY(ctx
->debuglist
[i
]))
892 print_active(ctx
, stderr
);
893 INSIST(ISC_LIST_EMPTY(ctx
->debuglist
[i
]));
898 for (i
= 0; i
<= ctx
->max_size
; i
++)
899 for (dl
= ISC_LIST_HEAD(ctx
->debuglist
[i
]);
901 dl
= ISC_LIST_HEAD(ctx
->debuglist
[i
])) {
902 ISC_LIST_UNLINK(ctx
->debuglist
[i
],
907 (ctx
->memfree
)(ctx
->arg
, ctx
->debuglist
);
910 INSIST(ctx
->references
== 0);
912 if (ctx
->checkfree
) {
913 for (i
= 0; i
<= ctx
->max_size
; i
++) {
914 #if ISC_MEM_TRACKLINES
915 if (ctx
->stats
[i
].gets
!= 0U)
916 print_active(ctx
, stderr
);
918 INSIST(ctx
->stats
[i
].gets
== 0U);
922 (ctx
->memfree
)(ctx
->arg
, ctx
->stats
);
924 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
925 for (i
= 0; i
< ctx
->basic_table_count
; i
++)
926 (ctx
->memfree
)(ctx
->arg
, ctx
->basic_table
[i
]);
927 (ctx
->memfree
)(ctx
->arg
, ctx
->freelists
);
928 if (ctx
->basic_table
!= NULL
)
929 (ctx
->memfree
)(ctx
->arg
, ctx
->basic_table
);
932 ondest
= ctx
->ondestroy
;
934 if ((ctx
->flags
& ISC_MEMFLAG_NOLOCK
) == 0)
935 DESTROYLOCK(&ctx
->lock
);
936 (ctx
->memfree
)(ctx
->arg
, ctx
);
938 isc_ondestroy_notify(&ondest
, ctx
);
942 isc_mem_attach(isc_mem_t
*source
, isc_mem_t
**targetp
) {
943 REQUIRE(VALID_CONTEXT(source
));
944 REQUIRE(targetp
!= NULL
&& *targetp
== NULL
);
946 MCTXLOCK(source
, &source
->lock
);
947 source
->references
++;
948 MCTXUNLOCK(source
, &source
->lock
);
954 isc_mem_detach(isc_mem_t
**ctxp
) {
956 isc_boolean_t want_destroy
= ISC_FALSE
;
958 REQUIRE(ctxp
!= NULL
);
960 REQUIRE(VALID_CONTEXT(ctx
));
962 MCTXLOCK(ctx
, &ctx
->lock
);
963 INSIST(ctx
->references
> 0);
965 if (ctx
->references
== 0)
966 want_destroy
= ISC_TRUE
;
967 MCTXUNLOCK(ctx
, &ctx
->lock
);
976 * isc_mem_putanddetach() is the equivalent of:
979 * isc_mem_attach(ptr->mctx, &mctx);
980 * isc_mem_detach(&ptr->mctx);
981 * isc_mem_put(mctx, ptr, sizeof(*ptr);
982 * isc_mem_detach(&mctx);
986 isc__mem_putanddetach(isc_mem_t
**ctxp
, void *ptr
, size_t size FLARG
) {
988 isc_boolean_t want_destroy
= ISC_FALSE
;
992 REQUIRE(ctxp
!= NULL
);
994 REQUIRE(VALID_CONTEXT(ctx
));
995 REQUIRE(ptr
!= NULL
);
998 * Must be before mem_putunlocked() as ctxp is usually within
1003 if ((isc_mem_debugging
& (ISC_MEM_DEBUGSIZE
|ISC_MEM_DEBUGCTX
)) != 0) {
1004 if ((isc_mem_debugging
& ISC_MEM_DEBUGSIZE
) != 0) {
1005 si
= &(((size_info
*)ptr
)[-1]);
1006 oldsize
= si
->u
.size
- ALIGNMENT_SIZE
;
1007 if ((isc_mem_debugging
& ISC_MEM_DEBUGCTX
) != 0)
1008 oldsize
-= ALIGNMENT_SIZE
;
1009 INSIST(oldsize
== size
);
1011 isc__mem_free(ctx
, ptr FLARG_PASS
);
1013 MCTXLOCK(ctx
, &ctx
->lock
);
1015 if (ctx
->references
== 0)
1016 want_destroy
= ISC_TRUE
;
1017 MCTXUNLOCK(ctx
, &ctx
->lock
);
1024 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
1025 MCTXLOCK(ctx
, &ctx
->lock
);
1026 mem_putunlocked(ctx
, ptr
, size
);
1028 mem_put(ctx
, ptr
, size
);
1029 MCTXLOCK(ctx
, &ctx
->lock
);
1030 mem_putstats(ctx
, ptr
, size
);
1033 DELETE_TRACE(ctx
, ptr
, size
, file
, line
);
1034 INSIST(ctx
->references
> 0);
1036 if (ctx
->references
== 0)
1037 want_destroy
= ISC_TRUE
;
1039 MCTXUNLOCK(ctx
, &ctx
->lock
);
1046 isc_mem_destroy(isc_mem_t
**ctxp
) {
1050 * This routine provides legacy support for callers who use mctxs
1051 * without attaching/detaching.
1054 REQUIRE(ctxp
!= NULL
);
1056 REQUIRE(VALID_CONTEXT(ctx
));
1058 MCTXLOCK(ctx
, &ctx
->lock
);
1059 #if ISC_MEM_TRACKLINES
1060 if (ctx
->references
!= 1)
1061 print_active(ctx
, stderr
);
1063 REQUIRE(ctx
->references
== 1);
1065 MCTXUNLOCK(ctx
, &ctx
->lock
);
1073 isc_mem_ondestroy(isc_mem_t
*ctx
, isc_task_t
*task
, isc_event_t
**event
) {
1076 MCTXLOCK(ctx
, &ctx
->lock
);
1077 res
= isc_ondestroy_register(&ctx
->ondestroy
, task
, event
);
1078 MCTXUNLOCK(ctx
, &ctx
->lock
);
1085 isc__mem_get(isc_mem_t
*ctx
, size_t size FLARG
) {
1087 isc_boolean_t call_water
= ISC_FALSE
;
1089 REQUIRE(VALID_CONTEXT(ctx
));
1091 if ((isc_mem_debugging
& (ISC_MEM_DEBUGSIZE
|ISC_MEM_DEBUGCTX
)) != 0)
1092 return (isc__mem_allocate(ctx
, size FLARG_PASS
));
1094 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
1095 MCTXLOCK(ctx
, &ctx
->lock
);
1096 ptr
= mem_getunlocked(ctx
, size
);
1098 ptr
= mem_get(ctx
, size
);
1099 MCTXLOCK(ctx
, &ctx
->lock
);
1101 mem_getstats(ctx
, size
);
1104 ADD_TRACE(ctx
, ptr
, size
, file
, line
);
1105 if (ctx
->hi_water
!= 0U && !ctx
->hi_called
&&
1106 ctx
->inuse
> ctx
->hi_water
) {
1107 call_water
= ISC_TRUE
;
1109 if (ctx
->inuse
> ctx
->maxinuse
) {
1110 ctx
->maxinuse
= ctx
->inuse
;
1111 if (ctx
->hi_water
!= 0U && ctx
->inuse
> ctx
->hi_water
&&
1112 (isc_mem_debugging
& ISC_MEM_DEBUGUSAGE
) != 0)
1113 fprintf(stderr
, "maxinuse = %lu\n",
1114 (unsigned long)ctx
->inuse
);
1116 MCTXUNLOCK(ctx
, &ctx
->lock
);
1119 (ctx
->water
)(ctx
->water_arg
, ISC_MEM_HIWATER
);
1125 isc__mem_put(isc_mem_t
*ctx
, void *ptr
, size_t size FLARG
)
1127 isc_boolean_t call_water
= ISC_FALSE
;
1131 REQUIRE(VALID_CONTEXT(ctx
));
1132 REQUIRE(ptr
!= NULL
);
1134 if ((isc_mem_debugging
& (ISC_MEM_DEBUGSIZE
|ISC_MEM_DEBUGCTX
)) != 0) {
1135 if ((isc_mem_debugging
& ISC_MEM_DEBUGSIZE
) != 0) {
1136 si
= &(((size_info
*)ptr
)[-1]);
1137 oldsize
= si
->u
.size
- ALIGNMENT_SIZE
;
1138 if ((isc_mem_debugging
& ISC_MEM_DEBUGCTX
) != 0)
1139 oldsize
-= ALIGNMENT_SIZE
;
1140 INSIST(oldsize
== size
);
1142 isc__mem_free(ctx
, ptr FLARG_PASS
);
1146 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
1147 MCTXLOCK(ctx
, &ctx
->lock
);
1148 mem_putunlocked(ctx
, ptr
, size
);
1150 mem_put(ctx
, ptr
, size
);
1151 MCTXLOCK(ctx
, &ctx
->lock
);
1152 mem_putstats(ctx
, ptr
, size
);
1155 DELETE_TRACE(ctx
, ptr
, size
, file
, line
);
1158 * The check against ctx->lo_water == 0 is for the condition
1159 * when the context was pushed over hi_water but then had
1160 * isc_mem_setwater() called with 0 for hi_water and lo_water.
1162 if (ctx
->hi_called
&&
1163 (ctx
->inuse
< ctx
->lo_water
|| ctx
->lo_water
== 0U)) {
1164 if (ctx
->water
!= NULL
)
1165 call_water
= ISC_TRUE
;
1167 MCTXUNLOCK(ctx
, &ctx
->lock
);
1170 (ctx
->water
)(ctx
->water_arg
, ISC_MEM_LOWATER
);
1174 isc_mem_waterack(isc_mem_t
*ctx
, int flag
) {
1175 REQUIRE(VALID_CONTEXT(ctx
));
1177 MCTXLOCK(ctx
, &ctx
->lock
);
1178 if (flag
== ISC_MEM_LOWATER
)
1179 ctx
->hi_called
= ISC_FALSE
;
1180 else if (flag
== ISC_MEM_HIWATER
)
1181 ctx
->hi_called
= ISC_TRUE
;
1182 MCTXUNLOCK(ctx
, &ctx
->lock
);
1185 #if ISC_MEM_TRACKLINES
1187 print_active(isc_mem_t
*mctx
, FILE *out
) {
1188 if (mctx
->debuglist
!= NULL
) {
1192 isc_boolean_t found
;
1194 fprintf(out
, "%s", isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1196 "Dump of all outstanding "
1197 "memory allocations:\n"));
1199 format
= isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1200 ISC_MSG_PTRFILELINE
,
1201 "\tptr %p size %u file %s line %u\n");
1202 for (i
= 0; i
<= mctx
->max_size
; i
++) {
1203 dl
= ISC_LIST_HEAD(mctx
->debuglist
[i
]);
1208 while (dl
!= NULL
) {
1209 for (j
= 0; j
< DEBUGLIST_COUNT
; j
++)
1210 if (dl
->ptr
[j
] != NULL
)
1211 fprintf(out
, format
,
1216 dl
= ISC_LIST_NEXT(dl
, link
);
1220 fprintf(out
, "%s", isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1221 ISC_MSG_NONE
, "\tNone.\n"));
1227 * Print the stats[] on the stream "out" with suitable formatting.
1230 isc_mem_stats(isc_mem_t
*ctx
, FILE *out
) {
1232 const struct stats
*s
;
1233 const isc_mempool_t
*pool
;
1235 REQUIRE(VALID_CONTEXT(ctx
));
1236 MCTXLOCK(ctx
, &ctx
->lock
);
1238 for (i
= 0; i
<= ctx
->max_size
; i
++) {
1241 if (s
->totalgets
== 0U && s
->gets
== 0U)
1243 fprintf(out
, "%s%5lu: %11lu gets, %11lu rem",
1244 (i
== ctx
->max_size
) ? ">=" : " ",
1245 (unsigned long) i
, s
->totalgets
, s
->gets
);
1246 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0 &&
1247 (s
->blocks
!= 0U || s
->freefrags
!= 0U))
1248 fprintf(out
, " (%lu bl, %lu ff)",
1249 s
->blocks
, s
->freefrags
);
1254 * Note that since a pool can be locked now, these stats might be
1255 * somewhat off if the pool is in active use at the time the stats
1256 * are dumped. The link fields are protected by the isc_mem_t's
1257 * lock, however, so walking this list and extracting integers from
1258 * stats fields is always safe.
1260 pool
= ISC_LIST_HEAD(ctx
->pools
);
1262 fprintf(out
, "%s", isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1264 "[Pool statistics]\n"));
1265 fprintf(out
, "%15s %10s %10s %10s %10s %10s %10s %10s %1s\n",
1266 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1267 ISC_MSG_POOLNAME
, "name"),
1268 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1269 ISC_MSG_POOLSIZE
, "size"),
1270 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1271 ISC_MSG_POOLMAXALLOC
, "maxalloc"),
1272 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1273 ISC_MSG_POOLALLOCATED
, "allocated"),
1274 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1275 ISC_MSG_POOLFREECOUNT
, "freecount"),
1276 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1277 ISC_MSG_POOLFREEMAX
, "freemax"),
1278 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1279 ISC_MSG_POOLFILLCOUNT
, "fillcount"),
1280 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1281 ISC_MSG_POOLGETS
, "gets"),
1284 while (pool
!= NULL
) {
1285 fprintf(out
, "%15s %10lu %10u %10u %10u %10u %10u %10u %s\n",
1286 pool
->name
, (unsigned long) pool
->size
, pool
->maxalloc
,
1287 pool
->allocated
, pool
->freecount
, pool
->freemax
,
1288 pool
->fillcount
, pool
->gets
,
1289 (pool
->lock
== NULL
? "N" : "Y"));
1290 pool
= ISC_LIST_NEXT(pool
, link
);
1293 #if ISC_MEM_TRACKLINES
1294 print_active(ctx
, out
);
1297 MCTXUNLOCK(ctx
, &ctx
->lock
);
1301 * Replacements for malloc() and free() -- they implicitly remember the
1302 * size of the object allocated (with some additional overhead).
1306 isc__mem_allocateunlocked(isc_mem_t
*ctx
, size_t size
) {
1309 size
+= ALIGNMENT_SIZE
;
1310 if ((isc_mem_debugging
& ISC_MEM_DEBUGCTX
) != 0)
1311 size
+= ALIGNMENT_SIZE
;
1313 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0)
1314 si
= mem_getunlocked(ctx
, size
);
1316 si
= mem_get(ctx
, size
);
1320 if ((isc_mem_debugging
& ISC_MEM_DEBUGCTX
) != 0) {
1329 isc__mem_allocate(isc_mem_t
*ctx
, size_t size FLARG
) {
1331 isc_boolean_t call_water
= ISC_FALSE
;
1333 REQUIRE(VALID_CONTEXT(ctx
));
1335 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
1336 MCTXLOCK(ctx
, &ctx
->lock
);
1337 si
= isc__mem_allocateunlocked(ctx
, size
);
1339 si
= isc__mem_allocateunlocked(ctx
, size
);
1340 MCTXLOCK(ctx
, &ctx
->lock
);
1342 mem_getstats(ctx
, si
[-1].u
.size
);
1345 #if ISC_MEM_TRACKLINES
1346 ADD_TRACE(ctx
, si
, si
[-1].u
.size
, file
, line
);
1348 if (ctx
->hi_water
!= 0U && !ctx
->hi_called
&&
1349 ctx
->inuse
> ctx
->hi_water
) {
1350 ctx
->hi_called
= ISC_TRUE
;
1351 call_water
= ISC_TRUE
;
1353 if (ctx
->inuse
> ctx
->maxinuse
) {
1354 ctx
->maxinuse
= ctx
->inuse
;
1355 if (ctx
->hi_water
!= 0U && ctx
->inuse
> ctx
->hi_water
&&
1356 (isc_mem_debugging
& ISC_MEM_DEBUGUSAGE
) != 0)
1357 fprintf(stderr
, "maxinuse = %lu\n",
1358 (unsigned long)ctx
->inuse
);
1360 MCTXUNLOCK(ctx
, &ctx
->lock
);
1363 (ctx
->water
)(ctx
->water_arg
, ISC_MEM_HIWATER
);
1369 isc__mem_reallocate(isc_mem_t
*ctx
, void *ptr
, size_t size FLARG
) {
1370 void *new_ptr
= NULL
;
1371 size_t oldsize
, copysize
;
1373 REQUIRE(VALID_CONTEXT(ctx
));
1376 * This function emulates the realloc(3) standard library function:
1377 * - if size > 0, allocate new memory; and if ptr is non NULL, copy
1378 * as much of the old contents to the new buffer and free the old one.
1379 * Note that when allocation fails the original pointer is intact;
1380 * the caller must free it.
1381 * - if size is 0 and ptr is non NULL, simply free the given ptr.
1382 * - this function returns:
1383 * pointer to the newly allocated memory, or
1384 * NULL if allocation fails or doesn't happen.
1387 new_ptr
= isc__mem_allocate(ctx
, size FLARG_PASS
);
1388 if (new_ptr
!= NULL
&& ptr
!= NULL
) {
1389 oldsize
= (((size_info
*)ptr
)[-1]).u
.size
;
1390 INSIST(oldsize
>= ALIGNMENT_SIZE
);
1391 oldsize
-= ALIGNMENT_SIZE
;
1392 copysize
= oldsize
> size
? size
: oldsize
;
1393 memcpy(new_ptr
, ptr
, copysize
);
1394 isc__mem_free(ctx
, ptr FLARG_PASS
);
1396 } else if (ptr
!= NULL
)
1397 isc__mem_free(ctx
, ptr FLARG_PASS
);
1403 isc__mem_free(isc_mem_t
*ctx
, void *ptr FLARG
) {
1406 isc_boolean_t call_water
= ISC_FALSE
;
1408 REQUIRE(VALID_CONTEXT(ctx
));
1409 REQUIRE(ptr
!= NULL
);
1411 if ((isc_mem_debugging
& ISC_MEM_DEBUGCTX
) != 0) {
1412 si
= &(((size_info
*)ptr
)[-2]);
1413 REQUIRE(si
->u
.ctx
== ctx
);
1414 size
= si
[1].u
.size
;
1416 si
= &(((size_info
*)ptr
)[-1]);
1420 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
1421 MCTXLOCK(ctx
, &ctx
->lock
);
1422 mem_putunlocked(ctx
, si
, size
);
1424 mem_put(ctx
, si
, size
);
1425 MCTXLOCK(ctx
, &ctx
->lock
);
1426 mem_putstats(ctx
, si
, size
);
1429 DELETE_TRACE(ctx
, ptr
, size
, file
, line
);
1432 * The check against ctx->lo_water == 0 is for the condition
1433 * when the context was pushed over hi_water but then had
1434 * isc_mem_setwater() called with 0 for hi_water and lo_water.
1436 if (ctx
->hi_called
&&
1437 (ctx
->inuse
< ctx
->lo_water
|| ctx
->lo_water
== 0U)) {
1438 ctx
->hi_called
= ISC_FALSE
;
1440 if (ctx
->water
!= NULL
)
1441 call_water
= ISC_TRUE
;
1443 MCTXUNLOCK(ctx
, &ctx
->lock
);
1446 (ctx
->water
)(ctx
->water_arg
, ISC_MEM_LOWATER
);
1451 * Other useful things.
1455 isc__mem_strdup(isc_mem_t
*mctx
, const char *s FLARG
) {
1459 REQUIRE(VALID_CONTEXT(mctx
));
1464 ns
= isc__mem_allocate(mctx
, len
+ 1 FLARG_PASS
);
1467 strncpy(ns
, s
, len
+ 1);
1473 isc_mem_setdestroycheck(isc_mem_t
*ctx
, isc_boolean_t flag
) {
1474 REQUIRE(VALID_CONTEXT(ctx
));
1475 MCTXLOCK(ctx
, &ctx
->lock
);
1477 ctx
->checkfree
= flag
;
1479 MCTXUNLOCK(ctx
, &ctx
->lock
);
1487 isc_mem_setquota(isc_mem_t
*ctx
, size_t quota
) {
1488 REQUIRE(VALID_CONTEXT(ctx
));
1489 MCTXLOCK(ctx
, &ctx
->lock
);
1493 MCTXUNLOCK(ctx
, &ctx
->lock
);
1497 isc_mem_getquota(isc_mem_t
*ctx
) {
1500 REQUIRE(VALID_CONTEXT(ctx
));
1501 MCTXLOCK(ctx
, &ctx
->lock
);
1505 MCTXUNLOCK(ctx
, &ctx
->lock
);
1511 isc_mem_inuse(isc_mem_t
*ctx
) {
1514 REQUIRE(VALID_CONTEXT(ctx
));
1515 MCTXLOCK(ctx
, &ctx
->lock
);
1519 MCTXUNLOCK(ctx
, &ctx
->lock
);
1525 isc_mem_setwater(isc_mem_t
*ctx
, isc_mem_water_t water
, void *water_arg
,
1526 size_t hiwater
, size_t lowater
)
1528 isc_boolean_t callwater
= ISC_FALSE
;
1529 isc_mem_water_t oldwater
;
1532 REQUIRE(VALID_CONTEXT(ctx
));
1533 REQUIRE(hiwater
>= lowater
);
1535 MCTXLOCK(ctx
, &ctx
->lock
);
1536 oldwater
= ctx
->water
;
1537 oldwater_arg
= ctx
->water_arg
;
1538 if (water
== NULL
) {
1539 callwater
= ctx
->hi_called
;
1541 ctx
->water_arg
= NULL
;
1544 ctx
->hi_called
= ISC_FALSE
;
1546 if (ctx
->hi_called
&&
1547 (ctx
->water
!= water
|| ctx
->water_arg
!= water_arg
||
1548 ctx
->inuse
< lowater
|| lowater
== 0U))
1549 callwater
= ISC_TRUE
;
1551 ctx
->water_arg
= water_arg
;
1552 ctx
->hi_water
= hiwater
;
1553 ctx
->lo_water
= lowater
;
1554 ctx
->hi_called
= ISC_FALSE
;
1556 MCTXUNLOCK(ctx
, &ctx
->lock
);
1558 if (callwater
&& oldwater
!= NULL
)
1559 (oldwater
)(oldwater_arg
, ISC_MEM_LOWATER
);
1563 isc_mem_setname(isc_mem_t
*ctx
, const char *name
, void *tag
) {
1564 REQUIRE(VALID_CONTEXT(ctx
));
1567 memset(ctx
->name
, 0, sizeof(ctx
->name
));
1568 strncpy(ctx
->name
, name
, sizeof(ctx
->name
) - 1);
1574 isc_mem_getname(isc_mem_t
*ctx
) {
1575 REQUIRE(VALID_CONTEXT(ctx
));
1581 isc_mem_gettag(isc_mem_t
*ctx
) {
1582 REQUIRE(VALID_CONTEXT(ctx
));
1592 isc_mempool_create(isc_mem_t
*mctx
, size_t size
, isc_mempool_t
**mpctxp
) {
1593 isc_mempool_t
*mpctx
;
1595 REQUIRE(VALID_CONTEXT(mctx
));
1597 REQUIRE(mpctxp
!= NULL
&& *mpctxp
== NULL
);
1600 * Allocate space for this pool, initialize values, and if all works
1601 * well, attach to the memory context.
1603 mpctx
= isc_mem_get(mctx
, sizeof(isc_mempool_t
));
1605 return (ISC_R_NOMEMORY
);
1607 mpctx
->magic
= MEMPOOL_MAGIC
;
1611 mpctx
->maxalloc
= UINT_MAX
;
1612 mpctx
->allocated
= 0;
1613 mpctx
->freecount
= 0;
1615 mpctx
->fillcount
= 1;
1617 #if ISC_MEMPOOL_NAMES
1620 mpctx
->items
= NULL
;
1624 MCTXLOCK(mctx
, &mctx
->lock
);
1625 ISC_LIST_INITANDAPPEND(mctx
->pools
, mpctx
, link
);
1627 MCTXUNLOCK(mctx
, &mctx
->lock
);
1629 return (ISC_R_SUCCESS
);
1633 isc_mempool_setname(isc_mempool_t
*mpctx
, const char *name
) {
1634 REQUIRE(name
!= NULL
);
1636 #if ISC_MEMPOOL_NAMES
1637 if (mpctx
->lock
!= NULL
)
1640 strncpy(mpctx
->name
, name
, sizeof(mpctx
->name
) - 1);
1641 mpctx
->name
[sizeof(mpctx
->name
) - 1] = '\0';
1643 if (mpctx
->lock
!= NULL
)
1644 UNLOCK(mpctx
->lock
);
1652 isc_mempool_destroy(isc_mempool_t
**mpctxp
) {
1653 isc_mempool_t
*mpctx
;
1658 REQUIRE(mpctxp
!= NULL
);
1660 REQUIRE(VALID_MEMPOOL(mpctx
));
1661 #if ISC_MEMPOOL_NAMES
1662 if (mpctx
->allocated
> 0)
1663 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
1664 "isc_mempool_destroy(): mempool %s "
1668 REQUIRE(mpctx
->allocated
== 0);
1678 * Return any items on the free list
1680 MCTXLOCK(mctx
, &mctx
->lock
);
1681 while (mpctx
->items
!= NULL
) {
1682 INSIST(mpctx
->freecount
> 0);
1684 item
= mpctx
->items
;
1685 mpctx
->items
= item
->next
;
1687 if ((mctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
1688 mem_putunlocked(mctx
, item
, mpctx
->size
);
1690 mem_put(mctx
, item
, mpctx
->size
);
1691 mem_putstats(mctx
, item
, mpctx
->size
);
1694 MCTXUNLOCK(mctx
, &mctx
->lock
);
1697 * Remove our linked list entry from the memory context.
1699 MCTXLOCK(mctx
, &mctx
->lock
);
1700 ISC_LIST_UNLINK(mctx
->pools
, mpctx
, link
);
1702 MCTXUNLOCK(mctx
, &mctx
->lock
);
1706 isc_mem_put(mpctx
->mctx
, mpctx
, sizeof(isc_mempool_t
));
1715 isc_mempool_associatelock(isc_mempool_t
*mpctx
, isc_mutex_t
*lock
) {
1716 REQUIRE(VALID_MEMPOOL(mpctx
));
1717 REQUIRE(mpctx
->lock
== NULL
);
1718 REQUIRE(lock
!= NULL
);
1724 isc__mempool_get(isc_mempool_t
*mpctx FLARG
) {
1729 REQUIRE(VALID_MEMPOOL(mpctx
));
1733 if (mpctx
->lock
!= NULL
)
1737 * Don't let the caller go over quota
1739 if (mpctx
->allocated
>= mpctx
->maxalloc
) {
1745 * if we have a free list item, return the first here
1747 item
= mpctx
->items
;
1749 mpctx
->items
= item
->next
;
1750 INSIST(mpctx
->freecount
> 0);
1758 * We need to dip into the well. Lock the memory context here and
1759 * fill up our free list.
1761 MCTXLOCK(mctx
, &mctx
->lock
);
1762 for (i
= 0; i
< mpctx
->fillcount
; i
++) {
1763 if ((mctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
1764 item
= mem_getunlocked(mctx
, mpctx
->size
);
1766 item
= mem_get(mctx
, mpctx
->size
);
1768 mem_getstats(mctx
, mpctx
->size
);
1772 item
->next
= mpctx
->items
;
1773 mpctx
->items
= item
;
1776 MCTXUNLOCK(mctx
, &mctx
->lock
);
1779 * If we didn't get any items, return NULL.
1781 item
= mpctx
->items
;
1785 mpctx
->items
= item
->next
;
1791 if (mpctx
->lock
!= NULL
)
1792 UNLOCK(mpctx
->lock
);
1794 #if ISC_MEM_TRACKLINES
1796 MCTXLOCK(mctx
, &mctx
->lock
);
1797 ADD_TRACE(mctx
, item
, mpctx
->size
, file
, line
);
1798 MCTXUNLOCK(mctx
, &mctx
->lock
);
1800 #endif /* ISC_MEM_TRACKLINES */
1806 isc__mempool_put(isc_mempool_t
*mpctx
, void *mem FLARG
) {
1810 REQUIRE(VALID_MEMPOOL(mpctx
));
1811 REQUIRE(mem
!= NULL
);
1815 if (mpctx
->lock
!= NULL
)
1818 INSIST(mpctx
->allocated
> 0);
1821 #if ISC_MEM_TRACKLINES
1822 MCTXLOCK(mctx
, &mctx
->lock
);
1823 DELETE_TRACE(mctx
, mem
, mpctx
->size
, file
, line
);
1824 MCTXUNLOCK(mctx
, &mctx
->lock
);
1825 #endif /* ISC_MEM_TRACKLINES */
1828 * If our free list is full, return this to the mctx directly.
1830 if (mpctx
->freecount
>= mpctx
->freemax
) {
1831 if ((mctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
1832 MCTXLOCK(mctx
, &mctx
->lock
);
1833 mem_putunlocked(mctx
, mem
, mpctx
->size
);
1834 MCTXUNLOCK(mctx
, &mctx
->lock
);
1836 mem_put(mctx
, mem
, mpctx
->size
);
1837 MCTXLOCK(mctx
, &mctx
->lock
);
1838 mem_putstats(mctx
, mem
, mpctx
->size
);
1839 MCTXUNLOCK(mctx
, &mctx
->lock
);
1841 if (mpctx
->lock
!= NULL
)
1842 UNLOCK(mpctx
->lock
);
1847 * Otherwise, attach it to our free list and bump the counter.
1850 item
= (element
*)mem
;
1851 item
->next
= mpctx
->items
;
1852 mpctx
->items
= item
;
1854 if (mpctx
->lock
!= NULL
)
1855 UNLOCK(mpctx
->lock
);
1863 isc_mempool_setfreemax(isc_mempool_t
*mpctx
, unsigned int limit
) {
1864 REQUIRE(VALID_MEMPOOL(mpctx
));
1866 if (mpctx
->lock
!= NULL
)
1869 mpctx
->freemax
= limit
;
1871 if (mpctx
->lock
!= NULL
)
1872 UNLOCK(mpctx
->lock
);
1876 isc_mempool_getfreemax(isc_mempool_t
*mpctx
) {
1877 unsigned int freemax
;
1879 REQUIRE(VALID_MEMPOOL(mpctx
));
1881 if (mpctx
->lock
!= NULL
)
1884 freemax
= mpctx
->freemax
;
1886 if (mpctx
->lock
!= NULL
)
1887 UNLOCK(mpctx
->lock
);
1893 isc_mempool_getfreecount(isc_mempool_t
*mpctx
) {
1894 unsigned int freecount
;
1896 REQUIRE(VALID_MEMPOOL(mpctx
));
1898 if (mpctx
->lock
!= NULL
)
1901 freecount
= mpctx
->freecount
;
1903 if (mpctx
->lock
!= NULL
)
1904 UNLOCK(mpctx
->lock
);
1910 isc_mempool_setmaxalloc(isc_mempool_t
*mpctx
, unsigned int limit
) {
1913 REQUIRE(VALID_MEMPOOL(mpctx
));
1915 if (mpctx
->lock
!= NULL
)
1918 mpctx
->maxalloc
= limit
;
1920 if (mpctx
->lock
!= NULL
)
1921 UNLOCK(mpctx
->lock
);
1925 isc_mempool_getmaxalloc(isc_mempool_t
*mpctx
) {
1926 unsigned int maxalloc
;
1928 REQUIRE(VALID_MEMPOOL(mpctx
));
1930 if (mpctx
->lock
!= NULL
)
1933 maxalloc
= mpctx
->maxalloc
;
1935 if (mpctx
->lock
!= NULL
)
1936 UNLOCK(mpctx
->lock
);
1942 isc_mempool_getallocated(isc_mempool_t
*mpctx
) {
1943 unsigned int allocated
;
1945 REQUIRE(VALID_MEMPOOL(mpctx
));
1947 if (mpctx
->lock
!= NULL
)
1950 allocated
= mpctx
->allocated
;
1952 if (mpctx
->lock
!= NULL
)
1953 UNLOCK(mpctx
->lock
);
1959 isc_mempool_setfillcount(isc_mempool_t
*mpctx
, unsigned int limit
) {
1961 REQUIRE(VALID_MEMPOOL(mpctx
));
1963 if (mpctx
->lock
!= NULL
)
1966 mpctx
->fillcount
= limit
;
1968 if (mpctx
->lock
!= NULL
)
1969 UNLOCK(mpctx
->lock
);
1973 isc_mempool_getfillcount(isc_mempool_t
*mpctx
) {
1974 unsigned int fillcount
;
1976 REQUIRE(VALID_MEMPOOL(mpctx
));
1978 if (mpctx
->lock
!= NULL
)
1981 fillcount
= mpctx
->fillcount
;
1983 if (mpctx
->lock
!= NULL
)
1984 UNLOCK(mpctx
->lock
);
1990 isc_mem_printactive(isc_mem_t
*ctx
, FILE *file
) {
1992 REQUIRE(VALID_CONTEXT(ctx
));
1993 REQUIRE(file
!= NULL
);
1995 #if !ISC_MEM_TRACKLINES
1999 print_active(ctx
, file
);
2004 isc_mem_printallactive(FILE *file
) {
2005 #if !ISC_MEM_TRACKLINES
2010 RUNTIME_CHECK(isc_once_do(&once
, initialize_action
) == ISC_R_SUCCESS
);
2013 for (ctx
= ISC_LIST_HEAD(contexts
);
2015 ctx
= ISC_LIST_NEXT(ctx
, link
)) {
2016 fprintf(file
, "context: %p\n", ctx
);
2017 print_active(ctx
, file
);
2024 isc_mem_checkdestroyed(FILE *file
) {
2026 RUNTIME_CHECK(isc_once_do(&once
, initialize_action
) == ISC_R_SUCCESS
);
2029 if (!ISC_LIST_EMPTY(contexts
)) {
2030 #if ISC_MEM_TRACKLINES
2033 for (ctx
= ISC_LIST_HEAD(contexts
);
2035 ctx
= ISC_LIST_NEXT(ctx
, link
)) {
2036 fprintf(file
, "context: %p\n", ctx
);
2037 print_active(ctx
, file
);
2048 typedef struct summarystat
{
2051 isc_uint64_t blocksize
;
2052 isc_uint64_t contextsize
;
2056 renderctx(isc_mem_t
*ctx
, summarystat_t
*summary
, xmlTextWriterPtr writer
) {
2057 REQUIRE(VALID_CONTEXT(ctx
));
2059 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"context");
2061 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"id");
2062 xmlTextWriterWriteFormatString(writer
, "%p", ctx
);
2063 xmlTextWriterEndElement(writer
); /* id */
2065 if (ctx
->name
[0] != 0) {
2066 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"name");
2067 xmlTextWriterWriteFormatString(writer
, "%s", ctx
->name
);
2068 xmlTextWriterEndElement(writer
); /* name */
2071 REQUIRE(VALID_CONTEXT(ctx
));
2072 MCTXLOCK(ctx
, &ctx
->lock
);
2074 summary
->contextsize
+= sizeof(*ctx
) +
2075 (ctx
->max_size
+ 1) * sizeof(struct stats
) +
2076 ctx
->max_size
* sizeof(element
*) +
2077 ctx
->basic_table_count
* sizeof(char *);
2078 #if ISC_MEM_TRACKLINES
2079 if (ctx
->debuglist
!= NULL
) {
2080 summary
->contextsize
+=
2081 (ctx
->max_size
+ 1) * sizeof(debuglist_t
) +
2082 ctx
->debuglistcnt
* sizeof(debuglink_t
);
2085 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"references");
2086 xmlTextWriterWriteFormatString(writer
, "%d", ctx
->references
);
2087 xmlTextWriterEndElement(writer
); /* references */
2089 summary
->total
+= ctx
->total
;
2090 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"total");
2091 xmlTextWriterWriteFormatString(writer
, "%" ISC_PRINT_QUADFORMAT
"u",
2092 (isc_uint64_t
)ctx
->total
);
2093 xmlTextWriterEndElement(writer
); /* total */
2095 summary
->inuse
+= ctx
->inuse
;
2096 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"inuse");
2097 xmlTextWriterWriteFormatString(writer
, "%" ISC_PRINT_QUADFORMAT
"u",
2098 (isc_uint64_t
)ctx
->inuse
);
2099 xmlTextWriterEndElement(writer
); /* inuse */
2101 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"maxinuse");
2102 xmlTextWriterWriteFormatString(writer
, "%" ISC_PRINT_QUADFORMAT
"u",
2103 (isc_uint64_t
)ctx
->maxinuse
);
2104 xmlTextWriterEndElement(writer
); /* maxinuse */
2106 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"blocksize");
2107 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
2108 summary
->blocksize
+= ctx
->basic_table_count
*
2109 NUM_BASIC_BLOCKS
* ctx
->mem_target
;
2110 xmlTextWriterWriteFormatString(writer
,
2111 "%" ISC_PRINT_QUADFORMAT
"u",
2113 ctx
->basic_table_count
*
2117 xmlTextWriterWriteFormatString(writer
, "%s", "-");
2118 xmlTextWriterEndElement(writer
); /* blocksize */
2120 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"pools");
2121 xmlTextWriterWriteFormatString(writer
, "%u", ctx
->poolcnt
);
2122 xmlTextWriterEndElement(writer
); /* pools */
2123 summary
->contextsize
+= ctx
->poolcnt
* sizeof(isc_mempool_t
);
2125 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"hiwater");
2126 xmlTextWriterWriteFormatString(writer
, "%" ISC_PRINT_QUADFORMAT
"u",
2127 (isc_uint64_t
)ctx
->hi_water
);
2128 xmlTextWriterEndElement(writer
); /* hiwater */
2130 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"lowater");
2131 xmlTextWriterWriteFormatString(writer
, "%" ISC_PRINT_QUADFORMAT
"u",
2132 (isc_uint64_t
)ctx
->lo_water
);
2133 xmlTextWriterEndElement(writer
); /* lowater */
2135 MCTXUNLOCK(ctx
, &ctx
->lock
);
2137 xmlTextWriterEndElement(writer
); /* context */
2141 isc_mem_renderxml(xmlTextWriterPtr writer
) {
2143 summarystat_t summary
;
2146 memset(&summary
, 0, sizeof(summary
));
2148 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"contexts");
2150 RUNTIME_CHECK(isc_once_do(&once
, initialize_action
) == ISC_R_SUCCESS
);
2154 for (ctx
= ISC_LIST_HEAD(contexts
);
2156 ctx
= ISC_LIST_NEXT(ctx
, link
)) {
2157 renderctx(ctx
, &summary
, writer
);
2161 xmlTextWriterEndElement(writer
); /* contexts */
2163 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"summary");
2165 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"TotalUse");
2166 xmlTextWriterWriteFormatString(writer
, "%" ISC_PRINT_QUADFORMAT
"u",
2168 xmlTextWriterEndElement(writer
); /* TotalUse */
2170 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"InUse");
2171 xmlTextWriterWriteFormatString(writer
, "%" ISC_PRINT_QUADFORMAT
"u",
2173 xmlTextWriterEndElement(writer
); /* InUse */
2175 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"BlockSize");
2176 xmlTextWriterWriteFormatString(writer
, "%" ISC_PRINT_QUADFORMAT
"u",
2178 xmlTextWriterEndElement(writer
); /* BlockSize */
2180 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"ContextSize");
2181 xmlTextWriterWriteFormatString(writer
, "%" ISC_PRINT_QUADFORMAT
"u",
2182 summary
.contextsize
);
2183 xmlTextWriterEndElement(writer
); /* ContextSize */
2185 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"Lost");
2186 xmlTextWriterWriteFormatString(writer
, "%" ISC_PRINT_QUADFORMAT
"u",
2188 xmlTextWriterEndElement(writer
); /* Lost */
2190 xmlTextWriterEndElement(writer
); /* summary */
2193 #endif /* HAVE_LIBXML2 */