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.153 2009/09/02 23:43:54 each 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 typedef struct isc__mem isc__mem_t
;
66 typedef struct isc__mempool isc__mempool_t
;
68 #if ISC_MEM_TRACKLINES
69 typedef struct debuglink debuglink_t
;
71 ISC_LINK(debuglink_t
) link
;
72 const void *ptr
[DEBUGLIST_COUNT
];
73 unsigned int size
[DEBUGLIST_COUNT
];
74 const char *file
[DEBUGLIST_COUNT
];
75 unsigned int line
[DEBUGLIST_COUNT
];
79 #define FLARG_PASS , file, line
80 #define FLARG , const char *file, int line
86 typedef struct element element
;
93 * This structure must be ALIGNMENT_SIZE bytes.
98 char bytes
[ALIGNMENT_SIZE
];
104 unsigned long totalgets
;
105 unsigned long blocks
;
106 unsigned long freefrags
;
109 #define MEM_MAGIC ISC_MAGIC('M', 'e', 'm', 'C')
110 #define VALID_CONTEXT(c) ISC_MAGIC_VALID(c, MEM_MAGIC)
112 #if ISC_MEM_TRACKLINES
113 typedef ISC_LIST(debuglink_t
) debuglist_t
;
116 /* List of all active memory contexts. */
118 static ISC_LIST(isc__mem_t
) contexts
;
119 static isc_once_t once
= ISC_ONCE_INIT
;
120 static isc_mutex_t lock
;
123 * Total size of lost memory due to a bug of external library.
124 * Locked by the global lock.
126 static isc_uint64_t totallost
;
130 isc_ondestroy_t ondestroy
;
133 isc_memalloc_t memalloc
;
134 isc_memfree_t memfree
;
137 isc_boolean_t checkfree
;
138 struct stats
* stats
;
139 unsigned int references
;
148 isc_boolean_t hi_called
;
149 isc_mem_water_t water
;
151 ISC_LIST(isc__mempool_t
) pools
;
152 unsigned int poolcnt
;
154 /* ISC_MEMFLAG_INTERNAL */
156 element
** freelists
;
157 element
* basic_blocks
;
158 unsigned char ** basic_table
;
159 unsigned int basic_table_count
;
160 unsigned int basic_table_size
;
161 unsigned char * lowest
;
162 unsigned char * highest
;
164 #if ISC_MEM_TRACKLINES
165 debuglist_t
* debuglist
;
166 unsigned int debuglistcnt
;
169 unsigned int memalloc_failures
;
170 ISC_LINK(isc__mem_t
) link
;
173 #define MEMPOOL_MAGIC ISC_MAGIC('M', 'E', 'M', 'p')
174 #define VALID_MEMPOOL(c) ISC_MAGIC_VALID(c, MEMPOOL_MAGIC)
176 struct isc__mempool
{
177 /* always unlocked */
178 isc_mempool_t common
; /*%< common header of mempool's */
179 isc_mutex_t
*lock
; /*%< optional lock */
180 isc__mem_t
*mctx
; /*%< our memory context */
181 /*%< locked via the memory context's lock */
182 ISC_LINK(isc__mempool_t
) link
; /*%< next pool in this mem context */
183 /*%< optionally locked from here down */
184 element
*items
; /*%< low water item list */
185 size_t size
; /*%< size of each item on this pool */
186 unsigned int maxalloc
; /*%< max number of items allowed */
187 unsigned int allocated
; /*%< # of items currently given out */
188 unsigned int freecount
; /*%< # of items on reserved list */
189 unsigned int freemax
; /*%< # of items allowed on free list */
190 unsigned int fillcount
; /*%< # of items to fetch on each fill */
192 unsigned int gets
; /*%< # of requests to this pool */
193 /*%< Debugging only. */
194 #if ISC_MEMPOOL_NAMES
195 char name
[16]; /*%< printed name in stats reports */
200 * Private Inline-able.
203 #if ! ISC_MEM_TRACKLINES
204 #define ADD_TRACE(a, b, c, d, e)
205 #define DELETE_TRACE(a, b, c, d, e)
207 #define ADD_TRACE(a, b, c, d, e) \
209 if ((isc_mem_debugging & (ISC_MEM_DEBUGTRACE | \
210 ISC_MEM_DEBUGRECORD)) != 0 && \
212 add_trace_entry(a, b, c, d, e); \
214 #define DELETE_TRACE(a, b, c, d, e) delete_trace_entry(a, b, c, d, e)
217 print_active(isc__mem_t
*ctx
, FILE *out
);
220 * The following can be either static or public, depending on build environment.
224 #define ISC_MEMFUNC_SCOPE
226 #define ISC_MEMFUNC_SCOPE static
229 ISC_MEMFUNC_SCOPE isc_result_t
230 isc__mem_createx(size_t init_max_size
, size_t target_size
,
231 isc_memalloc_t memalloc
, isc_memfree_t memfree
, void *arg
,
233 ISC_MEMFUNC_SCOPE isc_result_t
234 isc__mem_createx2(size_t init_max_size
, size_t target_size
,
235 isc_memalloc_t memalloc
, isc_memfree_t memfree
, void *arg
,
236 isc_mem_t
**ctxp
, unsigned int flags
);
237 ISC_MEMFUNC_SCOPE isc_result_t
238 isc__mem_create(size_t init_max_size
, size_t target_size
, isc_mem_t
**ctxp
);
239 ISC_MEMFUNC_SCOPE isc_result_t
240 isc__mem_create2(size_t init_max_size
, size_t target_size
,
241 isc_mem_t
**ctxp
, unsigned int flags
);
242 ISC_MEMFUNC_SCOPE
void
243 isc__mem_attach(isc_mem_t
*source
, isc_mem_t
**targetp
);
244 ISC_MEMFUNC_SCOPE
void
245 isc__mem_detach(isc_mem_t
**ctxp
);
246 ISC_MEMFUNC_SCOPE
void
247 isc___mem_putanddetach(isc_mem_t
**ctxp
, void *ptr
, size_t size FLARG
);
248 ISC_MEMFUNC_SCOPE
void
249 isc__mem_destroy(isc_mem_t
**ctxp
);
250 ISC_MEMFUNC_SCOPE isc_result_t
251 isc__mem_ondestroy(isc_mem_t
*ctx
, isc_task_t
*task
, isc_event_t
**event
);
252 ISC_MEMFUNC_SCOPE
void *
253 isc___mem_get(isc_mem_t
*ctx
, size_t size FLARG
);
254 ISC_MEMFUNC_SCOPE
void
255 isc___mem_put(isc_mem_t
*ctx
, void *ptr
, size_t size FLARG
);
256 ISC_MEMFUNC_SCOPE
void
257 isc__mem_stats(isc_mem_t
*ctx
, FILE *out
);
258 ISC_MEMFUNC_SCOPE
void *
259 isc___mem_allocate(isc_mem_t
*ctx
, size_t size FLARG
);
260 ISC_MEMFUNC_SCOPE
void *
261 isc___mem_reallocate(isc_mem_t
*ctx
, void *ptr
, size_t size FLARG
);
262 ISC_MEMFUNC_SCOPE
void
263 isc___mem_free(isc_mem_t
*ctx
, void *ptr FLARG
);
264 ISC_MEMFUNC_SCOPE
char *
265 isc___mem_strdup(isc_mem_t
*mctx
, const char *s FLARG
);
266 ISC_MEMFUNC_SCOPE
void
267 isc__mem_setdestroycheck(isc_mem_t
*ctx
, isc_boolean_t flag
);
268 ISC_MEMFUNC_SCOPE
void
269 isc__mem_setquota(isc_mem_t
*ctx
, size_t quota
);
270 ISC_MEMFUNC_SCOPE
size_t
271 isc__mem_getquota(isc_mem_t
*ctx
);
272 ISC_MEMFUNC_SCOPE
size_t
273 isc__mem_inuse(isc_mem_t
*ctx
);
274 ISC_MEMFUNC_SCOPE
void
275 isc__mem_setwater(isc_mem_t
*ctx
, isc_mem_water_t water
, void *water_arg
,
276 size_t hiwater
, size_t lowater
);
277 ISC_MEMFUNC_SCOPE
void
278 isc__mem_waterack(isc_mem_t
*ctx0
, int flag
);
279 ISC_MEMFUNC_SCOPE
void
280 isc__mem_setname(isc_mem_t
*ctx
, const char *name
, void *tag
);
281 ISC_MEMFUNC_SCOPE
const char *
282 isc__mem_getname(isc_mem_t
*ctx
);
283 ISC_MEMFUNC_SCOPE
void *
284 isc__mem_gettag(isc_mem_t
*ctx
);
285 ISC_MEMFUNC_SCOPE isc_result_t
286 isc__mempool_create(isc_mem_t
*mctx
, size_t size
, isc_mempool_t
**mpctxp
);
287 ISC_MEMFUNC_SCOPE
void
288 isc__mempool_setname(isc_mempool_t
*mpctx
, const char *name
);
289 ISC_MEMFUNC_SCOPE
void
290 isc__mempool_destroy(isc_mempool_t
**mpctxp
);
291 ISC_MEMFUNC_SCOPE
void
292 isc__mempool_associatelock(isc_mempool_t
*mpctx
, isc_mutex_t
*lock
);
293 ISC_MEMFUNC_SCOPE
void *
294 isc___mempool_get(isc_mempool_t
*mpctx FLARG
);
295 ISC_MEMFUNC_SCOPE
void
296 isc___mempool_put(isc_mempool_t
*mpctx
, void *mem FLARG
);
297 ISC_MEMFUNC_SCOPE
void
298 isc__mempool_setfreemax(isc_mempool_t
*mpctx
, unsigned int limit
);
299 ISC_MEMFUNC_SCOPE
unsigned int
300 isc__mempool_getfreemax(isc_mempool_t
*mpctx
);
301 ISC_MEMFUNC_SCOPE
unsigned int
302 isc__mempool_getfreecount(isc_mempool_t
*mpctx
);
303 ISC_MEMFUNC_SCOPE
void
304 isc__mempool_setmaxalloc(isc_mempool_t
*mpctx
, unsigned int limit
);
305 ISC_MEMFUNC_SCOPE
unsigned int
306 isc__mempool_getmaxalloc(isc_mempool_t
*mpctx
);
307 ISC_MEMFUNC_SCOPE
unsigned int
308 isc__mempool_getallocated(isc_mempool_t
*mpctx
);
309 ISC_MEMFUNC_SCOPE
void
310 isc__mempool_setfillcount(isc_mempool_t
*mpctx
, unsigned int limit
);
311 ISC_MEMFUNC_SCOPE
unsigned int
312 isc__mempool_getfillcount(isc_mempool_t
*mpctx
);
314 ISC_MEMFUNC_SCOPE
void
315 isc__mem_printactive(isc_mem_t
*ctx0
, FILE *file
);
316 ISC_MEMFUNC_SCOPE
void
317 isc__mem_printallactive(FILE *file
);
318 ISC_MEMFUNC_SCOPE
void
319 isc__mem_checkdestroyed(FILE *file
);
320 ISC_MEMFUNC_SCOPE
unsigned int
321 isc__mem_references(isc_mem_t
*ctx0
);
324 static struct isc__memmethods
{
325 isc_memmethods_t methods
;
328 * The following are defined just for avoiding unused static functions.
331 void *createx
, *create
, *create2
, *ondestroy
, *stats
,
332 *setquota
, *getquota
, *setname
, *getname
, *gettag
;
341 isc___mem_putanddetach
,
343 isc___mem_reallocate
,
346 isc__mem_setdestroycheck
,
354 (void *)isc__mem_createx
, (void *)isc__mem_create
,
355 (void *)isc__mem_create2
, (void *)isc__mem_ondestroy
,
356 (void *)isc__mem_stats
, (void *)isc__mem_setquota
,
357 (void *)isc__mem_getquota
, (void *)isc__mem_setname
,
358 (void *)isc__mem_getname
, (void *)isc__mem_gettag
362 static struct isc__mempoolmethods
{
363 isc_mempoolmethods_t methods
;
366 * The following are defined just for avoiding unused static functions.
369 void *getfreemax
, *getfreecount
, *getmaxalloc
, *getfillcount
;
373 isc__mempool_destroy
,
376 isc__mempool_getallocated
,
377 isc__mempool_setmaxalloc
,
378 isc__mempool_setfreemax
,
379 isc__mempool_setname
,
380 isc__mempool_associatelock
,
381 isc__mempool_setfillcount
385 (void *)isc__mempool_getfreemax
, (void *)isc__mempool_getfreecount
,
386 (void *)isc__mempool_getmaxalloc
, (void *)isc__mempool_getfillcount
391 * mctx must be locked.
394 add_trace_entry(isc__mem_t
*mctx
, const void *ptr
, unsigned int size
400 if ((isc_mem_debugging
& ISC_MEM_DEBUGTRACE
) != 0)
401 fprintf(stderr
, isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
404 "file %s line %u mctx %p\n"),
405 ptr
, size
, file
, line
, mctx
);
407 if (mctx
->debuglist
== NULL
)
410 if (size
> mctx
->max_size
)
411 size
= mctx
->max_size
;
413 dl
= ISC_LIST_HEAD(mctx
->debuglist
[size
]);
415 if (dl
->count
== DEBUGLIST_COUNT
)
417 for (i
= 0; i
< DEBUGLIST_COUNT
; i
++) {
418 if (dl
->ptr
[i
] == NULL
) {
428 dl
= ISC_LIST_NEXT(dl
, link
);
431 dl
= malloc(sizeof(debuglink_t
));
434 ISC_LINK_INIT(dl
, link
);
435 for (i
= 1; i
< DEBUGLIST_COUNT
; i
++) {
448 ISC_LIST_PREPEND(mctx
->debuglist
[size
], dl
, link
);
449 mctx
->debuglistcnt
++;
453 delete_trace_entry(isc__mem_t
*mctx
, const void *ptr
, unsigned int size
,
454 const char *file
, unsigned int line
)
459 if ((isc_mem_debugging
& ISC_MEM_DEBUGTRACE
) != 0)
460 fprintf(stderr
, isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
463 "file %s line %u mctx %p\n"),
464 ptr
, size
, file
, line
, mctx
);
466 if (mctx
->debuglist
== NULL
)
469 if (size
> mctx
->max_size
)
470 size
= mctx
->max_size
;
472 dl
= ISC_LIST_HEAD(mctx
->debuglist
[size
]);
474 for (i
= 0; i
< DEBUGLIST_COUNT
; i
++) {
475 if (dl
->ptr
[i
] == ptr
) {
481 INSIST(dl
->count
> 0);
483 if (dl
->count
== 0) {
484 ISC_LIST_UNLINK(mctx
->debuglist
[size
],
491 dl
= ISC_LIST_NEXT(dl
, link
);
495 * If we get here, we didn't find the item on the list. We're
500 #endif /* ISC_MEM_TRACKLINES */
503 rmsize(size_t size
) {
505 * round down to ALIGNMENT_SIZE
507 return (size
& (~(ALIGNMENT_SIZE
- 1)));
511 quantize(size_t size
) {
513 * Round up the result in order to get a size big
514 * enough to satisfy the request and be aligned on ALIGNMENT_SIZE
519 return (ALIGNMENT_SIZE
);
520 return ((size
+ ALIGNMENT_SIZE
- 1) & (~(ALIGNMENT_SIZE
- 1)));
523 static inline isc_boolean_t
524 more_basic_blocks(isc__mem_t
*ctx
) {
526 unsigned char *curr
, *next
;
527 unsigned char *first
, *last
;
528 unsigned char **table
;
529 unsigned int table_size
;
533 /* Require: we hold the context lock. */
536 * Did we hit the quota for this context?
538 increment
= NUM_BASIC_BLOCKS
* ctx
->mem_target
;
539 if (ctx
->quota
!= 0U && ctx
->total
+ increment
> ctx
->quota
)
542 INSIST(ctx
->basic_table_count
<= ctx
->basic_table_size
);
543 if (ctx
->basic_table_count
== ctx
->basic_table_size
) {
544 table_size
= ctx
->basic_table_size
+ TABLE_INCREMENT
;
545 table
= (ctx
->memalloc
)(ctx
->arg
,
546 table_size
* sizeof(unsigned char *));
548 ctx
->memalloc_failures
++;
551 if (ctx
->basic_table_size
!= 0) {
552 memcpy(table
, ctx
->basic_table
,
553 ctx
->basic_table_size
*
554 sizeof(unsigned char *));
555 (ctx
->memfree
)(ctx
->arg
, ctx
->basic_table
);
557 ctx
->basic_table
= table
;
558 ctx
->basic_table_size
= table_size
;
561 new = (ctx
->memalloc
)(ctx
->arg
, NUM_BASIC_BLOCKS
* ctx
->mem_target
);
563 ctx
->memalloc_failures
++;
566 ctx
->total
+= increment
;
567 ctx
->basic_table
[ctx
->basic_table_count
] = new;
568 ctx
->basic_table_count
++;
571 next
= curr
+ ctx
->mem_target
;
572 for (i
= 0; i
< (NUM_BASIC_BLOCKS
- 1); i
++) {
573 ((element
*)curr
)->next
= (element
*)next
;
575 next
+= ctx
->mem_target
;
578 * curr is now pointing at the last block in the
581 ((element
*)curr
)->next
= NULL
;
583 last
= first
+ NUM_BASIC_BLOCKS
* ctx
->mem_target
- 1;
584 if (first
< ctx
->lowest
|| ctx
->lowest
== NULL
)
586 if (last
> ctx
->highest
)
588 ctx
->basic_blocks
= new;
593 static inline isc_boolean_t
594 more_frags(isc__mem_t
*ctx
, size_t new_size
) {
598 unsigned char *curr
, *next
;
601 * Try to get more fragments by chopping up a basic block.
604 if (ctx
->basic_blocks
== NULL
) {
605 if (!more_basic_blocks(ctx
)) {
607 * We can't get more memory from the OS, or we've
608 * hit the quota for this context.
611 * XXXRTH "At quota" notification here.
617 total_size
= ctx
->mem_target
;
618 new = ctx
->basic_blocks
;
619 ctx
->basic_blocks
= ctx
->basic_blocks
->next
;
620 frags
= total_size
/ new_size
;
621 ctx
->stats
[new_size
].blocks
++;
622 ctx
->stats
[new_size
].freefrags
+= frags
;
624 * Set up a linked-list of blocks of size
628 next
= curr
+ new_size
;
629 total_size
-= new_size
;
630 for (i
= 0; i
< (frags
- 1); i
++) {
631 ((element
*)curr
)->next
= (element
*)next
;
634 total_size
-= new_size
;
637 * Add the remaining fragment of the basic block to a free list.
639 total_size
= rmsize(total_size
);
640 if (total_size
> 0U) {
641 ((element
*)next
)->next
= ctx
->freelists
[total_size
];
642 ctx
->freelists
[total_size
] = (element
*)next
;
643 ctx
->stats
[total_size
].freefrags
++;
646 * curr is now pointing at the last block in the
649 ((element
*)curr
)->next
= NULL
;
650 ctx
->freelists
[new_size
] = new;
656 mem_getunlocked(isc__mem_t
*ctx
, size_t size
) {
657 size_t new_size
= quantize(size
);
660 if (size
>= ctx
->max_size
|| new_size
>= ctx
->max_size
) {
662 * memget() was called on something beyond our upper limit.
664 if (ctx
->quota
!= 0U && ctx
->total
+ size
> ctx
->quota
) {
668 ret
= (ctx
->memalloc
)(ctx
->arg
, size
);
670 ctx
->memalloc_failures
++;
675 ctx
->stats
[ctx
->max_size
].gets
++;
676 ctx
->stats
[ctx
->max_size
].totalgets
++;
678 * If we don't set new_size to size, then the
679 * ISC_MEM_FILL code might write over bytes we
687 * If there are no blocks in the free list for this size, get a chunk
688 * of memory and then break it up into "new_size"-sized blocks, adding
689 * them to the free list.
691 if (ctx
->freelists
[new_size
] == NULL
&& !more_frags(ctx
, new_size
))
695 * The free list uses the "rounded-up" size "new_size".
697 ret
= ctx
->freelists
[new_size
];
698 ctx
->freelists
[new_size
] = ctx
->freelists
[new_size
]->next
;
701 * The stats[] uses the _actual_ "size" requested by the
702 * caller, with the caveat (in the code above) that "size" >= the
703 * max. size (max_size) ends up getting recorded as a call to
706 ctx
->stats
[size
].gets
++;
707 ctx
->stats
[size
].totalgets
++;
708 ctx
->stats
[new_size
].freefrags
--;
709 ctx
->inuse
+= new_size
;
715 memset(ret
, 0xbe, new_size
); /* Mnemonic for "beef". */
721 #if ISC_MEM_FILL && ISC_MEM_CHECKOVERRUN
723 check_overrun(void *mem
, size_t size
, size_t new_size
) {
726 cp
= (unsigned char *)mem
;
728 while (size
< new_size
) {
737 mem_putunlocked(isc__mem_t
*ctx
, void *mem
, size_t size
) {
738 size_t new_size
= quantize(size
);
740 if (size
== ctx
->max_size
|| new_size
>= ctx
->max_size
) {
742 * memput() called on something beyond our upper limit.
745 memset(mem
, 0xde, size
); /* Mnemonic for "dead". */
747 (ctx
->memfree
)(ctx
->arg
, mem
);
748 INSIST(ctx
->stats
[ctx
->max_size
].gets
!= 0U);
749 ctx
->stats
[ctx
->max_size
].gets
--;
750 INSIST(size
<= ctx
->total
);
757 #if ISC_MEM_CHECKOVERRUN
758 check_overrun(mem
, size
, new_size
);
760 memset(mem
, 0xde, new_size
); /* Mnemonic for "dead". */
764 * The free list uses the "rounded-up" size "new_size".
766 ((element
*)mem
)->next
= ctx
->freelists
[new_size
];
767 ctx
->freelists
[new_size
] = (element
*)mem
;
770 * The stats[] uses the _actual_ "size" requested by the
771 * caller, with the caveat (in the code above) that "size" >= the
772 * max. size (max_size) ends up getting recorded as a call to
775 INSIST(ctx
->stats
[size
].gets
!= 0U);
776 ctx
->stats
[size
].gets
--;
777 ctx
->stats
[new_size
].freefrags
++;
778 ctx
->inuse
-= new_size
;
782 * Perform a malloc, doing memory filling and overrun detection as necessary.
785 mem_get(isc__mem_t
*ctx
, size_t size
) {
788 #if ISC_MEM_CHECKOVERRUN
792 ret
= (ctx
->memalloc
)(ctx
->arg
, size
);
794 ctx
->memalloc_failures
++;
798 memset(ret
, 0xbe, size
); /* Mnemonic for "beef". */
800 # if ISC_MEM_CHECKOVERRUN
810 * Perform a free, doing memory filling and overrun detection as necessary.
813 mem_put(isc__mem_t
*ctx
, void *mem
, size_t size
) {
814 #if ISC_MEM_CHECKOVERRUN
815 INSIST(((unsigned char *)mem
)[size
] == 0xbe);
818 memset(mem
, 0xde, size
); /* Mnemonic for "dead". */
822 (ctx
->memfree
)(ctx
->arg
, mem
);
826 * Update internal counters after a memory get.
829 mem_getstats(isc__mem_t
*ctx
, size_t size
) {
833 if (size
> ctx
->max_size
) {
834 ctx
->stats
[ctx
->max_size
].gets
++;
835 ctx
->stats
[ctx
->max_size
].totalgets
++;
837 ctx
->stats
[size
].gets
++;
838 ctx
->stats
[size
].totalgets
++;
843 * Update internal counters after a memory put.
846 mem_putstats(isc__mem_t
*ctx
, void *ptr
, size_t size
) {
849 INSIST(ctx
->inuse
>= size
);
852 if (size
> ctx
->max_size
) {
853 INSIST(ctx
->stats
[ctx
->max_size
].gets
> 0U);
854 ctx
->stats
[ctx
->max_size
].gets
--;
856 INSIST(ctx
->stats
[size
].gets
> 0U);
857 ctx
->stats
[size
].gets
--;
866 default_memalloc(void *arg
, size_t size
) {
870 return (malloc(size
));
874 default_memfree(void *arg
, void *ptr
) {
880 initialize_action(void) {
881 RUNTIME_CHECK(isc_mutex_init(&lock
) == ISC_R_SUCCESS
);
882 ISC_LIST_INIT(contexts
);
890 ISC_MEMFUNC_SCOPE isc_result_t
891 isc__mem_createx(size_t init_max_size
, size_t target_size
,
892 isc_memalloc_t memalloc
, isc_memfree_t memfree
, void *arg
,
895 return (isc__mem_createx2(init_max_size
, target_size
, memalloc
, memfree
,
896 arg
, ctxp
, ISC_MEMFLAG_DEFAULT
));
900 ISC_MEMFUNC_SCOPE isc_result_t
901 isc__mem_createx2(size_t init_max_size
, size_t target_size
,
902 isc_memalloc_t memalloc
, isc_memfree_t memfree
, void *arg
,
903 isc_mem_t
**ctxp
, unsigned int flags
)
908 REQUIRE(ctxp
!= NULL
&& *ctxp
== NULL
);
909 REQUIRE(memalloc
!= NULL
);
910 REQUIRE(memfree
!= NULL
);
912 INSIST((ALIGNMENT_SIZE
& (ALIGNMENT_SIZE
- 1)) == 0);
914 RUNTIME_CHECK(isc_once_do(&once
, initialize_action
) == ISC_R_SUCCESS
);
916 ctx
= (memalloc
)(arg
, sizeof(*ctx
));
918 return (ISC_R_NOMEMORY
);
920 if ((flags
& ISC_MEMFLAG_NOLOCK
) == 0) {
921 result
= isc_mutex_init(&ctx
->lock
);
922 if (result
!= ISC_R_SUCCESS
) {
928 if (init_max_size
== 0U)
929 ctx
->max_size
= DEF_MAX_SIZE
;
931 ctx
->max_size
= init_max_size
;
934 memset(ctx
->name
, 0, sizeof(ctx
->name
));
942 ctx
->hi_called
= ISC_FALSE
;
944 ctx
->water_arg
= NULL
;
945 ctx
->common
.impmagic
= MEM_MAGIC
;
946 ctx
->common
.magic
= ISCAPI_MCTX_MAGIC
;
947 ctx
->common
.methods
= (isc_memmethods_t
*)&memmethods
;
948 isc_ondestroy_init(&ctx
->ondestroy
);
949 ctx
->memalloc
= memalloc
;
950 ctx
->memfree
= memfree
;
953 ctx
->checkfree
= ISC_TRUE
;
954 #if ISC_MEM_TRACKLINES
955 ctx
->debuglist
= NULL
;
956 ctx
->debuglistcnt
= 0;
958 ISC_LIST_INIT(ctx
->pools
);
960 ctx
->freelists
= NULL
;
961 ctx
->basic_blocks
= NULL
;
962 ctx
->basic_table
= NULL
;
963 ctx
->basic_table_count
= 0;
964 ctx
->basic_table_size
= 0;
968 ctx
->stats
= (memalloc
)(arg
,
969 (ctx
->max_size
+1) * sizeof(struct stats
));
970 if (ctx
->stats
== NULL
) {
971 result
= ISC_R_NOMEMORY
;
974 memset(ctx
->stats
, 0, (ctx
->max_size
+ 1) * sizeof(struct stats
));
976 if ((flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
977 if (target_size
== 0U)
978 ctx
->mem_target
= DEF_MEM_TARGET
;
980 ctx
->mem_target
= target_size
;
981 ctx
->freelists
= (memalloc
)(arg
, ctx
->max_size
*
983 if (ctx
->freelists
== NULL
) {
984 result
= ISC_R_NOMEMORY
;
987 memset(ctx
->freelists
, 0,
988 ctx
->max_size
* sizeof(element
*));
991 #if ISC_MEM_TRACKLINES
992 if ((isc_mem_debugging
& ISC_MEM_DEBUGRECORD
) != 0) {
995 ctx
->debuglist
= (memalloc
)(arg
,
996 (ctx
->max_size
+1) * sizeof(debuglist_t
));
997 if (ctx
->debuglist
== NULL
) {
998 result
= ISC_R_NOMEMORY
;
1001 for (i
= 0; i
<= ctx
->max_size
; i
++)
1002 ISC_LIST_INIT(ctx
->debuglist
[i
]);
1006 ctx
->memalloc_failures
= 0;
1009 ISC_LIST_INITANDAPPEND(contexts
, ctx
, link
);
1012 *ctxp
= (isc_mem_t
*)ctx
;
1013 return (ISC_R_SUCCESS
);
1017 if (ctx
->stats
!= NULL
)
1018 (memfree
)(arg
, ctx
->stats
);
1019 if (ctx
->freelists
!= NULL
)
1020 (memfree
)(arg
, ctx
->freelists
);
1021 #if ISC_MEM_TRACKLINES
1022 if (ctx
->debuglist
!= NULL
)
1023 (ctx
->memfree
)(ctx
->arg
, ctx
->debuglist
);
1024 #endif /* ISC_MEM_TRACKLINES */
1025 if ((ctx
->flags
& ISC_MEMFLAG_NOLOCK
) == 0)
1026 DESTROYLOCK(&ctx
->lock
);
1027 (memfree
)(arg
, ctx
);
1033 ISC_MEMFUNC_SCOPE isc_result_t
1034 isc__mem_create(size_t init_max_size
, size_t target_size
, isc_mem_t
**ctxp
) {
1035 return (isc__mem_createx2(init_max_size
, target_size
,
1036 default_memalloc
, default_memfree
, NULL
,
1037 ctxp
, ISC_MEMFLAG_DEFAULT
));
1040 ISC_MEMFUNC_SCOPE isc_result_t
1041 isc__mem_create2(size_t init_max_size
, size_t target_size
,
1042 isc_mem_t
**ctxp
, unsigned int flags
)
1044 return (isc__mem_createx2(init_max_size
, target_size
,
1045 default_memalloc
, default_memfree
, NULL
,
1050 destroy(isc__mem_t
*ctx
) {
1052 isc_ondestroy_t ondest
;
1054 ctx
->common
.impmagic
= 0;
1055 ctx
->common
.magic
= 0;
1058 ISC_LIST_UNLINK(contexts
, ctx
, link
);
1059 totallost
+= ctx
->inuse
;
1062 INSIST(ISC_LIST_EMPTY(ctx
->pools
));
1064 #if ISC_MEM_TRACKLINES
1065 if (ctx
->debuglist
!= NULL
) {
1066 if (ctx
->checkfree
) {
1067 for (i
= 0; i
<= ctx
->max_size
; i
++) {
1068 if (!ISC_LIST_EMPTY(ctx
->debuglist
[i
]))
1069 print_active(ctx
, stderr
);
1070 INSIST(ISC_LIST_EMPTY(ctx
->debuglist
[i
]));
1075 for (i
= 0; i
<= ctx
->max_size
; i
++)
1076 for (dl
= ISC_LIST_HEAD(ctx
->debuglist
[i
]);
1078 dl
= ISC_LIST_HEAD(ctx
->debuglist
[i
])) {
1079 ISC_LIST_UNLINK(ctx
->debuglist
[i
],
1084 (ctx
->memfree
)(ctx
->arg
, ctx
->debuglist
);
1087 INSIST(ctx
->references
== 0);
1089 if (ctx
->checkfree
) {
1090 for (i
= 0; i
<= ctx
->max_size
; i
++) {
1091 #if ISC_MEM_TRACKLINES
1092 if (ctx
->stats
[i
].gets
!= 0U)
1093 print_active(ctx
, stderr
);
1095 INSIST(ctx
->stats
[i
].gets
== 0U);
1099 (ctx
->memfree
)(ctx
->arg
, ctx
->stats
);
1101 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
1102 for (i
= 0; i
< ctx
->basic_table_count
; i
++)
1103 (ctx
->memfree
)(ctx
->arg
, ctx
->basic_table
[i
]);
1104 (ctx
->memfree
)(ctx
->arg
, ctx
->freelists
);
1105 if (ctx
->basic_table
!= NULL
)
1106 (ctx
->memfree
)(ctx
->arg
, ctx
->basic_table
);
1109 ondest
= ctx
->ondestroy
;
1111 if ((ctx
->flags
& ISC_MEMFLAG_NOLOCK
) == 0)
1112 DESTROYLOCK(&ctx
->lock
);
1113 (ctx
->memfree
)(ctx
->arg
, ctx
);
1115 isc_ondestroy_notify(&ondest
, ctx
);
1118 ISC_MEMFUNC_SCOPE
void
1119 isc__mem_attach(isc_mem_t
*source0
, isc_mem_t
**targetp
) {
1120 isc__mem_t
*source
= (isc__mem_t
*)source0
;
1122 REQUIRE(VALID_CONTEXT(source
));
1123 REQUIRE(targetp
!= NULL
&& *targetp
== NULL
);
1125 MCTXLOCK(source
, &source
->lock
);
1126 source
->references
++;
1127 MCTXUNLOCK(source
, &source
->lock
);
1129 *targetp
= (isc_mem_t
*)source
;
1132 ISC_MEMFUNC_SCOPE
void
1133 isc__mem_detach(isc_mem_t
**ctxp
) {
1135 isc_boolean_t want_destroy
= ISC_FALSE
;
1137 REQUIRE(ctxp
!= NULL
);
1138 ctx
= (isc__mem_t
*)*ctxp
;
1139 REQUIRE(VALID_CONTEXT(ctx
));
1141 MCTXLOCK(ctx
, &ctx
->lock
);
1142 INSIST(ctx
->references
> 0);
1144 if (ctx
->references
== 0)
1145 want_destroy
= ISC_TRUE
;
1146 MCTXUNLOCK(ctx
, &ctx
->lock
);
1155 * isc_mem_putanddetach() is the equivalent of:
1158 * isc_mem_attach(ptr->mctx, &mctx);
1159 * isc_mem_detach(&ptr->mctx);
1160 * isc_mem_put(mctx, ptr, sizeof(*ptr);
1161 * isc_mem_detach(&mctx);
1164 ISC_MEMFUNC_SCOPE
void
1165 isc___mem_putanddetach(isc_mem_t
**ctxp
, void *ptr
, size_t size FLARG
) {
1167 isc_boolean_t want_destroy
= ISC_FALSE
;
1171 REQUIRE(ctxp
!= NULL
);
1172 ctx
= (isc__mem_t
*)*ctxp
;
1173 REQUIRE(VALID_CONTEXT(ctx
));
1174 REQUIRE(ptr
!= NULL
);
1177 * Must be before mem_putunlocked() as ctxp is usually within
1182 if ((isc_mem_debugging
& (ISC_MEM_DEBUGSIZE
|ISC_MEM_DEBUGCTX
)) != 0) {
1183 if ((isc_mem_debugging
& ISC_MEM_DEBUGSIZE
) != 0) {
1184 si
= &(((size_info
*)ptr
)[-1]);
1185 oldsize
= si
->u
.size
- ALIGNMENT_SIZE
;
1186 if ((isc_mem_debugging
& ISC_MEM_DEBUGCTX
) != 0)
1187 oldsize
-= ALIGNMENT_SIZE
;
1188 INSIST(oldsize
== size
);
1190 isc_mem_free((isc_mem_t
*)ctx
, ptr
);
1192 MCTXLOCK(ctx
, &ctx
->lock
);
1194 if (ctx
->references
== 0)
1195 want_destroy
= ISC_TRUE
;
1196 MCTXUNLOCK(ctx
, &ctx
->lock
);
1203 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
1204 MCTXLOCK(ctx
, &ctx
->lock
);
1205 mem_putunlocked(ctx
, ptr
, size
);
1207 mem_put(ctx
, ptr
, size
);
1208 MCTXLOCK(ctx
, &ctx
->lock
);
1209 mem_putstats(ctx
, ptr
, size
);
1212 DELETE_TRACE(ctx
, ptr
, size
, file
, line
);
1213 INSIST(ctx
->references
> 0);
1215 if (ctx
->references
== 0)
1216 want_destroy
= ISC_TRUE
;
1218 MCTXUNLOCK(ctx
, &ctx
->lock
);
1224 ISC_MEMFUNC_SCOPE
void
1225 isc__mem_destroy(isc_mem_t
**ctxp
) {
1229 * This routine provides legacy support for callers who use mctxs
1230 * without attaching/detaching.
1233 REQUIRE(ctxp
!= NULL
);
1234 ctx
= (isc__mem_t
*)*ctxp
;
1235 REQUIRE(VALID_CONTEXT(ctx
));
1237 MCTXLOCK(ctx
, &ctx
->lock
);
1238 #if ISC_MEM_TRACKLINES
1239 if (ctx
->references
!= 1)
1240 print_active(ctx
, stderr
);
1242 REQUIRE(ctx
->references
== 1);
1244 MCTXUNLOCK(ctx
, &ctx
->lock
);
1251 ISC_MEMFUNC_SCOPE isc_result_t
1252 isc__mem_ondestroy(isc_mem_t
*ctx0
, isc_task_t
*task
, isc_event_t
**event
) {
1253 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1256 MCTXLOCK(ctx
, &ctx
->lock
);
1257 res
= isc_ondestroy_register(&ctx
->ondestroy
, task
, event
);
1258 MCTXUNLOCK(ctx
, &ctx
->lock
);
1263 ISC_MEMFUNC_SCOPE
void *
1264 isc___mem_get(isc_mem_t
*ctx0
, size_t size FLARG
) {
1265 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1267 isc_boolean_t call_water
= ISC_FALSE
;
1269 REQUIRE(VALID_CONTEXT(ctx
));
1271 if ((isc_mem_debugging
& (ISC_MEM_DEBUGSIZE
|ISC_MEM_DEBUGCTX
)) != 0)
1272 return (isc_mem_allocate((isc_mem_t
*)ctx
, size
));
1274 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
1275 MCTXLOCK(ctx
, &ctx
->lock
);
1276 ptr
= mem_getunlocked(ctx
, size
);
1278 ptr
= mem_get(ctx
, size
);
1279 MCTXLOCK(ctx
, &ctx
->lock
);
1281 mem_getstats(ctx
, size
);
1284 ADD_TRACE(ctx
, ptr
, size
, file
, line
);
1285 if (ctx
->hi_water
!= 0U && !ctx
->hi_called
&&
1286 ctx
->inuse
> ctx
->hi_water
) {
1287 call_water
= ISC_TRUE
;
1289 if (ctx
->inuse
> ctx
->maxinuse
) {
1290 ctx
->maxinuse
= ctx
->inuse
;
1291 if (ctx
->hi_water
!= 0U && ctx
->inuse
> ctx
->hi_water
&&
1292 (isc_mem_debugging
& ISC_MEM_DEBUGUSAGE
) != 0)
1293 fprintf(stderr
, "maxinuse = %lu\n",
1294 (unsigned long)ctx
->inuse
);
1296 MCTXUNLOCK(ctx
, &ctx
->lock
);
1299 (ctx
->water
)(ctx
->water_arg
, ISC_MEM_HIWATER
);
1304 ISC_MEMFUNC_SCOPE
void
1305 isc___mem_put(isc_mem_t
*ctx0
, void *ptr
, size_t size FLARG
) {
1306 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1307 isc_boolean_t call_water
= ISC_FALSE
;
1311 REQUIRE(VALID_CONTEXT(ctx
));
1312 REQUIRE(ptr
!= NULL
);
1314 if ((isc_mem_debugging
& (ISC_MEM_DEBUGSIZE
|ISC_MEM_DEBUGCTX
)) != 0) {
1315 if ((isc_mem_debugging
& ISC_MEM_DEBUGSIZE
) != 0) {
1316 si
= &(((size_info
*)ptr
)[-1]);
1317 oldsize
= si
->u
.size
- ALIGNMENT_SIZE
;
1318 if ((isc_mem_debugging
& ISC_MEM_DEBUGCTX
) != 0)
1319 oldsize
-= ALIGNMENT_SIZE
;
1320 INSIST(oldsize
== size
);
1322 isc_mem_free((isc_mem_t
*)ctx
, ptr
);
1326 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
1327 MCTXLOCK(ctx
, &ctx
->lock
);
1328 mem_putunlocked(ctx
, ptr
, size
);
1330 mem_put(ctx
, ptr
, size
);
1331 MCTXLOCK(ctx
, &ctx
->lock
);
1332 mem_putstats(ctx
, ptr
, size
);
1335 DELETE_TRACE(ctx
, ptr
, size
, file
, line
);
1338 * The check against ctx->lo_water == 0 is for the condition
1339 * when the context was pushed over hi_water but then had
1340 * isc_mem_setwater() called with 0 for hi_water and lo_water.
1342 if (ctx
->hi_called
&&
1343 (ctx
->inuse
< ctx
->lo_water
|| ctx
->lo_water
== 0U)) {
1344 if (ctx
->water
!= NULL
)
1345 call_water
= ISC_TRUE
;
1347 MCTXUNLOCK(ctx
, &ctx
->lock
);
1350 (ctx
->water
)(ctx
->water_arg
, ISC_MEM_LOWATER
);
1353 ISC_MEMFUNC_SCOPE
void
1354 isc__mem_waterack(isc_mem_t
*ctx0
, int flag
) {
1355 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1357 REQUIRE(VALID_CONTEXT(ctx
));
1359 MCTXLOCK(ctx
, &ctx
->lock
);
1360 if (flag
== ISC_MEM_LOWATER
)
1361 ctx
->hi_called
= ISC_FALSE
;
1362 else if (flag
== ISC_MEM_HIWATER
)
1363 ctx
->hi_called
= ISC_TRUE
;
1364 MCTXUNLOCK(ctx
, &ctx
->lock
);
1367 #if ISC_MEM_TRACKLINES
1369 print_active(isc__mem_t
*mctx
, FILE *out
) {
1370 if (mctx
->debuglist
!= NULL
) {
1374 isc_boolean_t found
;
1376 fprintf(out
, "%s", isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1378 "Dump of all outstanding "
1379 "memory allocations:\n"));
1381 format
= isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1382 ISC_MSG_PTRFILELINE
,
1383 "\tptr %p size %u file %s line %u\n");
1384 for (i
= 0; i
<= mctx
->max_size
; i
++) {
1385 dl
= ISC_LIST_HEAD(mctx
->debuglist
[i
]);
1390 while (dl
!= NULL
) {
1391 for (j
= 0; j
< DEBUGLIST_COUNT
; j
++)
1392 if (dl
->ptr
[j
] != NULL
)
1393 fprintf(out
, format
,
1398 dl
= ISC_LIST_NEXT(dl
, link
);
1402 fprintf(out
, "%s", isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1403 ISC_MSG_NONE
, "\tNone.\n"));
1409 * Print the stats[] on the stream "out" with suitable formatting.
1411 ISC_MEMFUNC_SCOPE
void
1412 isc__mem_stats(isc_mem_t
*ctx0
, FILE *out
) {
1413 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1415 const struct stats
*s
;
1416 const isc__mempool_t
*pool
;
1418 REQUIRE(VALID_CONTEXT(ctx
));
1419 MCTXLOCK(ctx
, &ctx
->lock
);
1421 for (i
= 0; i
<= ctx
->max_size
; i
++) {
1424 if (s
->totalgets
== 0U && s
->gets
== 0U)
1426 fprintf(out
, "%s%5lu: %11lu gets, %11lu rem",
1427 (i
== ctx
->max_size
) ? ">=" : " ",
1428 (unsigned long) i
, s
->totalgets
, s
->gets
);
1429 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0 &&
1430 (s
->blocks
!= 0U || s
->freefrags
!= 0U))
1431 fprintf(out
, " (%lu bl, %lu ff)",
1432 s
->blocks
, s
->freefrags
);
1437 * Note that since a pool can be locked now, these stats might be
1438 * somewhat off if the pool is in active use at the time the stats
1439 * are dumped. The link fields are protected by the isc_mem_t's
1440 * lock, however, so walking this list and extracting integers from
1441 * stats fields is always safe.
1443 pool
= ISC_LIST_HEAD(ctx
->pools
);
1445 fprintf(out
, "%s", isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1447 "[Pool statistics]\n"));
1448 fprintf(out
, "%15s %10s %10s %10s %10s %10s %10s %10s %1s\n",
1449 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1450 ISC_MSG_POOLNAME
, "name"),
1451 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1452 ISC_MSG_POOLSIZE
, "size"),
1453 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1454 ISC_MSG_POOLMAXALLOC
, "maxalloc"),
1455 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1456 ISC_MSG_POOLALLOCATED
, "allocated"),
1457 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1458 ISC_MSG_POOLFREECOUNT
, "freecount"),
1459 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1460 ISC_MSG_POOLFREEMAX
, "freemax"),
1461 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1462 ISC_MSG_POOLFILLCOUNT
, "fillcount"),
1463 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1464 ISC_MSG_POOLGETS
, "gets"),
1467 while (pool
!= NULL
) {
1468 fprintf(out
, "%15s %10lu %10u %10u %10u %10u %10u %10u %s\n",
1469 pool
->name
, (unsigned long) pool
->size
, pool
->maxalloc
,
1470 pool
->allocated
, pool
->freecount
, pool
->freemax
,
1471 pool
->fillcount
, pool
->gets
,
1472 (pool
->lock
== NULL
? "N" : "Y"));
1473 pool
= ISC_LIST_NEXT(pool
, link
);
1476 #if ISC_MEM_TRACKLINES
1477 print_active(ctx
, out
);
1480 MCTXUNLOCK(ctx
, &ctx
->lock
);
1484 * Replacements for malloc() and free() -- they implicitly remember the
1485 * size of the object allocated (with some additional overhead).
1489 isc__mem_allocateunlocked(isc_mem_t
*ctx0
, size_t size
) {
1490 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1493 size
+= ALIGNMENT_SIZE
;
1494 if ((isc_mem_debugging
& ISC_MEM_DEBUGCTX
) != 0)
1495 size
+= ALIGNMENT_SIZE
;
1497 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0)
1498 si
= mem_getunlocked(ctx
, size
);
1500 si
= mem_get(ctx
, size
);
1504 if ((isc_mem_debugging
& ISC_MEM_DEBUGCTX
) != 0) {
1512 ISC_MEMFUNC_SCOPE
void *
1513 isc___mem_allocate(isc_mem_t
*ctx0
, size_t size FLARG
) {
1514 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1516 isc_boolean_t call_water
= ISC_FALSE
;
1518 REQUIRE(VALID_CONTEXT(ctx
));
1520 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
1521 MCTXLOCK(ctx
, &ctx
->lock
);
1522 si
= isc__mem_allocateunlocked((isc_mem_t
*)ctx
, size
);
1524 si
= isc__mem_allocateunlocked((isc_mem_t
*)ctx
, size
);
1525 MCTXLOCK(ctx
, &ctx
->lock
);
1527 mem_getstats(ctx
, si
[-1].u
.size
);
1530 #if ISC_MEM_TRACKLINES
1531 ADD_TRACE(ctx
, si
, si
[-1].u
.size
, file
, line
);
1533 if (ctx
->hi_water
!= 0U && !ctx
->hi_called
&&
1534 ctx
->inuse
> ctx
->hi_water
) {
1535 ctx
->hi_called
= ISC_TRUE
;
1536 call_water
= ISC_TRUE
;
1538 if (ctx
->inuse
> ctx
->maxinuse
) {
1539 ctx
->maxinuse
= ctx
->inuse
;
1540 if (ctx
->hi_water
!= 0U && ctx
->inuse
> ctx
->hi_water
&&
1541 (isc_mem_debugging
& ISC_MEM_DEBUGUSAGE
) != 0)
1542 fprintf(stderr
, "maxinuse = %lu\n",
1543 (unsigned long)ctx
->inuse
);
1545 MCTXUNLOCK(ctx
, &ctx
->lock
);
1548 (ctx
->water
)(ctx
->water_arg
, ISC_MEM_HIWATER
);
1553 ISC_MEMFUNC_SCOPE
void *
1554 isc___mem_reallocate(isc_mem_t
*ctx0
, void *ptr
, size_t size FLARG
) {
1555 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1556 void *new_ptr
= NULL
;
1557 size_t oldsize
, copysize
;
1559 REQUIRE(VALID_CONTEXT(ctx
));
1562 * This function emulates the realloc(3) standard library function:
1563 * - if size > 0, allocate new memory; and if ptr is non NULL, copy
1564 * as much of the old contents to the new buffer and free the old one.
1565 * Note that when allocation fails the original pointer is intact;
1566 * the caller must free it.
1567 * - if size is 0 and ptr is non NULL, simply free the given ptr.
1568 * - this function returns:
1569 * pointer to the newly allocated memory, or
1570 * NULL if allocation fails or doesn't happen.
1573 new_ptr
= isc__mem_allocate(ctx0
, size FLARG_PASS
);
1574 if (new_ptr
!= NULL
&& ptr
!= NULL
) {
1575 oldsize
= (((size_info
*)ptr
)[-1]).u
.size
;
1576 INSIST(oldsize
>= ALIGNMENT_SIZE
);
1577 oldsize
-= ALIGNMENT_SIZE
;
1578 copysize
= oldsize
> size
? size
: oldsize
;
1579 memcpy(new_ptr
, ptr
, copysize
);
1580 isc__mem_free(ctx0
, ptr FLARG_PASS
);
1582 } else if (ptr
!= NULL
)
1583 isc__mem_free(ctx0
, ptr FLARG_PASS
);
1588 ISC_MEMFUNC_SCOPE
void
1589 isc___mem_free(isc_mem_t
*ctx0
, void *ptr FLARG
) {
1590 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1593 isc_boolean_t call_water
= ISC_FALSE
;
1595 REQUIRE(VALID_CONTEXT(ctx
));
1596 REQUIRE(ptr
!= NULL
);
1598 if ((isc_mem_debugging
& ISC_MEM_DEBUGCTX
) != 0) {
1599 si
= &(((size_info
*)ptr
)[-2]);
1600 REQUIRE(si
->u
.ctx
== ctx
);
1601 size
= si
[1].u
.size
;
1603 si
= &(((size_info
*)ptr
)[-1]);
1607 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
1608 MCTXLOCK(ctx
, &ctx
->lock
);
1609 mem_putunlocked(ctx
, si
, size
);
1611 mem_put(ctx
, si
, size
);
1612 MCTXLOCK(ctx
, &ctx
->lock
);
1613 mem_putstats(ctx
, si
, size
);
1616 DELETE_TRACE(ctx
, ptr
, size
, file
, line
);
1619 * The check against ctx->lo_water == 0 is for the condition
1620 * when the context was pushed over hi_water but then had
1621 * isc_mem_setwater() called with 0 for hi_water and lo_water.
1623 if (ctx
->hi_called
&&
1624 (ctx
->inuse
< ctx
->lo_water
|| ctx
->lo_water
== 0U)) {
1625 ctx
->hi_called
= ISC_FALSE
;
1627 if (ctx
->water
!= NULL
)
1628 call_water
= ISC_TRUE
;
1630 MCTXUNLOCK(ctx
, &ctx
->lock
);
1633 (ctx
->water
)(ctx
->water_arg
, ISC_MEM_LOWATER
);
1638 * Other useful things.
1641 ISC_MEMFUNC_SCOPE
char *
1642 isc___mem_strdup(isc_mem_t
*mctx0
, const char *s FLARG
) {
1643 isc__mem_t
*mctx
= (isc__mem_t
*)mctx0
;
1647 REQUIRE(VALID_CONTEXT(mctx
));
1652 ns
= isc___mem_allocate((isc_mem_t
*)mctx
, len
+ 1 FLARG_PASS
);
1655 strncpy(ns
, s
, len
+ 1);
1660 ISC_MEMFUNC_SCOPE
void
1661 isc__mem_setdestroycheck(isc_mem_t
*ctx0
, isc_boolean_t flag
) {
1662 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1664 REQUIRE(VALID_CONTEXT(ctx
));
1665 MCTXLOCK(ctx
, &ctx
->lock
);
1667 ctx
->checkfree
= flag
;
1669 MCTXUNLOCK(ctx
, &ctx
->lock
);
1676 ISC_MEMFUNC_SCOPE
void
1677 isc__mem_setquota(isc_mem_t
*ctx0
, size_t quota
) {
1678 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1680 REQUIRE(VALID_CONTEXT(ctx
));
1681 MCTXLOCK(ctx
, &ctx
->lock
);
1685 MCTXUNLOCK(ctx
, &ctx
->lock
);
1688 ISC_MEMFUNC_SCOPE
size_t
1689 isc__mem_getquota(isc_mem_t
*ctx0
) {
1690 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1693 REQUIRE(VALID_CONTEXT(ctx
));
1694 MCTXLOCK(ctx
, &ctx
->lock
);
1698 MCTXUNLOCK(ctx
, &ctx
->lock
);
1703 ISC_MEMFUNC_SCOPE
size_t
1704 isc__mem_inuse(isc_mem_t
*ctx0
) {
1705 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1708 REQUIRE(VALID_CONTEXT(ctx
));
1709 MCTXLOCK(ctx
, &ctx
->lock
);
1713 MCTXUNLOCK(ctx
, &ctx
->lock
);
1718 ISC_MEMFUNC_SCOPE
void
1719 isc__mem_setwater(isc_mem_t
*ctx0
, isc_mem_water_t water
, void *water_arg
,
1720 size_t hiwater
, size_t lowater
)
1722 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1723 isc_boolean_t callwater
= ISC_FALSE
;
1724 isc_mem_water_t oldwater
;
1727 REQUIRE(VALID_CONTEXT(ctx
));
1728 REQUIRE(hiwater
>= lowater
);
1730 MCTXLOCK(ctx
, &ctx
->lock
);
1731 oldwater
= ctx
->water
;
1732 oldwater_arg
= ctx
->water_arg
;
1733 if (water
== NULL
) {
1734 callwater
= ctx
->hi_called
;
1736 ctx
->water_arg
= NULL
;
1739 ctx
->hi_called
= ISC_FALSE
;
1741 if (ctx
->hi_called
&&
1742 (ctx
->water
!= water
|| ctx
->water_arg
!= water_arg
||
1743 ctx
->inuse
< lowater
|| lowater
== 0U))
1744 callwater
= ISC_TRUE
;
1746 ctx
->water_arg
= water_arg
;
1747 ctx
->hi_water
= hiwater
;
1748 ctx
->lo_water
= lowater
;
1749 ctx
->hi_called
= ISC_FALSE
;
1751 MCTXUNLOCK(ctx
, &ctx
->lock
);
1753 if (callwater
&& oldwater
!= NULL
)
1754 (oldwater
)(oldwater_arg
, ISC_MEM_LOWATER
);
1757 ISC_MEMFUNC_SCOPE
void
1758 isc__mem_setname(isc_mem_t
*ctx0
, const char *name
, void *tag
) {
1759 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1761 REQUIRE(VALID_CONTEXT(ctx
));
1764 memset(ctx
->name
, 0, sizeof(ctx
->name
));
1765 strncpy(ctx
->name
, name
, sizeof(ctx
->name
) - 1);
1770 ISC_MEMFUNC_SCOPE
const char *
1771 isc__mem_getname(isc_mem_t
*ctx0
) {
1772 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1774 REQUIRE(VALID_CONTEXT(ctx
));
1779 ISC_MEMFUNC_SCOPE
void *
1780 isc__mem_gettag(isc_mem_t
*ctx0
) {
1781 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1783 REQUIRE(VALID_CONTEXT(ctx
));
1792 ISC_MEMFUNC_SCOPE isc_result_t
1793 isc__mempool_create(isc_mem_t
*mctx0
, size_t size
, isc_mempool_t
**mpctxp
) {
1794 isc__mem_t
*mctx
= (isc__mem_t
*)mctx0
;
1795 isc__mempool_t
*mpctx
;
1797 REQUIRE(VALID_CONTEXT(mctx
));
1799 REQUIRE(mpctxp
!= NULL
&& *mpctxp
== NULL
);
1802 * Allocate space for this pool, initialize values, and if all works
1803 * well, attach to the memory context.
1805 mpctx
= isc_mem_get((isc_mem_t
*)mctx
, sizeof(isc__mempool_t
));
1807 return (ISC_R_NOMEMORY
);
1809 mpctx
->common
.methods
= (isc_mempoolmethods_t
*)&mempoolmethods
;
1810 mpctx
->common
.impmagic
= MEMPOOL_MAGIC
;
1811 mpctx
->common
.magic
= ISCAPI_MPOOL_MAGIC
;
1815 mpctx
->maxalloc
= UINT_MAX
;
1816 mpctx
->allocated
= 0;
1817 mpctx
->freecount
= 0;
1819 mpctx
->fillcount
= 1;
1821 #if ISC_MEMPOOL_NAMES
1824 mpctx
->items
= NULL
;
1826 *mpctxp
= (isc_mempool_t
*)mpctx
;
1828 MCTXLOCK(mctx
, &mctx
->lock
);
1829 ISC_LIST_INITANDAPPEND(mctx
->pools
, mpctx
, link
);
1831 MCTXUNLOCK(mctx
, &mctx
->lock
);
1833 return (ISC_R_SUCCESS
);
1836 ISC_MEMFUNC_SCOPE
void
1837 isc__mempool_setname(isc_mempool_t
*mpctx0
, const char *name
) {
1838 isc__mempool_t
*mpctx
= (isc__mempool_t
*)mpctx0
;
1840 REQUIRE(name
!= NULL
);
1841 REQUIRE(VALID_MEMPOOL(mpctx
));
1843 #if ISC_MEMPOOL_NAMES
1844 if (mpctx
->lock
!= NULL
)
1847 strncpy(mpctx
->name
, name
, sizeof(mpctx
->name
) - 1);
1848 mpctx
->name
[sizeof(mpctx
->name
) - 1] = '\0';
1850 if (mpctx
->lock
!= NULL
)
1851 UNLOCK(mpctx
->lock
);
1858 ISC_MEMFUNC_SCOPE
void
1859 isc__mempool_destroy(isc_mempool_t
**mpctxp
) {
1860 isc__mempool_t
*mpctx
;
1865 REQUIRE(mpctxp
!= NULL
);
1866 mpctx
= (isc__mempool_t
*)*mpctxp
;
1867 REQUIRE(VALID_MEMPOOL(mpctx
));
1868 #if ISC_MEMPOOL_NAMES
1869 if (mpctx
->allocated
> 0)
1870 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
1871 "isc__mempool_destroy(): mempool %s "
1875 REQUIRE(mpctx
->allocated
== 0);
1885 * Return any items on the free list
1887 MCTXLOCK(mctx
, &mctx
->lock
);
1888 while (mpctx
->items
!= NULL
) {
1889 INSIST(mpctx
->freecount
> 0);
1891 item
= mpctx
->items
;
1892 mpctx
->items
= item
->next
;
1894 if ((mctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
1895 mem_putunlocked(mctx
, item
, mpctx
->size
);
1897 mem_put(mctx
, item
, mpctx
->size
);
1898 mem_putstats(mctx
, item
, mpctx
->size
);
1901 MCTXUNLOCK(mctx
, &mctx
->lock
);
1904 * Remove our linked list entry from the memory context.
1906 MCTXLOCK(mctx
, &mctx
->lock
);
1907 ISC_LIST_UNLINK(mctx
->pools
, mpctx
, link
);
1909 MCTXUNLOCK(mctx
, &mctx
->lock
);
1911 mpctx
->common
.impmagic
= 0;
1912 mpctx
->common
.magic
= 0;
1914 isc_mem_put((isc_mem_t
*)mpctx
->mctx
, mpctx
, sizeof(isc__mempool_t
));
1922 ISC_MEMFUNC_SCOPE
void
1923 isc__mempool_associatelock(isc_mempool_t
*mpctx0
, isc_mutex_t
*lock
) {
1924 isc__mempool_t
*mpctx
= (isc__mempool_t
*)mpctx0
;
1926 REQUIRE(VALID_MEMPOOL(mpctx
));
1927 REQUIRE(mpctx
->lock
== NULL
);
1928 REQUIRE(lock
!= NULL
);
1933 ISC_MEMFUNC_SCOPE
void *
1934 isc___mempool_get(isc_mempool_t
*mpctx0 FLARG
) {
1935 isc__mempool_t
*mpctx
= (isc__mempool_t
*)mpctx0
;
1940 REQUIRE(VALID_MEMPOOL(mpctx
));
1944 if (mpctx
->lock
!= NULL
)
1948 * Don't let the caller go over quota
1950 if (mpctx
->allocated
>= mpctx
->maxalloc
) {
1956 * if we have a free list item, return the first here
1958 item
= mpctx
->items
;
1960 mpctx
->items
= item
->next
;
1961 INSIST(mpctx
->freecount
> 0);
1969 * We need to dip into the well. Lock the memory context here and
1970 * fill up our free list.
1972 MCTXLOCK(mctx
, &mctx
->lock
);
1973 for (i
= 0; i
< mpctx
->fillcount
; i
++) {
1974 if ((mctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
1975 item
= mem_getunlocked(mctx
, mpctx
->size
);
1977 item
= mem_get(mctx
, mpctx
->size
);
1979 mem_getstats(mctx
, mpctx
->size
);
1983 item
->next
= mpctx
->items
;
1984 mpctx
->items
= item
;
1987 MCTXUNLOCK(mctx
, &mctx
->lock
);
1990 * If we didn't get any items, return NULL.
1992 item
= mpctx
->items
;
1996 mpctx
->items
= item
->next
;
2002 if (mpctx
->lock
!= NULL
)
2003 UNLOCK(mpctx
->lock
);
2005 #if ISC_MEM_TRACKLINES
2007 MCTXLOCK(mctx
, &mctx
->lock
);
2008 ADD_TRACE(mctx
, item
, mpctx
->size
, file
, line
);
2009 MCTXUNLOCK(mctx
, &mctx
->lock
);
2011 #endif /* ISC_MEM_TRACKLINES */
2016 ISC_MEMFUNC_SCOPE
void
2017 isc___mempool_put(isc_mempool_t
*mpctx0
, void *mem FLARG
) {
2018 isc__mempool_t
*mpctx
= (isc__mempool_t
*)mpctx0
;
2022 REQUIRE(VALID_MEMPOOL(mpctx
));
2023 REQUIRE(mem
!= NULL
);
2027 if (mpctx
->lock
!= NULL
)
2030 INSIST(mpctx
->allocated
> 0);
2033 #if ISC_MEM_TRACKLINES
2034 MCTXLOCK(mctx
, &mctx
->lock
);
2035 DELETE_TRACE(mctx
, mem
, mpctx
->size
, file
, line
);
2036 MCTXUNLOCK(mctx
, &mctx
->lock
);
2037 #endif /* ISC_MEM_TRACKLINES */
2040 * If our free list is full, return this to the mctx directly.
2042 if (mpctx
->freecount
>= mpctx
->freemax
) {
2043 if ((mctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
2044 MCTXLOCK(mctx
, &mctx
->lock
);
2045 mem_putunlocked(mctx
, mem
, mpctx
->size
);
2046 MCTXUNLOCK(mctx
, &mctx
->lock
);
2048 mem_put(mctx
, mem
, mpctx
->size
);
2049 MCTXLOCK(mctx
, &mctx
->lock
);
2050 mem_putstats(mctx
, mem
, mpctx
->size
);
2051 MCTXUNLOCK(mctx
, &mctx
->lock
);
2053 if (mpctx
->lock
!= NULL
)
2054 UNLOCK(mpctx
->lock
);
2059 * Otherwise, attach it to our free list and bump the counter.
2062 item
= (element
*)mem
;
2063 item
->next
= mpctx
->items
;
2064 mpctx
->items
= item
;
2066 if (mpctx
->lock
!= NULL
)
2067 UNLOCK(mpctx
->lock
);
2074 ISC_MEMFUNC_SCOPE
void
2075 isc__mempool_setfreemax(isc_mempool_t
*mpctx0
, unsigned int limit
) {
2076 isc__mempool_t
*mpctx
= (isc__mempool_t
*)mpctx0
;
2078 REQUIRE(VALID_MEMPOOL(mpctx
));
2080 if (mpctx
->lock
!= NULL
)
2083 mpctx
->freemax
= limit
;
2085 if (mpctx
->lock
!= NULL
)
2086 UNLOCK(mpctx
->lock
);
2089 ISC_MEMFUNC_SCOPE
unsigned int
2090 isc__mempool_getfreemax(isc_mempool_t
*mpctx0
) {
2091 isc__mempool_t
*mpctx
= (isc__mempool_t
*)mpctx0
;
2092 unsigned int freemax
;
2094 REQUIRE(VALID_MEMPOOL(mpctx
));
2096 if (mpctx
->lock
!= NULL
)
2099 freemax
= mpctx
->freemax
;
2101 if (mpctx
->lock
!= NULL
)
2102 UNLOCK(mpctx
->lock
);
2107 ISC_MEMFUNC_SCOPE
unsigned int
2108 isc__mempool_getfreecount(isc_mempool_t
*mpctx0
) {
2109 isc__mempool_t
*mpctx
= (isc__mempool_t
*)mpctx0
;
2110 unsigned int freecount
;
2112 REQUIRE(VALID_MEMPOOL(mpctx
));
2114 if (mpctx
->lock
!= NULL
)
2117 freecount
= mpctx
->freecount
;
2119 if (mpctx
->lock
!= NULL
)
2120 UNLOCK(mpctx
->lock
);
2125 ISC_MEMFUNC_SCOPE
void
2126 isc__mempool_setmaxalloc(isc_mempool_t
*mpctx0
, unsigned int limit
) {
2127 isc__mempool_t
*mpctx
= (isc__mempool_t
*)mpctx0
;
2131 REQUIRE(VALID_MEMPOOL(mpctx
));
2133 if (mpctx
->lock
!= NULL
)
2136 mpctx
->maxalloc
= limit
;
2138 if (mpctx
->lock
!= NULL
)
2139 UNLOCK(mpctx
->lock
);
2142 ISC_MEMFUNC_SCOPE
unsigned int
2143 isc__mempool_getmaxalloc(isc_mempool_t
*mpctx0
) {
2144 isc__mempool_t
*mpctx
= (isc__mempool_t
*)mpctx0
;
2145 unsigned int maxalloc
;
2147 REQUIRE(VALID_MEMPOOL(mpctx
));
2149 if (mpctx
->lock
!= NULL
)
2152 maxalloc
= mpctx
->maxalloc
;
2154 if (mpctx
->lock
!= NULL
)
2155 UNLOCK(mpctx
->lock
);
2160 ISC_MEMFUNC_SCOPE
unsigned int
2161 isc__mempool_getallocated(isc_mempool_t
*mpctx0
) {
2162 isc__mempool_t
*mpctx
= (isc__mempool_t
*)mpctx0
;
2163 unsigned int allocated
;
2165 REQUIRE(VALID_MEMPOOL(mpctx
));
2167 if (mpctx
->lock
!= NULL
)
2170 allocated
= mpctx
->allocated
;
2172 if (mpctx
->lock
!= NULL
)
2173 UNLOCK(mpctx
->lock
);
2178 ISC_MEMFUNC_SCOPE
void
2179 isc__mempool_setfillcount(isc_mempool_t
*mpctx0
, unsigned int limit
) {
2180 isc__mempool_t
*mpctx
= (isc__mempool_t
*)mpctx0
;
2183 REQUIRE(VALID_MEMPOOL(mpctx
));
2185 if (mpctx
->lock
!= NULL
)
2188 mpctx
->fillcount
= limit
;
2190 if (mpctx
->lock
!= NULL
)
2191 UNLOCK(mpctx
->lock
);
2194 ISC_MEMFUNC_SCOPE
unsigned int
2195 isc__mempool_getfillcount(isc_mempool_t
*mpctx0
) {
2196 isc__mempool_t
*mpctx
= (isc__mempool_t
*)mpctx0
;
2198 unsigned int fillcount
;
2200 REQUIRE(VALID_MEMPOOL(mpctx
));
2202 if (mpctx
->lock
!= NULL
)
2205 fillcount
= mpctx
->fillcount
;
2207 if (mpctx
->lock
!= NULL
)
2208 UNLOCK(mpctx
->lock
);
2213 #ifdef USE_MEMIMPREGISTER
2215 isc__mem_register() {
2216 return (isc_mem_register(isc__mem_create2
));
2221 ISC_MEMFUNC_SCOPE
void
2222 isc__mem_printactive(isc_mem_t
*ctx0
, FILE *file
) {
2223 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
2225 REQUIRE(VALID_CONTEXT(ctx
));
2226 REQUIRE(file
!= NULL
);
2228 #if !ISC_MEM_TRACKLINES
2232 print_active(ctx
, file
);
2236 ISC_MEMFUNC_SCOPE
void
2237 isc__mem_printallactive(FILE *file
) {
2238 #if !ISC_MEM_TRACKLINES
2243 RUNTIME_CHECK(isc_once_do(&once
, initialize_action
) == ISC_R_SUCCESS
);
2246 for (ctx
= ISC_LIST_HEAD(contexts
);
2248 ctx
= ISC_LIST_NEXT(ctx
, link
)) {
2249 fprintf(file
, "context: %p\n", ctx
);
2250 print_active(ctx
, file
);
2256 ISC_MEMFUNC_SCOPE
void
2257 isc__mem_checkdestroyed(FILE *file
) {
2259 RUNTIME_CHECK(isc_once_do(&once
, initialize_action
) == ISC_R_SUCCESS
);
2262 if (!ISC_LIST_EMPTY(contexts
)) {
2263 #if ISC_MEM_TRACKLINES
2266 for (ctx
= ISC_LIST_HEAD(contexts
);
2268 ctx
= ISC_LIST_NEXT(ctx
, link
)) {
2269 fprintf(file
, "context: %p\n", ctx
);
2270 print_active(ctx
, file
);
2279 ISC_MEMFUNC_SCOPE
unsigned int
2280 isc_mem_references(isc_mem_t
*ctx0
) {
2281 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
2282 unsigned int references
;
2284 REQUIRE(VALID_CONTEXT(ctx
));
2286 MCTXLOCK(ctx
, &ctx
->lock
);
2287 references
= ctx
->references
;
2288 MCTXUNLOCK(ctx
, &ctx
->lock
);
2290 return (references
);
2295 typedef struct summarystat
{
2298 isc_uint64_t blocksize
;
2299 isc_uint64_t contextsize
;
2303 renderctx(isc__mem_t
*ctx
, summarystat_t
*summary
, xmlTextWriterPtr writer
) {
2304 REQUIRE(VALID_CONTEXT(ctx
));
2306 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"context");
2308 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"id");
2309 xmlTextWriterWriteFormatString(writer
, "%p", ctx
);
2310 xmlTextWriterEndElement(writer
); /* id */
2312 if (ctx
->name
[0] != 0) {
2313 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"name");
2314 xmlTextWriterWriteFormatString(writer
, "%s", ctx
->name
);
2315 xmlTextWriterEndElement(writer
); /* name */
2318 REQUIRE(VALID_CONTEXT(ctx
));
2319 MCTXLOCK(ctx
, &ctx
->lock
);
2321 summary
->contextsize
+= sizeof(*ctx
) +
2322 (ctx
->max_size
+ 1) * sizeof(struct stats
) +
2323 ctx
->max_size
* sizeof(element
*) +
2324 ctx
->basic_table_count
* sizeof(char *);
2325 #if ISC_MEM_TRACKLINES
2326 if (ctx
->debuglist
!= NULL
) {
2327 summary
->contextsize
+=
2328 (ctx
->max_size
+ 1) * sizeof(debuglist_t
) +
2329 ctx
->debuglistcnt
* sizeof(debuglink_t
);
2332 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"references");
2333 xmlTextWriterWriteFormatString(writer
, "%d", ctx
->references
);
2334 xmlTextWriterEndElement(writer
); /* references */
2336 summary
->total
+= ctx
->total
;
2337 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"total");
2338 xmlTextWriterWriteFormatString(writer
, "%" ISC_PRINT_QUADFORMAT
"u",
2339 (isc_uint64_t
)ctx
->total
);
2340 xmlTextWriterEndElement(writer
); /* total */
2342 summary
->inuse
+= ctx
->inuse
;
2343 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"inuse");
2344 xmlTextWriterWriteFormatString(writer
, "%" ISC_PRINT_QUADFORMAT
"u",
2345 (isc_uint64_t
)ctx
->inuse
);
2346 xmlTextWriterEndElement(writer
); /* inuse */
2348 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"maxinuse");
2349 xmlTextWriterWriteFormatString(writer
, "%" ISC_PRINT_QUADFORMAT
"u",
2350 (isc_uint64_t
)ctx
->maxinuse
);
2351 xmlTextWriterEndElement(writer
); /* maxinuse */
2353 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"blocksize");
2354 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
2355 summary
->blocksize
+= ctx
->basic_table_count
*
2356 NUM_BASIC_BLOCKS
* ctx
->mem_target
;
2357 xmlTextWriterWriteFormatString(writer
,
2358 "%" ISC_PRINT_QUADFORMAT
"u",
2360 ctx
->basic_table_count
*
2364 xmlTextWriterWriteFormatString(writer
, "%s", "-");
2365 xmlTextWriterEndElement(writer
); /* blocksize */
2367 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"pools");
2368 xmlTextWriterWriteFormatString(writer
, "%u", ctx
->poolcnt
);
2369 xmlTextWriterEndElement(writer
); /* pools */
2370 summary
->contextsize
+= ctx
->poolcnt
* sizeof(isc_mempool_t
);
2372 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"hiwater");
2373 xmlTextWriterWriteFormatString(writer
, "%" ISC_PRINT_QUADFORMAT
"u",
2374 (isc_uint64_t
)ctx
->hi_water
);
2375 xmlTextWriterEndElement(writer
); /* hiwater */
2377 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"lowater");
2378 xmlTextWriterWriteFormatString(writer
, "%" ISC_PRINT_QUADFORMAT
"u",
2379 (isc_uint64_t
)ctx
->lo_water
);
2380 xmlTextWriterEndElement(writer
); /* lowater */
2382 MCTXUNLOCK(ctx
, &ctx
->lock
);
2384 xmlTextWriterEndElement(writer
); /* context */
2388 isc_mem_renderxml(xmlTextWriterPtr writer
) {
2390 summarystat_t summary
;
2393 memset(&summary
, 0, sizeof(summary
));
2395 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"contexts");
2397 RUNTIME_CHECK(isc_once_do(&once
, initialize_action
) == ISC_R_SUCCESS
);
2401 for (ctx
= ISC_LIST_HEAD(contexts
);
2403 ctx
= ISC_LIST_NEXT(ctx
, link
)) {
2404 renderctx(ctx
, &summary
, writer
);
2408 xmlTextWriterEndElement(writer
); /* contexts */
2410 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"summary");
2412 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"TotalUse");
2413 xmlTextWriterWriteFormatString(writer
, "%" ISC_PRINT_QUADFORMAT
"u",
2415 xmlTextWriterEndElement(writer
); /* TotalUse */
2417 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"InUse");
2418 xmlTextWriterWriteFormatString(writer
, "%" ISC_PRINT_QUADFORMAT
"u",
2420 xmlTextWriterEndElement(writer
); /* InUse */
2422 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"BlockSize");
2423 xmlTextWriterWriteFormatString(writer
, "%" ISC_PRINT_QUADFORMAT
"u",
2425 xmlTextWriterEndElement(writer
); /* BlockSize */
2427 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"ContextSize");
2428 xmlTextWriterWriteFormatString(writer
, "%" ISC_PRINT_QUADFORMAT
"u",
2429 summary
.contextsize
);
2430 xmlTextWriterEndElement(writer
); /* ContextSize */
2432 xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"Lost");
2433 xmlTextWriterWriteFormatString(writer
, "%" ISC_PRINT_QUADFORMAT
"u",
2435 xmlTextWriterEndElement(writer
); /* Lost */
2437 xmlTextWriterEndElement(writer
); /* summary */
2440 #endif /* HAVE_LIBXML2 */