Remove building with NOCRYPTO option
[minix.git] / external / bsd / bind / dist / lib / isc / mem.c
blob0227506b79ee64ea82a34480c63517cd6efd422a
1 /* $NetBSD: mem.c,v 1.12 2015/07/08 17:28:59 christos Exp $ */
3 /*
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.
20 /* Id */
22 /*! \file */
24 #include <config.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <stddef.h>
30 #include <limits.h>
32 #include <isc/bind9.h>
33 #include <isc/json.h>
34 #include <isc/magic.h>
35 #include <isc/mem.h>
36 #include <isc/msgs.h>
37 #include <isc/once.h>
38 #include <isc/ondestroy.h>
39 #include <isc/string.h>
40 #include <isc/mutex.h>
41 #include <isc/print.h>
42 #include <isc/util.h>
43 #include <isc/xml.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
50 #endif
51 LIBISC_EXTERNAL_DATA unsigned int isc_mem_debugging = ISC_MEM_DEBUGGING;
54 * Constants.
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
65 * Types.
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;
72 struct debuglink {
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];
78 unsigned int count;
81 #define FLARG_PASS , file, line
82 #define FLARG , const char *file, unsigned int line
83 #else
84 #define FLARG_PASS
85 #define FLARG
86 #endif
88 typedef struct element element;
89 struct element {
90 element * next;
93 typedef struct {
94 /*!
95 * This structure must be ALIGNMENT_SIZE bytes.
97 union {
98 size_t size;
99 isc__mem_t *ctx;
100 char bytes[ALIGNMENT_SIZE];
101 } u;
102 } size_info;
104 struct stats {
105 unsigned long gets;
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;
116 #endif
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;
132 struct isc__mem {
133 isc_mem_t common;
134 isc_ondestroy_t ondestroy;
135 unsigned int flags;
136 isc_mutex_t lock;
137 isc_memalloc_t memalloc;
138 isc_memfree_t memfree;
139 void * arg;
140 size_t max_size;
141 isc_boolean_t checkfree;
142 struct stats * stats;
143 unsigned int references;
144 char name[16];
145 void * tag;
146 size_t quota;
147 size_t total;
148 size_t inuse;
149 size_t maxinuse;
150 size_t hi_water;
151 size_t lo_water;
152 isc_boolean_t hi_called;
153 isc_boolean_t is_overmem;
154 isc_mem_water_t water;
155 void * water_arg;
156 ISC_LIST(isc__mempool_t) pools;
157 unsigned int poolcnt;
159 /* ISC_MEMFLAG_INTERNAL */
160 size_t mem_target;
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;
172 #endif
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 */
196 /*%< Stats only. */
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 */
201 #endif
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
212 #else
213 #define ADD_TRACE(a, b, c, d, e) \
214 do { \
215 if ((isc_mem_debugging & (ISC_MEM_DEBUGTRACE | \
216 ISC_MEM_DEBUGRECORD)) != 0 && \
217 b != NULL) \
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)
222 static void
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.
231 isc_result_t
232 isc__mem_create2(size_t init_max_size, size_t target_size,
233 isc_mem_t **ctxp, unsigned int flags);
234 void
235 isc__mem_attach(isc_mem_t *source, isc_mem_t **targetp);
236 void
237 isc__mem_detach(isc_mem_t **ctxp);
238 void
239 isc___mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG);
240 void
241 isc__mem_destroy(isc_mem_t **ctxp);
242 isc_result_t
243 isc__mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event);
244 void *
245 isc___mem_get(isc_mem_t *ctx, size_t size FLARG);
246 void
247 isc___mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG);
248 void
249 isc__mem_stats(isc_mem_t *ctx, FILE *out);
250 void *
251 isc___mem_allocate(isc_mem_t *ctx, size_t size FLARG);
252 void *
253 isc___mem_reallocate(isc_mem_t *ctx, void *ptr, size_t size FLARG);
254 void
255 isc___mem_free(isc_mem_t *ctx, void *ptr FLARG);
256 char *
257 isc___mem_strdup(isc_mem_t *mctx, const char *s FLARG);
258 void
259 isc__mem_setdestroycheck(isc_mem_t *ctx, isc_boolean_t flag);
260 void
261 isc__mem_setquota(isc_mem_t *ctx, size_t quota);
262 size_t
263 isc__mem_getquota(isc_mem_t *ctx);
264 size_t
265 isc__mem_inuse(isc_mem_t *ctx);
266 size_t
267 isc__mem_maxinuse(isc_mem_t *ctx);
268 size_t
269 isc__mem_total(isc_mem_t *ctx);
270 isc_boolean_t
271 isc__mem_isovermem(isc_mem_t *ctx);
272 void
273 isc__mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg,
274 size_t hiwater, size_t lowater);
275 void
276 isc__mem_waterack(isc_mem_t *ctx0, int flag);
277 void
278 isc__mem_setname(isc_mem_t *ctx, const char *name, void *tag);
279 const char *
280 isc__mem_getname(isc_mem_t *ctx);
281 void *
282 isc__mem_gettag(isc_mem_t *ctx);
283 isc_result_t
284 isc__mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp);
285 void
286 isc__mempool_setname(isc_mempool_t *mpctx, const char *name);
287 void
288 isc__mempool_destroy(isc_mempool_t **mpctxp);
289 void
290 isc__mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock);
291 void *
292 isc___mempool_get(isc_mempool_t *mpctx FLARG);
293 void
294 isc___mempool_put(isc_mempool_t *mpctx, void *mem FLARG);
295 void
296 isc__mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit);
297 unsigned int
298 isc__mempool_getfreemax(isc_mempool_t *mpctx);
299 unsigned int
300 isc__mempool_getfreecount(isc_mempool_t *mpctx);
301 void
302 isc__mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit);
303 unsigned int
304 isc__mempool_getmaxalloc(isc_mempool_t *mpctx);
305 unsigned int
306 isc__mempool_getallocated(isc_mempool_t *mpctx);
307 void
308 isc__mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit);
309 unsigned int
310 isc__mempool_getfillcount(isc_mempool_t *mpctx);
311 void
312 isc__mem_printactive(isc_mem_t *ctx0, FILE *file);
313 void
314 isc__mem_printallactive(FILE *file);
315 unsigned int
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;
327 } memmethods = {
329 isc__mem_attach,
330 isc__mem_detach,
331 isc__mem_destroy,
332 isc___mem_get,
333 isc___mem_put,
334 isc___mem_putanddetach,
335 isc___mem_allocate,
336 isc___mem_reallocate,
337 isc___mem_strdup,
338 isc___mem_free,
339 isc__mem_setdestroycheck,
340 isc__mem_setwater,
341 isc__mem_waterack,
342 isc__mem_inuse,
343 isc__mem_maxinuse,
344 isc__mem_total,
345 isc__mem_isovermem,
346 isc__mempool_create
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;
367 } mempoolmethods = {
369 isc__mempool_destroy,
370 isc___mempool_get,
371 isc___mempool_put,
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.
389 static inline void
390 add_trace_entry(isc__mem_t *mctx, const void *ptr, size_t size FLARG) {
391 debuglink_t *dl;
392 unsigned int i;
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,
397 ISC_MSG_ADDTRACE,
398 "add %p size %u "
399 "file %s line %u mctx %p\n"),
400 ptr, size, file, line, mctx);
402 if (mctx->debuglist == NULL)
403 return;
405 if (mysize > mctx->max_size)
406 mysize = mctx->max_size;
408 dl = ISC_LIST_HEAD(mctx->debuglist[mysize]);
409 while (dl != NULL) {
410 if (dl->count == DEBUGLIST_COUNT)
411 goto next;
412 for (i = 0; i < DEBUGLIST_COUNT; i++) {
413 if (dl->ptr[i] == NULL) {
414 dl->ptr[i] = ptr;
415 dl->size[i] = size;
416 dl->file[i] = file;
417 dl->line[i] = line;
418 dl->count++;
419 return;
422 next:
423 dl = ISC_LIST_NEXT(dl, link);
426 dl = malloc(sizeof(debuglink_t));
427 INSIST(dl != NULL);
429 ISC_LINK_INIT(dl, link);
430 for (i = 1; i < DEBUGLIST_COUNT; i++) {
431 dl->ptr[i] = NULL;
432 dl->size[i] = 0;
433 dl->file[i] = NULL;
434 dl->line[i] = 0;
437 dl->ptr[0] = ptr;
438 dl->size[0] = size;
439 dl->file[0] = file;
440 dl->line[0] = line;
441 dl->count = 1;
443 ISC_LIST_PREPEND(mctx->debuglist[mysize], dl, link);
444 mctx->debuglistcnt++;
447 static inline void
448 delete_trace_entry(isc__mem_t *mctx, const void *ptr, size_t size,
449 const char *file, unsigned int line)
451 debuglink_t *dl;
452 unsigned int i;
454 if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
455 fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
456 ISC_MSG_DELTRACE,
457 "del %p size %u "
458 "file %s line %u mctx %p\n"),
459 ptr, size, file, line, mctx);
461 if (mctx->debuglist == NULL)
462 return;
464 if (size > mctx->max_size)
465 size = mctx->max_size;
467 dl = ISC_LIST_HEAD(mctx->debuglist[size]);
468 while (dl != NULL) {
469 for (i = 0; i < DEBUGLIST_COUNT; i++) {
470 if (dl->ptr[i] == ptr) {
471 dl->ptr[i] = NULL;
472 dl->size[i] = 0;
473 dl->file[i] = NULL;
474 dl->line[i] = 0;
476 INSIST(dl->count > 0);
477 dl->count--;
478 if (dl->count == 0) {
479 ISC_LIST_UNLINK(mctx->debuglist[size],
480 dl, link);
481 free(dl);
483 return;
486 dl = ISC_LIST_NEXT(dl, link);
490 * If we get here, we didn't find the item on the list. We're
491 * screwed.
493 INSIST(dl != NULL);
495 #endif /* ISC_MEM_TRACKLINES */
497 static inline size_t
498 rmsize(size_t size) {
500 * round down to ALIGNMENT_SIZE
502 return (size & (~(ALIGNMENT_SIZE - 1)));
505 static inline size_t
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
510 * byte boundaries.
513 if (size == 0U)
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) {
520 void *new;
521 unsigned char *curr, *next;
522 unsigned char *first, *last;
523 unsigned char **table;
524 unsigned int table_size;
525 size_t increment;
526 int i;
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)
535 return (ISC_FALSE);
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 *));
542 if (table == NULL) {
543 ctx->memalloc_failures++;
544 return (ISC_FALSE);
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);
557 if (new == NULL) {
558 ctx->memalloc_failures++;
559 return (ISC_FALSE);
561 ctx->total += increment;
562 ctx->basic_table[ctx->basic_table_count] = new;
563 ctx->basic_table_count++;
565 curr = new;
566 next = curr + ctx->mem_target;
567 for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) {
568 ((element *)curr)->next = (element *)next;
569 curr = next;
570 next += ctx->mem_target;
573 * curr is now pointing at the last block in the
574 * array.
576 ((element *)curr)->next = NULL;
577 first = new;
578 last = first + NUM_BASIC_BLOCKS * ctx->mem_target - 1;
579 if (first < ctx->lowest || ctx->lowest == NULL)
580 ctx->lowest = first;
581 if (last > ctx->highest)
582 ctx->highest = last;
583 ctx->basic_blocks = new;
585 return (ISC_TRUE);
588 static inline isc_boolean_t
589 more_frags(isc__mem_t *ctx, size_t new_size) {
590 int i, frags;
591 size_t total_size;
592 void *new;
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.
608 return (ISC_FALSE);
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
620 * "new_size".
622 curr = new;
623 next = curr + new_size;
624 total_size -= new_size;
625 for (i = 0; i < (frags - 1); i++) {
626 ((element *)curr)->next = (element *)next;
627 curr = next;
628 next += new_size;
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
642 * array.
644 ((element *)curr)->next = NULL;
645 ctx->freelists[new_size] = new;
647 return (ISC_TRUE);
650 static inline void *
651 mem_getunlocked(isc__mem_t *ctx, size_t size) {
652 size_t new_size = quantize(size);
653 void *ret;
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) {
660 ret = NULL;
661 goto done;
663 ret = (ctx->memalloc)(ctx->arg, size);
664 if (ret == NULL) {
665 ctx->memalloc_failures++;
666 goto done;
668 ctx->total += size;
669 ctx->inuse += size;
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
675 * don't own.
677 new_size = size;
678 goto done;
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))
687 return (NULL);
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
699 * max_size.
701 ctx->stats[size].gets++;
702 ctx->stats[size].totalgets++;
703 ctx->stats[new_size].freefrags--;
704 ctx->inuse += new_size;
706 done:
708 #if ISC_MEM_FILL
709 if (ret != NULL)
710 memset(ret, 0xbe, new_size); /* Mnemonic for "beef". */
711 #endif
713 return (ret);
716 #if ISC_MEM_FILL && ISC_MEM_CHECKOVERRUN
717 static inline void
718 check_overrun(void *mem, size_t size, size_t new_size) {
719 unsigned char *cp;
721 cp = (unsigned char *)mem;
722 cp += size;
723 while (size < new_size) {
724 INSIST(*cp == 0xbe);
725 cp++;
726 size++;
729 #endif
731 /* coverity[+free : arg-1] */
732 static inline void
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.
740 #if ISC_MEM_FILL
741 memset(mem, 0xde, size); /* Mnemonic for "dead". */
742 #endif
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);
747 ctx->inuse -= size;
748 return;
751 #if ISC_MEM_FILL
752 #if ISC_MEM_CHECKOVERRUN
753 check_overrun(mem, size, new_size);
754 #endif
755 memset(mem, 0xde, new_size); /* Mnemonic for "dead". */
756 #endif
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
768 * max_size.
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.
779 static inline void *
780 mem_get(isc__mem_t *ctx, size_t size) {
781 char *ret;
783 #if ISC_MEM_CHECKOVERRUN
784 size += 1;
785 #endif
787 ret = (ctx->memalloc)(ctx->arg, size);
788 if (ret == NULL)
789 ctx->memalloc_failures++;
791 #if ISC_MEM_FILL
792 if (ret != NULL)
793 memset(ret, 0xbe, size); /* Mnemonic for "beef". */
794 #else
795 # if ISC_MEM_CHECKOVERRUN
796 if (ret != NULL)
797 ret[size-1] = 0xbe;
798 # endif
799 #endif
801 return (ret);
805 * Perform a free, doing memory filling and overrun detection as necessary.
807 /* coverity[+free : arg-1] */
808 static inline void
809 mem_put(isc__mem_t *ctx, void *mem, size_t size) {
810 #if ISC_MEM_CHECKOVERRUN
811 INSIST(((unsigned char *)mem)[size] == 0xbe);
812 #endif
813 #if ISC_MEM_FILL
814 memset(mem, 0xde, size); /* Mnemonic for "dead". */
815 #else
816 UNUSED(size);
817 #endif
818 (ctx->memfree)(ctx->arg, mem);
822 * Update internal counters after a memory get.
824 static inline void
825 mem_getstats(isc__mem_t *ctx, size_t size) {
826 ctx->total += size;
827 ctx->inuse += size;
829 if (size > ctx->max_size) {
830 ctx->stats[ctx->max_size].gets++;
831 ctx->stats[ctx->max_size].totalgets++;
832 } else {
833 ctx->stats[size].gets++;
834 ctx->stats[size].totalgets++;
839 * Update internal counters after a memory put.
841 static inline void
842 mem_putstats(isc__mem_t *ctx, void *ptr, size_t size) {
843 UNUSED(ptr);
845 INSIST(ctx->inuse >= size);
846 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--;
851 } else {
852 INSIST(ctx->stats[size].gets > 0U);
853 ctx->stats[size].gets--;
858 * Private.
861 static void *
862 default_memalloc(void *arg, size_t size) {
863 UNUSED(arg);
864 if (size == 0U)
865 size = 1;
866 return (malloc(size));
869 static void
870 default_memfree(void *arg, void *ptr) {
871 UNUSED(arg);
872 free(ptr);
875 static void
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);
880 totallost = 0;
884 * Public.
887 isc_result_t
888 isc_mem_createx(size_t init_max_size, size_t target_size,
889 isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
890 isc_mem_t **ctxp)
892 return (isc_mem_createx2(init_max_size, target_size, memalloc, memfree,
893 arg, ctxp, ISC_MEMFLAG_DEFAULT));
897 isc_result_t
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)
902 isc__mem_t *ctx;
903 isc_result_t result;
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));
914 if (ctx == NULL)
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) {
920 (memfree)(arg, ctx);
921 return (result);
925 if (init_max_size == 0U)
926 ctx->max_size = DEF_MAX_SIZE;
927 else
928 ctx->max_size = init_max_size;
929 ctx->flags = flags;
930 ctx->references = 1;
931 memset(ctx->name, 0, sizeof(ctx->name));
932 ctx->tag = NULL;
933 ctx->quota = 0;
934 ctx->total = 0;
935 ctx->inuse = 0;
936 ctx->maxinuse = 0;
937 ctx->hi_water = 0;
938 ctx->lo_water = 0;
939 ctx->hi_called = ISC_FALSE;
940 ctx->is_overmem = ISC_FALSE;
941 ctx->water = NULL;
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;
949 ctx->arg = arg;
950 ctx->stats = NULL;
951 ctx->checkfree = ISC_TRUE;
952 #if ISC_MEM_TRACKLINES
953 ctx->debuglist = NULL;
954 ctx->debuglistcnt = 0;
955 #endif
956 ISC_LIST_INIT(ctx->pools);
957 ctx->poolcnt = 0;
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;
963 ctx->lowest = NULL;
964 ctx->highest = NULL;
966 ctx->stats = (memalloc)(arg,
967 (ctx->max_size+1) * sizeof(struct stats));
968 if (ctx->stats == NULL) {
969 result = ISC_R_NOMEMORY;
970 goto error;
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;
977 else
978 ctx->mem_target = target_size;
979 ctx->freelists = (memalloc)(arg, ctx->max_size *
980 sizeof(element *));
981 if (ctx->freelists == NULL) {
982 result = ISC_R_NOMEMORY;
983 goto error;
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) {
991 unsigned int i;
993 ctx->debuglist = (memalloc)(arg,
994 (ctx->max_size+1) * sizeof(debuglist_t));
995 if (ctx->debuglist == NULL) {
996 result = ISC_R_NOMEMORY;
997 goto error;
999 for (i = 0; i <= ctx->max_size; i++)
1000 ISC_LIST_INIT(ctx->debuglist[i]);
1002 #endif
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);
1013 error:
1014 if (ctx != NULL) {
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);
1028 return (result);
1031 static void
1032 destroy(isc__mem_t *ctx) {
1033 unsigned int i;
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]));
1054 } else {
1055 debuglink_t *dl;
1057 for (i = 0; i <= ctx->max_size; i++)
1058 for (dl = ISC_LIST_HEAD(ctx->debuglist[i]);
1059 dl != NULL;
1060 dl = ISC_LIST_HEAD(ctx->debuglist[i])) {
1061 ISC_LIST_UNLINK(ctx->debuglist[i],
1062 dl, link);
1063 free(dl);
1066 (ctx->memfree)(ctx->arg, ctx->debuglist);
1068 #endif
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);
1076 #endif
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);
1100 void
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;
1114 void
1115 isc__mem_detach(isc_mem_t **ctxp) {
1116 isc__mem_t *ctx;
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);
1125 ctx->references--;
1126 if (ctx->references == 0)
1127 want_destroy = ISC_TRUE;
1128 MCTXUNLOCK(ctx, &ctx->lock);
1130 if (want_destroy)
1131 destroy(ctx);
1133 *ctxp = NULL;
1137 * isc_mem_putanddetach() is the equivalent of:
1139 * mctx = NULL;
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);
1146 void
1147 isc___mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) {
1148 isc__mem_t *ctx;
1149 isc_boolean_t want_destroy = ISC_FALSE;
1150 size_info *si;
1151 size_t oldsize;
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
1160 * [ptr..ptr+size).
1162 *ctxp = NULL;
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);
1175 ctx->references--;
1176 if (ctx->references == 0)
1177 want_destroy = ISC_TRUE;
1178 MCTXUNLOCK(ctx, &ctx->lock);
1179 if (want_destroy)
1180 destroy(ctx);
1182 return;
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);
1191 } else {
1192 mem_putstats(ctx, ptr, size);
1193 mem_put(ctx, ptr, size);
1196 INSIST(ctx->references > 0);
1197 ctx->references--;
1198 if (ctx->references == 0)
1199 want_destroy = ISC_TRUE;
1201 MCTXUNLOCK(ctx, &ctx->lock);
1203 if (want_destroy)
1204 destroy(ctx);
1207 void
1208 isc__mem_destroy(isc_mem_t **ctxp) {
1209 isc__mem_t *ctx;
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);
1224 #endif
1225 REQUIRE(ctx->references == 1);
1226 ctx->references--;
1227 MCTXUNLOCK(ctx, &ctx->lock);
1229 destroy(ctx);
1231 *ctxp = NULL;
1234 isc_result_t
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;
1237 isc_result_t res;
1239 MCTXLOCK(ctx, &ctx->lock);
1240 res = isc_ondestroy_register(&ctx->ondestroy, task, event);
1241 MCTXUNLOCK(ctx, &ctx->lock);
1243 return (res);
1246 void *
1247 isc___mem_get(isc_mem_t *ctx0, size_t size FLARG) {
1248 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1249 void *ptr;
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);
1260 } else {
1261 ptr = mem_get(ctx, size);
1262 MCTXLOCK(ctx, &ctx->lock);
1263 if (ptr != NULL)
1264 mem_getstats(ctx, size);
1267 ADD_TRACE(ctx, ptr, size, file, line);
1268 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1269 !ctx->is_overmem) {
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);
1285 if (call_water)
1286 (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
1288 return (ptr);
1291 void
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;
1295 size_info *si;
1296 size_t oldsize;
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);
1310 return;
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);
1319 } else {
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);
1340 if (call_water)
1341 (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
1344 void
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
1359 static void
1360 print_active(isc__mem_t *mctx, FILE *out) {
1361 if (mctx->debuglist != NULL) {
1362 debuglink_t *dl;
1363 unsigned int i, j;
1364 const char *format;
1365 isc_boolean_t found;
1367 fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1368 ISC_MSG_DUMPALLOC,
1369 "Dump of all outstanding "
1370 "memory allocations:\n"));
1371 found = ISC_FALSE;
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]);
1378 if (dl != NULL)
1379 found = ISC_TRUE;
1381 while (dl != NULL) {
1382 for (j = 0; j < DEBUGLIST_COUNT; j++)
1383 if (dl->ptr[j] != NULL)
1384 fprintf(out, format,
1385 dl->ptr[j],
1386 dl->size[j],
1387 dl->file[j],
1388 dl->line[j]);
1389 dl = ISC_LIST_NEXT(dl, link);
1392 if (!found)
1393 fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1394 ISC_MSG_NONE, "\tNone.\n"));
1397 #endif
1400 * Print the stats[] on the stream "out" with suitable formatting.
1402 void
1403 isc_mem_stats(isc_mem_t *ctx0, FILE *out) {
1404 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1405 size_t i;
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++) {
1413 s = &ctx->stats[i];
1415 if (s->totalgets == 0U && s->gets == 0U)
1416 continue;
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);
1424 fputc('\n', out);
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);
1435 if (pool != NULL) {
1436 fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1437 ISC_MSG_POOLSTATS,
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"),
1456 "L");
1458 while (pool != NULL) {
1459 fprintf(out, "%15s %10lu %10u %10u %10u %10u %10u %10u %s\n",
1460 #if ISC_MEMPOOL_NAMES
1461 pool->name,
1462 #else
1463 "(not tracked)",
1464 #endif
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);
1474 #endif
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).
1484 static void *
1485 mem_allocateunlocked(isc_mem_t *ctx0, size_t size) {
1486 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1487 size_info *si;
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);
1495 else
1496 si = mem_get(ctx, size);
1498 if (si == NULL)
1499 return (NULL);
1500 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
1501 si->u.ctx = ctx;
1502 si++;
1504 si->u.size = size;
1505 return (&si[1]);
1508 void *
1509 isc___mem_allocate(isc_mem_t *ctx0, size_t size FLARG) {
1510 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1511 size_info *si;
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);
1519 } else {
1520 si = mem_allocateunlocked((isc_mem_t *)ctx, size);
1521 MCTXLOCK(ctx, &ctx->lock);
1522 if (si != NULL)
1523 mem_getstats(ctx, si[-1].u.size);
1526 #if ISC_MEM_TRACKLINES
1527 ADD_TRACE(ctx, si, si[-1].u.size, file, line);
1528 #endif
1529 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1530 !ctx->is_overmem) {
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);
1548 if (call_water)
1549 (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
1551 return (si);
1554 void *
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.
1573 if (size > 0U) {
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);
1590 return (new_ptr);
1593 void
1594 isc___mem_free(isc_mem_t *ctx0, void *ptr FLARG) {
1595 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1596 size_info *si;
1597 size_t size;
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;
1607 } else {
1608 si = &(((size_info *)ptr)[-1]);
1609 size = si->u.size;
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);
1618 } else {
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);
1642 if (call_water)
1643 (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
1648 * Other useful things.
1651 char *
1652 isc___mem_strdup(isc_mem_t *mctx0, const char *s FLARG) {
1653 isc__mem_t *mctx = (isc__mem_t *)mctx0;
1654 size_t len;
1655 char *ns;
1657 REQUIRE(VALID_CONTEXT(mctx));
1658 REQUIRE(s != NULL);
1660 len = strlen(s);
1662 ns = isc__mem_allocate((isc_mem_t *)mctx, len + 1 FLARG_PASS);
1664 if (ns != NULL)
1665 strncpy(ns, s, len + 1);
1667 return (ns);
1670 void
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);
1683 * Quotas
1686 void
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);
1693 ctx->quota = quota;
1695 MCTXUNLOCK(ctx, &ctx->lock);
1698 size_t
1699 isc_mem_getquota(isc_mem_t *ctx0) {
1700 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1701 size_t quota;
1703 REQUIRE(VALID_CONTEXT(ctx));
1704 MCTXLOCK(ctx, &ctx->lock);
1706 quota = ctx->quota;
1708 MCTXUNLOCK(ctx, &ctx->lock);
1710 return (quota);
1713 size_t
1714 isc__mem_inuse(isc_mem_t *ctx0) {
1715 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1716 size_t inuse;
1718 REQUIRE(VALID_CONTEXT(ctx));
1719 MCTXLOCK(ctx, &ctx->lock);
1721 inuse = ctx->inuse;
1723 MCTXUNLOCK(ctx, &ctx->lock);
1725 return (inuse);
1728 size_t
1729 isc__mem_maxinuse(isc_mem_t *ctx0) {
1730 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1731 size_t maxinuse;
1733 REQUIRE(VALID_CONTEXT(ctx));
1734 MCTXLOCK(ctx, &ctx->lock);
1736 maxinuse = ctx->maxinuse;
1738 MCTXUNLOCK(ctx, &ctx->lock);
1740 return (maxinuse);
1743 size_t
1744 isc__mem_total(isc_mem_t *ctx0) {
1745 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1746 size_t total;
1748 REQUIRE(VALID_CONTEXT(ctx));
1749 MCTXLOCK(ctx, &ctx->lock);
1751 total = ctx->total;
1753 MCTXUNLOCK(ctx, &ctx->lock);
1755 return (total);
1758 void
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;
1765 void *oldwater_arg;
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;
1775 ctx->water = NULL;
1776 ctx->water_arg = NULL;
1777 ctx->hi_water = 0;
1778 ctx->lo_water = 0;
1779 ctx->hi_called = ISC_FALSE;
1780 } else {
1781 if (ctx->hi_called &&
1782 (ctx->water != water || ctx->water_arg != water_arg ||
1783 ctx->inuse < lowater || lowater == 0U))
1784 callwater = ISC_TRUE;
1785 ctx->water = water;
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);
1796 isc_boolean_t
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);
1810 void
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));
1816 LOCK(&ctx->lock);
1817 memset(ctx->name, 0, sizeof(ctx->name));
1818 strncpy(ctx->name, name, sizeof(ctx->name) - 1);
1819 ctx->tag = tag;
1820 UNLOCK(&ctx->lock);
1823 const char *
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)
1830 return ("");
1832 return (ctx->name);
1835 void *
1836 isc_mem_gettag(isc_mem_t *ctx0) {
1837 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1839 REQUIRE(VALID_CONTEXT(ctx));
1841 return (ctx->tag);
1845 * Memory pool stuff
1848 isc_result_t
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));
1854 REQUIRE(size > 0U);
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));
1862 if (mpctx == NULL)
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;
1868 mpctx->lock = NULL;
1869 mpctx->mctx = mctx;
1870 mpctx->size = size;
1871 mpctx->maxalloc = UINT_MAX;
1872 mpctx->allocated = 0;
1873 mpctx->freecount = 0;
1874 mpctx->freemax = 1;
1875 mpctx->fillcount = 1;
1876 mpctx->gets = 0;
1877 #if ISC_MEMPOOL_NAMES
1878 mpctx->name[0] = 0;
1879 #endif
1880 mpctx->items = NULL;
1882 *mpctxp = (isc_mempool_t *)mpctx;
1884 MCTXLOCK(mctx, &mctx->lock);
1885 ISC_LIST_INITANDAPPEND(mctx->pools, mpctx, link);
1886 mctx->poolcnt++;
1887 MCTXUNLOCK(mctx, &mctx->lock);
1889 return (ISC_R_SUCCESS);
1892 void
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)
1901 LOCK(mpctx->lock);
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);
1908 #else
1909 UNUSED(mpctx);
1910 UNUSED(name);
1911 #endif
1914 void
1915 isc__mempool_destroy(isc_mempool_t **mpctxp) {
1916 isc__mempool_t *mpctx;
1917 isc__mem_t *mctx;
1918 isc_mutex_t *lock;
1919 element *item;
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 "
1928 "leaked memory",
1929 mpctx->name);
1930 #endif
1931 REQUIRE(mpctx->allocated == 0);
1933 mctx = mpctx->mctx;
1935 lock = mpctx->lock;
1937 if (lock != NULL)
1938 LOCK(lock);
1941 * Return any items on the free list
1943 MCTXLOCK(mctx, &mctx->lock);
1944 while (mpctx->items != NULL) {
1945 INSIST(mpctx->freecount > 0);
1946 mpctx->freecount--;
1947 item = mpctx->items;
1948 mpctx->items = item->next;
1950 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1951 mem_putunlocked(mctx, item, mpctx->size);
1952 } else {
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);
1964 mctx->poolcnt--;
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));
1972 if (lock != NULL)
1973 UNLOCK(lock);
1975 *mpctxp = NULL;
1978 void
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);
1986 mpctx->lock = lock;
1989 void *
1990 isc___mempool_get(isc_mempool_t *mpctx0 FLARG) {
1991 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
1992 element *item;
1993 isc__mem_t *mctx;
1994 unsigned int i;
1996 REQUIRE(VALID_MEMPOOL(mpctx));
1998 mctx = mpctx->mctx;
2000 if (mpctx->lock != NULL)
2001 LOCK(mpctx->lock);
2004 * Don't let the caller go over quota
2006 if (mpctx->allocated >= mpctx->maxalloc) {
2007 item = NULL;
2008 goto out;
2012 * if we have a free list item, return the first here
2014 item = mpctx->items;
2015 if (item != NULL) {
2016 mpctx->items = item->next;
2017 INSIST(mpctx->freecount > 0);
2018 mpctx->freecount--;
2019 mpctx->gets++;
2020 mpctx->allocated++;
2021 goto out;
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);
2032 } else {
2033 item = mem_get(mctx, mpctx->size);
2034 if (item != NULL)
2035 mem_getstats(mctx, mpctx->size);
2037 if (item == NULL)
2038 break;
2039 item->next = mpctx->items;
2040 mpctx->items = item;
2041 mpctx->freecount++;
2043 MCTXUNLOCK(mctx, &mctx->lock);
2046 * If we didn't get any items, return NULL.
2048 item = mpctx->items;
2049 if (item == NULL)
2050 goto out;
2052 mpctx->items = item->next;
2053 mpctx->freecount--;
2054 mpctx->gets++;
2055 mpctx->allocated++;
2057 out:
2058 if (mpctx->lock != NULL)
2059 UNLOCK(mpctx->lock);
2061 #if ISC_MEM_TRACKLINES
2062 if (item != NULL) {
2063 MCTXLOCK(mctx, &mctx->lock);
2064 ADD_TRACE(mctx, item, mpctx->size, file, line);
2065 MCTXUNLOCK(mctx, &mctx->lock);
2067 #endif /* ISC_MEM_TRACKLINES */
2069 return (item);
2072 /* coverity[+free : arg-1] */
2073 void
2074 isc___mempool_put(isc_mempool_t *mpctx0, void *mem FLARG) {
2075 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2076 isc__mem_t *mctx;
2077 element *item;
2079 REQUIRE(VALID_MEMPOOL(mpctx));
2080 REQUIRE(mem != NULL);
2082 mctx = mpctx->mctx;
2084 if (mpctx->lock != NULL)
2085 LOCK(mpctx->lock);
2087 INSIST(mpctx->allocated > 0);
2088 mpctx->allocated--;
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);
2103 } else {
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);
2110 return;
2114 * Otherwise, attach it to our free list and bump the counter.
2116 mpctx->freecount++;
2117 item = (element *)mem;
2118 item->next = mpctx->items;
2119 mpctx->items = item;
2121 if (mpctx->lock != NULL)
2122 UNLOCK(mpctx->lock);
2126 * Quotas
2129 void
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)
2136 LOCK(mpctx->lock);
2138 mpctx->freemax = limit;
2140 if (mpctx->lock != NULL)
2141 UNLOCK(mpctx->lock);
2144 unsigned int
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)
2152 LOCK(mpctx->lock);
2154 freemax = mpctx->freemax;
2156 if (mpctx->lock != NULL)
2157 UNLOCK(mpctx->lock);
2159 return (freemax);
2162 unsigned int
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)
2170 LOCK(mpctx->lock);
2172 freecount = mpctx->freecount;
2174 if (mpctx->lock != NULL)
2175 UNLOCK(mpctx->lock);
2177 return (freecount);
2180 void
2181 isc__mempool_setmaxalloc(isc_mempool_t *mpctx0, unsigned int limit) {
2182 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2184 REQUIRE(limit > 0);
2186 REQUIRE(VALID_MEMPOOL(mpctx));
2188 if (mpctx->lock != NULL)
2189 LOCK(mpctx->lock);
2191 mpctx->maxalloc = limit;
2193 if (mpctx->lock != NULL)
2194 UNLOCK(mpctx->lock);
2197 unsigned int
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)
2205 LOCK(mpctx->lock);
2207 maxalloc = mpctx->maxalloc;
2209 if (mpctx->lock != NULL)
2210 UNLOCK(mpctx->lock);
2212 return (maxalloc);
2215 unsigned int
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)
2223 LOCK(mpctx->lock);
2225 allocated = mpctx->allocated;
2227 if (mpctx->lock != NULL)
2228 UNLOCK(mpctx->lock);
2230 return (allocated);
2233 void
2234 isc__mempool_setfillcount(isc_mempool_t *mpctx0, unsigned int limit) {
2235 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2237 REQUIRE(limit > 0);
2238 REQUIRE(VALID_MEMPOOL(mpctx));
2240 if (mpctx->lock != NULL)
2241 LOCK(mpctx->lock);
2243 mpctx->fillcount = limit;
2245 if (mpctx->lock != NULL)
2246 UNLOCK(mpctx->lock);
2249 unsigned int
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)
2258 LOCK(mpctx->lock);
2260 fillcount = mpctx->fillcount;
2262 if (mpctx->lock != NULL)
2263 UNLOCK(mpctx->lock);
2265 return (fillcount);
2268 isc_result_t
2269 isc__mem_register(void) {
2270 return (isc_mem_register(isc_mem_create2));
2273 void
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);
2282 #else
2283 UNUSED(ctx0);
2284 UNUSED(file);
2285 #endif
2288 void
2289 isc_mem_printallactive(FILE *file) {
2290 #if !ISC_MEM_TRACKLINES
2291 UNUSED(file);
2292 #else
2293 isc__mem_t *ctx;
2295 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2297 LOCK(&contextslock);
2298 for (ctx = ISC_LIST_HEAD(contexts);
2299 ctx != NULL;
2300 ctx = ISC_LIST_NEXT(ctx, link)) {
2301 fprintf(file, "context: %p\n", ctx);
2302 print_active(ctx, file);
2304 UNLOCK(&contextslock);
2305 #endif
2308 void
2309 isc_mem_checkdestroyed(FILE *file) {
2310 #if !ISC_MEM_TRACKLINES
2311 UNUSED(file);
2312 #endif
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
2319 isc__mem_t *ctx;
2321 for (ctx = ISC_LIST_HEAD(contexts);
2322 ctx != NULL;
2323 ctx = ISC_LIST_NEXT(ctx, link)) {
2324 fprintf(file, "context: %p\n", ctx);
2325 print_active(ctx, file);
2327 fflush(file);
2328 #endif
2329 INSIST(0);
2331 UNLOCK(&contextslock);
2334 unsigned int
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 {
2350 isc_uint64_t total;
2351 isc_uint64_t inuse;
2352 isc_uint64_t blocksize;
2353 isc_uint64_t contextsize;
2354 } summarystat_t;
2355 #endif
2357 #ifdef HAVE_LIBXML2
2358 #define TRY0(a) do { xmlrc = (a); if (xmlrc < 0) goto error; } while(/*CONSTCOND*/0)
2359 static int
2360 xml_renderctx(isc__mem_t *ctx, summarystat_t *summary,
2361 xmlTextWriterPtr writer)
2363 int xmlrc;
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);
2391 #endif
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",
2422 (isc_uint64_t)
2423 ctx->basic_table_count *
2424 NUM_BASIC_BLOCKS *
2425 ctx->mem_target));
2426 } else
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 */
2449 error:
2450 MCTXUNLOCK(ctx, &ctx->lock);
2452 return (xmlrc);
2456 isc_mem_renderxml(xmlTextWriterPtr writer) {
2457 isc__mem_t *ctx;
2458 summarystat_t summary;
2459 isc_uint64_t lost;
2460 int xmlrc;
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);
2469 lost = totallost;
2470 for (ctx = ISC_LIST_HEAD(contexts);
2471 ctx != NULL;
2472 ctx = ISC_LIST_NEXT(ctx, link)) {
2473 xmlrc = xml_renderctx(ctx, &summary, writer);
2474 if (xmlrc < 0) {
2475 UNLOCK(&contextslock);
2476 goto error;
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",
2488 summary.total));
2489 TRY0(xmlTextWriterEndElement(writer)); /* TotalUse */
2491 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "InUse"));
2492 TRY0(xmlTextWriterWriteFormatString(writer,
2493 "%" ISC_PRINT_QUADFORMAT "u",
2494 summary.inuse));
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",
2512 lost));
2513 TRY0(xmlTextWriterEndElement(writer)); /* Lost */
2515 TRY0(xmlTextWriterEndElement(writer)); /* summary */
2516 error:
2517 return (xmlrc);
2520 #endif /* HAVE_LIBXML2 */
2522 #ifdef HAVE_JSON
2523 #define CHECKMEM(m) do { \
2524 if (m == NULL) { \
2525 result = ISC_R_NOMEMORY;\
2526 goto error;\
2528 } while(/*CONSTCOND*/0)
2530 static isc_result_t
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;
2534 char buf[1024];
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);
2557 #endif
2559 ctxobj = json_object_new_object();
2560 CHECKMEM(ctxobj);
2562 sprintf(buf, "%p", ctx);
2563 obj = json_object_new_string(buf);
2564 CHECKMEM(obj);
2565 json_object_object_add(ctxobj, "id", obj);
2567 if (ctx->name[0] != 0) {
2568 obj = json_object_new_string(ctx->name);
2569 CHECKMEM(obj);
2570 json_object_object_add(ctxobj, "name", obj);
2573 obj = json_object_new_int64(ctx->references);
2574 CHECKMEM(obj);
2575 json_object_object_add(ctxobj, "references", obj);
2577 obj = json_object_new_int64(ctx->total);
2578 CHECKMEM(obj);
2579 json_object_object_add(ctxobj, "total", obj);
2581 obj = json_object_new_int64(ctx->inuse);
2582 CHECKMEM(obj);
2583 json_object_object_add(ctxobj, "inuse", obj);
2585 obj = json_object_new_int64(ctx->maxinuse);
2586 CHECKMEM(obj);
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 *
2592 ctx->mem_target;
2593 obj = json_object_new_int64(blocksize);
2594 CHECKMEM(obj);
2595 json_object_object_add(ctxobj, "blocksize", obj);
2598 obj = json_object_new_int64(ctx->poolcnt);
2599 CHECKMEM(obj);
2600 json_object_object_add(ctxobj, "pools", obj);
2602 obj = json_object_new_int64(ctx->hi_water);
2603 CHECKMEM(obj);
2604 json_object_object_add(ctxobj, "hiwater", obj);
2606 obj = json_object_new_int64(ctx->lo_water);
2607 CHECKMEM(obj);
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);
2614 error:
2615 MCTXUNLOCK(ctx, &ctx->lock);
2616 if (ctxobj != NULL)
2617 json_object_put(ctxobj);
2618 return (result);
2621 isc_result_t
2622 isc_mem_renderjson(json_object *memobj) {
2623 isc_result_t result = ISC_R_SUCCESS;
2624 isc__mem_t *ctx;
2625 summarystat_t summary;
2626 isc_uint64_t lost;
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();
2633 CHECKMEM(ctxarray);
2635 LOCK(&contextslock);
2636 lost = totallost;
2637 for (ctx = ISC_LIST_HEAD(contexts);
2638 ctx != NULL;
2639 ctx = ISC_LIST_NEXT(ctx, link)) {
2640 result = json_renderctx(ctx, &summary, ctxarray);
2641 if (result != ISC_R_SUCCESS) {
2642 UNLOCK(&contextslock);
2643 goto error;
2646 UNLOCK(&contextslock);
2648 obj = json_object_new_int64(summary.total);
2649 CHECKMEM(obj);
2650 json_object_object_add(memobj, "TotalUse", obj);
2652 obj = json_object_new_int64(summary.inuse);
2653 CHECKMEM(obj);
2654 json_object_object_add(memobj, "InUse", obj);
2656 obj = json_object_new_int64(summary.blocksize);
2657 CHECKMEM(obj);
2658 json_object_object_add(memobj, "BlockSize", obj);
2660 obj = json_object_new_int64(summary.contextsize);
2661 CHECKMEM(obj);
2662 json_object_object_add(memobj, "ContextSize", obj);
2664 obj = json_object_new_int64(lost);
2665 CHECKMEM(obj);
2666 json_object_object_add(memobj, "Lost", obj);
2668 json_object_object_add(memobj, "contexts", ctxarray);
2669 return (ISC_R_SUCCESS);
2671 error:
2672 if (ctxarray != NULL)
2673 json_object_put(ctxarray);
2674 return (result);
2676 #endif /* HAVE_JSON */
2678 static isc_memcreatefunc_t mem_createfunc = NULL;
2680 isc_result_t
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);
2686 LOCK(&createlock);
2687 if (mem_createfunc == NULL)
2688 mem_createfunc = createfunc;
2689 else
2690 result = ISC_R_EXISTS;
2691 UNLOCK(&createlock);
2693 return (result);
2697 isc_result_t
2698 isc__mem_create2(size_t init_max_size, size_t target_size, isc_mem_t **mctxp,
2699 unsigned int flags)
2701 isc_result_t result;
2703 LOCK(&createlock);
2705 REQUIRE(mem_createfunc != NULL);
2706 result = (*mem_createfunc)(init_max_size, target_size, mctxp, flags);
2708 UNLOCK(&createlock);
2710 return (result);
2713 isc_result_t
2714 isc_mem_create(size_t init_max_size, size_t target_size, isc_mem_t **mctxp) {
2715 isc_result_t result;
2717 if (isc_bind9)
2718 return (isc_mem_createx2(init_max_size, target_size,
2719 default_memalloc, default_memfree,
2720 NULL, mctxp, ISC_MEMFLAG_DEFAULT));
2721 LOCK(&createlock);
2723 REQUIRE(mem_createfunc != NULL);
2724 result = (*mem_createfunc)(init_max_size, target_size, mctxp,
2725 ISC_MEMFLAG_DEFAULT);
2727 UNLOCK(&createlock);
2729 return (result);
2732 isc_result_t
2733 isc_mem_create2(size_t init_max_size, size_t target_size, isc_mem_t **mctxp,
2734 unsigned int flags)
2736 if (isc_bind9)
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));
2746 void
2747 isc_mem_attach(isc_mem_t *source, isc_mem_t **targetp) {
2748 REQUIRE(ISCAPI_MCTX_VALID(source));
2749 REQUIRE(targetp != NULL && *targetp == NULL);
2751 if (isc_bind9)
2752 isc__mem_attach(source, targetp);
2753 else
2754 source->methods->attach(source, targetp);
2756 ENSURE(*targetp == source);
2759 void
2760 isc_mem_detach(isc_mem_t **mctxp) {
2761 REQUIRE(mctxp != NULL && ISCAPI_MCTX_VALID(*mctxp));
2763 if (isc_bind9)
2764 isc__mem_detach(mctxp);
2765 else
2766 (*mctxp)->methods->detach(mctxp);
2768 ENSURE(*mctxp == NULL);
2771 void
2772 isc_mem_destroy(isc_mem_t **mctxp) {
2773 REQUIRE(mctxp != NULL && ISCAPI_MCTX_VALID(*mctxp));
2775 if (isc_bind9)
2776 isc__mem_destroy(mctxp);
2777 else
2778 (*mctxp)->methods->destroy(mctxp);
2780 ENSURE(*mctxp == NULL);
2783 void
2784 isc_mem_setdestroycheck(isc_mem_t *mctx, isc_boolean_t flag) {
2785 REQUIRE(ISCAPI_MCTX_VALID(mctx));
2787 mctx->methods->setdestroycheck(mctx, flag);
2790 void
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));
2796 if (isc_bind9)
2797 isc__mem_setwater(ctx, water, water_arg, hiwater, lowater);
2798 else
2799 ctx->methods->setwater(ctx, water, water_arg, hiwater, lowater);
2802 void
2803 isc_mem_waterack(isc_mem_t *ctx, int flag) {
2804 REQUIRE(ISCAPI_MCTX_VALID(ctx));
2806 if (isc_bind9)
2807 isc__mem_waterack(ctx, flag);
2808 else
2809 ctx->methods->waterack(ctx, flag);
2812 size_t
2813 isc_mem_inuse(isc_mem_t *mctx) {
2814 REQUIRE(ISCAPI_MCTX_VALID(mctx));
2816 if (isc_bind9)
2817 return (isc__mem_inuse(mctx));
2819 return (mctx->methods->inuse(mctx));
2822 size_t
2823 isc_mem_maxinuse(isc_mem_t *mctx) {
2824 REQUIRE(ISCAPI_MCTX_VALID(mctx));
2826 if (isc_bind9)
2827 return (isc__mem_maxinuse(mctx));
2829 return (mctx->methods->maxinuse(mctx));
2832 size_t
2833 isc_mem_total(isc_mem_t *mctx) {
2834 REQUIRE(ISCAPI_MCTX_VALID(mctx));
2836 if (isc_bind9)
2837 return (isc__mem_total(mctx));
2839 return (mctx->methods->total(mctx));
2842 isc_boolean_t
2843 isc_mem_isovermem(isc_mem_t *mctx) {
2844 REQUIRE(ISCAPI_MCTX_VALID(mctx));
2846 if (isc_bind9)
2847 return (isc__mem_isovermem(mctx));
2849 return (mctx->methods->isovermem(mctx));
2853 isc_result_t
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));
2860 void
2861 isc_mempool_destroy(isc_mempool_t **mpctxp) {
2862 REQUIRE(mpctxp != NULL && ISCAPI_MPOOL_VALID(*mpctxp));
2864 if (isc_bind9)
2865 isc__mempool_destroy(mpctxp);
2866 else
2867 (*mpctxp)->methods->destroy(mpctxp);
2869 ENSURE(*mpctxp == NULL);
2872 unsigned int
2873 isc_mempool_getallocated(isc_mempool_t *mpctx) {
2874 REQUIRE(ISCAPI_MPOOL_VALID(mpctx));
2876 if (isc_bind9)
2877 return (isc__mempool_getallocated(mpctx));
2879 return (mpctx->methods->getallocated(mpctx));
2882 void
2883 isc_mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit) {
2884 REQUIRE(ISCAPI_MPOOL_VALID(mpctx));
2886 if (isc_bind9)
2887 isc__mempool_setmaxalloc(mpctx, limit);
2888 else
2889 mpctx->methods->setmaxalloc(mpctx, limit);
2892 void
2893 isc_mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit) {
2894 REQUIRE(ISCAPI_MPOOL_VALID(mpctx));
2896 if (isc_bind9)
2897 isc__mempool_setfreemax(mpctx, limit);
2898 else
2899 mpctx->methods->setfreemax(mpctx, limit);
2902 void
2903 isc_mempool_setname(isc_mempool_t *mpctx, const char *name) {
2904 REQUIRE(ISCAPI_MPOOL_VALID(mpctx));
2906 if (isc_bind9)
2907 isc__mempool_setname(mpctx, name);
2908 else
2909 mpctx->methods->setname(mpctx, name);
2912 void
2913 isc_mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock) {
2914 REQUIRE(ISCAPI_MPOOL_VALID(mpctx));
2916 if (isc_bind9)
2917 isc__mempool_associatelock(mpctx, lock);
2918 else
2919 mpctx->methods->associatelock(mpctx, lock);
2922 void
2923 isc_mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit) {
2924 REQUIRE(ISCAPI_MPOOL_VALID(mpctx));
2926 if (isc_bind9)
2927 isc__mempool_setfillcount(mpctx, limit);
2928 else
2929 mpctx->methods->setfillcount(mpctx, limit);
2932 void *
2933 isc__mem_get(isc_mem_t *mctx, size_t size FLARG) {
2934 REQUIRE(ISCAPI_MCTX_VALID(mctx));
2936 if (isc_bind9)
2937 return (isc___mem_get(mctx, size FLARG_PASS));
2939 return (mctx->methods->memget(mctx, size FLARG_PASS));
2943 void
2944 isc__mem_put(isc_mem_t *mctx, void *ptr, size_t size FLARG) {
2945 REQUIRE(ISCAPI_MCTX_VALID(mctx));
2947 if (isc_bind9)
2948 isc___mem_put(mctx, ptr, size FLARG_PASS);
2949 else
2950 mctx->methods->memput(mctx, ptr, size FLARG_PASS);
2953 void
2954 isc__mem_putanddetach(isc_mem_t **mctxp, void *ptr, size_t size FLARG) {
2955 REQUIRE(mctxp != NULL && ISCAPI_MCTX_VALID(*mctxp));
2957 if (isc_bind9)
2958 isc___mem_putanddetach(mctxp, ptr, size FLARG_PASS);
2959 else
2960 (*mctxp)->methods->memputanddetach(mctxp, ptr, size FLARG_PASS);
2963 * XXX: We cannot always ensure *mctxp == NULL here
2964 * (see lib/isc/mem.c).
2968 void *
2969 isc__mem_allocate(isc_mem_t *mctx, size_t size FLARG) {
2970 REQUIRE(ISCAPI_MCTX_VALID(mctx));
2972 if (isc_bind9)
2973 return (isc___mem_allocate(mctx, size FLARG_PASS));
2975 return (mctx->methods->memallocate(mctx, size FLARG_PASS));
2978 void *
2979 isc__mem_reallocate(isc_mem_t *mctx, void *ptr, size_t size FLARG) {
2980 REQUIRE(ISCAPI_MCTX_VALID(mctx));
2982 if (isc_bind9)
2983 return (isc___mem_reallocate(mctx, ptr, size FLARG_PASS));
2985 return (mctx->methods->memreallocate(mctx, ptr, size FLARG_PASS));
2988 char *
2989 isc__mem_strdup(isc_mem_t *mctx, const char *s FLARG) {
2990 REQUIRE(ISCAPI_MCTX_VALID(mctx));
2992 if (isc_bind9)
2993 return (isc___mem_strdup(mctx, s FLARG_PASS));
2995 return (mctx->methods->memstrdup(mctx, s FLARG_PASS));
2998 void
2999 isc__mem_free(isc_mem_t *mctx, void *ptr FLARG) {
3000 REQUIRE(ISCAPI_MCTX_VALID(mctx));
3002 if (isc_bind9)
3003 isc___mem_free(mctx, ptr FLARG_PASS);
3004 else
3005 mctx->methods->memfree(mctx, ptr FLARG_PASS);
3008 void *
3009 isc__mempool_get(isc_mempool_t *mpctx FLARG) {
3010 REQUIRE(ISCAPI_MPOOL_VALID(mpctx));
3012 if (isc_bind9)
3013 return (isc___mempool_get(mpctx FLARG_PASS));
3015 return (mpctx->methods->get(mpctx FLARG_PASS));
3018 void
3019 isc__mempool_put(isc_mempool_t *mpctx, void *mem FLARG) {
3020 REQUIRE(ISCAPI_MPOOL_VALID(mpctx));
3022 if (isc_bind9)
3023 isc___mempool_put(mpctx, mem FLARG_PASS);
3024 else
3025 mpctx->methods->put(mpctx, mem FLARG_PASS);