Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / bsd / bind / dist / lib / isc / mem.c
blob3bfb22739ebe7889d9b47f223939852123811994
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1997-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: mem.c,v 1.153 2009/09/02 23:43:54 each Exp */
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/magic.h>
33 #include <isc/mem.h>
34 #include <isc/msgs.h>
35 #include <isc/once.h>
36 #include <isc/ondestroy.h>
37 #include <isc/string.h>
38 #include <isc/mutex.h>
39 #include <isc/print.h>
40 #include <isc/util.h>
41 #include <isc/xml.h>
43 #define MCTXLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) LOCK(l)
44 #define MCTXUNLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) UNLOCK(l)
46 #ifndef ISC_MEM_DEBUGGING
47 #define ISC_MEM_DEBUGGING 0
48 #endif
49 LIBISC_EXTERNAL_DATA unsigned int isc_mem_debugging = ISC_MEM_DEBUGGING;
52 * Constants.
55 #define DEF_MAX_SIZE 1100
56 #define DEF_MEM_TARGET 4096
57 #define ALIGNMENT_SIZE 8U /*%< must be a power of 2 */
58 #define NUM_BASIC_BLOCKS 64 /*%< must be > 1 */
59 #define TABLE_INCREMENT 1024
60 #define DEBUGLIST_COUNT 1024
63 * Types.
65 typedef struct isc__mem isc__mem_t;
66 typedef struct isc__mempool isc__mempool_t;
68 #if ISC_MEM_TRACKLINES
69 typedef struct debuglink debuglink_t;
70 struct debuglink {
71 ISC_LINK(debuglink_t) link;
72 const void *ptr[DEBUGLIST_COUNT];
73 unsigned int size[DEBUGLIST_COUNT];
74 const char *file[DEBUGLIST_COUNT];
75 unsigned int line[DEBUGLIST_COUNT];
76 unsigned int count;
79 #define FLARG_PASS , file, line
80 #define FLARG , const char *file, int line
81 #else
82 #define FLARG_PASS
83 #define FLARG
84 #endif
86 typedef struct element element;
87 struct element {
88 element * next;
91 typedef struct {
92 /*!
93 * This structure must be ALIGNMENT_SIZE bytes.
95 union {
96 size_t size;
97 isc__mem_t *ctx;
98 char bytes[ALIGNMENT_SIZE];
99 } u;
100 } size_info;
102 struct stats {
103 unsigned long gets;
104 unsigned long totalgets;
105 unsigned long blocks;
106 unsigned long freefrags;
109 #define MEM_MAGIC ISC_MAGIC('M', 'e', 'm', 'C')
110 #define VALID_CONTEXT(c) ISC_MAGIC_VALID(c, MEM_MAGIC)
112 #if ISC_MEM_TRACKLINES
113 typedef ISC_LIST(debuglink_t) debuglist_t;
114 #endif
116 /* List of all active memory contexts. */
118 static ISC_LIST(isc__mem_t) contexts;
119 static isc_once_t once = ISC_ONCE_INIT;
120 static isc_mutex_t lock;
123 * Total size of lost memory due to a bug of external library.
124 * Locked by the global lock.
126 static isc_uint64_t totallost;
128 struct isc__mem {
129 isc_mem_t common;
130 isc_ondestroy_t ondestroy;
131 unsigned int flags;
132 isc_mutex_t lock;
133 isc_memalloc_t memalloc;
134 isc_memfree_t memfree;
135 void * arg;
136 size_t max_size;
137 isc_boolean_t checkfree;
138 struct stats * stats;
139 unsigned int references;
140 char name[16];
141 void * tag;
142 size_t quota;
143 size_t total;
144 size_t inuse;
145 size_t maxinuse;
146 size_t hi_water;
147 size_t lo_water;
148 isc_boolean_t hi_called;
149 isc_mem_water_t water;
150 void * water_arg;
151 ISC_LIST(isc__mempool_t) pools;
152 unsigned int poolcnt;
154 /* ISC_MEMFLAG_INTERNAL */
155 size_t mem_target;
156 element ** freelists;
157 element * basic_blocks;
158 unsigned char ** basic_table;
159 unsigned int basic_table_count;
160 unsigned int basic_table_size;
161 unsigned char * lowest;
162 unsigned char * highest;
164 #if ISC_MEM_TRACKLINES
165 debuglist_t * debuglist;
166 unsigned int debuglistcnt;
167 #endif
169 unsigned int memalloc_failures;
170 ISC_LINK(isc__mem_t) link;
173 #define MEMPOOL_MAGIC ISC_MAGIC('M', 'E', 'M', 'p')
174 #define VALID_MEMPOOL(c) ISC_MAGIC_VALID(c, MEMPOOL_MAGIC)
176 struct isc__mempool {
177 /* always unlocked */
178 isc_mempool_t common; /*%< common header of mempool's */
179 isc_mutex_t *lock; /*%< optional lock */
180 isc__mem_t *mctx; /*%< our memory context */
181 /*%< locked via the memory context's lock */
182 ISC_LINK(isc__mempool_t) link; /*%< next pool in this mem context */
183 /*%< optionally locked from here down */
184 element *items; /*%< low water item list */
185 size_t size; /*%< size of each item on this pool */
186 unsigned int maxalloc; /*%< max number of items allowed */
187 unsigned int allocated; /*%< # of items currently given out */
188 unsigned int freecount; /*%< # of items on reserved list */
189 unsigned int freemax; /*%< # of items allowed on free list */
190 unsigned int fillcount; /*%< # of items to fetch on each fill */
191 /*%< Stats only. */
192 unsigned int gets; /*%< # of requests to this pool */
193 /*%< Debugging only. */
194 #if ISC_MEMPOOL_NAMES
195 char name[16]; /*%< printed name in stats reports */
196 #endif
200 * Private Inline-able.
203 #if ! ISC_MEM_TRACKLINES
204 #define ADD_TRACE(a, b, c, d, e)
205 #define DELETE_TRACE(a, b, c, d, e)
206 #else
207 #define ADD_TRACE(a, b, c, d, e) \
208 do { \
209 if ((isc_mem_debugging & (ISC_MEM_DEBUGTRACE | \
210 ISC_MEM_DEBUGRECORD)) != 0 && \
211 b != NULL) \
212 add_trace_entry(a, b, c, d, e); \
213 } while (0)
214 #define DELETE_TRACE(a, b, c, d, e) delete_trace_entry(a, b, c, d, e)
216 static void
217 print_active(isc__mem_t *ctx, FILE *out);
220 * The following can be either static or public, depending on build environment.
223 #ifdef BIND9
224 #define ISC_MEMFUNC_SCOPE
225 #else
226 #define ISC_MEMFUNC_SCOPE static
227 #endif
229 ISC_MEMFUNC_SCOPE isc_result_t
230 isc__mem_createx(size_t init_max_size, size_t target_size,
231 isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
232 isc_mem_t **ctxp);
233 ISC_MEMFUNC_SCOPE isc_result_t
234 isc__mem_createx2(size_t init_max_size, size_t target_size,
235 isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
236 isc_mem_t **ctxp, unsigned int flags);
237 ISC_MEMFUNC_SCOPE isc_result_t
238 isc__mem_create(size_t init_max_size, size_t target_size, isc_mem_t **ctxp);
239 ISC_MEMFUNC_SCOPE isc_result_t
240 isc__mem_create2(size_t init_max_size, size_t target_size,
241 isc_mem_t **ctxp, unsigned int flags);
242 ISC_MEMFUNC_SCOPE void
243 isc__mem_attach(isc_mem_t *source, isc_mem_t **targetp);
244 ISC_MEMFUNC_SCOPE void
245 isc__mem_detach(isc_mem_t **ctxp);
246 ISC_MEMFUNC_SCOPE void
247 isc___mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG);
248 ISC_MEMFUNC_SCOPE void
249 isc__mem_destroy(isc_mem_t **ctxp);
250 ISC_MEMFUNC_SCOPE isc_result_t
251 isc__mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event);
252 ISC_MEMFUNC_SCOPE void *
253 isc___mem_get(isc_mem_t *ctx, size_t size FLARG);
254 ISC_MEMFUNC_SCOPE void
255 isc___mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG);
256 ISC_MEMFUNC_SCOPE void
257 isc__mem_stats(isc_mem_t *ctx, FILE *out);
258 ISC_MEMFUNC_SCOPE void *
259 isc___mem_allocate(isc_mem_t *ctx, size_t size FLARG);
260 ISC_MEMFUNC_SCOPE void *
261 isc___mem_reallocate(isc_mem_t *ctx, void *ptr, size_t size FLARG);
262 ISC_MEMFUNC_SCOPE void
263 isc___mem_free(isc_mem_t *ctx, void *ptr FLARG);
264 ISC_MEMFUNC_SCOPE char *
265 isc___mem_strdup(isc_mem_t *mctx, const char *s FLARG);
266 ISC_MEMFUNC_SCOPE void
267 isc__mem_setdestroycheck(isc_mem_t *ctx, isc_boolean_t flag);
268 ISC_MEMFUNC_SCOPE void
269 isc__mem_setquota(isc_mem_t *ctx, size_t quota);
270 ISC_MEMFUNC_SCOPE size_t
271 isc__mem_getquota(isc_mem_t *ctx);
272 ISC_MEMFUNC_SCOPE size_t
273 isc__mem_inuse(isc_mem_t *ctx);
274 ISC_MEMFUNC_SCOPE void
275 isc__mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg,
276 size_t hiwater, size_t lowater);
277 ISC_MEMFUNC_SCOPE void
278 isc__mem_waterack(isc_mem_t *ctx0, int flag);
279 ISC_MEMFUNC_SCOPE void
280 isc__mem_setname(isc_mem_t *ctx, const char *name, void *tag);
281 ISC_MEMFUNC_SCOPE const char *
282 isc__mem_getname(isc_mem_t *ctx);
283 ISC_MEMFUNC_SCOPE void *
284 isc__mem_gettag(isc_mem_t *ctx);
285 ISC_MEMFUNC_SCOPE isc_result_t
286 isc__mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp);
287 ISC_MEMFUNC_SCOPE void
288 isc__mempool_setname(isc_mempool_t *mpctx, const char *name);
289 ISC_MEMFUNC_SCOPE void
290 isc__mempool_destroy(isc_mempool_t **mpctxp);
291 ISC_MEMFUNC_SCOPE void
292 isc__mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock);
293 ISC_MEMFUNC_SCOPE void *
294 isc___mempool_get(isc_mempool_t *mpctx FLARG);
295 ISC_MEMFUNC_SCOPE void
296 isc___mempool_put(isc_mempool_t *mpctx, void *mem FLARG);
297 ISC_MEMFUNC_SCOPE void
298 isc__mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit);
299 ISC_MEMFUNC_SCOPE unsigned int
300 isc__mempool_getfreemax(isc_mempool_t *mpctx);
301 ISC_MEMFUNC_SCOPE unsigned int
302 isc__mempool_getfreecount(isc_mempool_t *mpctx);
303 ISC_MEMFUNC_SCOPE void
304 isc__mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit);
305 ISC_MEMFUNC_SCOPE unsigned int
306 isc__mempool_getmaxalloc(isc_mempool_t *mpctx);
307 ISC_MEMFUNC_SCOPE unsigned int
308 isc__mempool_getallocated(isc_mempool_t *mpctx);
309 ISC_MEMFUNC_SCOPE void
310 isc__mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit);
311 ISC_MEMFUNC_SCOPE unsigned int
312 isc__mempool_getfillcount(isc_mempool_t *mpctx);
313 #ifdef BIND9
314 ISC_MEMFUNC_SCOPE void
315 isc__mem_printactive(isc_mem_t *ctx0, FILE *file);
316 ISC_MEMFUNC_SCOPE void
317 isc__mem_printallactive(FILE *file);
318 ISC_MEMFUNC_SCOPE void
319 isc__mem_checkdestroyed(FILE *file);
320 ISC_MEMFUNC_SCOPE unsigned int
321 isc__mem_references(isc_mem_t *ctx0);
322 #endif
324 static struct isc__memmethods {
325 isc_memmethods_t methods;
328 * The following are defined just for avoiding unused static functions.
330 #ifndef BIND9
331 void *createx, *create, *create2, *ondestroy, *stats,
332 *setquota, *getquota, *setname, *getname, *gettag;
333 #endif
334 } memmethods = {
336 isc__mem_attach,
337 isc__mem_detach,
338 isc__mem_destroy,
339 isc___mem_get,
340 isc___mem_put,
341 isc___mem_putanddetach,
342 isc___mem_allocate,
343 isc___mem_reallocate,
344 isc___mem_strdup,
345 isc___mem_free,
346 isc__mem_setdestroycheck,
347 isc__mem_setwater,
348 isc__mem_waterack,
349 isc__mem_inuse,
350 isc__mempool_create
352 #ifndef BIND9
354 (void *)isc__mem_createx, (void *)isc__mem_create,
355 (void *)isc__mem_create2, (void *)isc__mem_ondestroy,
356 (void *)isc__mem_stats, (void *)isc__mem_setquota,
357 (void *)isc__mem_getquota, (void *)isc__mem_setname,
358 (void *)isc__mem_getname, (void *)isc__mem_gettag
359 #endif
362 static struct isc__mempoolmethods {
363 isc_mempoolmethods_t methods;
366 * The following are defined just for avoiding unused static functions.
368 #ifndef BIND9
369 void *getfreemax, *getfreecount, *getmaxalloc, *getfillcount;
370 #endif
371 } mempoolmethods = {
373 isc__mempool_destroy,
374 isc___mempool_get,
375 isc___mempool_put,
376 isc__mempool_getallocated,
377 isc__mempool_setmaxalloc,
378 isc__mempool_setfreemax,
379 isc__mempool_setname,
380 isc__mempool_associatelock,
381 isc__mempool_setfillcount
383 #ifndef BIND9
385 (void *)isc__mempool_getfreemax, (void *)isc__mempool_getfreecount,
386 (void *)isc__mempool_getmaxalloc, (void *)isc__mempool_getfillcount
387 #endif
391 * mctx must be locked.
393 static inline void
394 add_trace_entry(isc__mem_t *mctx, const void *ptr, unsigned int size
395 FLARG)
397 debuglink_t *dl;
398 unsigned int i;
400 if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
401 fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
402 ISC_MSG_ADDTRACE,
403 "add %p size %u "
404 "file %s line %u mctx %p\n"),
405 ptr, size, file, line, mctx);
407 if (mctx->debuglist == NULL)
408 return;
410 if (size > mctx->max_size)
411 size = mctx->max_size;
413 dl = ISC_LIST_HEAD(mctx->debuglist[size]);
414 while (dl != NULL) {
415 if (dl->count == DEBUGLIST_COUNT)
416 goto next;
417 for (i = 0; i < DEBUGLIST_COUNT; i++) {
418 if (dl->ptr[i] == NULL) {
419 dl->ptr[i] = ptr;
420 dl->size[i] = size;
421 dl->file[i] = file;
422 dl->line[i] = line;
423 dl->count++;
424 return;
427 next:
428 dl = ISC_LIST_NEXT(dl, link);
431 dl = malloc(sizeof(debuglink_t));
432 INSIST(dl != NULL);
434 ISC_LINK_INIT(dl, link);
435 for (i = 1; i < DEBUGLIST_COUNT; i++) {
436 dl->ptr[i] = NULL;
437 dl->size[i] = 0;
438 dl->file[i] = NULL;
439 dl->line[i] = 0;
442 dl->ptr[0] = ptr;
443 dl->size[0] = size;
444 dl->file[0] = file;
445 dl->line[0] = line;
446 dl->count = 1;
448 ISC_LIST_PREPEND(mctx->debuglist[size], dl, link);
449 mctx->debuglistcnt++;
452 static inline void
453 delete_trace_entry(isc__mem_t *mctx, const void *ptr, unsigned int size,
454 const char *file, unsigned int line)
456 debuglink_t *dl;
457 unsigned int i;
459 if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
460 fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
461 ISC_MSG_DELTRACE,
462 "del %p size %u "
463 "file %s line %u mctx %p\n"),
464 ptr, size, file, line, mctx);
466 if (mctx->debuglist == NULL)
467 return;
469 if (size > mctx->max_size)
470 size = mctx->max_size;
472 dl = ISC_LIST_HEAD(mctx->debuglist[size]);
473 while (dl != NULL) {
474 for (i = 0; i < DEBUGLIST_COUNT; i++) {
475 if (dl->ptr[i] == ptr) {
476 dl->ptr[i] = NULL;
477 dl->size[i] = 0;
478 dl->file[i] = NULL;
479 dl->line[i] = 0;
481 INSIST(dl->count > 0);
482 dl->count--;
483 if (dl->count == 0) {
484 ISC_LIST_UNLINK(mctx->debuglist[size],
485 dl, link);
486 free(dl);
488 return;
491 dl = ISC_LIST_NEXT(dl, link);
495 * If we get here, we didn't find the item on the list. We're
496 * screwed.
498 INSIST(dl != NULL);
500 #endif /* ISC_MEM_TRACKLINES */
502 static inline size_t
503 rmsize(size_t size) {
505 * round down to ALIGNMENT_SIZE
507 return (size & (~(ALIGNMENT_SIZE - 1)));
510 static inline size_t
511 quantize(size_t size) {
513 * Round up the result in order to get a size big
514 * enough to satisfy the request and be aligned on ALIGNMENT_SIZE
515 * byte boundaries.
518 if (size == 0U)
519 return (ALIGNMENT_SIZE);
520 return ((size + ALIGNMENT_SIZE - 1) & (~(ALIGNMENT_SIZE - 1)));
523 static inline isc_boolean_t
524 more_basic_blocks(isc__mem_t *ctx) {
525 void *new;
526 unsigned char *curr, *next;
527 unsigned char *first, *last;
528 unsigned char **table;
529 unsigned int table_size;
530 size_t increment;
531 int i;
533 /* Require: we hold the context lock. */
536 * Did we hit the quota for this context?
538 increment = NUM_BASIC_BLOCKS * ctx->mem_target;
539 if (ctx->quota != 0U && ctx->total + increment > ctx->quota)
540 return (ISC_FALSE);
542 INSIST(ctx->basic_table_count <= ctx->basic_table_size);
543 if (ctx->basic_table_count == ctx->basic_table_size) {
544 table_size = ctx->basic_table_size + TABLE_INCREMENT;
545 table = (ctx->memalloc)(ctx->arg,
546 table_size * sizeof(unsigned char *));
547 if (table == NULL) {
548 ctx->memalloc_failures++;
549 return (ISC_FALSE);
551 if (ctx->basic_table_size != 0) {
552 memcpy(table, ctx->basic_table,
553 ctx->basic_table_size *
554 sizeof(unsigned char *));
555 (ctx->memfree)(ctx->arg, ctx->basic_table);
557 ctx->basic_table = table;
558 ctx->basic_table_size = table_size;
561 new = (ctx->memalloc)(ctx->arg, NUM_BASIC_BLOCKS * ctx->mem_target);
562 if (new == NULL) {
563 ctx->memalloc_failures++;
564 return (ISC_FALSE);
566 ctx->total += increment;
567 ctx->basic_table[ctx->basic_table_count] = new;
568 ctx->basic_table_count++;
570 curr = new;
571 next = curr + ctx->mem_target;
572 for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) {
573 ((element *)curr)->next = (element *)next;
574 curr = next;
575 next += ctx->mem_target;
578 * curr is now pointing at the last block in the
579 * array.
581 ((element *)curr)->next = NULL;
582 first = new;
583 last = first + NUM_BASIC_BLOCKS * ctx->mem_target - 1;
584 if (first < ctx->lowest || ctx->lowest == NULL)
585 ctx->lowest = first;
586 if (last > ctx->highest)
587 ctx->highest = last;
588 ctx->basic_blocks = new;
590 return (ISC_TRUE);
593 static inline isc_boolean_t
594 more_frags(isc__mem_t *ctx, size_t new_size) {
595 int i, frags;
596 size_t total_size;
597 void *new;
598 unsigned char *curr, *next;
601 * Try to get more fragments by chopping up a basic block.
604 if (ctx->basic_blocks == NULL) {
605 if (!more_basic_blocks(ctx)) {
607 * We can't get more memory from the OS, or we've
608 * hit the quota for this context.
611 * XXXRTH "At quota" notification here.
613 return (ISC_FALSE);
617 total_size = ctx->mem_target;
618 new = ctx->basic_blocks;
619 ctx->basic_blocks = ctx->basic_blocks->next;
620 frags = total_size / new_size;
621 ctx->stats[new_size].blocks++;
622 ctx->stats[new_size].freefrags += frags;
624 * Set up a linked-list of blocks of size
625 * "new_size".
627 curr = new;
628 next = curr + new_size;
629 total_size -= new_size;
630 for (i = 0; i < (frags - 1); i++) {
631 ((element *)curr)->next = (element *)next;
632 curr = next;
633 next += new_size;
634 total_size -= new_size;
637 * Add the remaining fragment of the basic block to a free list.
639 total_size = rmsize(total_size);
640 if (total_size > 0U) {
641 ((element *)next)->next = ctx->freelists[total_size];
642 ctx->freelists[total_size] = (element *)next;
643 ctx->stats[total_size].freefrags++;
646 * curr is now pointing at the last block in the
647 * array.
649 ((element *)curr)->next = NULL;
650 ctx->freelists[new_size] = new;
652 return (ISC_TRUE);
655 static inline void *
656 mem_getunlocked(isc__mem_t *ctx, size_t size) {
657 size_t new_size = quantize(size);
658 void *ret;
660 if (size >= ctx->max_size || new_size >= ctx->max_size) {
662 * memget() was called on something beyond our upper limit.
664 if (ctx->quota != 0U && ctx->total + size > ctx->quota) {
665 ret = NULL;
666 goto done;
668 ret = (ctx->memalloc)(ctx->arg, size);
669 if (ret == NULL) {
670 ctx->memalloc_failures++;
671 goto done;
673 ctx->total += size;
674 ctx->inuse += size;
675 ctx->stats[ctx->max_size].gets++;
676 ctx->stats[ctx->max_size].totalgets++;
678 * If we don't set new_size to size, then the
679 * ISC_MEM_FILL code might write over bytes we
680 * don't own.
682 new_size = size;
683 goto done;
687 * If there are no blocks in the free list for this size, get a chunk
688 * of memory and then break it up into "new_size"-sized blocks, adding
689 * them to the free list.
691 if (ctx->freelists[new_size] == NULL && !more_frags(ctx, new_size))
692 return (NULL);
695 * The free list uses the "rounded-up" size "new_size".
697 ret = ctx->freelists[new_size];
698 ctx->freelists[new_size] = ctx->freelists[new_size]->next;
701 * The stats[] uses the _actual_ "size" requested by the
702 * caller, with the caveat (in the code above) that "size" >= the
703 * max. size (max_size) ends up getting recorded as a call to
704 * max_size.
706 ctx->stats[size].gets++;
707 ctx->stats[size].totalgets++;
708 ctx->stats[new_size].freefrags--;
709 ctx->inuse += new_size;
711 done:
713 #if ISC_MEM_FILL
714 if (ret != NULL)
715 memset(ret, 0xbe, new_size); /* Mnemonic for "beef". */
716 #endif
718 return (ret);
721 #if ISC_MEM_FILL && ISC_MEM_CHECKOVERRUN
722 static inline void
723 check_overrun(void *mem, size_t size, size_t new_size) {
724 unsigned char *cp;
726 cp = (unsigned char *)mem;
727 cp += size;
728 while (size < new_size) {
729 INSIST(*cp == 0xbe);
730 cp++;
731 size++;
734 #endif
736 static inline void
737 mem_putunlocked(isc__mem_t *ctx, void *mem, size_t size) {
738 size_t new_size = quantize(size);
740 if (size == ctx->max_size || new_size >= ctx->max_size) {
742 * memput() called on something beyond our upper limit.
744 #if ISC_MEM_FILL
745 memset(mem, 0xde, size); /* Mnemonic for "dead". */
746 #endif
747 (ctx->memfree)(ctx->arg, mem);
748 INSIST(ctx->stats[ctx->max_size].gets != 0U);
749 ctx->stats[ctx->max_size].gets--;
750 INSIST(size <= ctx->total);
751 ctx->inuse -= size;
752 ctx->total -= size;
753 return;
756 #if ISC_MEM_FILL
757 #if ISC_MEM_CHECKOVERRUN
758 check_overrun(mem, size, new_size);
759 #endif
760 memset(mem, 0xde, new_size); /* Mnemonic for "dead". */
761 #endif
764 * The free list uses the "rounded-up" size "new_size".
766 ((element *)mem)->next = ctx->freelists[new_size];
767 ctx->freelists[new_size] = (element *)mem;
770 * The stats[] uses the _actual_ "size" requested by the
771 * caller, with the caveat (in the code above) that "size" >= the
772 * max. size (max_size) ends up getting recorded as a call to
773 * max_size.
775 INSIST(ctx->stats[size].gets != 0U);
776 ctx->stats[size].gets--;
777 ctx->stats[new_size].freefrags++;
778 ctx->inuse -= new_size;
782 * Perform a malloc, doing memory filling and overrun detection as necessary.
784 static inline void *
785 mem_get(isc__mem_t *ctx, size_t size) {
786 char *ret;
788 #if ISC_MEM_CHECKOVERRUN
789 size += 1;
790 #endif
792 ret = (ctx->memalloc)(ctx->arg, size);
793 if (ret == NULL)
794 ctx->memalloc_failures++;
796 #if ISC_MEM_FILL
797 if (ret != NULL)
798 memset(ret, 0xbe, size); /* Mnemonic for "beef". */
799 #else
800 # if ISC_MEM_CHECKOVERRUN
801 if (ret != NULL)
802 ret[size-1] = 0xbe;
803 # endif
804 #endif
806 return (ret);
810 * Perform a free, doing memory filling and overrun detection as necessary.
812 static inline void
813 mem_put(isc__mem_t *ctx, void *mem, size_t size) {
814 #if ISC_MEM_CHECKOVERRUN
815 INSIST(((unsigned char *)mem)[size] == 0xbe);
816 #endif
817 #if ISC_MEM_FILL
818 memset(mem, 0xde, size); /* Mnemonic for "dead". */
819 #else
820 UNUSED(size);
821 #endif
822 (ctx->memfree)(ctx->arg, mem);
826 * Update internal counters after a memory get.
828 static inline void
829 mem_getstats(isc__mem_t *ctx, size_t size) {
830 ctx->total += size;
831 ctx->inuse += size;
833 if (size > ctx->max_size) {
834 ctx->stats[ctx->max_size].gets++;
835 ctx->stats[ctx->max_size].totalgets++;
836 } else {
837 ctx->stats[size].gets++;
838 ctx->stats[size].totalgets++;
843 * Update internal counters after a memory put.
845 static inline void
846 mem_putstats(isc__mem_t *ctx, void *ptr, size_t size) {
847 UNUSED(ptr);
849 INSIST(ctx->inuse >= size);
850 ctx->inuse -= size;
852 if (size > ctx->max_size) {
853 INSIST(ctx->stats[ctx->max_size].gets > 0U);
854 ctx->stats[ctx->max_size].gets--;
855 } else {
856 INSIST(ctx->stats[size].gets > 0U);
857 ctx->stats[size].gets--;
862 * Private.
865 static void *
866 default_memalloc(void *arg, size_t size) {
867 UNUSED(arg);
868 if (size == 0U)
869 size = 1;
870 return (malloc(size));
873 static void
874 default_memfree(void *arg, void *ptr) {
875 UNUSED(arg);
876 free(ptr);
879 static void
880 initialize_action(void) {
881 RUNTIME_CHECK(isc_mutex_init(&lock) == ISC_R_SUCCESS);
882 ISC_LIST_INIT(contexts);
883 totallost = 0;
887 * Public.
890 ISC_MEMFUNC_SCOPE isc_result_t
891 isc__mem_createx(size_t init_max_size, size_t target_size,
892 isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
893 isc_mem_t **ctxp)
895 return (isc__mem_createx2(init_max_size, target_size, memalloc, memfree,
896 arg, ctxp, ISC_MEMFLAG_DEFAULT));
900 ISC_MEMFUNC_SCOPE isc_result_t
901 isc__mem_createx2(size_t init_max_size, size_t target_size,
902 isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
903 isc_mem_t **ctxp, unsigned int flags)
905 isc__mem_t *ctx;
906 isc_result_t result;
908 REQUIRE(ctxp != NULL && *ctxp == NULL);
909 REQUIRE(memalloc != NULL);
910 REQUIRE(memfree != NULL);
912 INSIST((ALIGNMENT_SIZE & (ALIGNMENT_SIZE - 1)) == 0);
914 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
916 ctx = (memalloc)(arg, sizeof(*ctx));
917 if (ctx == NULL)
918 return (ISC_R_NOMEMORY);
920 if ((flags & ISC_MEMFLAG_NOLOCK) == 0) {
921 result = isc_mutex_init(&ctx->lock);
922 if (result != ISC_R_SUCCESS) {
923 (memfree)(arg, ctx);
924 return (result);
928 if (init_max_size == 0U)
929 ctx->max_size = DEF_MAX_SIZE;
930 else
931 ctx->max_size = init_max_size;
932 ctx->flags = flags;
933 ctx->references = 1;
934 memset(ctx->name, 0, sizeof(ctx->name));
935 ctx->tag = NULL;
936 ctx->quota = 0;
937 ctx->total = 0;
938 ctx->inuse = 0;
939 ctx->maxinuse = 0;
940 ctx->hi_water = 0;
941 ctx->lo_water = 0;
942 ctx->hi_called = ISC_FALSE;
943 ctx->water = NULL;
944 ctx->water_arg = NULL;
945 ctx->common.impmagic = MEM_MAGIC;
946 ctx->common.magic = ISCAPI_MCTX_MAGIC;
947 ctx->common.methods = (isc_memmethods_t *)&memmethods;
948 isc_ondestroy_init(&ctx->ondestroy);
949 ctx->memalloc = memalloc;
950 ctx->memfree = memfree;
951 ctx->arg = arg;
952 ctx->stats = NULL;
953 ctx->checkfree = ISC_TRUE;
954 #if ISC_MEM_TRACKLINES
955 ctx->debuglist = NULL;
956 ctx->debuglistcnt = 0;
957 #endif
958 ISC_LIST_INIT(ctx->pools);
959 ctx->poolcnt = 0;
960 ctx->freelists = NULL;
961 ctx->basic_blocks = NULL;
962 ctx->basic_table = NULL;
963 ctx->basic_table_count = 0;
964 ctx->basic_table_size = 0;
965 ctx->lowest = NULL;
966 ctx->highest = NULL;
968 ctx->stats = (memalloc)(arg,
969 (ctx->max_size+1) * sizeof(struct stats));
970 if (ctx->stats == NULL) {
971 result = ISC_R_NOMEMORY;
972 goto error;
974 memset(ctx->stats, 0, (ctx->max_size + 1) * sizeof(struct stats));
976 if ((flags & ISC_MEMFLAG_INTERNAL) != 0) {
977 if (target_size == 0U)
978 ctx->mem_target = DEF_MEM_TARGET;
979 else
980 ctx->mem_target = target_size;
981 ctx->freelists = (memalloc)(arg, ctx->max_size *
982 sizeof(element *));
983 if (ctx->freelists == NULL) {
984 result = ISC_R_NOMEMORY;
985 goto error;
987 memset(ctx->freelists, 0,
988 ctx->max_size * sizeof(element *));
991 #if ISC_MEM_TRACKLINES
992 if ((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0) {
993 unsigned int i;
995 ctx->debuglist = (memalloc)(arg,
996 (ctx->max_size+1) * sizeof(debuglist_t));
997 if (ctx->debuglist == NULL) {
998 result = ISC_R_NOMEMORY;
999 goto error;
1001 for (i = 0; i <= ctx->max_size; i++)
1002 ISC_LIST_INIT(ctx->debuglist[i]);
1004 #endif
1006 ctx->memalloc_failures = 0;
1008 LOCK(&lock);
1009 ISC_LIST_INITANDAPPEND(contexts, ctx, link);
1010 UNLOCK(&lock);
1012 *ctxp = (isc_mem_t *)ctx;
1013 return (ISC_R_SUCCESS);
1015 error:
1016 if (ctx != NULL) {
1017 if (ctx->stats != NULL)
1018 (memfree)(arg, ctx->stats);
1019 if (ctx->freelists != NULL)
1020 (memfree)(arg, ctx->freelists);
1021 #if ISC_MEM_TRACKLINES
1022 if (ctx->debuglist != NULL)
1023 (ctx->memfree)(ctx->arg, ctx->debuglist);
1024 #endif /* ISC_MEM_TRACKLINES */
1025 if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
1026 DESTROYLOCK(&ctx->lock);
1027 (memfree)(arg, ctx);
1030 return (result);
1033 ISC_MEMFUNC_SCOPE isc_result_t
1034 isc__mem_create(size_t init_max_size, size_t target_size, isc_mem_t **ctxp) {
1035 return (isc__mem_createx2(init_max_size, target_size,
1036 default_memalloc, default_memfree, NULL,
1037 ctxp, ISC_MEMFLAG_DEFAULT));
1040 ISC_MEMFUNC_SCOPE isc_result_t
1041 isc__mem_create2(size_t init_max_size, size_t target_size,
1042 isc_mem_t **ctxp, unsigned int flags)
1044 return (isc__mem_createx2(init_max_size, target_size,
1045 default_memalloc, default_memfree, NULL,
1046 ctxp, flags));
1049 static void
1050 destroy(isc__mem_t *ctx) {
1051 unsigned int i;
1052 isc_ondestroy_t ondest;
1054 ctx->common.impmagic = 0;
1055 ctx->common.magic = 0;
1057 LOCK(&lock);
1058 ISC_LIST_UNLINK(contexts, ctx, link);
1059 totallost += ctx->inuse;
1060 UNLOCK(&lock);
1062 INSIST(ISC_LIST_EMPTY(ctx->pools));
1064 #if ISC_MEM_TRACKLINES
1065 if (ctx->debuglist != NULL) {
1066 if (ctx->checkfree) {
1067 for (i = 0; i <= ctx->max_size; i++) {
1068 if (!ISC_LIST_EMPTY(ctx->debuglist[i]))
1069 print_active(ctx, stderr);
1070 INSIST(ISC_LIST_EMPTY(ctx->debuglist[i]));
1072 } else {
1073 debuglink_t *dl;
1075 for (i = 0; i <= ctx->max_size; i++)
1076 for (dl = ISC_LIST_HEAD(ctx->debuglist[i]);
1077 dl != NULL;
1078 dl = ISC_LIST_HEAD(ctx->debuglist[i])) {
1079 ISC_LIST_UNLINK(ctx->debuglist[i],
1080 dl, link);
1081 free(dl);
1084 (ctx->memfree)(ctx->arg, ctx->debuglist);
1086 #endif
1087 INSIST(ctx->references == 0);
1089 if (ctx->checkfree) {
1090 for (i = 0; i <= ctx->max_size; i++) {
1091 #if ISC_MEM_TRACKLINES
1092 if (ctx->stats[i].gets != 0U)
1093 print_active(ctx, stderr);
1094 #endif
1095 INSIST(ctx->stats[i].gets == 0U);
1099 (ctx->memfree)(ctx->arg, ctx->stats);
1101 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1102 for (i = 0; i < ctx->basic_table_count; i++)
1103 (ctx->memfree)(ctx->arg, ctx->basic_table[i]);
1104 (ctx->memfree)(ctx->arg, ctx->freelists);
1105 if (ctx->basic_table != NULL)
1106 (ctx->memfree)(ctx->arg, ctx->basic_table);
1109 ondest = ctx->ondestroy;
1111 if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
1112 DESTROYLOCK(&ctx->lock);
1113 (ctx->memfree)(ctx->arg, ctx);
1115 isc_ondestroy_notify(&ondest, ctx);
1118 ISC_MEMFUNC_SCOPE void
1119 isc__mem_attach(isc_mem_t *source0, isc_mem_t **targetp) {
1120 isc__mem_t *source = (isc__mem_t *)source0;
1122 REQUIRE(VALID_CONTEXT(source));
1123 REQUIRE(targetp != NULL && *targetp == NULL);
1125 MCTXLOCK(source, &source->lock);
1126 source->references++;
1127 MCTXUNLOCK(source, &source->lock);
1129 *targetp = (isc_mem_t *)source;
1132 ISC_MEMFUNC_SCOPE void
1133 isc__mem_detach(isc_mem_t **ctxp) {
1134 isc__mem_t *ctx;
1135 isc_boolean_t want_destroy = ISC_FALSE;
1137 REQUIRE(ctxp != NULL);
1138 ctx = (isc__mem_t *)*ctxp;
1139 REQUIRE(VALID_CONTEXT(ctx));
1141 MCTXLOCK(ctx, &ctx->lock);
1142 INSIST(ctx->references > 0);
1143 ctx->references--;
1144 if (ctx->references == 0)
1145 want_destroy = ISC_TRUE;
1146 MCTXUNLOCK(ctx, &ctx->lock);
1148 if (want_destroy)
1149 destroy(ctx);
1151 *ctxp = NULL;
1155 * isc_mem_putanddetach() is the equivalent of:
1157 * mctx = NULL;
1158 * isc_mem_attach(ptr->mctx, &mctx);
1159 * isc_mem_detach(&ptr->mctx);
1160 * isc_mem_put(mctx, ptr, sizeof(*ptr);
1161 * isc_mem_detach(&mctx);
1164 ISC_MEMFUNC_SCOPE void
1165 isc___mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) {
1166 isc__mem_t *ctx;
1167 isc_boolean_t want_destroy = ISC_FALSE;
1168 size_info *si;
1169 size_t oldsize;
1171 REQUIRE(ctxp != NULL);
1172 ctx = (isc__mem_t *)*ctxp;
1173 REQUIRE(VALID_CONTEXT(ctx));
1174 REQUIRE(ptr != NULL);
1177 * Must be before mem_putunlocked() as ctxp is usually within
1178 * [ptr..ptr+size).
1180 *ctxp = NULL;
1182 if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) {
1183 if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) {
1184 si = &(((size_info *)ptr)[-1]);
1185 oldsize = si->u.size - ALIGNMENT_SIZE;
1186 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
1187 oldsize -= ALIGNMENT_SIZE;
1188 INSIST(oldsize == size);
1190 isc_mem_free((isc_mem_t *)ctx, ptr);
1192 MCTXLOCK(ctx, &ctx->lock);
1193 ctx->references--;
1194 if (ctx->references == 0)
1195 want_destroy = ISC_TRUE;
1196 MCTXUNLOCK(ctx, &ctx->lock);
1197 if (want_destroy)
1198 destroy(ctx);
1200 return;
1203 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1204 MCTXLOCK(ctx, &ctx->lock);
1205 mem_putunlocked(ctx, ptr, size);
1206 } else {
1207 mem_put(ctx, ptr, size);
1208 MCTXLOCK(ctx, &ctx->lock);
1209 mem_putstats(ctx, ptr, size);
1212 DELETE_TRACE(ctx, ptr, size, file, line);
1213 INSIST(ctx->references > 0);
1214 ctx->references--;
1215 if (ctx->references == 0)
1216 want_destroy = ISC_TRUE;
1218 MCTXUNLOCK(ctx, &ctx->lock);
1220 if (want_destroy)
1221 destroy(ctx);
1224 ISC_MEMFUNC_SCOPE void
1225 isc__mem_destroy(isc_mem_t **ctxp) {
1226 isc__mem_t *ctx;
1229 * This routine provides legacy support for callers who use mctxs
1230 * without attaching/detaching.
1233 REQUIRE(ctxp != NULL);
1234 ctx = (isc__mem_t *)*ctxp;
1235 REQUIRE(VALID_CONTEXT(ctx));
1237 MCTXLOCK(ctx, &ctx->lock);
1238 #if ISC_MEM_TRACKLINES
1239 if (ctx->references != 1)
1240 print_active(ctx, stderr);
1241 #endif
1242 REQUIRE(ctx->references == 1);
1243 ctx->references--;
1244 MCTXUNLOCK(ctx, &ctx->lock);
1246 destroy(ctx);
1248 *ctxp = NULL;
1251 ISC_MEMFUNC_SCOPE isc_result_t
1252 isc__mem_ondestroy(isc_mem_t *ctx0, isc_task_t *task, isc_event_t **event) {
1253 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1254 isc_result_t res;
1256 MCTXLOCK(ctx, &ctx->lock);
1257 res = isc_ondestroy_register(&ctx->ondestroy, task, event);
1258 MCTXUNLOCK(ctx, &ctx->lock);
1260 return (res);
1263 ISC_MEMFUNC_SCOPE void *
1264 isc___mem_get(isc_mem_t *ctx0, size_t size FLARG) {
1265 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1266 void *ptr;
1267 isc_boolean_t call_water = ISC_FALSE;
1269 REQUIRE(VALID_CONTEXT(ctx));
1271 if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0)
1272 return (isc_mem_allocate((isc_mem_t *)ctx, size));
1274 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1275 MCTXLOCK(ctx, &ctx->lock);
1276 ptr = mem_getunlocked(ctx, size);
1277 } else {
1278 ptr = mem_get(ctx, size);
1279 MCTXLOCK(ctx, &ctx->lock);
1280 if (ptr != NULL)
1281 mem_getstats(ctx, size);
1284 ADD_TRACE(ctx, ptr, size, file, line);
1285 if (ctx->hi_water != 0U && !ctx->hi_called &&
1286 ctx->inuse > ctx->hi_water) {
1287 call_water = ISC_TRUE;
1289 if (ctx->inuse > ctx->maxinuse) {
1290 ctx->maxinuse = ctx->inuse;
1291 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1292 (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
1293 fprintf(stderr, "maxinuse = %lu\n",
1294 (unsigned long)ctx->inuse);
1296 MCTXUNLOCK(ctx, &ctx->lock);
1298 if (call_water)
1299 (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
1301 return (ptr);
1304 ISC_MEMFUNC_SCOPE void
1305 isc___mem_put(isc_mem_t *ctx0, void *ptr, size_t size FLARG) {
1306 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1307 isc_boolean_t call_water = ISC_FALSE;
1308 size_info *si;
1309 size_t oldsize;
1311 REQUIRE(VALID_CONTEXT(ctx));
1312 REQUIRE(ptr != NULL);
1314 if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) {
1315 if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) {
1316 si = &(((size_info *)ptr)[-1]);
1317 oldsize = si->u.size - ALIGNMENT_SIZE;
1318 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
1319 oldsize -= ALIGNMENT_SIZE;
1320 INSIST(oldsize == size);
1322 isc_mem_free((isc_mem_t *)ctx, ptr);
1323 return;
1326 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1327 MCTXLOCK(ctx, &ctx->lock);
1328 mem_putunlocked(ctx, ptr, size);
1329 } else {
1330 mem_put(ctx, ptr, size);
1331 MCTXLOCK(ctx, &ctx->lock);
1332 mem_putstats(ctx, ptr, size);
1335 DELETE_TRACE(ctx, ptr, size, file, line);
1338 * The check against ctx->lo_water == 0 is for the condition
1339 * when the context was pushed over hi_water but then had
1340 * isc_mem_setwater() called with 0 for hi_water and lo_water.
1342 if (ctx->hi_called &&
1343 (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1344 if (ctx->water != NULL)
1345 call_water = ISC_TRUE;
1347 MCTXUNLOCK(ctx, &ctx->lock);
1349 if (call_water)
1350 (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
1353 ISC_MEMFUNC_SCOPE void
1354 isc__mem_waterack(isc_mem_t *ctx0, int flag) {
1355 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1357 REQUIRE(VALID_CONTEXT(ctx));
1359 MCTXLOCK(ctx, &ctx->lock);
1360 if (flag == ISC_MEM_LOWATER)
1361 ctx->hi_called = ISC_FALSE;
1362 else if (flag == ISC_MEM_HIWATER)
1363 ctx->hi_called = ISC_TRUE;
1364 MCTXUNLOCK(ctx, &ctx->lock);
1367 #if ISC_MEM_TRACKLINES
1368 static void
1369 print_active(isc__mem_t *mctx, FILE *out) {
1370 if (mctx->debuglist != NULL) {
1371 debuglink_t *dl;
1372 unsigned int i, j;
1373 const char *format;
1374 isc_boolean_t found;
1376 fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1377 ISC_MSG_DUMPALLOC,
1378 "Dump of all outstanding "
1379 "memory allocations:\n"));
1380 found = ISC_FALSE;
1381 format = isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1382 ISC_MSG_PTRFILELINE,
1383 "\tptr %p size %u file %s line %u\n");
1384 for (i = 0; i <= mctx->max_size; i++) {
1385 dl = ISC_LIST_HEAD(mctx->debuglist[i]);
1387 if (dl != NULL)
1388 found = ISC_TRUE;
1390 while (dl != NULL) {
1391 for (j = 0; j < DEBUGLIST_COUNT; j++)
1392 if (dl->ptr[j] != NULL)
1393 fprintf(out, format,
1394 dl->ptr[j],
1395 dl->size[j],
1396 dl->file[j],
1397 dl->line[j]);
1398 dl = ISC_LIST_NEXT(dl, link);
1401 if (!found)
1402 fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1403 ISC_MSG_NONE, "\tNone.\n"));
1406 #endif
1409 * Print the stats[] on the stream "out" with suitable formatting.
1411 ISC_MEMFUNC_SCOPE void
1412 isc__mem_stats(isc_mem_t *ctx0, FILE *out) {
1413 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1414 size_t i;
1415 const struct stats *s;
1416 const isc__mempool_t *pool;
1418 REQUIRE(VALID_CONTEXT(ctx));
1419 MCTXLOCK(ctx, &ctx->lock);
1421 for (i = 0; i <= ctx->max_size; i++) {
1422 s = &ctx->stats[i];
1424 if (s->totalgets == 0U && s->gets == 0U)
1425 continue;
1426 fprintf(out, "%s%5lu: %11lu gets, %11lu rem",
1427 (i == ctx->max_size) ? ">=" : " ",
1428 (unsigned long) i, s->totalgets, s->gets);
1429 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0 &&
1430 (s->blocks != 0U || s->freefrags != 0U))
1431 fprintf(out, " (%lu bl, %lu ff)",
1432 s->blocks, s->freefrags);
1433 fputc('\n', out);
1437 * Note that since a pool can be locked now, these stats might be
1438 * somewhat off if the pool is in active use at the time the stats
1439 * are dumped. The link fields are protected by the isc_mem_t's
1440 * lock, however, so walking this list and extracting integers from
1441 * stats fields is always safe.
1443 pool = ISC_LIST_HEAD(ctx->pools);
1444 if (pool != NULL) {
1445 fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1446 ISC_MSG_POOLSTATS,
1447 "[Pool statistics]\n"));
1448 fprintf(out, "%15s %10s %10s %10s %10s %10s %10s %10s %1s\n",
1449 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1450 ISC_MSG_POOLNAME, "name"),
1451 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1452 ISC_MSG_POOLSIZE, "size"),
1453 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1454 ISC_MSG_POOLMAXALLOC, "maxalloc"),
1455 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1456 ISC_MSG_POOLALLOCATED, "allocated"),
1457 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1458 ISC_MSG_POOLFREECOUNT, "freecount"),
1459 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1460 ISC_MSG_POOLFREEMAX, "freemax"),
1461 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1462 ISC_MSG_POOLFILLCOUNT, "fillcount"),
1463 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1464 ISC_MSG_POOLGETS, "gets"),
1465 "L");
1467 while (pool != NULL) {
1468 fprintf(out, "%15s %10lu %10u %10u %10u %10u %10u %10u %s\n",
1469 pool->name, (unsigned long) pool->size, pool->maxalloc,
1470 pool->allocated, pool->freecount, pool->freemax,
1471 pool->fillcount, pool->gets,
1472 (pool->lock == NULL ? "N" : "Y"));
1473 pool = ISC_LIST_NEXT(pool, link);
1476 #if ISC_MEM_TRACKLINES
1477 print_active(ctx, out);
1478 #endif
1480 MCTXUNLOCK(ctx, &ctx->lock);
1484 * Replacements for malloc() and free() -- they implicitly remember the
1485 * size of the object allocated (with some additional overhead).
1488 static void *
1489 isc__mem_allocateunlocked(isc_mem_t *ctx0, size_t size) {
1490 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1491 size_info *si;
1493 size += ALIGNMENT_SIZE;
1494 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
1495 size += ALIGNMENT_SIZE;
1497 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0)
1498 si = mem_getunlocked(ctx, size);
1499 else
1500 si = mem_get(ctx, size);
1502 if (si == NULL)
1503 return (NULL);
1504 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
1505 si->u.ctx = ctx;
1506 si++;
1508 si->u.size = size;
1509 return (&si[1]);
1512 ISC_MEMFUNC_SCOPE void *
1513 isc___mem_allocate(isc_mem_t *ctx0, size_t size FLARG) {
1514 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1515 size_info *si;
1516 isc_boolean_t call_water = ISC_FALSE;
1518 REQUIRE(VALID_CONTEXT(ctx));
1520 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1521 MCTXLOCK(ctx, &ctx->lock);
1522 si = isc__mem_allocateunlocked((isc_mem_t *)ctx, size);
1523 } else {
1524 si = isc__mem_allocateunlocked((isc_mem_t *)ctx, size);
1525 MCTXLOCK(ctx, &ctx->lock);
1526 if (si != NULL)
1527 mem_getstats(ctx, si[-1].u.size);
1530 #if ISC_MEM_TRACKLINES
1531 ADD_TRACE(ctx, si, si[-1].u.size, file, line);
1532 #endif
1533 if (ctx->hi_water != 0U && !ctx->hi_called &&
1534 ctx->inuse > ctx->hi_water) {
1535 ctx->hi_called = ISC_TRUE;
1536 call_water = ISC_TRUE;
1538 if (ctx->inuse > ctx->maxinuse) {
1539 ctx->maxinuse = ctx->inuse;
1540 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1541 (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
1542 fprintf(stderr, "maxinuse = %lu\n",
1543 (unsigned long)ctx->inuse);
1545 MCTXUNLOCK(ctx, &ctx->lock);
1547 if (call_water)
1548 (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
1550 return (si);
1553 ISC_MEMFUNC_SCOPE void *
1554 isc___mem_reallocate(isc_mem_t *ctx0, void *ptr, size_t size FLARG) {
1555 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1556 void *new_ptr = NULL;
1557 size_t oldsize, copysize;
1559 REQUIRE(VALID_CONTEXT(ctx));
1562 * This function emulates the realloc(3) standard library function:
1563 * - if size > 0, allocate new memory; and if ptr is non NULL, copy
1564 * as much of the old contents to the new buffer and free the old one.
1565 * Note that when allocation fails the original pointer is intact;
1566 * the caller must free it.
1567 * - if size is 0 and ptr is non NULL, simply free the given ptr.
1568 * - this function returns:
1569 * pointer to the newly allocated memory, or
1570 * NULL if allocation fails or doesn't happen.
1572 if (size > 0U) {
1573 new_ptr = isc__mem_allocate(ctx0, size FLARG_PASS);
1574 if (new_ptr != NULL && ptr != NULL) {
1575 oldsize = (((size_info *)ptr)[-1]).u.size;
1576 INSIST(oldsize >= ALIGNMENT_SIZE);
1577 oldsize -= ALIGNMENT_SIZE;
1578 copysize = oldsize > size ? size : oldsize;
1579 memcpy(new_ptr, ptr, copysize);
1580 isc__mem_free(ctx0, ptr FLARG_PASS);
1582 } else if (ptr != NULL)
1583 isc__mem_free(ctx0, ptr FLARG_PASS);
1585 return (new_ptr);
1588 ISC_MEMFUNC_SCOPE void
1589 isc___mem_free(isc_mem_t *ctx0, void *ptr FLARG) {
1590 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1591 size_info *si;
1592 size_t size;
1593 isc_boolean_t call_water= ISC_FALSE;
1595 REQUIRE(VALID_CONTEXT(ctx));
1596 REQUIRE(ptr != NULL);
1598 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
1599 si = &(((size_info *)ptr)[-2]);
1600 REQUIRE(si->u.ctx == ctx);
1601 size = si[1].u.size;
1602 } else {
1603 si = &(((size_info *)ptr)[-1]);
1604 size = si->u.size;
1607 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1608 MCTXLOCK(ctx, &ctx->lock);
1609 mem_putunlocked(ctx, si, size);
1610 } else {
1611 mem_put(ctx, si, size);
1612 MCTXLOCK(ctx, &ctx->lock);
1613 mem_putstats(ctx, si, size);
1616 DELETE_TRACE(ctx, ptr, size, file, line);
1619 * The check against ctx->lo_water == 0 is for the condition
1620 * when the context was pushed over hi_water but then had
1621 * isc_mem_setwater() called with 0 for hi_water and lo_water.
1623 if (ctx->hi_called &&
1624 (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1625 ctx->hi_called = ISC_FALSE;
1627 if (ctx->water != NULL)
1628 call_water = ISC_TRUE;
1630 MCTXUNLOCK(ctx, &ctx->lock);
1632 if (call_water)
1633 (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
1638 * Other useful things.
1641 ISC_MEMFUNC_SCOPE char *
1642 isc___mem_strdup(isc_mem_t *mctx0, const char *s FLARG) {
1643 isc__mem_t *mctx = (isc__mem_t *)mctx0;
1644 size_t len;
1645 char *ns;
1647 REQUIRE(VALID_CONTEXT(mctx));
1648 REQUIRE(s != NULL);
1650 len = strlen(s);
1652 ns = isc___mem_allocate((isc_mem_t *)mctx, len + 1 FLARG_PASS);
1654 if (ns != NULL)
1655 strncpy(ns, s, len + 1);
1657 return (ns);
1660 ISC_MEMFUNC_SCOPE void
1661 isc__mem_setdestroycheck(isc_mem_t *ctx0, isc_boolean_t flag) {
1662 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1664 REQUIRE(VALID_CONTEXT(ctx));
1665 MCTXLOCK(ctx, &ctx->lock);
1667 ctx->checkfree = flag;
1669 MCTXUNLOCK(ctx, &ctx->lock);
1673 * Quotas
1676 ISC_MEMFUNC_SCOPE void
1677 isc__mem_setquota(isc_mem_t *ctx0, size_t quota) {
1678 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1680 REQUIRE(VALID_CONTEXT(ctx));
1681 MCTXLOCK(ctx, &ctx->lock);
1683 ctx->quota = quota;
1685 MCTXUNLOCK(ctx, &ctx->lock);
1688 ISC_MEMFUNC_SCOPE size_t
1689 isc__mem_getquota(isc_mem_t *ctx0) {
1690 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1691 size_t quota;
1693 REQUIRE(VALID_CONTEXT(ctx));
1694 MCTXLOCK(ctx, &ctx->lock);
1696 quota = ctx->quota;
1698 MCTXUNLOCK(ctx, &ctx->lock);
1700 return (quota);
1703 ISC_MEMFUNC_SCOPE size_t
1704 isc__mem_inuse(isc_mem_t *ctx0) {
1705 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1706 size_t inuse;
1708 REQUIRE(VALID_CONTEXT(ctx));
1709 MCTXLOCK(ctx, &ctx->lock);
1711 inuse = ctx->inuse;
1713 MCTXUNLOCK(ctx, &ctx->lock);
1715 return (inuse);
1718 ISC_MEMFUNC_SCOPE void
1719 isc__mem_setwater(isc_mem_t *ctx0, isc_mem_water_t water, void *water_arg,
1720 size_t hiwater, size_t lowater)
1722 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1723 isc_boolean_t callwater = ISC_FALSE;
1724 isc_mem_water_t oldwater;
1725 void *oldwater_arg;
1727 REQUIRE(VALID_CONTEXT(ctx));
1728 REQUIRE(hiwater >= lowater);
1730 MCTXLOCK(ctx, &ctx->lock);
1731 oldwater = ctx->water;
1732 oldwater_arg = ctx->water_arg;
1733 if (water == NULL) {
1734 callwater = ctx->hi_called;
1735 ctx->water = NULL;
1736 ctx->water_arg = NULL;
1737 ctx->hi_water = 0;
1738 ctx->lo_water = 0;
1739 ctx->hi_called = ISC_FALSE;
1740 } else {
1741 if (ctx->hi_called &&
1742 (ctx->water != water || ctx->water_arg != water_arg ||
1743 ctx->inuse < lowater || lowater == 0U))
1744 callwater = ISC_TRUE;
1745 ctx->water = water;
1746 ctx->water_arg = water_arg;
1747 ctx->hi_water = hiwater;
1748 ctx->lo_water = lowater;
1749 ctx->hi_called = ISC_FALSE;
1751 MCTXUNLOCK(ctx, &ctx->lock);
1753 if (callwater && oldwater != NULL)
1754 (oldwater)(oldwater_arg, ISC_MEM_LOWATER);
1757 ISC_MEMFUNC_SCOPE void
1758 isc__mem_setname(isc_mem_t *ctx0, const char *name, void *tag) {
1759 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1761 REQUIRE(VALID_CONTEXT(ctx));
1763 LOCK(&ctx->lock);
1764 memset(ctx->name, 0, sizeof(ctx->name));
1765 strncpy(ctx->name, name, sizeof(ctx->name) - 1);
1766 ctx->tag = tag;
1767 UNLOCK(&ctx->lock);
1770 ISC_MEMFUNC_SCOPE const char *
1771 isc__mem_getname(isc_mem_t *ctx0) {
1772 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1774 REQUIRE(VALID_CONTEXT(ctx));
1776 return (ctx->name);
1779 ISC_MEMFUNC_SCOPE void *
1780 isc__mem_gettag(isc_mem_t *ctx0) {
1781 isc__mem_t *ctx = (isc__mem_t *)ctx0;
1783 REQUIRE(VALID_CONTEXT(ctx));
1785 return (ctx->tag);
1789 * Memory pool stuff
1792 ISC_MEMFUNC_SCOPE isc_result_t
1793 isc__mempool_create(isc_mem_t *mctx0, size_t size, isc_mempool_t **mpctxp) {
1794 isc__mem_t *mctx = (isc__mem_t *)mctx0;
1795 isc__mempool_t *mpctx;
1797 REQUIRE(VALID_CONTEXT(mctx));
1798 REQUIRE(size > 0U);
1799 REQUIRE(mpctxp != NULL && *mpctxp == NULL);
1802 * Allocate space for this pool, initialize values, and if all works
1803 * well, attach to the memory context.
1805 mpctx = isc_mem_get((isc_mem_t *)mctx, sizeof(isc__mempool_t));
1806 if (mpctx == NULL)
1807 return (ISC_R_NOMEMORY);
1809 mpctx->common.methods = (isc_mempoolmethods_t *)&mempoolmethods;
1810 mpctx->common.impmagic = MEMPOOL_MAGIC;
1811 mpctx->common.magic = ISCAPI_MPOOL_MAGIC;
1812 mpctx->lock = NULL;
1813 mpctx->mctx = mctx;
1814 mpctx->size = size;
1815 mpctx->maxalloc = UINT_MAX;
1816 mpctx->allocated = 0;
1817 mpctx->freecount = 0;
1818 mpctx->freemax = 1;
1819 mpctx->fillcount = 1;
1820 mpctx->gets = 0;
1821 #if ISC_MEMPOOL_NAMES
1822 mpctx->name[0] = 0;
1823 #endif
1824 mpctx->items = NULL;
1826 *mpctxp = (isc_mempool_t *)mpctx;
1828 MCTXLOCK(mctx, &mctx->lock);
1829 ISC_LIST_INITANDAPPEND(mctx->pools, mpctx, link);
1830 mctx->poolcnt++;
1831 MCTXUNLOCK(mctx, &mctx->lock);
1833 return (ISC_R_SUCCESS);
1836 ISC_MEMFUNC_SCOPE void
1837 isc__mempool_setname(isc_mempool_t *mpctx0, const char *name) {
1838 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
1840 REQUIRE(name != NULL);
1841 REQUIRE(VALID_MEMPOOL(mpctx));
1843 #if ISC_MEMPOOL_NAMES
1844 if (mpctx->lock != NULL)
1845 LOCK(mpctx->lock);
1847 strncpy(mpctx->name, name, sizeof(mpctx->name) - 1);
1848 mpctx->name[sizeof(mpctx->name) - 1] = '\0';
1850 if (mpctx->lock != NULL)
1851 UNLOCK(mpctx->lock);
1852 #else
1853 UNUSED(mpctx);
1854 UNUSED(name);
1855 #endif
1858 ISC_MEMFUNC_SCOPE void
1859 isc__mempool_destroy(isc_mempool_t **mpctxp) {
1860 isc__mempool_t *mpctx;
1861 isc__mem_t *mctx;
1862 isc_mutex_t *lock;
1863 element *item;
1865 REQUIRE(mpctxp != NULL);
1866 mpctx = (isc__mempool_t *)*mpctxp;
1867 REQUIRE(VALID_MEMPOOL(mpctx));
1868 #if ISC_MEMPOOL_NAMES
1869 if (mpctx->allocated > 0)
1870 UNEXPECTED_ERROR(__FILE__, __LINE__,
1871 "isc__mempool_destroy(): mempool %s "
1872 "leaked memory",
1873 mpctx->name);
1874 #endif
1875 REQUIRE(mpctx->allocated == 0);
1877 mctx = mpctx->mctx;
1879 lock = mpctx->lock;
1881 if (lock != NULL)
1882 LOCK(lock);
1885 * Return any items on the free list
1887 MCTXLOCK(mctx, &mctx->lock);
1888 while (mpctx->items != NULL) {
1889 INSIST(mpctx->freecount > 0);
1890 mpctx->freecount--;
1891 item = mpctx->items;
1892 mpctx->items = item->next;
1894 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1895 mem_putunlocked(mctx, item, mpctx->size);
1896 } else {
1897 mem_put(mctx, item, mpctx->size);
1898 mem_putstats(mctx, item, mpctx->size);
1901 MCTXUNLOCK(mctx, &mctx->lock);
1904 * Remove our linked list entry from the memory context.
1906 MCTXLOCK(mctx, &mctx->lock);
1907 ISC_LIST_UNLINK(mctx->pools, mpctx, link);
1908 mctx->poolcnt--;
1909 MCTXUNLOCK(mctx, &mctx->lock);
1911 mpctx->common.impmagic = 0;
1912 mpctx->common.magic = 0;
1914 isc_mem_put((isc_mem_t *)mpctx->mctx, mpctx, sizeof(isc__mempool_t));
1916 if (lock != NULL)
1917 UNLOCK(lock);
1919 *mpctxp = NULL;
1922 ISC_MEMFUNC_SCOPE void
1923 isc__mempool_associatelock(isc_mempool_t *mpctx0, isc_mutex_t *lock) {
1924 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
1926 REQUIRE(VALID_MEMPOOL(mpctx));
1927 REQUIRE(mpctx->lock == NULL);
1928 REQUIRE(lock != NULL);
1930 mpctx->lock = lock;
1933 ISC_MEMFUNC_SCOPE void *
1934 isc___mempool_get(isc_mempool_t *mpctx0 FLARG) {
1935 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
1936 element *item;
1937 isc__mem_t *mctx;
1938 unsigned int i;
1940 REQUIRE(VALID_MEMPOOL(mpctx));
1942 mctx = mpctx->mctx;
1944 if (mpctx->lock != NULL)
1945 LOCK(mpctx->lock);
1948 * Don't let the caller go over quota
1950 if (mpctx->allocated >= mpctx->maxalloc) {
1951 item = NULL;
1952 goto out;
1956 * if we have a free list item, return the first here
1958 item = mpctx->items;
1959 if (item != NULL) {
1960 mpctx->items = item->next;
1961 INSIST(mpctx->freecount > 0);
1962 mpctx->freecount--;
1963 mpctx->gets++;
1964 mpctx->allocated++;
1965 goto out;
1969 * We need to dip into the well. Lock the memory context here and
1970 * fill up our free list.
1972 MCTXLOCK(mctx, &mctx->lock);
1973 for (i = 0; i < mpctx->fillcount; i++) {
1974 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1975 item = mem_getunlocked(mctx, mpctx->size);
1976 } else {
1977 item = mem_get(mctx, mpctx->size);
1978 if (item != NULL)
1979 mem_getstats(mctx, mpctx->size);
1981 if (item == NULL)
1982 break;
1983 item->next = mpctx->items;
1984 mpctx->items = item;
1985 mpctx->freecount++;
1987 MCTXUNLOCK(mctx, &mctx->lock);
1990 * If we didn't get any items, return NULL.
1992 item = mpctx->items;
1993 if (item == NULL)
1994 goto out;
1996 mpctx->items = item->next;
1997 mpctx->freecount--;
1998 mpctx->gets++;
1999 mpctx->allocated++;
2001 out:
2002 if (mpctx->lock != NULL)
2003 UNLOCK(mpctx->lock);
2005 #if ISC_MEM_TRACKLINES
2006 if (item != NULL) {
2007 MCTXLOCK(mctx, &mctx->lock);
2008 ADD_TRACE(mctx, item, mpctx->size, file, line);
2009 MCTXUNLOCK(mctx, &mctx->lock);
2011 #endif /* ISC_MEM_TRACKLINES */
2013 return (item);
2016 ISC_MEMFUNC_SCOPE void
2017 isc___mempool_put(isc_mempool_t *mpctx0, void *mem FLARG) {
2018 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2019 isc__mem_t *mctx;
2020 element *item;
2022 REQUIRE(VALID_MEMPOOL(mpctx));
2023 REQUIRE(mem != NULL);
2025 mctx = mpctx->mctx;
2027 if (mpctx->lock != NULL)
2028 LOCK(mpctx->lock);
2030 INSIST(mpctx->allocated > 0);
2031 mpctx->allocated--;
2033 #if ISC_MEM_TRACKLINES
2034 MCTXLOCK(mctx, &mctx->lock);
2035 DELETE_TRACE(mctx, mem, mpctx->size, file, line);
2036 MCTXUNLOCK(mctx, &mctx->lock);
2037 #endif /* ISC_MEM_TRACKLINES */
2040 * If our free list is full, return this to the mctx directly.
2042 if (mpctx->freecount >= mpctx->freemax) {
2043 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
2044 MCTXLOCK(mctx, &mctx->lock);
2045 mem_putunlocked(mctx, mem, mpctx->size);
2046 MCTXUNLOCK(mctx, &mctx->lock);
2047 } else {
2048 mem_put(mctx, mem, mpctx->size);
2049 MCTXLOCK(mctx, &mctx->lock);
2050 mem_putstats(mctx, mem, mpctx->size);
2051 MCTXUNLOCK(mctx, &mctx->lock);
2053 if (mpctx->lock != NULL)
2054 UNLOCK(mpctx->lock);
2055 return;
2059 * Otherwise, attach it to our free list and bump the counter.
2061 mpctx->freecount++;
2062 item = (element *)mem;
2063 item->next = mpctx->items;
2064 mpctx->items = item;
2066 if (mpctx->lock != NULL)
2067 UNLOCK(mpctx->lock);
2071 * Quotas
2074 ISC_MEMFUNC_SCOPE void
2075 isc__mempool_setfreemax(isc_mempool_t *mpctx0, unsigned int limit) {
2076 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2078 REQUIRE(VALID_MEMPOOL(mpctx));
2080 if (mpctx->lock != NULL)
2081 LOCK(mpctx->lock);
2083 mpctx->freemax = limit;
2085 if (mpctx->lock != NULL)
2086 UNLOCK(mpctx->lock);
2089 ISC_MEMFUNC_SCOPE unsigned int
2090 isc__mempool_getfreemax(isc_mempool_t *mpctx0) {
2091 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2092 unsigned int freemax;
2094 REQUIRE(VALID_MEMPOOL(mpctx));
2096 if (mpctx->lock != NULL)
2097 LOCK(mpctx->lock);
2099 freemax = mpctx->freemax;
2101 if (mpctx->lock != NULL)
2102 UNLOCK(mpctx->lock);
2104 return (freemax);
2107 ISC_MEMFUNC_SCOPE unsigned int
2108 isc__mempool_getfreecount(isc_mempool_t *mpctx0) {
2109 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2110 unsigned int freecount;
2112 REQUIRE(VALID_MEMPOOL(mpctx));
2114 if (mpctx->lock != NULL)
2115 LOCK(mpctx->lock);
2117 freecount = mpctx->freecount;
2119 if (mpctx->lock != NULL)
2120 UNLOCK(mpctx->lock);
2122 return (freecount);
2125 ISC_MEMFUNC_SCOPE void
2126 isc__mempool_setmaxalloc(isc_mempool_t *mpctx0, unsigned int limit) {
2127 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2129 REQUIRE(limit > 0);
2131 REQUIRE(VALID_MEMPOOL(mpctx));
2133 if (mpctx->lock != NULL)
2134 LOCK(mpctx->lock);
2136 mpctx->maxalloc = limit;
2138 if (mpctx->lock != NULL)
2139 UNLOCK(mpctx->lock);
2142 ISC_MEMFUNC_SCOPE unsigned int
2143 isc__mempool_getmaxalloc(isc_mempool_t *mpctx0) {
2144 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2145 unsigned int maxalloc;
2147 REQUIRE(VALID_MEMPOOL(mpctx));
2149 if (mpctx->lock != NULL)
2150 LOCK(mpctx->lock);
2152 maxalloc = mpctx->maxalloc;
2154 if (mpctx->lock != NULL)
2155 UNLOCK(mpctx->lock);
2157 return (maxalloc);
2160 ISC_MEMFUNC_SCOPE unsigned int
2161 isc__mempool_getallocated(isc_mempool_t *mpctx0) {
2162 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2163 unsigned int allocated;
2165 REQUIRE(VALID_MEMPOOL(mpctx));
2167 if (mpctx->lock != NULL)
2168 LOCK(mpctx->lock);
2170 allocated = mpctx->allocated;
2172 if (mpctx->lock != NULL)
2173 UNLOCK(mpctx->lock);
2175 return (allocated);
2178 ISC_MEMFUNC_SCOPE void
2179 isc__mempool_setfillcount(isc_mempool_t *mpctx0, unsigned int limit) {
2180 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2182 REQUIRE(limit > 0);
2183 REQUIRE(VALID_MEMPOOL(mpctx));
2185 if (mpctx->lock != NULL)
2186 LOCK(mpctx->lock);
2188 mpctx->fillcount = limit;
2190 if (mpctx->lock != NULL)
2191 UNLOCK(mpctx->lock);
2194 ISC_MEMFUNC_SCOPE unsigned int
2195 isc__mempool_getfillcount(isc_mempool_t *mpctx0) {
2196 isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2198 unsigned int fillcount;
2200 REQUIRE(VALID_MEMPOOL(mpctx));
2202 if (mpctx->lock != NULL)
2203 LOCK(mpctx->lock);
2205 fillcount = mpctx->fillcount;
2207 if (mpctx->lock != NULL)
2208 UNLOCK(mpctx->lock);
2210 return (fillcount);
2213 #ifdef USE_MEMIMPREGISTER
2214 isc_result_t
2215 isc__mem_register() {
2216 return (isc_mem_register(isc__mem_create2));
2218 #endif
2220 #ifdef BIND9
2221 ISC_MEMFUNC_SCOPE void
2222 isc__mem_printactive(isc_mem_t *ctx0, FILE *file) {
2223 isc__mem_t *ctx = (isc__mem_t *)ctx0;
2225 REQUIRE(VALID_CONTEXT(ctx));
2226 REQUIRE(file != NULL);
2228 #if !ISC_MEM_TRACKLINES
2229 UNUSED(ctx);
2230 UNUSED(file);
2231 #else
2232 print_active(ctx, file);
2233 #endif
2236 ISC_MEMFUNC_SCOPE void
2237 isc__mem_printallactive(FILE *file) {
2238 #if !ISC_MEM_TRACKLINES
2239 UNUSED(file);
2240 #else
2241 isc__mem_t *ctx;
2243 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2245 LOCK(&lock);
2246 for (ctx = ISC_LIST_HEAD(contexts);
2247 ctx != NULL;
2248 ctx = ISC_LIST_NEXT(ctx, link)) {
2249 fprintf(file, "context: %p\n", ctx);
2250 print_active(ctx, file);
2252 UNLOCK(&lock);
2253 #endif
2256 ISC_MEMFUNC_SCOPE void
2257 isc__mem_checkdestroyed(FILE *file) {
2259 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2261 LOCK(&lock);
2262 if (!ISC_LIST_EMPTY(contexts)) {
2263 #if ISC_MEM_TRACKLINES
2264 isc__mem_t *ctx;
2266 for (ctx = ISC_LIST_HEAD(contexts);
2267 ctx != NULL;
2268 ctx = ISC_LIST_NEXT(ctx, link)) {
2269 fprintf(file, "context: %p\n", ctx);
2270 print_active(ctx, file);
2272 fflush(file);
2273 #endif
2274 INSIST(0);
2276 UNLOCK(&lock);
2279 ISC_MEMFUNC_SCOPE unsigned int
2280 isc_mem_references(isc_mem_t *ctx0) {
2281 isc__mem_t *ctx = (isc__mem_t *)ctx0;
2282 unsigned int references;
2284 REQUIRE(VALID_CONTEXT(ctx));
2286 MCTXLOCK(ctx, &ctx->lock);
2287 references = ctx->references;
2288 MCTXUNLOCK(ctx, &ctx->lock);
2290 return (references);
2293 #ifdef HAVE_LIBXML2
2295 typedef struct summarystat {
2296 isc_uint64_t total;
2297 isc_uint64_t inuse;
2298 isc_uint64_t blocksize;
2299 isc_uint64_t contextsize;
2300 } summarystat_t;
2302 static void
2303 renderctx(isc__mem_t *ctx, summarystat_t *summary, xmlTextWriterPtr writer) {
2304 REQUIRE(VALID_CONTEXT(ctx));
2306 xmlTextWriterStartElement(writer, ISC_XMLCHAR "context");
2308 xmlTextWriterStartElement(writer, ISC_XMLCHAR "id");
2309 xmlTextWriterWriteFormatString(writer, "%p", ctx);
2310 xmlTextWriterEndElement(writer); /* id */
2312 if (ctx->name[0] != 0) {
2313 xmlTextWriterStartElement(writer, ISC_XMLCHAR "name");
2314 xmlTextWriterWriteFormatString(writer, "%s", ctx->name);
2315 xmlTextWriterEndElement(writer); /* name */
2318 REQUIRE(VALID_CONTEXT(ctx));
2319 MCTXLOCK(ctx, &ctx->lock);
2321 summary->contextsize += sizeof(*ctx) +
2322 (ctx->max_size + 1) * sizeof(struct stats) +
2323 ctx->max_size * sizeof(element *) +
2324 ctx->basic_table_count * sizeof(char *);
2325 #if ISC_MEM_TRACKLINES
2326 if (ctx->debuglist != NULL) {
2327 summary->contextsize +=
2328 (ctx->max_size + 1) * sizeof(debuglist_t) +
2329 ctx->debuglistcnt * sizeof(debuglink_t);
2331 #endif
2332 xmlTextWriterStartElement(writer, ISC_XMLCHAR "references");
2333 xmlTextWriterWriteFormatString(writer, "%d", ctx->references);
2334 xmlTextWriterEndElement(writer); /* references */
2336 summary->total += ctx->total;
2337 xmlTextWriterStartElement(writer, ISC_XMLCHAR "total");
2338 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2339 (isc_uint64_t)ctx->total);
2340 xmlTextWriterEndElement(writer); /* total */
2342 summary->inuse += ctx->inuse;
2343 xmlTextWriterStartElement(writer, ISC_XMLCHAR "inuse");
2344 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2345 (isc_uint64_t)ctx->inuse);
2346 xmlTextWriterEndElement(writer); /* inuse */
2348 xmlTextWriterStartElement(writer, ISC_XMLCHAR "maxinuse");
2349 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2350 (isc_uint64_t)ctx->maxinuse);
2351 xmlTextWriterEndElement(writer); /* maxinuse */
2353 xmlTextWriterStartElement(writer, ISC_XMLCHAR "blocksize");
2354 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
2355 summary->blocksize += ctx->basic_table_count *
2356 NUM_BASIC_BLOCKS * ctx->mem_target;
2357 xmlTextWriterWriteFormatString(writer,
2358 "%" ISC_PRINT_QUADFORMAT "u",
2359 (isc_uint64_t)
2360 ctx->basic_table_count *
2361 NUM_BASIC_BLOCKS *
2362 ctx->mem_target);
2363 } else
2364 xmlTextWriterWriteFormatString(writer, "%s", "-");
2365 xmlTextWriterEndElement(writer); /* blocksize */
2367 xmlTextWriterStartElement(writer, ISC_XMLCHAR "pools");
2368 xmlTextWriterWriteFormatString(writer, "%u", ctx->poolcnt);
2369 xmlTextWriterEndElement(writer); /* pools */
2370 summary->contextsize += ctx->poolcnt * sizeof(isc_mempool_t);
2372 xmlTextWriterStartElement(writer, ISC_XMLCHAR "hiwater");
2373 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2374 (isc_uint64_t)ctx->hi_water);
2375 xmlTextWriterEndElement(writer); /* hiwater */
2377 xmlTextWriterStartElement(writer, ISC_XMLCHAR "lowater");
2378 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2379 (isc_uint64_t)ctx->lo_water);
2380 xmlTextWriterEndElement(writer); /* lowater */
2382 MCTXUNLOCK(ctx, &ctx->lock);
2384 xmlTextWriterEndElement(writer); /* context */
2387 void
2388 isc_mem_renderxml(xmlTextWriterPtr writer) {
2389 isc__mem_t *ctx;
2390 summarystat_t summary;
2391 isc_uint64_t lost;
2393 memset(&summary, 0, sizeof(summary));
2395 xmlTextWriterStartElement(writer, ISC_XMLCHAR "contexts");
2397 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2399 LOCK(&lock);
2400 lost = totallost;
2401 for (ctx = ISC_LIST_HEAD(contexts);
2402 ctx != NULL;
2403 ctx = ISC_LIST_NEXT(ctx, link)) {
2404 renderctx(ctx, &summary, writer);
2406 UNLOCK(&lock);
2408 xmlTextWriterEndElement(writer); /* contexts */
2410 xmlTextWriterStartElement(writer, ISC_XMLCHAR "summary");
2412 xmlTextWriterStartElement(writer, ISC_XMLCHAR "TotalUse");
2413 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2414 summary.total);
2415 xmlTextWriterEndElement(writer); /* TotalUse */
2417 xmlTextWriterStartElement(writer, ISC_XMLCHAR "InUse");
2418 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2419 summary.inuse);
2420 xmlTextWriterEndElement(writer); /* InUse */
2422 xmlTextWriterStartElement(writer, ISC_XMLCHAR "BlockSize");
2423 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2424 summary.blocksize);
2425 xmlTextWriterEndElement(writer); /* BlockSize */
2427 xmlTextWriterStartElement(writer, ISC_XMLCHAR "ContextSize");
2428 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2429 summary.contextsize);
2430 xmlTextWriterEndElement(writer); /* ContextSize */
2432 xmlTextWriterStartElement(writer, ISC_XMLCHAR "Lost");
2433 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2434 lost);
2435 xmlTextWriterEndElement(writer); /* Lost */
2437 xmlTextWriterEndElement(writer); /* summary */
2440 #endif /* HAVE_LIBXML2 */
2441 #endif /* BIND9 */