1 /* $NetBSD: mem.c,v 1.12 2015/07/08 17:28:59 christos Exp $ */
4 * Copyright (C) 2004-2010, 2012-2015 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.
32 #include <isc/bind9.h>
34 #include <isc/magic.h>
38 #include <isc/ondestroy.h>
39 #include <isc/string.h>
40 #include <isc/mutex.h>
41 #include <isc/print.h>
45 #define MCTXLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) LOCK(l)
46 #define MCTXUNLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) UNLOCK(l)
48 #ifndef ISC_MEM_DEBUGGING
49 #define ISC_MEM_DEBUGGING 0
51 LIBISC_EXTERNAL_DATA
unsigned int isc_mem_debugging
= ISC_MEM_DEBUGGING
;
57 #define DEF_MAX_SIZE 1100
58 #define DEF_MEM_TARGET 4096
59 #define ALIGNMENT_SIZE 8U /*%< must be a power of 2 */
60 #define NUM_BASIC_BLOCKS 64 /*%< must be > 1 */
61 #define TABLE_INCREMENT 1024
62 #define DEBUGLIST_COUNT 1024
67 typedef struct isc__mem isc__mem_t
;
68 typedef struct isc__mempool isc__mempool_t
;
70 #if ISC_MEM_TRACKLINES
71 typedef struct debuglink debuglink_t
;
73 ISC_LINK(debuglink_t
) link
;
74 const void *ptr
[DEBUGLIST_COUNT
];
75 size_t size
[DEBUGLIST_COUNT
];
76 const char *file
[DEBUGLIST_COUNT
];
77 unsigned int line
[DEBUGLIST_COUNT
];
81 #define FLARG_PASS , file, line
82 #define FLARG , const char *file, unsigned int line
88 typedef struct element element
;
95 * This structure must be ALIGNMENT_SIZE bytes.
100 char bytes
[ALIGNMENT_SIZE
];
106 unsigned long totalgets
;
107 unsigned long blocks
;
108 unsigned long freefrags
;
111 #define MEM_MAGIC ISC_MAGIC('M', 'e', 'm', 'C')
112 #define VALID_CONTEXT(c) ISC_MAGIC_VALID(c, MEM_MAGIC)
114 #if ISC_MEM_TRACKLINES
115 typedef ISC_LIST(debuglink_t
) debuglist_t
;
118 /* List of all active memory contexts. */
120 static ISC_LIST(isc__mem_t
) contexts
;
122 static isc_once_t once
= ISC_ONCE_INIT
;
123 static isc_mutex_t contextslock
;
124 static isc_mutex_t createlock
;
127 * Total size of lost memory due to a bug of external library.
128 * Locked by the global lock.
130 static isc_uint64_t totallost
;
134 isc_ondestroy_t ondestroy
;
137 isc_memalloc_t memalloc
;
138 isc_memfree_t memfree
;
141 isc_boolean_t checkfree
;
142 struct stats
* stats
;
143 unsigned int references
;
152 isc_boolean_t hi_called
;
153 isc_boolean_t is_overmem
;
154 isc_mem_water_t water
;
156 ISC_LIST(isc__mempool_t
) pools
;
157 unsigned int poolcnt
;
159 /* ISC_MEMFLAG_INTERNAL */
161 element
** freelists
;
162 element
* basic_blocks
;
163 unsigned char ** basic_table
;
164 unsigned int basic_table_count
;
165 unsigned int basic_table_size
;
166 unsigned char * lowest
;
167 unsigned char * highest
;
169 #if ISC_MEM_TRACKLINES
170 debuglist_t
* debuglist
;
171 unsigned int debuglistcnt
;
174 unsigned int memalloc_failures
;
175 ISC_LINK(isc__mem_t
) link
;
178 #define MEMPOOL_MAGIC ISC_MAGIC('M', 'E', 'M', 'p')
179 #define VALID_MEMPOOL(c) ISC_MAGIC_VALID(c, MEMPOOL_MAGIC)
181 struct isc__mempool
{
182 /* always unlocked */
183 isc_mempool_t common
; /*%< common header of mempool's */
184 isc_mutex_t
*lock
; /*%< optional lock */
185 isc__mem_t
*mctx
; /*%< our memory context */
186 /*%< locked via the memory context's lock */
187 ISC_LINK(isc__mempool_t
) link
; /*%< next pool in this mem context */
188 /*%< optionally locked from here down */
189 element
*items
; /*%< low water item list */
190 size_t size
; /*%< size of each item on this pool */
191 unsigned int maxalloc
; /*%< max number of items allowed */
192 unsigned int allocated
; /*%< # of items currently given out */
193 unsigned int freecount
; /*%< # of items on reserved list */
194 unsigned int freemax
; /*%< # of items allowed on free list */
195 unsigned int fillcount
; /*%< # of items to fetch on each fill */
197 unsigned int gets
; /*%< # of requests to this pool */
198 /*%< Debugging only. */
199 #if ISC_MEMPOOL_NAMES
200 char name
[16]; /*%< printed name in stats reports */
205 * Private Inline-able.
208 #if ! ISC_MEM_TRACKLINES
209 #define ADD_TRACE(a, b, c, d, e)
210 #define DELETE_TRACE(a, b, c, d, e)
211 #define ISC_MEMFUNC_SCOPE
213 #define ADD_TRACE(a, b, c, d, e) \
215 if ((isc_mem_debugging & (ISC_MEM_DEBUGTRACE | \
216 ISC_MEM_DEBUGRECORD)) != 0 && \
218 add_trace_entry(a, b, c, d, e); \
219 } while (/*CONSTCOND*/0)
220 #define DELETE_TRACE(a, b, c, d, e) delete_trace_entry(a, b, c, d, e)
223 print_active(isc__mem_t
*ctx
, FILE *out
);
226 * The following are intended for internal use (indicated by "isc__"
227 * prefix) but are not declared as static, allowing direct access
228 * from unit tests, etc.
232 isc__mem_create2(size_t init_max_size
, size_t target_size
,
233 isc_mem_t
**ctxp
, unsigned int flags
);
235 isc__mem_attach(isc_mem_t
*source
, isc_mem_t
**targetp
);
237 isc__mem_detach(isc_mem_t
**ctxp
);
239 isc___mem_putanddetach(isc_mem_t
**ctxp
, void *ptr
, size_t size FLARG
);
241 isc__mem_destroy(isc_mem_t
**ctxp
);
243 isc__mem_ondestroy(isc_mem_t
*ctx
, isc_task_t
*task
, isc_event_t
**event
);
245 isc___mem_get(isc_mem_t
*ctx
, size_t size FLARG
);
247 isc___mem_put(isc_mem_t
*ctx
, void *ptr
, size_t size FLARG
);
249 isc__mem_stats(isc_mem_t
*ctx
, FILE *out
);
251 isc___mem_allocate(isc_mem_t
*ctx
, size_t size FLARG
);
253 isc___mem_reallocate(isc_mem_t
*ctx
, void *ptr
, size_t size FLARG
);
255 isc___mem_free(isc_mem_t
*ctx
, void *ptr FLARG
);
257 isc___mem_strdup(isc_mem_t
*mctx
, const char *s FLARG
);
259 isc__mem_setdestroycheck(isc_mem_t
*ctx
, isc_boolean_t flag
);
261 isc__mem_setquota(isc_mem_t
*ctx
, size_t quota
);
263 isc__mem_getquota(isc_mem_t
*ctx
);
265 isc__mem_inuse(isc_mem_t
*ctx
);
267 isc__mem_maxinuse(isc_mem_t
*ctx
);
269 isc__mem_total(isc_mem_t
*ctx
);
271 isc__mem_isovermem(isc_mem_t
*ctx
);
273 isc__mem_setwater(isc_mem_t
*ctx
, isc_mem_water_t water
, void *water_arg
,
274 size_t hiwater
, size_t lowater
);
276 isc__mem_waterack(isc_mem_t
*ctx0
, int flag
);
278 isc__mem_setname(isc_mem_t
*ctx
, const char *name
, void *tag
);
280 isc__mem_getname(isc_mem_t
*ctx
);
282 isc__mem_gettag(isc_mem_t
*ctx
);
284 isc__mempool_create(isc_mem_t
*mctx
, size_t size
, isc_mempool_t
**mpctxp
);
286 isc__mempool_setname(isc_mempool_t
*mpctx
, const char *name
);
288 isc__mempool_destroy(isc_mempool_t
**mpctxp
);
290 isc__mempool_associatelock(isc_mempool_t
*mpctx
, isc_mutex_t
*lock
);
292 isc___mempool_get(isc_mempool_t
*mpctx FLARG
);
294 isc___mempool_put(isc_mempool_t
*mpctx
, void *mem FLARG
);
296 isc__mempool_setfreemax(isc_mempool_t
*mpctx
, unsigned int limit
);
298 isc__mempool_getfreemax(isc_mempool_t
*mpctx
);
300 isc__mempool_getfreecount(isc_mempool_t
*mpctx
);
302 isc__mempool_setmaxalloc(isc_mempool_t
*mpctx
, unsigned int limit
);
304 isc__mempool_getmaxalloc(isc_mempool_t
*mpctx
);
306 isc__mempool_getallocated(isc_mempool_t
*mpctx
);
308 isc__mempool_setfillcount(isc_mempool_t
*mpctx
, unsigned int limit
);
310 isc__mempool_getfillcount(isc_mempool_t
*mpctx
);
312 isc__mem_printactive(isc_mem_t
*ctx0
, FILE *file
);
314 isc__mem_printallactive(FILE *file
);
316 isc__mem_references(isc_mem_t
*ctx0
);
317 #endif /* ISC_MEM_TRACKLINES */
319 static struct isc__memmethods
{
320 isc_memmethods_t methods
;
323 * The following are defined just for avoiding unused static functions.
325 void *createx
, *create
, *create2
, *ondestroy
, *stats
,
326 *setquota
, *getquota
, *setname
, *getname
, *gettag
;
334 isc___mem_putanddetach
,
336 isc___mem_reallocate
,
339 isc__mem_setdestroycheck
,
348 (void *)isc_mem_createx
,
349 (void *)isc_mem_create
,
350 (void *)isc_mem_create2
,
351 (void *)isc_mem_ondestroy
,
352 (void *)isc_mem_stats
,
353 (void *)isc_mem_setquota
,
354 (void *)isc_mem_getquota
,
355 (void *)isc_mem_setname
,
356 (void *)isc_mem_getname
,
357 (void *)isc_mem_gettag
360 static struct isc__mempoolmethods
{
361 isc_mempoolmethods_t methods
;
364 * The following are defined just for avoiding unused static functions.
366 void *getfreemax
, *getfreecount
, *getmaxalloc
, *getfillcount
;
369 isc__mempool_destroy
,
372 isc__mempool_getallocated
,
373 isc__mempool_setmaxalloc
,
374 isc__mempool_setfreemax
,
375 isc__mempool_setname
,
376 isc__mempool_associatelock
,
377 isc__mempool_setfillcount
379 (void *)isc_mempool_getfreemax
,
380 (void *)isc_mempool_getfreecount
,
381 (void *)isc_mempool_getmaxalloc
,
382 (void *)isc_mempool_getfillcount
385 #if ISC_MEM_TRACKLINES
387 * mctx must be locked.
390 add_trace_entry(isc__mem_t
*mctx
, const void *ptr
, size_t size FLARG
) {
393 size_t mysize
= size
;
395 if ((isc_mem_debugging
& ISC_MEM_DEBUGTRACE
) != 0)
396 fprintf(stderr
, isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
399 "file %s line %u mctx %p\n"),
400 ptr
, size
, file
, line
, mctx
);
402 if (mctx
->debuglist
== NULL
)
405 if (mysize
> mctx
->max_size
)
406 mysize
= mctx
->max_size
;
408 dl
= ISC_LIST_HEAD(mctx
->debuglist
[mysize
]);
410 if (dl
->count
== DEBUGLIST_COUNT
)
412 for (i
= 0; i
< DEBUGLIST_COUNT
; i
++) {
413 if (dl
->ptr
[i
] == NULL
) {
423 dl
= ISC_LIST_NEXT(dl
, link
);
426 dl
= malloc(sizeof(debuglink_t
));
429 ISC_LINK_INIT(dl
, link
);
430 for (i
= 1; i
< DEBUGLIST_COUNT
; i
++) {
443 ISC_LIST_PREPEND(mctx
->debuglist
[mysize
], dl
, link
);
444 mctx
->debuglistcnt
++;
448 delete_trace_entry(isc__mem_t
*mctx
, const void *ptr
, size_t size
,
449 const char *file
, unsigned int line
)
454 if ((isc_mem_debugging
& ISC_MEM_DEBUGTRACE
) != 0)
455 fprintf(stderr
, isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
458 "file %s line %u mctx %p\n"),
459 ptr
, size
, file
, line
, mctx
);
461 if (mctx
->debuglist
== NULL
)
464 if (size
> mctx
->max_size
)
465 size
= mctx
->max_size
;
467 dl
= ISC_LIST_HEAD(mctx
->debuglist
[size
]);
469 for (i
= 0; i
< DEBUGLIST_COUNT
; i
++) {
470 if (dl
->ptr
[i
] == ptr
) {
476 INSIST(dl
->count
> 0);
478 if (dl
->count
== 0) {
479 ISC_LIST_UNLINK(mctx
->debuglist
[size
],
486 dl
= ISC_LIST_NEXT(dl
, link
);
490 * If we get here, we didn't find the item on the list. We're
495 #endif /* ISC_MEM_TRACKLINES */
498 rmsize(size_t size
) {
500 * round down to ALIGNMENT_SIZE
502 return (size
& (~(ALIGNMENT_SIZE
- 1)));
506 quantize(size_t size
) {
508 * Round up the result in order to get a size big
509 * enough to satisfy the request and be aligned on ALIGNMENT_SIZE
514 return (ALIGNMENT_SIZE
);
515 return ((size
+ ALIGNMENT_SIZE
- 1) & (~(ALIGNMENT_SIZE
- 1)));
518 static inline isc_boolean_t
519 more_basic_blocks(isc__mem_t
*ctx
) {
521 unsigned char *curr
, *next
;
522 unsigned char *first
, *last
;
523 unsigned char **table
;
524 unsigned int table_size
;
528 /* Require: we hold the context lock. */
531 * Did we hit the quota for this context?
533 increment
= NUM_BASIC_BLOCKS
* ctx
->mem_target
;
534 if (ctx
->quota
!= 0U && ctx
->total
+ increment
> ctx
->quota
)
537 INSIST(ctx
->basic_table_count
<= ctx
->basic_table_size
);
538 if (ctx
->basic_table_count
== ctx
->basic_table_size
) {
539 table_size
= ctx
->basic_table_size
+ TABLE_INCREMENT
;
540 table
= (ctx
->memalloc
)(ctx
->arg
,
541 table_size
* sizeof(unsigned char *));
543 ctx
->memalloc_failures
++;
546 if (ctx
->basic_table_size
!= 0) {
547 memmove(table
, ctx
->basic_table
,
548 ctx
->basic_table_size
*
549 sizeof(unsigned char *));
550 (ctx
->memfree
)(ctx
->arg
, ctx
->basic_table
);
552 ctx
->basic_table
= table
;
553 ctx
->basic_table_size
= table_size
;
556 new = (ctx
->memalloc
)(ctx
->arg
, NUM_BASIC_BLOCKS
* ctx
->mem_target
);
558 ctx
->memalloc_failures
++;
561 ctx
->total
+= increment
;
562 ctx
->basic_table
[ctx
->basic_table_count
] = new;
563 ctx
->basic_table_count
++;
566 next
= curr
+ ctx
->mem_target
;
567 for (i
= 0; i
< (NUM_BASIC_BLOCKS
- 1); i
++) {
568 ((element
*)curr
)->next
= (element
*)next
;
570 next
+= ctx
->mem_target
;
573 * curr is now pointing at the last block in the
576 ((element
*)curr
)->next
= NULL
;
578 last
= first
+ NUM_BASIC_BLOCKS
* ctx
->mem_target
- 1;
579 if (first
< ctx
->lowest
|| ctx
->lowest
== NULL
)
581 if (last
> ctx
->highest
)
583 ctx
->basic_blocks
= new;
588 static inline isc_boolean_t
589 more_frags(isc__mem_t
*ctx
, size_t new_size
) {
593 unsigned char *curr
, *next
;
596 * Try to get more fragments by chopping up a basic block.
599 if (ctx
->basic_blocks
== NULL
) {
600 if (!more_basic_blocks(ctx
)) {
602 * We can't get more memory from the OS, or we've
603 * hit the quota for this context.
606 * XXXRTH "At quota" notification here.
612 total_size
= ctx
->mem_target
;
613 new = ctx
->basic_blocks
;
614 ctx
->basic_blocks
= ctx
->basic_blocks
->next
;
615 frags
= (int)(total_size
/ new_size
);
616 ctx
->stats
[new_size
].blocks
++;
617 ctx
->stats
[new_size
].freefrags
+= frags
;
619 * Set up a linked-list of blocks of size
623 next
= curr
+ new_size
;
624 total_size
-= new_size
;
625 for (i
= 0; i
< (frags
- 1); i
++) {
626 ((element
*)curr
)->next
= (element
*)next
;
629 total_size
-= new_size
;
632 * Add the remaining fragment of the basic block to a free list.
634 total_size
= rmsize(total_size
);
635 if (total_size
> 0U) {
636 ((element
*)next
)->next
= ctx
->freelists
[total_size
];
637 ctx
->freelists
[total_size
] = (element
*)next
;
638 ctx
->stats
[total_size
].freefrags
++;
641 * curr is now pointing at the last block in the
644 ((element
*)curr
)->next
= NULL
;
645 ctx
->freelists
[new_size
] = new;
651 mem_getunlocked(isc__mem_t
*ctx
, size_t size
) {
652 size_t new_size
= quantize(size
);
655 if (size
>= ctx
->max_size
|| new_size
>= ctx
->max_size
) {
657 * memget() was called on something beyond our upper limit.
659 if (ctx
->quota
!= 0U && ctx
->total
+ size
> ctx
->quota
) {
663 ret
= (ctx
->memalloc
)(ctx
->arg
, size
);
665 ctx
->memalloc_failures
++;
670 ctx
->stats
[ctx
->max_size
].gets
++;
671 ctx
->stats
[ctx
->max_size
].totalgets
++;
673 * If we don't set new_size to size, then the
674 * ISC_MEM_FILL code might write over bytes we
682 * If there are no blocks in the free list for this size, get a chunk
683 * of memory and then break it up into "new_size"-sized blocks, adding
684 * them to the free list.
686 if (ctx
->freelists
[new_size
] == NULL
&& !more_frags(ctx
, new_size
))
690 * The free list uses the "rounded-up" size "new_size".
692 ret
= ctx
->freelists
[new_size
];
693 ctx
->freelists
[new_size
] = ctx
->freelists
[new_size
]->next
;
696 * The stats[] uses the _actual_ "size" requested by the
697 * caller, with the caveat (in the code above) that "size" >= the
698 * max. size (max_size) ends up getting recorded as a call to
701 ctx
->stats
[size
].gets
++;
702 ctx
->stats
[size
].totalgets
++;
703 ctx
->stats
[new_size
].freefrags
--;
704 ctx
->inuse
+= new_size
;
710 memset(ret
, 0xbe, new_size
); /* Mnemonic for "beef". */
716 #if ISC_MEM_FILL && ISC_MEM_CHECKOVERRUN
718 check_overrun(void *mem
, size_t size
, size_t new_size
) {
721 cp
= (unsigned char *)mem
;
723 while (size
< new_size
) {
731 /* coverity[+free : arg-1] */
733 mem_putunlocked(isc__mem_t
*ctx
, void *mem
, size_t size
) {
734 size_t new_size
= quantize(size
);
736 if (size
== ctx
->max_size
|| new_size
>= ctx
->max_size
) {
738 * memput() called on something beyond our upper limit.
741 memset(mem
, 0xde, size
); /* Mnemonic for "dead". */
743 (ctx
->memfree
)(ctx
->arg
, mem
);
744 INSIST(ctx
->stats
[ctx
->max_size
].gets
!= 0U);
745 ctx
->stats
[ctx
->max_size
].gets
--;
746 INSIST(size
<= ctx
->inuse
);
752 #if ISC_MEM_CHECKOVERRUN
753 check_overrun(mem
, size
, new_size
);
755 memset(mem
, 0xde, new_size
); /* Mnemonic for "dead". */
759 * The free list uses the "rounded-up" size "new_size".
761 ((element
*)mem
)->next
= ctx
->freelists
[new_size
];
762 ctx
->freelists
[new_size
] = (element
*)mem
;
765 * The stats[] uses the _actual_ "size" requested by the
766 * caller, with the caveat (in the code above) that "size" >= the
767 * max. size (max_size) ends up getting recorded as a call to
770 INSIST(ctx
->stats
[size
].gets
!= 0U);
771 ctx
->stats
[size
].gets
--;
772 ctx
->stats
[new_size
].freefrags
++;
773 ctx
->inuse
-= new_size
;
777 * Perform a malloc, doing memory filling and overrun detection as necessary.
780 mem_get(isc__mem_t
*ctx
, size_t size
) {
783 #if ISC_MEM_CHECKOVERRUN
787 ret
= (ctx
->memalloc
)(ctx
->arg
, size
);
789 ctx
->memalloc_failures
++;
793 memset(ret
, 0xbe, size
); /* Mnemonic for "beef". */
795 # if ISC_MEM_CHECKOVERRUN
805 * Perform a free, doing memory filling and overrun detection as necessary.
807 /* coverity[+free : arg-1] */
809 mem_put(isc__mem_t
*ctx
, void *mem
, size_t size
) {
810 #if ISC_MEM_CHECKOVERRUN
811 INSIST(((unsigned char *)mem
)[size
] == 0xbe);
814 memset(mem
, 0xde, size
); /* Mnemonic for "dead". */
818 (ctx
->memfree
)(ctx
->arg
, mem
);
822 * Update internal counters after a memory get.
825 mem_getstats(isc__mem_t
*ctx
, size_t size
) {
829 if (size
> ctx
->max_size
) {
830 ctx
->stats
[ctx
->max_size
].gets
++;
831 ctx
->stats
[ctx
->max_size
].totalgets
++;
833 ctx
->stats
[size
].gets
++;
834 ctx
->stats
[size
].totalgets
++;
839 * Update internal counters after a memory put.
842 mem_putstats(isc__mem_t
*ctx
, void *ptr
, size_t size
) {
845 INSIST(ctx
->inuse
>= size
);
848 if (size
> ctx
->max_size
) {
849 INSIST(ctx
->stats
[ctx
->max_size
].gets
> 0U);
850 ctx
->stats
[ctx
->max_size
].gets
--;
852 INSIST(ctx
->stats
[size
].gets
> 0U);
853 ctx
->stats
[size
].gets
--;
862 default_memalloc(void *arg
, size_t size
) {
866 return (malloc(size
));
870 default_memfree(void *arg
, void *ptr
) {
876 initialize_action(void) {
877 RUNTIME_CHECK(isc_mutex_init(&createlock
) == ISC_R_SUCCESS
);
878 RUNTIME_CHECK(isc_mutex_init(&contextslock
) == ISC_R_SUCCESS
);
879 ISC_LIST_INIT(contexts
);
888 isc_mem_createx(size_t init_max_size
, size_t target_size
,
889 isc_memalloc_t memalloc
, isc_memfree_t memfree
, void *arg
,
892 return (isc_mem_createx2(init_max_size
, target_size
, memalloc
, memfree
,
893 arg
, ctxp
, ISC_MEMFLAG_DEFAULT
));
898 isc_mem_createx2(size_t init_max_size
, size_t target_size
,
899 isc_memalloc_t memalloc
, isc_memfree_t memfree
, void *arg
,
900 isc_mem_t
**ctxp
, unsigned int flags
)
905 REQUIRE(ctxp
!= NULL
&& *ctxp
== NULL
);
906 REQUIRE(memalloc
!= NULL
);
907 REQUIRE(memfree
!= NULL
);
909 INSIST((ALIGNMENT_SIZE
& (ALIGNMENT_SIZE
- 1)) == 0);
911 RUNTIME_CHECK(isc_once_do(&once
, initialize_action
) == ISC_R_SUCCESS
);
913 ctx
= (memalloc
)(arg
, sizeof(*ctx
));
915 return (ISC_R_NOMEMORY
);
917 if ((flags
& ISC_MEMFLAG_NOLOCK
) == 0) {
918 result
= isc_mutex_init(&ctx
->lock
);
919 if (result
!= ISC_R_SUCCESS
) {
925 if (init_max_size
== 0U)
926 ctx
->max_size
= DEF_MAX_SIZE
;
928 ctx
->max_size
= init_max_size
;
931 memset(ctx
->name
, 0, sizeof(ctx
->name
));
939 ctx
->hi_called
= ISC_FALSE
;
940 ctx
->is_overmem
= ISC_FALSE
;
942 ctx
->water_arg
= NULL
;
943 ctx
->common
.impmagic
= MEM_MAGIC
;
944 ctx
->common
.magic
= ISCAPI_MCTX_MAGIC
;
945 ctx
->common
.methods
= (isc_memmethods_t
*)&memmethods
;
946 isc_ondestroy_init(&ctx
->ondestroy
);
947 ctx
->memalloc
= memalloc
;
948 ctx
->memfree
= memfree
;
951 ctx
->checkfree
= ISC_TRUE
;
952 #if ISC_MEM_TRACKLINES
953 ctx
->debuglist
= NULL
;
954 ctx
->debuglistcnt
= 0;
956 ISC_LIST_INIT(ctx
->pools
);
958 ctx
->freelists
= NULL
;
959 ctx
->basic_blocks
= NULL
;
960 ctx
->basic_table
= NULL
;
961 ctx
->basic_table_count
= 0;
962 ctx
->basic_table_size
= 0;
966 ctx
->stats
= (memalloc
)(arg
,
967 (ctx
->max_size
+1) * sizeof(struct stats
));
968 if (ctx
->stats
== NULL
) {
969 result
= ISC_R_NOMEMORY
;
972 memset(ctx
->stats
, 0, (ctx
->max_size
+ 1) * sizeof(struct stats
));
974 if ((flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
975 if (target_size
== 0U)
976 ctx
->mem_target
= DEF_MEM_TARGET
;
978 ctx
->mem_target
= target_size
;
979 ctx
->freelists
= (memalloc
)(arg
, ctx
->max_size
*
981 if (ctx
->freelists
== NULL
) {
982 result
= ISC_R_NOMEMORY
;
985 memset(ctx
->freelists
, 0,
986 ctx
->max_size
* sizeof(element
*));
989 #if ISC_MEM_TRACKLINES
990 if ((isc_mem_debugging
& ISC_MEM_DEBUGRECORD
) != 0) {
993 ctx
->debuglist
= (memalloc
)(arg
,
994 (ctx
->max_size
+1) * sizeof(debuglist_t
));
995 if (ctx
->debuglist
== NULL
) {
996 result
= ISC_R_NOMEMORY
;
999 for (i
= 0; i
<= ctx
->max_size
; i
++)
1000 ISC_LIST_INIT(ctx
->debuglist
[i
]);
1004 ctx
->memalloc_failures
= 0;
1006 LOCK(&contextslock
);
1007 ISC_LIST_INITANDAPPEND(contexts
, ctx
, link
);
1008 UNLOCK(&contextslock
);
1010 *ctxp
= (isc_mem_t
*)ctx
;
1011 return (ISC_R_SUCCESS
);
1015 if (ctx
->stats
!= NULL
)
1016 (memfree
)(arg
, ctx
->stats
);
1017 if (ctx
->freelists
!= NULL
)
1018 (memfree
)(arg
, ctx
->freelists
);
1019 #if ISC_MEM_TRACKLINES
1020 if (ctx
->debuglist
!= NULL
)
1021 (ctx
->memfree
)(ctx
->arg
, ctx
->debuglist
);
1022 #endif /* ISC_MEM_TRACKLINES */
1023 if ((ctx
->flags
& ISC_MEMFLAG_NOLOCK
) == 0)
1024 DESTROYLOCK(&ctx
->lock
);
1025 (memfree
)(arg
, ctx
);
1032 destroy(isc__mem_t
*ctx
) {
1034 isc_ondestroy_t ondest
;
1036 LOCK(&contextslock
);
1037 ISC_LIST_UNLINK(contexts
, ctx
, link
);
1038 totallost
+= ctx
->inuse
;
1039 UNLOCK(&contextslock
);
1041 ctx
->common
.impmagic
= 0;
1042 ctx
->common
.magic
= 0;
1044 INSIST(ISC_LIST_EMPTY(ctx
->pools
));
1046 #if ISC_MEM_TRACKLINES
1047 if (ctx
->debuglist
!= NULL
) {
1048 if (ctx
->checkfree
) {
1049 for (i
= 0; i
<= ctx
->max_size
; i
++) {
1050 if (!ISC_LIST_EMPTY(ctx
->debuglist
[i
]))
1051 print_active(ctx
, stderr
);
1052 INSIST(ISC_LIST_EMPTY(ctx
->debuglist
[i
]));
1057 for (i
= 0; i
<= ctx
->max_size
; i
++)
1058 for (dl
= ISC_LIST_HEAD(ctx
->debuglist
[i
]);
1060 dl
= ISC_LIST_HEAD(ctx
->debuglist
[i
])) {
1061 ISC_LIST_UNLINK(ctx
->debuglist
[i
],
1066 (ctx
->memfree
)(ctx
->arg
, ctx
->debuglist
);
1069 INSIST(ctx
->references
== 0);
1071 if (ctx
->checkfree
) {
1072 for (i
= 0; i
<= ctx
->max_size
; i
++) {
1073 #if ISC_MEM_TRACKLINES
1074 if (ctx
->stats
[i
].gets
!= 0U)
1075 print_active(ctx
, stderr
);
1077 INSIST(ctx
->stats
[i
].gets
== 0U);
1081 (ctx
->memfree
)(ctx
->arg
, ctx
->stats
);
1083 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
1084 for (i
= 0; i
< ctx
->basic_table_count
; i
++)
1085 (ctx
->memfree
)(ctx
->arg
, ctx
->basic_table
[i
]);
1086 (ctx
->memfree
)(ctx
->arg
, ctx
->freelists
);
1087 if (ctx
->basic_table
!= NULL
)
1088 (ctx
->memfree
)(ctx
->arg
, ctx
->basic_table
);
1091 ondest
= ctx
->ondestroy
;
1093 if ((ctx
->flags
& ISC_MEMFLAG_NOLOCK
) == 0)
1094 DESTROYLOCK(&ctx
->lock
);
1095 (ctx
->memfree
)(ctx
->arg
, ctx
);
1097 isc_ondestroy_notify(&ondest
, ctx
);
1101 isc__mem_attach(isc_mem_t
*source0
, isc_mem_t
**targetp
) {
1102 isc__mem_t
*source
= (isc__mem_t
*)source0
;
1104 REQUIRE(VALID_CONTEXT(source
));
1105 REQUIRE(targetp
!= NULL
&& *targetp
== NULL
);
1107 MCTXLOCK(source
, &source
->lock
);
1108 source
->references
++;
1109 MCTXUNLOCK(source
, &source
->lock
);
1111 *targetp
= (isc_mem_t
*)source
;
1115 isc__mem_detach(isc_mem_t
**ctxp
) {
1117 isc_boolean_t want_destroy
= ISC_FALSE
;
1119 REQUIRE(ctxp
!= NULL
);
1120 ctx
= (isc__mem_t
*)*ctxp
;
1121 REQUIRE(VALID_CONTEXT(ctx
));
1123 MCTXLOCK(ctx
, &ctx
->lock
);
1124 INSIST(ctx
->references
> 0);
1126 if (ctx
->references
== 0)
1127 want_destroy
= ISC_TRUE
;
1128 MCTXUNLOCK(ctx
, &ctx
->lock
);
1137 * isc_mem_putanddetach() is the equivalent of:
1140 * isc_mem_attach(ptr->mctx, &mctx);
1141 * isc_mem_detach(&ptr->mctx);
1142 * isc_mem_put(mctx, ptr, sizeof(*ptr);
1143 * isc_mem_detach(&mctx);
1147 isc___mem_putanddetach(isc_mem_t
**ctxp
, void *ptr
, size_t size FLARG
) {
1149 isc_boolean_t want_destroy
= ISC_FALSE
;
1153 REQUIRE(ctxp
!= NULL
);
1154 ctx
= (isc__mem_t
*)*ctxp
;
1155 REQUIRE(VALID_CONTEXT(ctx
));
1156 REQUIRE(ptr
!= NULL
);
1159 * Must be before mem_putunlocked() as ctxp is usually within
1164 if ((isc_mem_debugging
& (ISC_MEM_DEBUGSIZE
|ISC_MEM_DEBUGCTX
)) != 0) {
1165 if ((isc_mem_debugging
& ISC_MEM_DEBUGSIZE
) != 0) {
1166 si
= &(((size_info
*)ptr
)[-1]);
1167 oldsize
= si
->u
.size
- ALIGNMENT_SIZE
;
1168 if ((isc_mem_debugging
& ISC_MEM_DEBUGCTX
) != 0)
1169 oldsize
-= ALIGNMENT_SIZE
;
1170 INSIST(oldsize
== size
);
1172 isc__mem_free((isc_mem_t
*)ctx
, ptr FLARG_PASS
);
1174 MCTXLOCK(ctx
, &ctx
->lock
);
1176 if (ctx
->references
== 0)
1177 want_destroy
= ISC_TRUE
;
1178 MCTXUNLOCK(ctx
, &ctx
->lock
);
1185 MCTXLOCK(ctx
, &ctx
->lock
);
1187 DELETE_TRACE(ctx
, ptr
, size
, file
, line
);
1189 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
1190 mem_putunlocked(ctx
, ptr
, size
);
1192 mem_putstats(ctx
, ptr
, size
);
1193 mem_put(ctx
, ptr
, size
);
1196 INSIST(ctx
->references
> 0);
1198 if (ctx
->references
== 0)
1199 want_destroy
= ISC_TRUE
;
1201 MCTXUNLOCK(ctx
, &ctx
->lock
);
1208 isc__mem_destroy(isc_mem_t
**ctxp
) {
1212 * This routine provides legacy support for callers who use mctxs
1213 * without attaching/detaching.
1216 REQUIRE(ctxp
!= NULL
);
1217 ctx
= (isc__mem_t
*)*ctxp
;
1218 REQUIRE(VALID_CONTEXT(ctx
));
1220 MCTXLOCK(ctx
, &ctx
->lock
);
1221 #if ISC_MEM_TRACKLINES
1222 if (ctx
->references
!= 1)
1223 print_active(ctx
, stderr
);
1225 REQUIRE(ctx
->references
== 1);
1227 MCTXUNLOCK(ctx
, &ctx
->lock
);
1235 isc_mem_ondestroy(isc_mem_t
*ctx0
, isc_task_t
*task
, isc_event_t
**event
) {
1236 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1239 MCTXLOCK(ctx
, &ctx
->lock
);
1240 res
= isc_ondestroy_register(&ctx
->ondestroy
, task
, event
);
1241 MCTXUNLOCK(ctx
, &ctx
->lock
);
1247 isc___mem_get(isc_mem_t
*ctx0
, size_t size FLARG
) {
1248 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1250 isc_boolean_t call_water
= ISC_FALSE
;
1252 REQUIRE(VALID_CONTEXT(ctx
));
1254 if ((isc_mem_debugging
& (ISC_MEM_DEBUGSIZE
|ISC_MEM_DEBUGCTX
)) != 0)
1255 return (isc__mem_allocate(ctx0
, size FLARG_PASS
));
1257 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
1258 MCTXLOCK(ctx
, &ctx
->lock
);
1259 ptr
= mem_getunlocked(ctx
, size
);
1261 ptr
= mem_get(ctx
, size
);
1262 MCTXLOCK(ctx
, &ctx
->lock
);
1264 mem_getstats(ctx
, size
);
1267 ADD_TRACE(ctx
, ptr
, size
, file
, line
);
1268 if (ctx
->hi_water
!= 0U && ctx
->inuse
> ctx
->hi_water
&&
1270 ctx
->is_overmem
= ISC_TRUE
;
1272 if (ctx
->hi_water
!= 0U && !ctx
->hi_called
&&
1273 ctx
->inuse
> ctx
->hi_water
) {
1274 call_water
= ISC_TRUE
;
1276 if (ctx
->inuse
> ctx
->maxinuse
) {
1277 ctx
->maxinuse
= ctx
->inuse
;
1278 if (ctx
->hi_water
!= 0U && ctx
->inuse
> ctx
->hi_water
&&
1279 (isc_mem_debugging
& ISC_MEM_DEBUGUSAGE
) != 0)
1280 fprintf(stderr
, "maxinuse = %lu\n",
1281 (unsigned long)ctx
->inuse
);
1283 MCTXUNLOCK(ctx
, &ctx
->lock
);
1286 (ctx
->water
)(ctx
->water_arg
, ISC_MEM_HIWATER
);
1292 isc___mem_put(isc_mem_t
*ctx0
, void *ptr
, size_t size FLARG
) {
1293 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1294 isc_boolean_t call_water
= ISC_FALSE
;
1298 REQUIRE(VALID_CONTEXT(ctx
));
1299 REQUIRE(ptr
!= NULL
);
1301 if ((isc_mem_debugging
& (ISC_MEM_DEBUGSIZE
|ISC_MEM_DEBUGCTX
)) != 0) {
1302 if ((isc_mem_debugging
& ISC_MEM_DEBUGSIZE
) != 0) {
1303 si
= &(((size_info
*)ptr
)[-1]);
1304 oldsize
= si
->u
.size
- ALIGNMENT_SIZE
;
1305 if ((isc_mem_debugging
& ISC_MEM_DEBUGCTX
) != 0)
1306 oldsize
-= ALIGNMENT_SIZE
;
1307 INSIST(oldsize
== size
);
1309 isc__mem_free((isc_mem_t
*)ctx
, ptr FLARG_PASS
);
1313 MCTXLOCK(ctx
, &ctx
->lock
);
1315 DELETE_TRACE(ctx
, ptr
, size
, file
, line
);
1317 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
1318 mem_putunlocked(ctx
, ptr
, size
);
1320 mem_putstats(ctx
, ptr
, size
);
1321 mem_put(ctx
, ptr
, size
);
1325 * The check against ctx->lo_water == 0 is for the condition
1326 * when the context was pushed over hi_water but then had
1327 * isc_mem_setwater() called with 0 for hi_water and lo_water.
1329 if (ctx
->is_overmem
&&
1330 (ctx
->inuse
< ctx
->lo_water
|| ctx
->lo_water
== 0U)) {
1331 ctx
->is_overmem
= ISC_FALSE
;
1333 if (ctx
->hi_called
&&
1334 (ctx
->inuse
< ctx
->lo_water
|| ctx
->lo_water
== 0U)) {
1335 if (ctx
->water
!= NULL
)
1336 call_water
= ISC_TRUE
;
1338 MCTXUNLOCK(ctx
, &ctx
->lock
);
1341 (ctx
->water
)(ctx
->water_arg
, ISC_MEM_LOWATER
);
1345 isc__mem_waterack(isc_mem_t
*ctx0
, int flag
) {
1346 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1348 REQUIRE(VALID_CONTEXT(ctx
));
1350 MCTXLOCK(ctx
, &ctx
->lock
);
1351 if (flag
== ISC_MEM_LOWATER
)
1352 ctx
->hi_called
= ISC_FALSE
;
1353 else if (flag
== ISC_MEM_HIWATER
)
1354 ctx
->hi_called
= ISC_TRUE
;
1355 MCTXUNLOCK(ctx
, &ctx
->lock
);
1358 #if ISC_MEM_TRACKLINES
1360 print_active(isc__mem_t
*mctx
, FILE *out
) {
1361 if (mctx
->debuglist
!= NULL
) {
1365 isc_boolean_t found
;
1367 fprintf(out
, "%s", isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1369 "Dump of all outstanding "
1370 "memory allocations:\n"));
1372 format
= isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1373 ISC_MSG_PTRFILELINE
,
1374 "\tptr %p size %u file %s line %u\n");
1375 for (i
= 0; i
<= mctx
->max_size
; i
++) {
1376 dl
= ISC_LIST_HEAD(mctx
->debuglist
[i
]);
1381 while (dl
!= NULL
) {
1382 for (j
= 0; j
< DEBUGLIST_COUNT
; j
++)
1383 if (dl
->ptr
[j
] != NULL
)
1384 fprintf(out
, format
,
1389 dl
= ISC_LIST_NEXT(dl
, link
);
1393 fprintf(out
, "%s", isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1394 ISC_MSG_NONE
, "\tNone.\n"));
1400 * Print the stats[] on the stream "out" with suitable formatting.
1403 isc_mem_stats(isc_mem_t
*ctx0
, FILE *out
) {
1404 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1406 const struct stats
*s
;
1407 const isc__mempool_t
*pool
;
1409 REQUIRE(VALID_CONTEXT(ctx
));
1410 MCTXLOCK(ctx
, &ctx
->lock
);
1412 for (i
= 0; i
<= ctx
->max_size
; i
++) {
1415 if (s
->totalgets
== 0U && s
->gets
== 0U)
1417 fprintf(out
, "%s%5lu: %11lu gets, %11lu rem",
1418 (i
== ctx
->max_size
) ? ">=" : " ",
1419 (unsigned long) i
, s
->totalgets
, s
->gets
);
1420 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0 &&
1421 (s
->blocks
!= 0U || s
->freefrags
!= 0U))
1422 fprintf(out
, " (%lu bl, %lu ff)",
1423 s
->blocks
, s
->freefrags
);
1428 * Note that since a pool can be locked now, these stats might be
1429 * somewhat off if the pool is in active use at the time the stats
1430 * are dumped. The link fields are protected by the isc_mem_t's
1431 * lock, however, so walking this list and extracting integers from
1432 * stats fields is always safe.
1434 pool
= ISC_LIST_HEAD(ctx
->pools
);
1436 fprintf(out
, "%s", isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1438 "[Pool statistics]\n"));
1439 fprintf(out
, "%15s %10s %10s %10s %10s %10s %10s %10s %1s\n",
1440 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1441 ISC_MSG_POOLNAME
, "name"),
1442 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1443 ISC_MSG_POOLSIZE
, "size"),
1444 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1445 ISC_MSG_POOLMAXALLOC
, "maxalloc"),
1446 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1447 ISC_MSG_POOLALLOCATED
, "allocated"),
1448 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1449 ISC_MSG_POOLFREECOUNT
, "freecount"),
1450 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1451 ISC_MSG_POOLFREEMAX
, "freemax"),
1452 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1453 ISC_MSG_POOLFILLCOUNT
, "fillcount"),
1454 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_MEM
,
1455 ISC_MSG_POOLGETS
, "gets"),
1458 while (pool
!= NULL
) {
1459 fprintf(out
, "%15s %10lu %10u %10u %10u %10u %10u %10u %s\n",
1460 #if ISC_MEMPOOL_NAMES
1465 (unsigned long) pool
->size
, pool
->maxalloc
,
1466 pool
->allocated
, pool
->freecount
, pool
->freemax
,
1467 pool
->fillcount
, pool
->gets
,
1468 (pool
->lock
== NULL
? "N" : "Y"));
1469 pool
= ISC_LIST_NEXT(pool
, link
);
1472 #if ISC_MEM_TRACKLINES
1473 print_active(ctx
, out
);
1476 MCTXUNLOCK(ctx
, &ctx
->lock
);
1480 * Replacements for malloc() and free() -- they implicitly remember the
1481 * size of the object allocated (with some additional overhead).
1485 mem_allocateunlocked(isc_mem_t
*ctx0
, size_t size
) {
1486 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1489 size
+= ALIGNMENT_SIZE
;
1490 if ((isc_mem_debugging
& ISC_MEM_DEBUGCTX
) != 0)
1491 size
+= ALIGNMENT_SIZE
;
1493 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0)
1494 si
= mem_getunlocked(ctx
, size
);
1496 si
= mem_get(ctx
, size
);
1500 if ((isc_mem_debugging
& ISC_MEM_DEBUGCTX
) != 0) {
1509 isc___mem_allocate(isc_mem_t
*ctx0
, size_t size FLARG
) {
1510 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1512 isc_boolean_t call_water
= ISC_FALSE
;
1514 REQUIRE(VALID_CONTEXT(ctx
));
1516 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
1517 MCTXLOCK(ctx
, &ctx
->lock
);
1518 si
= mem_allocateunlocked((isc_mem_t
*)ctx
, size
);
1520 si
= mem_allocateunlocked((isc_mem_t
*)ctx
, size
);
1521 MCTXLOCK(ctx
, &ctx
->lock
);
1523 mem_getstats(ctx
, si
[-1].u
.size
);
1526 #if ISC_MEM_TRACKLINES
1527 ADD_TRACE(ctx
, si
, si
[-1].u
.size
, file
, line
);
1529 if (ctx
->hi_water
!= 0U && ctx
->inuse
> ctx
->hi_water
&&
1531 ctx
->is_overmem
= ISC_TRUE
;
1534 if (ctx
->hi_water
!= 0U && !ctx
->hi_called
&&
1535 ctx
->inuse
> ctx
->hi_water
) {
1536 ctx
->hi_called
= ISC_TRUE
;
1537 call_water
= ISC_TRUE
;
1539 if (ctx
->inuse
> ctx
->maxinuse
) {
1540 ctx
->maxinuse
= ctx
->inuse
;
1541 if (ctx
->hi_water
!= 0U && ctx
->inuse
> ctx
->hi_water
&&
1542 (isc_mem_debugging
& ISC_MEM_DEBUGUSAGE
) != 0)
1543 fprintf(stderr
, "maxinuse = %lu\n",
1544 (unsigned long)ctx
->inuse
);
1546 MCTXUNLOCK(ctx
, &ctx
->lock
);
1549 (ctx
->water
)(ctx
->water_arg
, ISC_MEM_HIWATER
);
1555 isc___mem_reallocate(isc_mem_t
*ctx0
, void *ptr
, size_t size FLARG
) {
1556 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1557 void *new_ptr
= NULL
;
1558 size_t oldsize
, copysize
;
1560 REQUIRE(VALID_CONTEXT(ctx
));
1563 * This function emulates the realloc(3) standard library function:
1564 * - if size > 0, allocate new memory; and if ptr is non NULL, copy
1565 * as much of the old contents to the new buffer and free the old one.
1566 * Note that when allocation fails the original pointer is intact;
1567 * the caller must free it.
1568 * - if size is 0 and ptr is non NULL, simply free the given ptr.
1569 * - this function returns:
1570 * pointer to the newly allocated memory, or
1571 * NULL if allocation fails or doesn't happen.
1574 new_ptr
= isc__mem_allocate(ctx0
, size FLARG_PASS
);
1575 if (new_ptr
!= NULL
&& ptr
!= NULL
) {
1576 oldsize
= (((size_info
*)ptr
)[-1]).u
.size
;
1577 INSIST(oldsize
>= ALIGNMENT_SIZE
);
1578 oldsize
-= ALIGNMENT_SIZE
;
1579 if ((isc_mem_debugging
& ISC_MEM_DEBUGCTX
) != 0) {
1580 INSIST(oldsize
>= ALIGNMENT_SIZE
);
1581 oldsize
-= ALIGNMENT_SIZE
;
1583 copysize
= (oldsize
> size
) ? size
: oldsize
;
1584 memmove(new_ptr
, ptr
, copysize
);
1585 isc__mem_free(ctx0
, ptr FLARG_PASS
);
1587 } else if (ptr
!= NULL
)
1588 isc__mem_free(ctx0
, ptr FLARG_PASS
);
1594 isc___mem_free(isc_mem_t
*ctx0
, void *ptr FLARG
) {
1595 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1598 isc_boolean_t call_water
= ISC_FALSE
;
1600 REQUIRE(VALID_CONTEXT(ctx
));
1601 REQUIRE(ptr
!= NULL
);
1603 if ((isc_mem_debugging
& ISC_MEM_DEBUGCTX
) != 0) {
1604 si
= &(((size_info
*)ptr
)[-2]);
1605 REQUIRE(si
->u
.ctx
== ctx
);
1606 size
= si
[1].u
.size
;
1608 si
= &(((size_info
*)ptr
)[-1]);
1612 MCTXLOCK(ctx
, &ctx
->lock
);
1614 DELETE_TRACE(ctx
, ptr
, size
, file
, line
);
1616 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
1617 mem_putunlocked(ctx
, si
, size
);
1619 mem_putstats(ctx
, si
, size
);
1620 mem_put(ctx
, si
, size
);
1624 * The check against ctx->lo_water == 0 is for the condition
1625 * when the context was pushed over hi_water but then had
1626 * isc_mem_setwater() called with 0 for hi_water and lo_water.
1628 if (ctx
->is_overmem
&&
1629 (ctx
->inuse
< ctx
->lo_water
|| ctx
->lo_water
== 0U)) {
1630 ctx
->is_overmem
= ISC_FALSE
;
1633 if (ctx
->hi_called
&&
1634 (ctx
->inuse
< ctx
->lo_water
|| ctx
->lo_water
== 0U)) {
1635 ctx
->hi_called
= ISC_FALSE
;
1637 if (ctx
->water
!= NULL
)
1638 call_water
= ISC_TRUE
;
1640 MCTXUNLOCK(ctx
, &ctx
->lock
);
1643 (ctx
->water
)(ctx
->water_arg
, ISC_MEM_LOWATER
);
1648 * Other useful things.
1652 isc___mem_strdup(isc_mem_t
*mctx0
, const char *s FLARG
) {
1653 isc__mem_t
*mctx
= (isc__mem_t
*)mctx0
;
1657 REQUIRE(VALID_CONTEXT(mctx
));
1662 ns
= isc__mem_allocate((isc_mem_t
*)mctx
, len
+ 1 FLARG_PASS
);
1665 strncpy(ns
, s
, len
+ 1);
1671 isc__mem_setdestroycheck(isc_mem_t
*ctx0
, isc_boolean_t flag
) {
1672 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1674 REQUIRE(VALID_CONTEXT(ctx
));
1675 MCTXLOCK(ctx
, &ctx
->lock
);
1677 ctx
->checkfree
= flag
;
1679 MCTXUNLOCK(ctx
, &ctx
->lock
);
1687 isc_mem_setquota(isc_mem_t
*ctx0
, size_t quota
) {
1688 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1690 REQUIRE(VALID_CONTEXT(ctx
));
1691 MCTXLOCK(ctx
, &ctx
->lock
);
1695 MCTXUNLOCK(ctx
, &ctx
->lock
);
1699 isc_mem_getquota(isc_mem_t
*ctx0
) {
1700 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1703 REQUIRE(VALID_CONTEXT(ctx
));
1704 MCTXLOCK(ctx
, &ctx
->lock
);
1708 MCTXUNLOCK(ctx
, &ctx
->lock
);
1714 isc__mem_inuse(isc_mem_t
*ctx0
) {
1715 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1718 REQUIRE(VALID_CONTEXT(ctx
));
1719 MCTXLOCK(ctx
, &ctx
->lock
);
1723 MCTXUNLOCK(ctx
, &ctx
->lock
);
1729 isc__mem_maxinuse(isc_mem_t
*ctx0
) {
1730 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1733 REQUIRE(VALID_CONTEXT(ctx
));
1734 MCTXLOCK(ctx
, &ctx
->lock
);
1736 maxinuse
= ctx
->maxinuse
;
1738 MCTXUNLOCK(ctx
, &ctx
->lock
);
1744 isc__mem_total(isc_mem_t
*ctx0
) {
1745 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1748 REQUIRE(VALID_CONTEXT(ctx
));
1749 MCTXLOCK(ctx
, &ctx
->lock
);
1753 MCTXUNLOCK(ctx
, &ctx
->lock
);
1759 isc__mem_setwater(isc_mem_t
*ctx0
, isc_mem_water_t water
, void *water_arg
,
1760 size_t hiwater
, size_t lowater
)
1762 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1763 isc_boolean_t callwater
= ISC_FALSE
;
1764 isc_mem_water_t oldwater
;
1767 REQUIRE(VALID_CONTEXT(ctx
));
1768 REQUIRE(hiwater
>= lowater
);
1770 MCTXLOCK(ctx
, &ctx
->lock
);
1771 oldwater
= ctx
->water
;
1772 oldwater_arg
= ctx
->water_arg
;
1773 if (water
== NULL
) {
1774 callwater
= ctx
->hi_called
;
1776 ctx
->water_arg
= NULL
;
1779 ctx
->hi_called
= ISC_FALSE
;
1781 if (ctx
->hi_called
&&
1782 (ctx
->water
!= water
|| ctx
->water_arg
!= water_arg
||
1783 ctx
->inuse
< lowater
|| lowater
== 0U))
1784 callwater
= ISC_TRUE
;
1786 ctx
->water_arg
= water_arg
;
1787 ctx
->hi_water
= hiwater
;
1788 ctx
->lo_water
= lowater
;
1790 MCTXUNLOCK(ctx
, &ctx
->lock
);
1792 if (callwater
&& oldwater
!= NULL
)
1793 (oldwater
)(oldwater_arg
, ISC_MEM_LOWATER
);
1797 isc__mem_isovermem(isc_mem_t
*ctx0
) {
1798 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1800 REQUIRE(VALID_CONTEXT(ctx
));
1803 * We don't bother to lock the context because 100% accuracy isn't
1804 * necessary (and even if we locked the context the returned value
1805 * could be different from the actual state when it's used anyway)
1807 return (ctx
->is_overmem
);
1811 isc_mem_setname(isc_mem_t
*ctx0
, const char *name
, void *tag
) {
1812 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1814 REQUIRE(VALID_CONTEXT(ctx
));
1817 memset(ctx
->name
, 0, sizeof(ctx
->name
));
1818 strncpy(ctx
->name
, name
, sizeof(ctx
->name
) - 1);
1824 isc_mem_getname(isc_mem_t
*ctx0
) {
1825 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1827 REQUIRE(VALID_CONTEXT(ctx
));
1829 if (ctx
->name
[0] == 0)
1836 isc_mem_gettag(isc_mem_t
*ctx0
) {
1837 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
1839 REQUIRE(VALID_CONTEXT(ctx
));
1849 isc__mempool_create(isc_mem_t
*mctx0
, size_t size
, isc_mempool_t
**mpctxp
) {
1850 isc__mem_t
*mctx
= (isc__mem_t
*)mctx0
;
1851 isc__mempool_t
*mpctx
;
1853 REQUIRE(VALID_CONTEXT(mctx
));
1855 REQUIRE(mpctxp
!= NULL
&& *mpctxp
== NULL
);
1858 * Allocate space for this pool, initialize values, and if all works
1859 * well, attach to the memory context.
1861 mpctx
= isc_mem_get((isc_mem_t
*)mctx
, sizeof(isc__mempool_t
));
1863 return (ISC_R_NOMEMORY
);
1865 mpctx
->common
.methods
= (isc_mempoolmethods_t
*)&mempoolmethods
;
1866 mpctx
->common
.impmagic
= MEMPOOL_MAGIC
;
1867 mpctx
->common
.magic
= ISCAPI_MPOOL_MAGIC
;
1871 mpctx
->maxalloc
= UINT_MAX
;
1872 mpctx
->allocated
= 0;
1873 mpctx
->freecount
= 0;
1875 mpctx
->fillcount
= 1;
1877 #if ISC_MEMPOOL_NAMES
1880 mpctx
->items
= NULL
;
1882 *mpctxp
= (isc_mempool_t
*)mpctx
;
1884 MCTXLOCK(mctx
, &mctx
->lock
);
1885 ISC_LIST_INITANDAPPEND(mctx
->pools
, mpctx
, link
);
1887 MCTXUNLOCK(mctx
, &mctx
->lock
);
1889 return (ISC_R_SUCCESS
);
1893 isc__mempool_setname(isc_mempool_t
*mpctx0
, const char *name
) {
1894 isc__mempool_t
*mpctx
= (isc__mempool_t
*)mpctx0
;
1896 REQUIRE(name
!= NULL
);
1897 REQUIRE(VALID_MEMPOOL(mpctx
));
1899 #if ISC_MEMPOOL_NAMES
1900 if (mpctx
->lock
!= NULL
)
1903 strncpy(mpctx
->name
, name
, sizeof(mpctx
->name
) - 1);
1904 mpctx
->name
[sizeof(mpctx
->name
) - 1] = '\0';
1906 if (mpctx
->lock
!= NULL
)
1907 UNLOCK(mpctx
->lock
);
1915 isc__mempool_destroy(isc_mempool_t
**mpctxp
) {
1916 isc__mempool_t
*mpctx
;
1921 REQUIRE(mpctxp
!= NULL
);
1922 mpctx
= (isc__mempool_t
*)*mpctxp
;
1923 REQUIRE(VALID_MEMPOOL(mpctx
));
1924 #if ISC_MEMPOOL_NAMES
1925 if (mpctx
->allocated
> 0)
1926 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
1927 "isc__mempool_destroy(): mempool %s "
1931 REQUIRE(mpctx
->allocated
== 0);
1941 * Return any items on the free list
1943 MCTXLOCK(mctx
, &mctx
->lock
);
1944 while (mpctx
->items
!= NULL
) {
1945 INSIST(mpctx
->freecount
> 0);
1947 item
= mpctx
->items
;
1948 mpctx
->items
= item
->next
;
1950 if ((mctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
1951 mem_putunlocked(mctx
, item
, mpctx
->size
);
1953 mem_putstats(mctx
, item
, mpctx
->size
);
1954 mem_put(mctx
, item
, mpctx
->size
);
1957 MCTXUNLOCK(mctx
, &mctx
->lock
);
1960 * Remove our linked list entry from the memory context.
1962 MCTXLOCK(mctx
, &mctx
->lock
);
1963 ISC_LIST_UNLINK(mctx
->pools
, mpctx
, link
);
1965 MCTXUNLOCK(mctx
, &mctx
->lock
);
1967 mpctx
->common
.impmagic
= 0;
1968 mpctx
->common
.magic
= 0;
1970 isc_mem_put((isc_mem_t
*)mpctx
->mctx
, mpctx
, sizeof(isc__mempool_t
));
1979 isc__mempool_associatelock(isc_mempool_t
*mpctx0
, isc_mutex_t
*lock
) {
1980 isc__mempool_t
*mpctx
= (isc__mempool_t
*)mpctx0
;
1982 REQUIRE(VALID_MEMPOOL(mpctx
));
1983 REQUIRE(mpctx
->lock
== NULL
);
1984 REQUIRE(lock
!= NULL
);
1990 isc___mempool_get(isc_mempool_t
*mpctx0 FLARG
) {
1991 isc__mempool_t
*mpctx
= (isc__mempool_t
*)mpctx0
;
1996 REQUIRE(VALID_MEMPOOL(mpctx
));
2000 if (mpctx
->lock
!= NULL
)
2004 * Don't let the caller go over quota
2006 if (mpctx
->allocated
>= mpctx
->maxalloc
) {
2012 * if we have a free list item, return the first here
2014 item
= mpctx
->items
;
2016 mpctx
->items
= item
->next
;
2017 INSIST(mpctx
->freecount
> 0);
2025 * We need to dip into the well. Lock the memory context here and
2026 * fill up our free list.
2028 MCTXLOCK(mctx
, &mctx
->lock
);
2029 for (i
= 0; i
< mpctx
->fillcount
; i
++) {
2030 if ((mctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
2031 item
= mem_getunlocked(mctx
, mpctx
->size
);
2033 item
= mem_get(mctx
, mpctx
->size
);
2035 mem_getstats(mctx
, mpctx
->size
);
2039 item
->next
= mpctx
->items
;
2040 mpctx
->items
= item
;
2043 MCTXUNLOCK(mctx
, &mctx
->lock
);
2046 * If we didn't get any items, return NULL.
2048 item
= mpctx
->items
;
2052 mpctx
->items
= item
->next
;
2058 if (mpctx
->lock
!= NULL
)
2059 UNLOCK(mpctx
->lock
);
2061 #if ISC_MEM_TRACKLINES
2063 MCTXLOCK(mctx
, &mctx
->lock
);
2064 ADD_TRACE(mctx
, item
, mpctx
->size
, file
, line
);
2065 MCTXUNLOCK(mctx
, &mctx
->lock
);
2067 #endif /* ISC_MEM_TRACKLINES */
2072 /* coverity[+free : arg-1] */
2074 isc___mempool_put(isc_mempool_t
*mpctx0
, void *mem FLARG
) {
2075 isc__mempool_t
*mpctx
= (isc__mempool_t
*)mpctx0
;
2079 REQUIRE(VALID_MEMPOOL(mpctx
));
2080 REQUIRE(mem
!= NULL
);
2084 if (mpctx
->lock
!= NULL
)
2087 INSIST(mpctx
->allocated
> 0);
2090 #if ISC_MEM_TRACKLINES
2091 MCTXLOCK(mctx
, &mctx
->lock
);
2092 DELETE_TRACE(mctx
, mem
, mpctx
->size
, file
, line
);
2093 MCTXUNLOCK(mctx
, &mctx
->lock
);
2094 #endif /* ISC_MEM_TRACKLINES */
2097 * If our free list is full, return this to the mctx directly.
2099 if (mpctx
->freecount
>= mpctx
->freemax
) {
2100 MCTXLOCK(mctx
, &mctx
->lock
);
2101 if ((mctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
2102 mem_putunlocked(mctx
, mem
, mpctx
->size
);
2104 mem_putstats(mctx
, mem
, mpctx
->size
);
2105 mem_put(mctx
, mem
, mpctx
->size
);
2107 MCTXUNLOCK(mctx
, &mctx
->lock
);
2108 if (mpctx
->lock
!= NULL
)
2109 UNLOCK(mpctx
->lock
);
2114 * Otherwise, attach it to our free list and bump the counter.
2117 item
= (element
*)mem
;
2118 item
->next
= mpctx
->items
;
2119 mpctx
->items
= item
;
2121 if (mpctx
->lock
!= NULL
)
2122 UNLOCK(mpctx
->lock
);
2130 isc__mempool_setfreemax(isc_mempool_t
*mpctx0
, unsigned int limit
) {
2131 isc__mempool_t
*mpctx
= (isc__mempool_t
*)mpctx0
;
2133 REQUIRE(VALID_MEMPOOL(mpctx
));
2135 if (mpctx
->lock
!= NULL
)
2138 mpctx
->freemax
= limit
;
2140 if (mpctx
->lock
!= NULL
)
2141 UNLOCK(mpctx
->lock
);
2145 isc_mempool_getfreemax(isc_mempool_t
*mpctx0
) {
2146 isc__mempool_t
*mpctx
= (isc__mempool_t
*)mpctx0
;
2147 unsigned int freemax
;
2149 REQUIRE(VALID_MEMPOOL(mpctx
));
2151 if (mpctx
->lock
!= NULL
)
2154 freemax
= mpctx
->freemax
;
2156 if (mpctx
->lock
!= NULL
)
2157 UNLOCK(mpctx
->lock
);
2163 isc_mempool_getfreecount(isc_mempool_t
*mpctx0
) {
2164 isc__mempool_t
*mpctx
= (isc__mempool_t
*)mpctx0
;
2165 unsigned int freecount
;
2167 REQUIRE(VALID_MEMPOOL(mpctx
));
2169 if (mpctx
->lock
!= NULL
)
2172 freecount
= mpctx
->freecount
;
2174 if (mpctx
->lock
!= NULL
)
2175 UNLOCK(mpctx
->lock
);
2181 isc__mempool_setmaxalloc(isc_mempool_t
*mpctx0
, unsigned int limit
) {
2182 isc__mempool_t
*mpctx
= (isc__mempool_t
*)mpctx0
;
2186 REQUIRE(VALID_MEMPOOL(mpctx
));
2188 if (mpctx
->lock
!= NULL
)
2191 mpctx
->maxalloc
= limit
;
2193 if (mpctx
->lock
!= NULL
)
2194 UNLOCK(mpctx
->lock
);
2198 isc_mempool_getmaxalloc(isc_mempool_t
*mpctx0
) {
2199 isc__mempool_t
*mpctx
= (isc__mempool_t
*)mpctx0
;
2200 unsigned int maxalloc
;
2202 REQUIRE(VALID_MEMPOOL(mpctx
));
2204 if (mpctx
->lock
!= NULL
)
2207 maxalloc
= mpctx
->maxalloc
;
2209 if (mpctx
->lock
!= NULL
)
2210 UNLOCK(mpctx
->lock
);
2216 isc__mempool_getallocated(isc_mempool_t
*mpctx0
) {
2217 isc__mempool_t
*mpctx
= (isc__mempool_t
*)mpctx0
;
2218 unsigned int allocated
;
2220 REQUIRE(VALID_MEMPOOL(mpctx
));
2222 if (mpctx
->lock
!= NULL
)
2225 allocated
= mpctx
->allocated
;
2227 if (mpctx
->lock
!= NULL
)
2228 UNLOCK(mpctx
->lock
);
2234 isc__mempool_setfillcount(isc_mempool_t
*mpctx0
, unsigned int limit
) {
2235 isc__mempool_t
*mpctx
= (isc__mempool_t
*)mpctx0
;
2238 REQUIRE(VALID_MEMPOOL(mpctx
));
2240 if (mpctx
->lock
!= NULL
)
2243 mpctx
->fillcount
= limit
;
2245 if (mpctx
->lock
!= NULL
)
2246 UNLOCK(mpctx
->lock
);
2250 isc_mempool_getfillcount(isc_mempool_t
*mpctx0
) {
2251 isc__mempool_t
*mpctx
= (isc__mempool_t
*)mpctx0
;
2253 unsigned int fillcount
;
2255 REQUIRE(VALID_MEMPOOL(mpctx
));
2257 if (mpctx
->lock
!= NULL
)
2260 fillcount
= mpctx
->fillcount
;
2262 if (mpctx
->lock
!= NULL
)
2263 UNLOCK(mpctx
->lock
);
2269 isc__mem_register(void) {
2270 return (isc_mem_register(isc_mem_create2
));
2274 isc__mem_printactive(isc_mem_t
*ctx0
, FILE *file
) {
2275 #if ISC_MEM_TRACKLINES
2276 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
2278 REQUIRE(VALID_CONTEXT(ctx
));
2279 REQUIRE(file
!= NULL
);
2281 print_active(ctx
, file
);
2289 isc_mem_printallactive(FILE *file
) {
2290 #if !ISC_MEM_TRACKLINES
2295 RUNTIME_CHECK(isc_once_do(&once
, initialize_action
) == ISC_R_SUCCESS
);
2297 LOCK(&contextslock
);
2298 for (ctx
= ISC_LIST_HEAD(contexts
);
2300 ctx
= ISC_LIST_NEXT(ctx
, link
)) {
2301 fprintf(file
, "context: %p\n", ctx
);
2302 print_active(ctx
, file
);
2304 UNLOCK(&contextslock
);
2309 isc_mem_checkdestroyed(FILE *file
) {
2310 #if !ISC_MEM_TRACKLINES
2314 RUNTIME_CHECK(isc_once_do(&once
, initialize_action
) == ISC_R_SUCCESS
);
2316 LOCK(&contextslock
);
2317 if (!ISC_LIST_EMPTY(contexts
)) {
2318 #if ISC_MEM_TRACKLINES
2321 for (ctx
= ISC_LIST_HEAD(contexts
);
2323 ctx
= ISC_LIST_NEXT(ctx
, link
)) {
2324 fprintf(file
, "context: %p\n", ctx
);
2325 print_active(ctx
, file
);
2331 UNLOCK(&contextslock
);
2335 isc_mem_references(isc_mem_t
*ctx0
) {
2336 isc__mem_t
*ctx
= (isc__mem_t
*)ctx0
;
2337 unsigned int references
;
2339 REQUIRE(VALID_CONTEXT(ctx
));
2341 MCTXLOCK(ctx
, &ctx
->lock
);
2342 references
= ctx
->references
;
2343 MCTXUNLOCK(ctx
, &ctx
->lock
);
2345 return (references
);
2348 #if defined(HAVE_LIBXML2) || defined(HAVE_JSON)
2349 typedef struct summarystat
{
2352 isc_uint64_t blocksize
;
2353 isc_uint64_t contextsize
;
2358 #define TRY0(a) do { xmlrc = (a); if (xmlrc < 0) goto error; } while(/*CONSTCOND*/0)
2360 xml_renderctx(isc__mem_t
*ctx
, summarystat_t
*summary
,
2361 xmlTextWriterPtr writer
)
2365 REQUIRE(VALID_CONTEXT(ctx
));
2367 MCTXLOCK(ctx
, &ctx
->lock
);
2369 TRY0(xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"context"));
2371 TRY0(xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"id"));
2372 TRY0(xmlTextWriterWriteFormatString(writer
, "%p", ctx
));
2373 TRY0(xmlTextWriterEndElement(writer
)); /* id */
2375 if (ctx
->name
[0] != 0) {
2376 TRY0(xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"name"));
2377 TRY0(xmlTextWriterWriteFormatString(writer
, "%s", ctx
->name
));
2378 TRY0(xmlTextWriterEndElement(writer
)); /* name */
2381 summary
->contextsize
+= sizeof(*ctx
) +
2382 (ctx
->max_size
+ 1) * sizeof(struct stats
) +
2383 ctx
->max_size
* sizeof(element
*) +
2384 ctx
->basic_table_count
* sizeof(char *);
2385 #if ISC_MEM_TRACKLINES
2386 if (ctx
->debuglist
!= NULL
) {
2387 summary
->contextsize
+=
2388 (ctx
->max_size
+ 1) * sizeof(debuglist_t
) +
2389 ctx
->debuglistcnt
* sizeof(debuglink_t
);
2392 TRY0(xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"references"));
2393 TRY0(xmlTextWriterWriteFormatString(writer
, "%d", ctx
->references
));
2394 TRY0(xmlTextWriterEndElement(writer
)); /* references */
2396 summary
->total
+= ctx
->total
;
2397 TRY0(xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"total"));
2398 TRY0(xmlTextWriterWriteFormatString(writer
,
2399 "%" ISC_PRINT_QUADFORMAT
"u",
2400 (isc_uint64_t
)ctx
->total
));
2401 TRY0(xmlTextWriterEndElement(writer
)); /* total */
2403 summary
->inuse
+= ctx
->inuse
;
2404 TRY0(xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"inuse"));
2405 TRY0(xmlTextWriterWriteFormatString(writer
,
2406 "%" ISC_PRINT_QUADFORMAT
"u",
2407 (isc_uint64_t
)ctx
->inuse
));
2408 TRY0(xmlTextWriterEndElement(writer
)); /* inuse */
2410 TRY0(xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"maxinuse"));
2411 TRY0(xmlTextWriterWriteFormatString(writer
,
2412 "%" ISC_PRINT_QUADFORMAT
"u",
2413 (isc_uint64_t
)ctx
->maxinuse
));
2414 TRY0(xmlTextWriterEndElement(writer
)); /* maxinuse */
2416 TRY0(xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"blocksize"));
2417 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
2418 summary
->blocksize
+= ctx
->basic_table_count
*
2419 NUM_BASIC_BLOCKS
* ctx
->mem_target
;
2420 TRY0(xmlTextWriterWriteFormatString(writer
,
2421 "%" ISC_PRINT_QUADFORMAT
"u",
2423 ctx
->basic_table_count
*
2427 TRY0(xmlTextWriterWriteFormatString(writer
, "%s", "-"));
2428 TRY0(xmlTextWriterEndElement(writer
)); /* blocksize */
2430 TRY0(xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"pools"));
2431 TRY0(xmlTextWriterWriteFormatString(writer
, "%u", ctx
->poolcnt
));
2432 TRY0(xmlTextWriterEndElement(writer
)); /* pools */
2433 summary
->contextsize
+= ctx
->poolcnt
* sizeof(isc_mempool_t
);
2435 TRY0(xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"hiwater"));
2436 TRY0(xmlTextWriterWriteFormatString(writer
,
2437 "%" ISC_PRINT_QUADFORMAT
"u",
2438 (isc_uint64_t
)ctx
->hi_water
));
2439 TRY0(xmlTextWriterEndElement(writer
)); /* hiwater */
2441 TRY0(xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"lowater"));
2442 TRY0(xmlTextWriterWriteFormatString(writer
,
2443 "%" ISC_PRINT_QUADFORMAT
"u",
2444 (isc_uint64_t
)ctx
->lo_water
));
2445 TRY0(xmlTextWriterEndElement(writer
)); /* lowater */
2447 TRY0(xmlTextWriterEndElement(writer
)); /* context */
2450 MCTXUNLOCK(ctx
, &ctx
->lock
);
2456 isc_mem_renderxml(xmlTextWriterPtr writer
) {
2458 summarystat_t summary
;
2462 memset(&summary
, 0, sizeof(summary
));
2464 TRY0(xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"contexts"));
2466 RUNTIME_CHECK(isc_once_do(&once
, initialize_action
) == ISC_R_SUCCESS
);
2468 LOCK(&contextslock
);
2470 for (ctx
= ISC_LIST_HEAD(contexts
);
2472 ctx
= ISC_LIST_NEXT(ctx
, link
)) {
2473 xmlrc
= xml_renderctx(ctx
, &summary
, writer
);
2475 UNLOCK(&contextslock
);
2479 UNLOCK(&contextslock
);
2481 TRY0(xmlTextWriterEndElement(writer
)); /* contexts */
2483 TRY0(xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"summary"));
2485 TRY0(xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"TotalUse"));
2486 TRY0(xmlTextWriterWriteFormatString(writer
,
2487 "%" ISC_PRINT_QUADFORMAT
"u",
2489 TRY0(xmlTextWriterEndElement(writer
)); /* TotalUse */
2491 TRY0(xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"InUse"));
2492 TRY0(xmlTextWriterWriteFormatString(writer
,
2493 "%" ISC_PRINT_QUADFORMAT
"u",
2495 TRY0(xmlTextWriterEndElement(writer
)); /* InUse */
2497 TRY0(xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"BlockSize"));
2498 TRY0(xmlTextWriterWriteFormatString(writer
,
2499 "%" ISC_PRINT_QUADFORMAT
"u",
2500 summary
.blocksize
));
2501 TRY0(xmlTextWriterEndElement(writer
)); /* BlockSize */
2503 TRY0(xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"ContextSize"));
2504 TRY0(xmlTextWriterWriteFormatString(writer
,
2505 "%" ISC_PRINT_QUADFORMAT
"u",
2506 summary
.contextsize
));
2507 TRY0(xmlTextWriterEndElement(writer
)); /* ContextSize */
2509 TRY0(xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"Lost"));
2510 TRY0(xmlTextWriterWriteFormatString(writer
,
2511 "%" ISC_PRINT_QUADFORMAT
"u",
2513 TRY0(xmlTextWriterEndElement(writer
)); /* Lost */
2515 TRY0(xmlTextWriterEndElement(writer
)); /* summary */
2520 #endif /* HAVE_LIBXML2 */
2523 #define CHECKMEM(m) do { \
2525 result = ISC_R_NOMEMORY;\
2528 } while(/*CONSTCOND*/0)
2531 json_renderctx(isc__mem_t
*ctx
, summarystat_t
*summary
, json_object
*array
) {
2532 isc_result_t result
= ISC_R_FAILURE
;
2533 json_object
*ctxobj
, *obj
;
2536 REQUIRE(VALID_CONTEXT(ctx
));
2537 REQUIRE(summary
!= NULL
);
2538 REQUIRE(array
!= NULL
);
2540 MCTXLOCK(ctx
, &ctx
->lock
);
2542 summary
->contextsize
+= sizeof(*ctx
) +
2543 (ctx
->max_size
+ 1) * sizeof(struct stats
) +
2544 ctx
->max_size
* sizeof(element
*) +
2545 ctx
->basic_table_count
* sizeof(char *);
2546 summary
->total
+= ctx
->total
;
2547 summary
->inuse
+= ctx
->inuse
;
2548 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0)
2549 summary
->blocksize
+= ctx
->basic_table_count
*
2550 NUM_BASIC_BLOCKS
* ctx
->mem_target
;
2551 #if ISC_MEM_TRACKLINES
2552 if (ctx
->debuglist
!= NULL
) {
2553 summary
->contextsize
+=
2554 (ctx
->max_size
+ 1) * sizeof(debuglist_t
) +
2555 ctx
->debuglistcnt
* sizeof(debuglink_t
);
2559 ctxobj
= json_object_new_object();
2562 sprintf(buf
, "%p", ctx
);
2563 obj
= json_object_new_string(buf
);
2565 json_object_object_add(ctxobj
, "id", obj
);
2567 if (ctx
->name
[0] != 0) {
2568 obj
= json_object_new_string(ctx
->name
);
2570 json_object_object_add(ctxobj
, "name", obj
);
2573 obj
= json_object_new_int64(ctx
->references
);
2575 json_object_object_add(ctxobj
, "references", obj
);
2577 obj
= json_object_new_int64(ctx
->total
);
2579 json_object_object_add(ctxobj
, "total", obj
);
2581 obj
= json_object_new_int64(ctx
->inuse
);
2583 json_object_object_add(ctxobj
, "inuse", obj
);
2585 obj
= json_object_new_int64(ctx
->maxinuse
);
2587 json_object_object_add(ctxobj
, "maxinuse", obj
);
2589 if ((ctx
->flags
& ISC_MEMFLAG_INTERNAL
) != 0) {
2590 isc_uint64_t blocksize
;
2591 blocksize
= ctx
->basic_table_count
* NUM_BASIC_BLOCKS
*
2593 obj
= json_object_new_int64(blocksize
);
2595 json_object_object_add(ctxobj
, "blocksize", obj
);
2598 obj
= json_object_new_int64(ctx
->poolcnt
);
2600 json_object_object_add(ctxobj
, "pools", obj
);
2602 obj
= json_object_new_int64(ctx
->hi_water
);
2604 json_object_object_add(ctxobj
, "hiwater", obj
);
2606 obj
= json_object_new_int64(ctx
->lo_water
);
2608 json_object_object_add(ctxobj
, "lowater", obj
);
2610 MCTXUNLOCK(ctx
, &ctx
->lock
);
2611 json_object_array_add(array
, ctxobj
);
2612 return (ISC_R_SUCCESS
);
2615 MCTXUNLOCK(ctx
, &ctx
->lock
);
2617 json_object_put(ctxobj
);
2622 isc_mem_renderjson(json_object
*memobj
) {
2623 isc_result_t result
= ISC_R_SUCCESS
;
2625 summarystat_t summary
;
2627 json_object
*ctxarray
, *obj
;
2629 memset(&summary
, 0, sizeof(summary
));
2630 RUNTIME_CHECK(isc_once_do(&once
, initialize_action
) == ISC_R_SUCCESS
);
2632 ctxarray
= json_object_new_array();
2635 LOCK(&contextslock
);
2637 for (ctx
= ISC_LIST_HEAD(contexts
);
2639 ctx
= ISC_LIST_NEXT(ctx
, link
)) {
2640 result
= json_renderctx(ctx
, &summary
, ctxarray
);
2641 if (result
!= ISC_R_SUCCESS
) {
2642 UNLOCK(&contextslock
);
2646 UNLOCK(&contextslock
);
2648 obj
= json_object_new_int64(summary
.total
);
2650 json_object_object_add(memobj
, "TotalUse", obj
);
2652 obj
= json_object_new_int64(summary
.inuse
);
2654 json_object_object_add(memobj
, "InUse", obj
);
2656 obj
= json_object_new_int64(summary
.blocksize
);
2658 json_object_object_add(memobj
, "BlockSize", obj
);
2660 obj
= json_object_new_int64(summary
.contextsize
);
2662 json_object_object_add(memobj
, "ContextSize", obj
);
2664 obj
= json_object_new_int64(lost
);
2666 json_object_object_add(memobj
, "Lost", obj
);
2668 json_object_object_add(memobj
, "contexts", ctxarray
);
2669 return (ISC_R_SUCCESS
);
2672 if (ctxarray
!= NULL
)
2673 json_object_put(ctxarray
);
2676 #endif /* HAVE_JSON */
2678 static isc_memcreatefunc_t mem_createfunc
= NULL
;
2681 isc_mem_register(isc_memcreatefunc_t createfunc
) {
2682 isc_result_t result
= ISC_R_SUCCESS
;
2684 RUNTIME_CHECK(isc_once_do(&once
, initialize_action
) == ISC_R_SUCCESS
);
2687 if (mem_createfunc
== NULL
)
2688 mem_createfunc
= createfunc
;
2690 result
= ISC_R_EXISTS
;
2691 UNLOCK(&createlock
);
2698 isc__mem_create2(size_t init_max_size
, size_t target_size
, isc_mem_t
**mctxp
,
2701 isc_result_t result
;
2705 REQUIRE(mem_createfunc
!= NULL
);
2706 result
= (*mem_createfunc
)(init_max_size
, target_size
, mctxp
, flags
);
2708 UNLOCK(&createlock
);
2714 isc_mem_create(size_t init_max_size
, size_t target_size
, isc_mem_t
**mctxp
) {
2715 isc_result_t result
;
2718 return (isc_mem_createx2(init_max_size
, target_size
,
2719 default_memalloc
, default_memfree
,
2720 NULL
, mctxp
, ISC_MEMFLAG_DEFAULT
));
2723 REQUIRE(mem_createfunc
!= NULL
);
2724 result
= (*mem_createfunc
)(init_max_size
, target_size
, mctxp
,
2725 ISC_MEMFLAG_DEFAULT
);
2727 UNLOCK(&createlock
);
2733 isc_mem_create2(size_t init_max_size
, size_t target_size
, isc_mem_t
**mctxp
,
2737 return (isc_mem_createx2(init_max_size
, target_size
,
2738 default_memalloc
, default_memfree
,
2739 NULL
, mctxp
, flags
));
2741 return (isc_mem_createx2(init_max_size
, target_size
,
2742 default_memalloc
, default_memfree
,
2743 NULL
, mctxp
, flags
));
2747 isc_mem_attach(isc_mem_t
*source
, isc_mem_t
**targetp
) {
2748 REQUIRE(ISCAPI_MCTX_VALID(source
));
2749 REQUIRE(targetp
!= NULL
&& *targetp
== NULL
);
2752 isc__mem_attach(source
, targetp
);
2754 source
->methods
->attach(source
, targetp
);
2756 ENSURE(*targetp
== source
);
2760 isc_mem_detach(isc_mem_t
**mctxp
) {
2761 REQUIRE(mctxp
!= NULL
&& ISCAPI_MCTX_VALID(*mctxp
));
2764 isc__mem_detach(mctxp
);
2766 (*mctxp
)->methods
->detach(mctxp
);
2768 ENSURE(*mctxp
== NULL
);
2772 isc_mem_destroy(isc_mem_t
**mctxp
) {
2773 REQUIRE(mctxp
!= NULL
&& ISCAPI_MCTX_VALID(*mctxp
));
2776 isc__mem_destroy(mctxp
);
2778 (*mctxp
)->methods
->destroy(mctxp
);
2780 ENSURE(*mctxp
== NULL
);
2784 isc_mem_setdestroycheck(isc_mem_t
*mctx
, isc_boolean_t flag
) {
2785 REQUIRE(ISCAPI_MCTX_VALID(mctx
));
2787 mctx
->methods
->setdestroycheck(mctx
, flag
);
2791 isc_mem_setwater(isc_mem_t
*ctx
, isc_mem_water_t water
, void *water_arg
,
2792 size_t hiwater
, size_t lowater
)
2794 REQUIRE(ISCAPI_MCTX_VALID(ctx
));
2797 isc__mem_setwater(ctx
, water
, water_arg
, hiwater
, lowater
);
2799 ctx
->methods
->setwater(ctx
, water
, water_arg
, hiwater
, lowater
);
2803 isc_mem_waterack(isc_mem_t
*ctx
, int flag
) {
2804 REQUIRE(ISCAPI_MCTX_VALID(ctx
));
2807 isc__mem_waterack(ctx
, flag
);
2809 ctx
->methods
->waterack(ctx
, flag
);
2813 isc_mem_inuse(isc_mem_t
*mctx
) {
2814 REQUIRE(ISCAPI_MCTX_VALID(mctx
));
2817 return (isc__mem_inuse(mctx
));
2819 return (mctx
->methods
->inuse(mctx
));
2823 isc_mem_maxinuse(isc_mem_t
*mctx
) {
2824 REQUIRE(ISCAPI_MCTX_VALID(mctx
));
2827 return (isc__mem_maxinuse(mctx
));
2829 return (mctx
->methods
->maxinuse(mctx
));
2833 isc_mem_total(isc_mem_t
*mctx
) {
2834 REQUIRE(ISCAPI_MCTX_VALID(mctx
));
2837 return (isc__mem_total(mctx
));
2839 return (mctx
->methods
->total(mctx
));
2843 isc_mem_isovermem(isc_mem_t
*mctx
) {
2844 REQUIRE(ISCAPI_MCTX_VALID(mctx
));
2847 return (isc__mem_isovermem(mctx
));
2849 return (mctx
->methods
->isovermem(mctx
));
2854 isc_mempool_create(isc_mem_t
*mctx
, size_t size
, isc_mempool_t
**mpctxp
) {
2855 REQUIRE(ISCAPI_MCTX_VALID(mctx
));
2857 return (mctx
->methods
->mpcreate(mctx
, size
, mpctxp
));
2861 isc_mempool_destroy(isc_mempool_t
**mpctxp
) {
2862 REQUIRE(mpctxp
!= NULL
&& ISCAPI_MPOOL_VALID(*mpctxp
));
2865 isc__mempool_destroy(mpctxp
);
2867 (*mpctxp
)->methods
->destroy(mpctxp
);
2869 ENSURE(*mpctxp
== NULL
);
2873 isc_mempool_getallocated(isc_mempool_t
*mpctx
) {
2874 REQUIRE(ISCAPI_MPOOL_VALID(mpctx
));
2877 return (isc__mempool_getallocated(mpctx
));
2879 return (mpctx
->methods
->getallocated(mpctx
));
2883 isc_mempool_setmaxalloc(isc_mempool_t
*mpctx
, unsigned int limit
) {
2884 REQUIRE(ISCAPI_MPOOL_VALID(mpctx
));
2887 isc__mempool_setmaxalloc(mpctx
, limit
);
2889 mpctx
->methods
->setmaxalloc(mpctx
, limit
);
2893 isc_mempool_setfreemax(isc_mempool_t
*mpctx
, unsigned int limit
) {
2894 REQUIRE(ISCAPI_MPOOL_VALID(mpctx
));
2897 isc__mempool_setfreemax(mpctx
, limit
);
2899 mpctx
->methods
->setfreemax(mpctx
, limit
);
2903 isc_mempool_setname(isc_mempool_t
*mpctx
, const char *name
) {
2904 REQUIRE(ISCAPI_MPOOL_VALID(mpctx
));
2907 isc__mempool_setname(mpctx
, name
);
2909 mpctx
->methods
->setname(mpctx
, name
);
2913 isc_mempool_associatelock(isc_mempool_t
*mpctx
, isc_mutex_t
*lock
) {
2914 REQUIRE(ISCAPI_MPOOL_VALID(mpctx
));
2917 isc__mempool_associatelock(mpctx
, lock
);
2919 mpctx
->methods
->associatelock(mpctx
, lock
);
2923 isc_mempool_setfillcount(isc_mempool_t
*mpctx
, unsigned int limit
) {
2924 REQUIRE(ISCAPI_MPOOL_VALID(mpctx
));
2927 isc__mempool_setfillcount(mpctx
, limit
);
2929 mpctx
->methods
->setfillcount(mpctx
, limit
);
2933 isc__mem_get(isc_mem_t
*mctx
, size_t size FLARG
) {
2934 REQUIRE(ISCAPI_MCTX_VALID(mctx
));
2937 return (isc___mem_get(mctx
, size FLARG_PASS
));
2939 return (mctx
->methods
->memget(mctx
, size FLARG_PASS
));
2944 isc__mem_put(isc_mem_t
*mctx
, void *ptr
, size_t size FLARG
) {
2945 REQUIRE(ISCAPI_MCTX_VALID(mctx
));
2948 isc___mem_put(mctx
, ptr
, size FLARG_PASS
);
2950 mctx
->methods
->memput(mctx
, ptr
, size FLARG_PASS
);
2954 isc__mem_putanddetach(isc_mem_t
**mctxp
, void *ptr
, size_t size FLARG
) {
2955 REQUIRE(mctxp
!= NULL
&& ISCAPI_MCTX_VALID(*mctxp
));
2958 isc___mem_putanddetach(mctxp
, ptr
, size FLARG_PASS
);
2960 (*mctxp
)->methods
->memputanddetach(mctxp
, ptr
, size FLARG_PASS
);
2963 * XXX: We cannot always ensure *mctxp == NULL here
2964 * (see lib/isc/mem.c).
2969 isc__mem_allocate(isc_mem_t
*mctx
, size_t size FLARG
) {
2970 REQUIRE(ISCAPI_MCTX_VALID(mctx
));
2973 return (isc___mem_allocate(mctx
, size FLARG_PASS
));
2975 return (mctx
->methods
->memallocate(mctx
, size FLARG_PASS
));
2979 isc__mem_reallocate(isc_mem_t
*mctx
, void *ptr
, size_t size FLARG
) {
2980 REQUIRE(ISCAPI_MCTX_VALID(mctx
));
2983 return (isc___mem_reallocate(mctx
, ptr
, size FLARG_PASS
));
2985 return (mctx
->methods
->memreallocate(mctx
, ptr
, size FLARG_PASS
));
2989 isc__mem_strdup(isc_mem_t
*mctx
, const char *s FLARG
) {
2990 REQUIRE(ISCAPI_MCTX_VALID(mctx
));
2993 return (isc___mem_strdup(mctx
, s FLARG_PASS
));
2995 return (mctx
->methods
->memstrdup(mctx
, s FLARG_PASS
));
2999 isc__mem_free(isc_mem_t
*mctx
, void *ptr FLARG
) {
3000 REQUIRE(ISCAPI_MCTX_VALID(mctx
));
3003 isc___mem_free(mctx
, ptr FLARG_PASS
);
3005 mctx
->methods
->memfree(mctx
, ptr FLARG_PASS
);
3009 isc__mempool_get(isc_mempool_t
*mpctx FLARG
) {
3010 REQUIRE(ISCAPI_MPOOL_VALID(mpctx
));
3013 return (isc___mempool_get(mpctx FLARG_PASS
));
3015 return (mpctx
->methods
->get(mpctx FLARG_PASS
));
3019 isc__mempool_put(isc_mempool_t
*mpctx
, void *mem FLARG
) {
3020 REQUIRE(ISCAPI_MPOOL_VALID(mpctx
));
3023 isc___mempool_put(mpctx
, mem FLARG_PASS
);
3025 mpctx
->methods
->put(mpctx
, mem FLARG_PASS
);