Sync usage with man page.
[netbsd-mini2440.git] / external / bsd / ntp / dist / lib / isc / mem.c
blob517bf7c93ccb655192283cc74bd0a1f4eddd2fec
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.145.120.4 2009/02/16 03:17:05 marka 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 #if ISC_MEM_TRACKLINES
66 typedef struct debuglink debuglink_t;
67 struct debuglink {
68 ISC_LINK(debuglink_t) link;
69 const void *ptr[DEBUGLIST_COUNT];
70 unsigned int size[DEBUGLIST_COUNT];
71 const char *file[DEBUGLIST_COUNT];
72 unsigned int line[DEBUGLIST_COUNT];
73 unsigned int count;
76 #define FLARG_PASS , file, line
77 #define FLARG , const char *file, int line
78 #else
79 #define FLARG_PASS
80 #define FLARG
81 #endif
83 typedef struct element element;
84 struct element {
85 element * next;
88 typedef struct {
89 /*!
90 * This structure must be ALIGNMENT_SIZE bytes.
92 union {
93 size_t size;
94 isc_mem_t *ctx;
95 char bytes[ALIGNMENT_SIZE];
96 } u;
97 } size_info;
99 struct stats {
100 unsigned long gets;
101 unsigned long totalgets;
102 unsigned long blocks;
103 unsigned long freefrags;
106 #define MEM_MAGIC ISC_MAGIC('M', 'e', 'm', 'C')
107 #define VALID_CONTEXT(c) ISC_MAGIC_VALID(c, MEM_MAGIC)
109 #if ISC_MEM_TRACKLINES
110 typedef ISC_LIST(debuglink_t) debuglist_t;
111 #endif
113 /* List of all active memory contexts. */
115 static ISC_LIST(isc_mem_t) contexts;
116 static isc_once_t once = ISC_ONCE_INIT;
117 static isc_mutex_t lock;
120 * Total size of lost memory due to a bug of external library.
121 * Locked by the global lock.
123 static isc_uint64_t totallost;
125 struct isc_mem {
126 unsigned int magic;
127 isc_ondestroy_t ondestroy;
128 unsigned int flags;
129 isc_mutex_t lock;
130 isc_memalloc_t memalloc;
131 isc_memfree_t memfree;
132 void * arg;
133 size_t max_size;
134 isc_boolean_t checkfree;
135 struct stats * stats;
136 unsigned int references;
137 char name[16];
138 void * tag;
139 size_t quota;
140 size_t total;
141 size_t inuse;
142 size_t maxinuse;
143 size_t hi_water;
144 size_t lo_water;
145 isc_boolean_t hi_called;
146 isc_mem_water_t water;
147 void * water_arg;
148 ISC_LIST(isc_mempool_t) pools;
149 unsigned int poolcnt;
151 /* ISC_MEMFLAG_INTERNAL */
152 size_t mem_target;
153 element ** freelists;
154 element * basic_blocks;
155 unsigned char ** basic_table;
156 unsigned int basic_table_count;
157 unsigned int basic_table_size;
158 unsigned char * lowest;
159 unsigned char * highest;
161 #if ISC_MEM_TRACKLINES
162 debuglist_t * debuglist;
163 unsigned int debuglistcnt;
164 #endif
166 unsigned int memalloc_failures;
167 ISC_LINK(isc_mem_t) link;
170 #define MEMPOOL_MAGIC ISC_MAGIC('M', 'E', 'M', 'p')
171 #define VALID_MEMPOOL(c) ISC_MAGIC_VALID(c, MEMPOOL_MAGIC)
173 struct isc_mempool {
174 /* always unlocked */
175 unsigned int magic; /*%< magic number */
176 isc_mutex_t *lock; /*%< optional lock */
177 isc_mem_t *mctx; /*%< our memory context */
178 /*%< locked via the memory context's lock */
179 ISC_LINK(isc_mempool_t) link; /*%< next pool in this mem context */
180 /*%< optionally locked from here down */
181 element *items; /*%< low water item list */
182 size_t size; /*%< size of each item on this pool */
183 unsigned int maxalloc; /*%< max number of items allowed */
184 unsigned int allocated; /*%< # of items currently given out */
185 unsigned int freecount; /*%< # of items on reserved list */
186 unsigned int freemax; /*%< # of items allowed on free list */
187 unsigned int fillcount; /*%< # of items to fetch on each fill */
188 /*%< Stats only. */
189 unsigned int gets; /*%< # of requests to this pool */
190 /*%< Debugging only. */
191 #if ISC_MEMPOOL_NAMES
192 char name[16]; /*%< printed name in stats reports */
193 #endif
197 * Private Inline-able.
200 #if ! ISC_MEM_TRACKLINES
201 #define ADD_TRACE(a, b, c, d, e)
202 #define DELETE_TRACE(a, b, c, d, e)
203 #else
204 #define ADD_TRACE(a, b, c, d, e) \
205 do { \
206 if ((isc_mem_debugging & (ISC_MEM_DEBUGTRACE | \
207 ISC_MEM_DEBUGRECORD)) != 0 && \
208 b != NULL) \
209 add_trace_entry(a, b, c, d, e); \
210 } while (0)
211 #define DELETE_TRACE(a, b, c, d, e) delete_trace_entry(a, b, c, d, e)
213 static void
214 print_active(isc_mem_t *ctx, FILE *out);
217 * mctx must be locked.
219 static inline void
220 add_trace_entry(isc_mem_t *mctx, const void *ptr, unsigned int size
221 FLARG)
223 debuglink_t *dl;
224 unsigned int i;
226 if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
227 fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
228 ISC_MSG_ADDTRACE,
229 "add %p size %u "
230 "file %s line %u mctx %p\n"),
231 ptr, size, file, line, mctx);
233 if (mctx->debuglist == NULL)
234 return;
236 if (size > mctx->max_size)
237 size = mctx->max_size;
239 dl = ISC_LIST_HEAD(mctx->debuglist[size]);
240 while (dl != NULL) {
241 if (dl->count == DEBUGLIST_COUNT)
242 goto next;
243 for (i = 0; i < DEBUGLIST_COUNT; i++) {
244 if (dl->ptr[i] == NULL) {
245 dl->ptr[i] = ptr;
246 dl->size[i] = size;
247 dl->file[i] = file;
248 dl->line[i] = line;
249 dl->count++;
250 return;
253 next:
254 dl = ISC_LIST_NEXT(dl, link);
257 dl = malloc(sizeof(debuglink_t));
258 INSIST(dl != NULL);
260 ISC_LINK_INIT(dl, link);
261 for (i = 1; i < DEBUGLIST_COUNT; i++) {
262 dl->ptr[i] = NULL;
263 dl->size[i] = 0;
264 dl->file[i] = NULL;
265 dl->line[i] = 0;
268 dl->ptr[0] = ptr;
269 dl->size[0] = size;
270 dl->file[0] = file;
271 dl->line[0] = line;
272 dl->count = 1;
274 ISC_LIST_PREPEND(mctx->debuglist[size], dl, link);
275 mctx->debuglistcnt++;
278 static inline void
279 delete_trace_entry(isc_mem_t *mctx, const void *ptr, unsigned int size,
280 const char *file, unsigned int line)
282 debuglink_t *dl;
283 unsigned int i;
285 if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
286 fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
287 ISC_MSG_DELTRACE,
288 "del %p size %u "
289 "file %s line %u mctx %p\n"),
290 ptr, size, file, line, mctx);
292 if (mctx->debuglist == NULL)
293 return;
295 if (size > mctx->max_size)
296 size = mctx->max_size;
298 dl = ISC_LIST_HEAD(mctx->debuglist[size]);
299 while (dl != NULL) {
300 for (i = 0; i < DEBUGLIST_COUNT; i++) {
301 if (dl->ptr[i] == ptr) {
302 dl->ptr[i] = NULL;
303 dl->size[i] = 0;
304 dl->file[i] = NULL;
305 dl->line[i] = 0;
307 INSIST(dl->count > 0);
308 dl->count--;
309 if (dl->count == 0) {
310 ISC_LIST_UNLINK(mctx->debuglist[size],
311 dl, link);
312 free(dl);
314 return;
317 dl = ISC_LIST_NEXT(dl, link);
321 * If we get here, we didn't find the item on the list. We're
322 * screwed.
324 INSIST(dl != NULL);
326 #endif /* ISC_MEM_TRACKLINES */
328 static inline size_t
329 rmsize(size_t size) {
331 * round down to ALIGNMENT_SIZE
333 return (size & (~(ALIGNMENT_SIZE - 1)));
336 static inline size_t
337 quantize(size_t size) {
339 * Round up the result in order to get a size big
340 * enough to satisfy the request and be aligned on ALIGNMENT_SIZE
341 * byte boundaries.
344 if (size == 0U)
345 return (ALIGNMENT_SIZE);
346 return ((size + ALIGNMENT_SIZE - 1) & (~(ALIGNMENT_SIZE - 1)));
349 static inline isc_boolean_t
350 more_basic_blocks(isc_mem_t *ctx) {
351 void *new;
352 unsigned char *curr, *next;
353 unsigned char *first, *last;
354 unsigned char **table;
355 unsigned int table_size;
356 size_t increment;
357 int i;
359 /* Require: we hold the context lock. */
362 * Did we hit the quota for this context?
364 increment = NUM_BASIC_BLOCKS * ctx->mem_target;
365 if (ctx->quota != 0U && ctx->total + increment > ctx->quota)
366 return (ISC_FALSE);
368 INSIST(ctx->basic_table_count <= ctx->basic_table_size);
369 if (ctx->basic_table_count == ctx->basic_table_size) {
370 table_size = ctx->basic_table_size + TABLE_INCREMENT;
371 table = (ctx->memalloc)(ctx->arg,
372 table_size * sizeof(unsigned char *));
373 if (table == NULL) {
374 ctx->memalloc_failures++;
375 return (ISC_FALSE);
377 if (ctx->basic_table_size != 0) {
378 memcpy(table, ctx->basic_table,
379 ctx->basic_table_size *
380 sizeof(unsigned char *));
381 (ctx->memfree)(ctx->arg, ctx->basic_table);
383 ctx->basic_table = table;
384 ctx->basic_table_size = table_size;
387 new = (ctx->memalloc)(ctx->arg, NUM_BASIC_BLOCKS * ctx->mem_target);
388 if (new == NULL) {
389 ctx->memalloc_failures++;
390 return (ISC_FALSE);
392 ctx->total += increment;
393 ctx->basic_table[ctx->basic_table_count] = new;
394 ctx->basic_table_count++;
396 curr = new;
397 next = curr + ctx->mem_target;
398 for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) {
399 ((element *)curr)->next = (element *)next;
400 curr = next;
401 next += ctx->mem_target;
404 * curr is now pointing at the last block in the
405 * array.
407 ((element *)curr)->next = NULL;
408 first = new;
409 last = first + NUM_BASIC_BLOCKS * ctx->mem_target - 1;
410 if (first < ctx->lowest || ctx->lowest == NULL)
411 ctx->lowest = first;
412 if (last > ctx->highest)
413 ctx->highest = last;
414 ctx->basic_blocks = new;
416 return (ISC_TRUE);
419 static inline isc_boolean_t
420 more_frags(isc_mem_t *ctx, size_t new_size) {
421 int i, frags;
422 size_t total_size;
423 void *new;
424 unsigned char *curr, *next;
427 * Try to get more fragments by chopping up a basic block.
430 if (ctx->basic_blocks == NULL) {
431 if (!more_basic_blocks(ctx)) {
433 * We can't get more memory from the OS, or we've
434 * hit the quota for this context.
437 * XXXRTH "At quota" notification here.
439 return (ISC_FALSE);
443 total_size = ctx->mem_target;
444 new = ctx->basic_blocks;
445 ctx->basic_blocks = ctx->basic_blocks->next;
446 frags = total_size / new_size;
447 ctx->stats[new_size].blocks++;
448 ctx->stats[new_size].freefrags += frags;
450 * Set up a linked-list of blocks of size
451 * "new_size".
453 curr = new;
454 next = curr + new_size;
455 total_size -= new_size;
456 for (i = 0; i < (frags - 1); i++) {
457 ((element *)curr)->next = (element *)next;
458 curr = next;
459 next += new_size;
460 total_size -= new_size;
463 * Add the remaining fragment of the basic block to a free list.
465 total_size = rmsize(total_size);
466 if (total_size > 0U) {
467 ((element *)next)->next = ctx->freelists[total_size];
468 ctx->freelists[total_size] = (element *)next;
469 ctx->stats[total_size].freefrags++;
472 * curr is now pointing at the last block in the
473 * array.
475 ((element *)curr)->next = NULL;
476 ctx->freelists[new_size] = new;
478 return (ISC_TRUE);
481 static inline void *
482 mem_getunlocked(isc_mem_t *ctx, size_t size) {
483 size_t new_size = quantize(size);
484 void *ret;
486 if (size >= ctx->max_size || new_size >= ctx->max_size) {
488 * memget() was called on something beyond our upper limit.
490 if (ctx->quota != 0U && ctx->total + size > ctx->quota) {
491 ret = NULL;
492 goto done;
494 ret = (ctx->memalloc)(ctx->arg, size);
495 if (ret == NULL) {
496 ctx->memalloc_failures++;
497 goto done;
499 ctx->total += size;
500 ctx->inuse += size;
501 ctx->stats[ctx->max_size].gets++;
502 ctx->stats[ctx->max_size].totalgets++;
504 * If we don't set new_size to size, then the
505 * ISC_MEM_FILL code might write over bytes we
506 * don't own.
508 new_size = size;
509 goto done;
513 * If there are no blocks in the free list for this size, get a chunk
514 * of memory and then break it up into "new_size"-sized blocks, adding
515 * them to the free list.
517 if (ctx->freelists[new_size] == NULL && !more_frags(ctx, new_size))
518 return (NULL);
521 * The free list uses the "rounded-up" size "new_size".
523 ret = ctx->freelists[new_size];
524 ctx->freelists[new_size] = ctx->freelists[new_size]->next;
527 * The stats[] uses the _actual_ "size" requested by the
528 * caller, with the caveat (in the code above) that "size" >= the
529 * max. size (max_size) ends up getting recorded as a call to
530 * max_size.
532 ctx->stats[size].gets++;
533 ctx->stats[size].totalgets++;
534 ctx->stats[new_size].freefrags--;
535 ctx->inuse += new_size;
537 done:
539 #if ISC_MEM_FILL
540 if (ret != NULL)
541 memset(ret, 0xbe, new_size); /* Mnemonic for "beef". */
542 #endif
544 return (ret);
547 #if ISC_MEM_FILL && ISC_MEM_CHECKOVERRUN
548 static inline void
549 check_overrun(void *mem, size_t size, size_t new_size) {
550 unsigned char *cp;
552 cp = (unsigned char *)mem;
553 cp += size;
554 while (size < new_size) {
555 INSIST(*cp == 0xbe);
556 cp++;
557 size++;
560 #endif
562 static inline void
563 mem_putunlocked(isc_mem_t *ctx, void *mem, size_t size) {
564 size_t new_size = quantize(size);
566 if (size == ctx->max_size || new_size >= ctx->max_size) {
568 * memput() called on something beyond our upper limit.
570 #if ISC_MEM_FILL
571 memset(mem, 0xde, size); /* Mnemonic for "dead". */
572 #endif
573 (ctx->memfree)(ctx->arg, mem);
574 INSIST(ctx->stats[ctx->max_size].gets != 0U);
575 ctx->stats[ctx->max_size].gets--;
576 INSIST(size <= ctx->total);
577 ctx->inuse -= size;
578 ctx->total -= size;
579 return;
582 #if ISC_MEM_FILL
583 #if ISC_MEM_CHECKOVERRUN
584 check_overrun(mem, size, new_size);
585 #endif
586 memset(mem, 0xde, new_size); /* Mnemonic for "dead". */
587 #endif
590 * The free list uses the "rounded-up" size "new_size".
592 ((element *)mem)->next = ctx->freelists[new_size];
593 ctx->freelists[new_size] = (element *)mem;
596 * The stats[] uses the _actual_ "size" requested by the
597 * caller, with the caveat (in the code above) that "size" >= the
598 * max. size (max_size) ends up getting recorded as a call to
599 * max_size.
601 INSIST(ctx->stats[size].gets != 0U);
602 ctx->stats[size].gets--;
603 ctx->stats[new_size].freefrags++;
604 ctx->inuse -= new_size;
608 * Perform a malloc, doing memory filling and overrun detection as necessary.
610 static inline void *
611 mem_get(isc_mem_t *ctx, size_t size) {
612 char *ret;
614 #if ISC_MEM_CHECKOVERRUN
615 size += 1;
616 #endif
618 ret = (ctx->memalloc)(ctx->arg, size);
619 if (ret == NULL)
620 ctx->memalloc_failures++;
622 #if ISC_MEM_FILL
623 if (ret != NULL)
624 memset(ret, 0xbe, size); /* Mnemonic for "beef". */
625 #else
626 # if ISC_MEM_CHECKOVERRUN
627 if (ret != NULL)
628 ret[size-1] = 0xbe;
629 # endif
630 #endif
632 return (ret);
636 * Perform a free, doing memory filling and overrun detection as necessary.
638 static inline void
639 mem_put(isc_mem_t *ctx, void *mem, size_t size) {
640 #if ISC_MEM_CHECKOVERRUN
641 INSIST(((unsigned char *)mem)[size] == 0xbe);
642 #endif
643 #if ISC_MEM_FILL
644 memset(mem, 0xde, size); /* Mnemonic for "dead". */
645 #else
646 UNUSED(size);
647 #endif
648 (ctx->memfree)(ctx->arg, mem);
652 * Update internal counters after a memory get.
654 static inline void
655 mem_getstats(isc_mem_t *ctx, size_t size) {
656 ctx->total += size;
657 ctx->inuse += size;
659 if (size > ctx->max_size) {
660 ctx->stats[ctx->max_size].gets++;
661 ctx->stats[ctx->max_size].totalgets++;
662 } else {
663 ctx->stats[size].gets++;
664 ctx->stats[size].totalgets++;
669 * Update internal counters after a memory put.
671 static inline void
672 mem_putstats(isc_mem_t *ctx, void *ptr, size_t size) {
673 UNUSED(ptr);
675 INSIST(ctx->inuse >= size);
676 ctx->inuse -= size;
678 if (size > ctx->max_size) {
679 INSIST(ctx->stats[ctx->max_size].gets > 0U);
680 ctx->stats[ctx->max_size].gets--;
681 } else {
682 INSIST(ctx->stats[size].gets > 0U);
683 ctx->stats[size].gets--;
688 * Private.
691 static void *
692 default_memalloc(void *arg, size_t size) {
693 UNUSED(arg);
694 if (size == 0U)
695 size = 1;
696 return (malloc(size));
699 static void
700 default_memfree(void *arg, void *ptr) {
701 UNUSED(arg);
702 free(ptr);
705 static void
706 initialize_action(void) {
707 RUNTIME_CHECK(isc_mutex_init(&lock) == ISC_R_SUCCESS);
708 ISC_LIST_INIT(contexts);
709 totallost = 0;
713 * Public.
716 isc_result_t
717 isc_mem_createx(size_t init_max_size, size_t target_size,
718 isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
719 isc_mem_t **ctxp)
721 return (isc_mem_createx2(init_max_size, target_size, memalloc, memfree,
722 arg, ctxp, ISC_MEMFLAG_DEFAULT));
726 isc_result_t
727 isc_mem_createx2(size_t init_max_size, size_t target_size,
728 isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
729 isc_mem_t **ctxp, unsigned int flags)
731 isc_mem_t *ctx;
732 isc_result_t result;
734 REQUIRE(ctxp != NULL && *ctxp == NULL);
735 REQUIRE(memalloc != NULL);
736 REQUIRE(memfree != NULL);
738 INSIST((ALIGNMENT_SIZE & (ALIGNMENT_SIZE - 1)) == 0);
740 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
742 ctx = (memalloc)(arg, sizeof(*ctx));
743 if (ctx == NULL)
744 return (ISC_R_NOMEMORY);
746 if ((flags & ISC_MEMFLAG_NOLOCK) == 0) {
747 result = isc_mutex_init(&ctx->lock);
748 if (result != ISC_R_SUCCESS) {
749 (memfree)(arg, ctx);
750 return (result);
754 if (init_max_size == 0U)
755 ctx->max_size = DEF_MAX_SIZE;
756 else
757 ctx->max_size = init_max_size;
758 ctx->flags = flags;
759 ctx->references = 1;
760 memset(ctx->name, 0, sizeof(ctx->name));
761 ctx->tag = NULL;
762 ctx->quota = 0;
763 ctx->total = 0;
764 ctx->inuse = 0;
765 ctx->maxinuse = 0;
766 ctx->hi_water = 0;
767 ctx->lo_water = 0;
768 ctx->hi_called = ISC_FALSE;
769 ctx->water = NULL;
770 ctx->water_arg = NULL;
771 ctx->magic = MEM_MAGIC;
772 isc_ondestroy_init(&ctx->ondestroy);
773 ctx->memalloc = memalloc;
774 ctx->memfree = memfree;
775 ctx->arg = arg;
776 ctx->stats = NULL;
777 ctx->checkfree = ISC_TRUE;
778 #if ISC_MEM_TRACKLINES
779 ctx->debuglist = NULL;
780 ctx->debuglistcnt = 0;
781 #endif
782 ISC_LIST_INIT(ctx->pools);
783 ctx->poolcnt = 0;
784 ctx->freelists = NULL;
785 ctx->basic_blocks = NULL;
786 ctx->basic_table = NULL;
787 ctx->basic_table_count = 0;
788 ctx->basic_table_size = 0;
789 ctx->lowest = NULL;
790 ctx->highest = NULL;
792 ctx->stats = (memalloc)(arg,
793 (ctx->max_size+1) * sizeof(struct stats));
794 if (ctx->stats == NULL) {
795 result = ISC_R_NOMEMORY;
796 goto error;
798 memset(ctx->stats, 0, (ctx->max_size + 1) * sizeof(struct stats));
800 if ((flags & ISC_MEMFLAG_INTERNAL) != 0) {
801 if (target_size == 0U)
802 ctx->mem_target = DEF_MEM_TARGET;
803 else
804 ctx->mem_target = target_size;
805 ctx->freelists = (memalloc)(arg, ctx->max_size *
806 sizeof(element *));
807 if (ctx->freelists == NULL) {
808 result = ISC_R_NOMEMORY;
809 goto error;
811 memset(ctx->freelists, 0,
812 ctx->max_size * sizeof(element *));
815 #if ISC_MEM_TRACKLINES
816 if ((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0) {
817 unsigned int i;
819 ctx->debuglist = (memalloc)(arg,
820 (ctx->max_size+1) * sizeof(debuglist_t));
821 if (ctx->debuglist == NULL) {
822 result = ISC_R_NOMEMORY;
823 goto error;
825 for (i = 0; i <= ctx->max_size; i++)
826 ISC_LIST_INIT(ctx->debuglist[i]);
828 #endif
830 ctx->memalloc_failures = 0;
832 LOCK(&lock);
833 ISC_LIST_INITANDAPPEND(contexts, ctx, link);
834 UNLOCK(&lock);
836 *ctxp = ctx;
837 return (ISC_R_SUCCESS);
839 error:
840 if (ctx != NULL) {
841 if (ctx->stats != NULL)
842 (memfree)(arg, ctx->stats);
843 if (ctx->freelists != NULL)
844 (memfree)(arg, ctx->freelists);
845 #if ISC_MEM_TRACKLINES
846 if (ctx->debuglist != NULL)
847 (ctx->memfree)(ctx->arg, ctx->debuglist);
848 #endif /* ISC_MEM_TRACKLINES */
849 if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
850 DESTROYLOCK(&ctx->lock);
851 (memfree)(arg, ctx);
854 return (result);
857 isc_result_t
858 isc_mem_create(size_t init_max_size, size_t target_size,
859 isc_mem_t **ctxp)
861 return (isc_mem_createx2(init_max_size, target_size,
862 default_memalloc, default_memfree, NULL,
863 ctxp, ISC_MEMFLAG_DEFAULT));
866 isc_result_t
867 isc_mem_create2(size_t init_max_size, size_t target_size,
868 isc_mem_t **ctxp, unsigned int flags)
870 return (isc_mem_createx2(init_max_size, target_size,
871 default_memalloc, default_memfree, NULL,
872 ctxp, flags));
875 static void
876 destroy(isc_mem_t *ctx) {
877 unsigned int i;
878 isc_ondestroy_t ondest;
880 ctx->magic = 0;
882 LOCK(&lock);
883 ISC_LIST_UNLINK(contexts, ctx, link);
884 totallost += ctx->inuse;
885 UNLOCK(&lock);
887 INSIST(ISC_LIST_EMPTY(ctx->pools));
889 #if ISC_MEM_TRACKLINES
890 if (ctx->debuglist != NULL) {
891 if (ctx->checkfree) {
892 for (i = 0; i <= ctx->max_size; i++) {
893 if (!ISC_LIST_EMPTY(ctx->debuglist[i]))
894 print_active(ctx, stderr);
895 INSIST(ISC_LIST_EMPTY(ctx->debuglist[i]));
897 } else {
898 debuglink_t *dl;
900 for (i = 0; i <= ctx->max_size; i++)
901 for (dl = ISC_LIST_HEAD(ctx->debuglist[i]);
902 dl != NULL;
903 dl = ISC_LIST_HEAD(ctx->debuglist[i])) {
904 ISC_LIST_UNLINK(ctx->debuglist[i],
905 dl, link);
906 free(dl);
909 (ctx->memfree)(ctx->arg, ctx->debuglist);
911 #endif
912 INSIST(ctx->references == 0);
914 if (ctx->checkfree) {
915 for (i = 0; i <= ctx->max_size; i++) {
916 #if ISC_MEM_TRACKLINES
917 if (ctx->stats[i].gets != 0U)
918 print_active(ctx, stderr);
919 #endif
920 INSIST(ctx->stats[i].gets == 0U);
924 (ctx->memfree)(ctx->arg, ctx->stats);
926 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
927 for (i = 0; i < ctx->basic_table_count; i++)
928 (ctx->memfree)(ctx->arg, ctx->basic_table[i]);
929 (ctx->memfree)(ctx->arg, ctx->freelists);
930 if (ctx->basic_table != NULL)
931 (ctx->memfree)(ctx->arg, ctx->basic_table);
934 ondest = ctx->ondestroy;
936 if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
937 DESTROYLOCK(&ctx->lock);
938 (ctx->memfree)(ctx->arg, ctx);
940 isc_ondestroy_notify(&ondest, ctx);
943 void
944 isc_mem_attach(isc_mem_t *source, isc_mem_t **targetp) {
945 REQUIRE(VALID_CONTEXT(source));
946 REQUIRE(targetp != NULL && *targetp == NULL);
948 MCTXLOCK(source, &source->lock);
949 source->references++;
950 MCTXUNLOCK(source, &source->lock);
952 *targetp = source;
955 void
956 isc_mem_detach(isc_mem_t **ctxp) {
957 isc_mem_t *ctx;
958 isc_boolean_t want_destroy = ISC_FALSE;
960 REQUIRE(ctxp != NULL);
961 ctx = *ctxp;
962 REQUIRE(VALID_CONTEXT(ctx));
964 MCTXLOCK(ctx, &ctx->lock);
965 INSIST(ctx->references > 0);
966 ctx->references--;
967 if (ctx->references == 0)
968 want_destroy = ISC_TRUE;
969 MCTXUNLOCK(ctx, &ctx->lock);
971 if (want_destroy)
972 destroy(ctx);
974 *ctxp = NULL;
978 * isc_mem_putanddetach() is the equivalent of:
980 * mctx = NULL;
981 * isc_mem_attach(ptr->mctx, &mctx);
982 * isc_mem_detach(&ptr->mctx);
983 * isc_mem_put(mctx, ptr, sizeof(*ptr);
984 * isc_mem_detach(&mctx);
987 void
988 isc__mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) {
989 isc_mem_t *ctx;
990 isc_boolean_t want_destroy = ISC_FALSE;
991 size_info *si;
992 size_t oldsize;
994 REQUIRE(ctxp != NULL);
995 ctx = *ctxp;
996 REQUIRE(VALID_CONTEXT(ctx));
997 REQUIRE(ptr != NULL);
1000 * Must be before mem_putunlocked() as ctxp is usually within
1001 * [ptr..ptr+size).
1003 *ctxp = NULL;
1005 if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) {
1006 if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) {
1007 si = &(((size_info *)ptr)[-1]);
1008 oldsize = si->u.size - ALIGNMENT_SIZE;
1009 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
1010 oldsize -= ALIGNMENT_SIZE;
1011 INSIST(oldsize == size);
1013 isc__mem_free(ctx, ptr FLARG_PASS);
1015 MCTXLOCK(ctx, &ctx->lock);
1016 ctx->references--;
1017 if (ctx->references == 0)
1018 want_destroy = ISC_TRUE;
1019 MCTXUNLOCK(ctx, &ctx->lock);
1020 if (want_destroy)
1021 destroy(ctx);
1023 return;
1026 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1027 MCTXLOCK(ctx, &ctx->lock);
1028 mem_putunlocked(ctx, ptr, size);
1029 } else {
1030 mem_put(ctx, ptr, size);
1031 MCTXLOCK(ctx, &ctx->lock);
1032 mem_putstats(ctx, ptr, size);
1035 DELETE_TRACE(ctx, ptr, size, file, line);
1036 INSIST(ctx->references > 0);
1037 ctx->references--;
1038 if (ctx->references == 0)
1039 want_destroy = ISC_TRUE;
1041 MCTXUNLOCK(ctx, &ctx->lock);
1043 if (want_destroy)
1044 destroy(ctx);
1047 void
1048 isc_mem_destroy(isc_mem_t **ctxp) {
1049 isc_mem_t *ctx;
1052 * This routine provides legacy support for callers who use mctxs
1053 * without attaching/detaching.
1056 REQUIRE(ctxp != NULL);
1057 ctx = *ctxp;
1058 REQUIRE(VALID_CONTEXT(ctx));
1060 MCTXLOCK(ctx, &ctx->lock);
1061 #if ISC_MEM_TRACKLINES
1062 if (ctx->references != 1)
1063 print_active(ctx, stderr);
1064 #endif
1065 REQUIRE(ctx->references == 1);
1066 ctx->references--;
1067 MCTXUNLOCK(ctx, &ctx->lock);
1069 destroy(ctx);
1071 *ctxp = NULL;
1074 isc_result_t
1075 isc_mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event) {
1076 isc_result_t res;
1078 MCTXLOCK(ctx, &ctx->lock);
1079 res = isc_ondestroy_register(&ctx->ondestroy, task, event);
1080 MCTXUNLOCK(ctx, &ctx->lock);
1082 return (res);
1086 void *
1087 isc__mem_get(isc_mem_t *ctx, size_t size FLARG) {
1088 void *ptr;
1089 isc_boolean_t call_water = ISC_FALSE;
1091 REQUIRE(VALID_CONTEXT(ctx));
1093 if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0)
1094 return (isc__mem_allocate(ctx, size FLARG_PASS));
1096 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1097 MCTXLOCK(ctx, &ctx->lock);
1098 ptr = mem_getunlocked(ctx, size);
1099 } else {
1100 ptr = mem_get(ctx, size);
1101 MCTXLOCK(ctx, &ctx->lock);
1102 if (ptr != NULL)
1103 mem_getstats(ctx, size);
1106 ADD_TRACE(ctx, ptr, size, file, line);
1107 if (ctx->hi_water != 0U && !ctx->hi_called &&
1108 ctx->inuse > ctx->hi_water) {
1109 call_water = ISC_TRUE;
1111 if (ctx->inuse > ctx->maxinuse) {
1112 ctx->maxinuse = ctx->inuse;
1113 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1114 (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
1115 fprintf(stderr, "maxinuse = %lu\n",
1116 (unsigned long)ctx->inuse);
1118 MCTXUNLOCK(ctx, &ctx->lock);
1120 if (call_water)
1121 (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
1123 return (ptr);
1126 void
1127 isc__mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG)
1129 isc_boolean_t call_water = ISC_FALSE;
1130 size_info *si;
1131 size_t oldsize;
1133 REQUIRE(VALID_CONTEXT(ctx));
1134 REQUIRE(ptr != NULL);
1136 if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) {
1137 if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) {
1138 si = &(((size_info *)ptr)[-1]);
1139 oldsize = si->u.size - ALIGNMENT_SIZE;
1140 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
1141 oldsize -= ALIGNMENT_SIZE;
1142 INSIST(oldsize == size);
1144 isc__mem_free(ctx, ptr FLARG_PASS);
1145 return;
1148 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1149 MCTXLOCK(ctx, &ctx->lock);
1150 mem_putunlocked(ctx, ptr, size);
1151 } else {
1152 mem_put(ctx, ptr, size);
1153 MCTXLOCK(ctx, &ctx->lock);
1154 mem_putstats(ctx, ptr, size);
1157 DELETE_TRACE(ctx, ptr, size, file, line);
1160 * The check against ctx->lo_water == 0 is for the condition
1161 * when the context was pushed over hi_water but then had
1162 * isc_mem_setwater() called with 0 for hi_water and lo_water.
1164 if (ctx->hi_called &&
1165 (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1166 if (ctx->water != NULL)
1167 call_water = ISC_TRUE;
1169 MCTXUNLOCK(ctx, &ctx->lock);
1171 if (call_water)
1172 (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
1175 void
1176 isc_mem_waterack(isc_mem_t *ctx, int flag) {
1177 REQUIRE(VALID_CONTEXT(ctx));
1179 MCTXLOCK(ctx, &ctx->lock);
1180 if (flag == ISC_MEM_LOWATER)
1181 ctx->hi_called = ISC_FALSE;
1182 else if (flag == ISC_MEM_HIWATER)
1183 ctx->hi_called = ISC_TRUE;
1184 MCTXUNLOCK(ctx, &ctx->lock);
1187 #if ISC_MEM_TRACKLINES
1188 static void
1189 print_active(isc_mem_t *mctx, FILE *out) {
1190 if (mctx->debuglist != NULL) {
1191 debuglink_t *dl;
1192 unsigned int i, j;
1193 const char *format;
1194 isc_boolean_t found;
1196 fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1197 ISC_MSG_DUMPALLOC,
1198 "Dump of all outstanding "
1199 "memory allocations:\n"));
1200 found = ISC_FALSE;
1201 format = isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1202 ISC_MSG_PTRFILELINE,
1203 "\tptr %p size %u file %s line %u\n");
1204 for (i = 0; i <= mctx->max_size; i++) {
1205 dl = ISC_LIST_HEAD(mctx->debuglist[i]);
1207 if (dl != NULL)
1208 found = ISC_TRUE;
1210 while (dl != NULL) {
1211 for (j = 0; j < DEBUGLIST_COUNT; j++)
1212 if (dl->ptr[j] != NULL)
1213 fprintf(out, format,
1214 dl->ptr[j],
1215 dl->size[j],
1216 dl->file[j],
1217 dl->line[j]);
1218 dl = ISC_LIST_NEXT(dl, link);
1221 if (!found)
1222 fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1223 ISC_MSG_NONE, "\tNone.\n"));
1226 #endif
1229 * Print the stats[] on the stream "out" with suitable formatting.
1231 void
1232 isc_mem_stats(isc_mem_t *ctx, FILE *out) {
1233 size_t i;
1234 const struct stats *s;
1235 const isc_mempool_t *pool;
1237 REQUIRE(VALID_CONTEXT(ctx));
1238 MCTXLOCK(ctx, &ctx->lock);
1240 for (i = 0; i <= ctx->max_size; i++) {
1241 s = &ctx->stats[i];
1243 if (s->totalgets == 0U && s->gets == 0U)
1244 continue;
1245 fprintf(out, "%s%5lu: %11lu gets, %11lu rem",
1246 (i == ctx->max_size) ? ">=" : " ",
1247 (unsigned long) i, s->totalgets, s->gets);
1248 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0 &&
1249 (s->blocks != 0U || s->freefrags != 0U))
1250 fprintf(out, " (%lu bl, %lu ff)",
1251 s->blocks, s->freefrags);
1252 fputc('\n', out);
1256 * Note that since a pool can be locked now, these stats might be
1257 * somewhat off if the pool is in active use at the time the stats
1258 * are dumped. The link fields are protected by the isc_mem_t's
1259 * lock, however, so walking this list and extracting integers from
1260 * stats fields is always safe.
1262 pool = ISC_LIST_HEAD(ctx->pools);
1263 if (pool != NULL) {
1264 fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1265 ISC_MSG_POOLSTATS,
1266 "[Pool statistics]\n"));
1267 fprintf(out, "%15s %10s %10s %10s %10s %10s %10s %10s %1s\n",
1268 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1269 ISC_MSG_POOLNAME, "name"),
1270 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1271 ISC_MSG_POOLSIZE, "size"),
1272 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1273 ISC_MSG_POOLMAXALLOC, "maxalloc"),
1274 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1275 ISC_MSG_POOLALLOCATED, "allocated"),
1276 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1277 ISC_MSG_POOLFREECOUNT, "freecount"),
1278 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1279 ISC_MSG_POOLFREEMAX, "freemax"),
1280 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1281 ISC_MSG_POOLFILLCOUNT, "fillcount"),
1282 isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1283 ISC_MSG_POOLGETS, "gets"),
1284 "L");
1286 while (pool != NULL) {
1287 fprintf(out, "%15s %10lu %10u %10u %10u %10u %10u %10u %s\n",
1288 pool->name, (unsigned long) pool->size, pool->maxalloc,
1289 pool->allocated, pool->freecount, pool->freemax,
1290 pool->fillcount, pool->gets,
1291 (pool->lock == NULL ? "N" : "Y"));
1292 pool = ISC_LIST_NEXT(pool, link);
1295 #if ISC_MEM_TRACKLINES
1296 print_active(ctx, out);
1297 #endif
1299 MCTXUNLOCK(ctx, &ctx->lock);
1303 * Replacements for malloc() and free() -- they implicitly remember the
1304 * size of the object allocated (with some additional overhead).
1307 static void *
1308 isc__mem_allocateunlocked(isc_mem_t *ctx, size_t size) {
1309 size_info *si;
1311 size += ALIGNMENT_SIZE;
1312 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
1313 size += ALIGNMENT_SIZE;
1315 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0)
1316 si = mem_getunlocked(ctx, size);
1317 else
1318 si = mem_get(ctx, size);
1320 if (si == NULL)
1321 return (NULL);
1322 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
1323 si->u.ctx = ctx;
1324 si++;
1326 si->u.size = size;
1327 return (&si[1]);
1330 void *
1331 isc__mem_allocate(isc_mem_t *ctx, size_t size FLARG) {
1332 size_info *si;
1333 isc_boolean_t call_water = ISC_FALSE;
1335 REQUIRE(VALID_CONTEXT(ctx));
1337 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1338 MCTXLOCK(ctx, &ctx->lock);
1339 si = isc__mem_allocateunlocked(ctx, size);
1340 } else {
1341 si = isc__mem_allocateunlocked(ctx, size);
1342 MCTXLOCK(ctx, &ctx->lock);
1343 if (si != NULL)
1344 mem_getstats(ctx, si[-1].u.size);
1347 #if ISC_MEM_TRACKLINES
1348 ADD_TRACE(ctx, si, si[-1].u.size, file, line);
1349 #endif
1350 if (ctx->hi_water != 0U && !ctx->hi_called &&
1351 ctx->inuse > ctx->hi_water) {
1352 ctx->hi_called = ISC_TRUE;
1353 call_water = ISC_TRUE;
1355 if (ctx->inuse > ctx->maxinuse) {
1356 ctx->maxinuse = ctx->inuse;
1357 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1358 (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
1359 fprintf(stderr, "maxinuse = %lu\n",
1360 (unsigned long)ctx->inuse);
1362 MCTXUNLOCK(ctx, &ctx->lock);
1364 if (call_water)
1365 (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
1367 return (si);
1370 void *
1371 isc__mem_reallocate(isc_mem_t *ctx, void *ptr, size_t size FLARG) {
1372 void *new_ptr = NULL;
1373 size_t oldsize, copysize;
1375 REQUIRE(VALID_CONTEXT(ctx));
1378 * This function emulates the realloc(3) standard library function:
1379 * - if size > 0, allocate new memory; and if ptr is non NULL, copy
1380 * as much of the old contents to the new buffer and free the old one.
1381 * Note that when allocation fails the original pointer is intact;
1382 * the caller must free it.
1383 * - if size is 0 and ptr is non NULL, simply free the given ptr.
1384 * - this function returns:
1385 * pointer to the newly allocated memory, or
1386 * NULL if allocation fails or doesn't happen.
1388 if (size > 0U) {
1389 new_ptr = isc__mem_allocate(ctx, size FLARG_PASS);
1390 if (new_ptr != NULL && ptr != NULL) {
1391 oldsize = (((size_info *)ptr)[-1]).u.size;
1392 INSIST(oldsize >= ALIGNMENT_SIZE);
1393 oldsize -= ALIGNMENT_SIZE;
1394 copysize = oldsize > size ? size : oldsize;
1395 memcpy(new_ptr, ptr, copysize);
1396 isc__mem_free(ctx, ptr FLARG_PASS);
1398 } else if (ptr != NULL)
1399 isc__mem_free(ctx, ptr FLARG_PASS);
1401 return (new_ptr);
1404 void
1405 isc__mem_free(isc_mem_t *ctx, void *ptr FLARG) {
1406 size_info *si;
1407 size_t size;
1408 isc_boolean_t call_water= ISC_FALSE;
1410 REQUIRE(VALID_CONTEXT(ctx));
1411 REQUIRE(ptr != NULL);
1413 if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
1414 si = &(((size_info *)ptr)[-2]);
1415 REQUIRE(si->u.ctx == ctx);
1416 size = si[1].u.size;
1417 } else {
1418 si = &(((size_info *)ptr)[-1]);
1419 size = si->u.size;
1422 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1423 MCTXLOCK(ctx, &ctx->lock);
1424 mem_putunlocked(ctx, si, size);
1425 } else {
1426 mem_put(ctx, si, size);
1427 MCTXLOCK(ctx, &ctx->lock);
1428 mem_putstats(ctx, si, size);
1431 DELETE_TRACE(ctx, ptr, size, file, line);
1434 * The check against ctx->lo_water == 0 is for the condition
1435 * when the context was pushed over hi_water but then had
1436 * isc_mem_setwater() called with 0 for hi_water and lo_water.
1438 if (ctx->hi_called &&
1439 (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1440 ctx->hi_called = ISC_FALSE;
1442 if (ctx->water != NULL)
1443 call_water = ISC_TRUE;
1445 MCTXUNLOCK(ctx, &ctx->lock);
1447 if (call_water)
1448 (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
1453 * Other useful things.
1456 char *
1457 isc__mem_strdup(isc_mem_t *mctx, const char *s FLARG) {
1458 size_t len;
1459 char *ns;
1461 REQUIRE(VALID_CONTEXT(mctx));
1462 REQUIRE(s != NULL);
1464 len = strlen(s);
1466 ns = isc__mem_allocate(mctx, len + 1 FLARG_PASS);
1468 if (ns != NULL)
1469 strncpy(ns, s, len + 1);
1471 return (ns);
1474 void
1475 isc_mem_setdestroycheck(isc_mem_t *ctx, isc_boolean_t flag) {
1476 REQUIRE(VALID_CONTEXT(ctx));
1477 MCTXLOCK(ctx, &ctx->lock);
1479 ctx->checkfree = flag;
1481 MCTXUNLOCK(ctx, &ctx->lock);
1485 * Quotas
1488 void
1489 isc_mem_setquota(isc_mem_t *ctx, size_t quota) {
1490 REQUIRE(VALID_CONTEXT(ctx));
1491 MCTXLOCK(ctx, &ctx->lock);
1493 ctx->quota = quota;
1495 MCTXUNLOCK(ctx, &ctx->lock);
1498 size_t
1499 isc_mem_getquota(isc_mem_t *ctx) {
1500 size_t quota;
1502 REQUIRE(VALID_CONTEXT(ctx));
1503 MCTXLOCK(ctx, &ctx->lock);
1505 quota = ctx->quota;
1507 MCTXUNLOCK(ctx, &ctx->lock);
1509 return (quota);
1512 size_t
1513 isc_mem_inuse(isc_mem_t *ctx) {
1514 size_t inuse;
1516 REQUIRE(VALID_CONTEXT(ctx));
1517 MCTXLOCK(ctx, &ctx->lock);
1519 inuse = ctx->inuse;
1521 MCTXUNLOCK(ctx, &ctx->lock);
1523 return (inuse);
1526 void
1527 isc_mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg,
1528 size_t hiwater, size_t lowater)
1530 isc_boolean_t callwater = ISC_FALSE;
1531 isc_mem_water_t oldwater;
1532 void *oldwater_arg;
1534 REQUIRE(VALID_CONTEXT(ctx));
1535 REQUIRE(hiwater >= lowater);
1537 MCTXLOCK(ctx, &ctx->lock);
1538 oldwater = ctx->water;
1539 oldwater_arg = ctx->water_arg;
1540 if (water == NULL) {
1541 callwater = ctx->hi_called;
1542 ctx->water = NULL;
1543 ctx->water_arg = NULL;
1544 ctx->hi_water = 0;
1545 ctx->lo_water = 0;
1546 ctx->hi_called = ISC_FALSE;
1547 } else {
1548 if (ctx->hi_called &&
1549 (ctx->water != water || ctx->water_arg != water_arg ||
1550 ctx->inuse < lowater || lowater == 0U))
1551 callwater = ISC_TRUE;
1552 ctx->water = water;
1553 ctx->water_arg = water_arg;
1554 ctx->hi_water = hiwater;
1555 ctx->lo_water = lowater;
1556 ctx->hi_called = ISC_FALSE;
1558 MCTXUNLOCK(ctx, &ctx->lock);
1560 if (callwater && oldwater != NULL)
1561 (oldwater)(oldwater_arg, ISC_MEM_LOWATER);
1564 void
1565 isc_mem_setname(isc_mem_t *ctx, const char *name, void *tag) {
1566 REQUIRE(VALID_CONTEXT(ctx));
1568 LOCK(&ctx->lock);
1569 memset(ctx->name, 0, sizeof(ctx->name));
1570 strncpy(ctx->name, name, sizeof(ctx->name) - 1);
1571 ctx->tag = tag;
1572 UNLOCK(&ctx->lock);
1575 const char *
1576 isc_mem_getname(isc_mem_t *ctx) {
1577 REQUIRE(VALID_CONTEXT(ctx));
1579 return (ctx->name);
1582 void *
1583 isc_mem_gettag(isc_mem_t *ctx) {
1584 REQUIRE(VALID_CONTEXT(ctx));
1586 return (ctx->tag);
1590 * Memory pool stuff
1593 isc_result_t
1594 isc_mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp) {
1595 isc_mempool_t *mpctx;
1597 REQUIRE(VALID_CONTEXT(mctx));
1598 REQUIRE(size > 0U);
1599 REQUIRE(mpctxp != NULL && *mpctxp == NULL);
1602 * Allocate space for this pool, initialize values, and if all works
1603 * well, attach to the memory context.
1605 mpctx = isc_mem_get(mctx, sizeof(isc_mempool_t));
1606 if (mpctx == NULL)
1607 return (ISC_R_NOMEMORY);
1609 mpctx->magic = MEMPOOL_MAGIC;
1610 mpctx->lock = NULL;
1611 mpctx->mctx = mctx;
1612 mpctx->size = size;
1613 mpctx->maxalloc = UINT_MAX;
1614 mpctx->allocated = 0;
1615 mpctx->freecount = 0;
1616 mpctx->freemax = 1;
1617 mpctx->fillcount = 1;
1618 mpctx->gets = 0;
1619 #if ISC_MEMPOOL_NAMES
1620 mpctx->name[0] = 0;
1621 #endif
1622 mpctx->items = NULL;
1624 *mpctxp = mpctx;
1626 MCTXLOCK(mctx, &mctx->lock);
1627 ISC_LIST_INITANDAPPEND(mctx->pools, mpctx, link);
1628 mctx->poolcnt++;
1629 MCTXUNLOCK(mctx, &mctx->lock);
1631 return (ISC_R_SUCCESS);
1634 void
1635 isc_mempool_setname(isc_mempool_t *mpctx, const char *name) {
1636 REQUIRE(name != NULL);
1638 #if ISC_MEMPOOL_NAMES
1639 if (mpctx->lock != NULL)
1640 LOCK(mpctx->lock);
1642 strncpy(mpctx->name, name, sizeof(mpctx->name) - 1);
1643 mpctx->name[sizeof(mpctx->name) - 1] = '\0';
1645 if (mpctx->lock != NULL)
1646 UNLOCK(mpctx->lock);
1647 #else
1648 UNUSED(mpctx);
1649 UNUSED(name);
1650 #endif
1653 void
1654 isc_mempool_destroy(isc_mempool_t **mpctxp) {
1655 isc_mempool_t *mpctx;
1656 isc_mem_t *mctx;
1657 isc_mutex_t *lock;
1658 element *item;
1660 REQUIRE(mpctxp != NULL);
1661 mpctx = *mpctxp;
1662 REQUIRE(VALID_MEMPOOL(mpctx));
1663 #if ISC_MEMPOOL_NAMES
1664 if (mpctx->allocated > 0)
1665 UNEXPECTED_ERROR(__FILE__, __LINE__,
1666 "isc_mempool_destroy(): mempool %s "
1667 "leaked memory",
1668 mpctx->name);
1669 #endif
1670 REQUIRE(mpctx->allocated == 0);
1672 mctx = mpctx->mctx;
1674 lock = mpctx->lock;
1676 if (lock != NULL)
1677 LOCK(lock);
1680 * Return any items on the free list
1682 MCTXLOCK(mctx, &mctx->lock);
1683 while (mpctx->items != NULL) {
1684 INSIST(mpctx->freecount > 0);
1685 mpctx->freecount--;
1686 item = mpctx->items;
1687 mpctx->items = item->next;
1689 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1690 mem_putunlocked(mctx, item, mpctx->size);
1691 } else {
1692 mem_put(mctx, item, mpctx->size);
1693 mem_putstats(mctx, item, mpctx->size);
1696 MCTXUNLOCK(mctx, &mctx->lock);
1699 * Remove our linked list entry from the memory context.
1701 MCTXLOCK(mctx, &mctx->lock);
1702 ISC_LIST_UNLINK(mctx->pools, mpctx, link);
1703 mctx->poolcnt--;
1704 MCTXUNLOCK(mctx, &mctx->lock);
1706 mpctx->magic = 0;
1708 isc_mem_put(mpctx->mctx, mpctx, sizeof(isc_mempool_t));
1710 if (lock != NULL)
1711 UNLOCK(lock);
1713 *mpctxp = NULL;
1716 void
1717 isc_mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock) {
1718 REQUIRE(VALID_MEMPOOL(mpctx));
1719 REQUIRE(mpctx->lock == NULL);
1720 REQUIRE(lock != NULL);
1722 mpctx->lock = lock;
1725 void *
1726 isc__mempool_get(isc_mempool_t *mpctx FLARG) {
1727 element *item;
1728 isc_mem_t *mctx;
1729 unsigned int i;
1731 REQUIRE(VALID_MEMPOOL(mpctx));
1733 mctx = mpctx->mctx;
1735 if (mpctx->lock != NULL)
1736 LOCK(mpctx->lock);
1739 * Don't let the caller go over quota
1741 if (mpctx->allocated >= mpctx->maxalloc) {
1742 item = NULL;
1743 goto out;
1747 * if we have a free list item, return the first here
1749 item = mpctx->items;
1750 if (item != NULL) {
1751 mpctx->items = item->next;
1752 INSIST(mpctx->freecount > 0);
1753 mpctx->freecount--;
1754 mpctx->gets++;
1755 mpctx->allocated++;
1756 goto out;
1760 * We need to dip into the well. Lock the memory context here and
1761 * fill up our free list.
1763 MCTXLOCK(mctx, &mctx->lock);
1764 for (i = 0; i < mpctx->fillcount; i++) {
1765 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1766 item = mem_getunlocked(mctx, mpctx->size);
1767 } else {
1768 item = mem_get(mctx, mpctx->size);
1769 if (item != NULL)
1770 mem_getstats(mctx, mpctx->size);
1772 if (item == NULL)
1773 break;
1774 item->next = mpctx->items;
1775 mpctx->items = item;
1776 mpctx->freecount++;
1778 MCTXUNLOCK(mctx, &mctx->lock);
1781 * If we didn't get any items, return NULL.
1783 item = mpctx->items;
1784 if (item == NULL)
1785 goto out;
1787 mpctx->items = item->next;
1788 mpctx->freecount--;
1789 mpctx->gets++;
1790 mpctx->allocated++;
1792 out:
1793 if (mpctx->lock != NULL)
1794 UNLOCK(mpctx->lock);
1796 #if ISC_MEM_TRACKLINES
1797 if (item != NULL) {
1798 MCTXLOCK(mctx, &mctx->lock);
1799 ADD_TRACE(mctx, item, mpctx->size, file, line);
1800 MCTXUNLOCK(mctx, &mctx->lock);
1802 #endif /* ISC_MEM_TRACKLINES */
1804 return (item);
1807 void
1808 isc__mempool_put(isc_mempool_t *mpctx, void *mem FLARG) {
1809 isc_mem_t *mctx;
1810 element *item;
1812 REQUIRE(VALID_MEMPOOL(mpctx));
1813 REQUIRE(mem != NULL);
1815 mctx = mpctx->mctx;
1817 if (mpctx->lock != NULL)
1818 LOCK(mpctx->lock);
1820 INSIST(mpctx->allocated > 0);
1821 mpctx->allocated--;
1823 #if ISC_MEM_TRACKLINES
1824 MCTXLOCK(mctx, &mctx->lock);
1825 DELETE_TRACE(mctx, mem, mpctx->size, file, line);
1826 MCTXUNLOCK(mctx, &mctx->lock);
1827 #endif /* ISC_MEM_TRACKLINES */
1830 * If our free list is full, return this to the mctx directly.
1832 if (mpctx->freecount >= mpctx->freemax) {
1833 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1834 MCTXLOCK(mctx, &mctx->lock);
1835 mem_putunlocked(mctx, mem, mpctx->size);
1836 MCTXUNLOCK(mctx, &mctx->lock);
1837 } else {
1838 mem_put(mctx, mem, mpctx->size);
1839 MCTXLOCK(mctx, &mctx->lock);
1840 mem_putstats(mctx, mem, mpctx->size);
1841 MCTXUNLOCK(mctx, &mctx->lock);
1843 if (mpctx->lock != NULL)
1844 UNLOCK(mpctx->lock);
1845 return;
1849 * Otherwise, attach it to our free list and bump the counter.
1851 mpctx->freecount++;
1852 item = (element *)mem;
1853 item->next = mpctx->items;
1854 mpctx->items = item;
1856 if (mpctx->lock != NULL)
1857 UNLOCK(mpctx->lock);
1861 * Quotas
1864 void
1865 isc_mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit) {
1866 REQUIRE(VALID_MEMPOOL(mpctx));
1868 if (mpctx->lock != NULL)
1869 LOCK(mpctx->lock);
1871 mpctx->freemax = limit;
1873 if (mpctx->lock != NULL)
1874 UNLOCK(mpctx->lock);
1877 unsigned int
1878 isc_mempool_getfreemax(isc_mempool_t *mpctx) {
1879 unsigned int freemax;
1881 REQUIRE(VALID_MEMPOOL(mpctx));
1883 if (mpctx->lock != NULL)
1884 LOCK(mpctx->lock);
1886 freemax = mpctx->freemax;
1888 if (mpctx->lock != NULL)
1889 UNLOCK(mpctx->lock);
1891 return (freemax);
1894 unsigned int
1895 isc_mempool_getfreecount(isc_mempool_t *mpctx) {
1896 unsigned int freecount;
1898 REQUIRE(VALID_MEMPOOL(mpctx));
1900 if (mpctx->lock != NULL)
1901 LOCK(mpctx->lock);
1903 freecount = mpctx->freecount;
1905 if (mpctx->lock != NULL)
1906 UNLOCK(mpctx->lock);
1908 return (freecount);
1911 void
1912 isc_mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit) {
1913 REQUIRE(limit > 0);
1915 REQUIRE(VALID_MEMPOOL(mpctx));
1917 if (mpctx->lock != NULL)
1918 LOCK(mpctx->lock);
1920 mpctx->maxalloc = limit;
1922 if (mpctx->lock != NULL)
1923 UNLOCK(mpctx->lock);
1926 unsigned int
1927 isc_mempool_getmaxalloc(isc_mempool_t *mpctx) {
1928 unsigned int maxalloc;
1930 REQUIRE(VALID_MEMPOOL(mpctx));
1932 if (mpctx->lock != NULL)
1933 LOCK(mpctx->lock);
1935 maxalloc = mpctx->maxalloc;
1937 if (mpctx->lock != NULL)
1938 UNLOCK(mpctx->lock);
1940 return (maxalloc);
1943 unsigned int
1944 isc_mempool_getallocated(isc_mempool_t *mpctx) {
1945 unsigned int allocated;
1947 REQUIRE(VALID_MEMPOOL(mpctx));
1949 if (mpctx->lock != NULL)
1950 LOCK(mpctx->lock);
1952 allocated = mpctx->allocated;
1954 if (mpctx->lock != NULL)
1955 UNLOCK(mpctx->lock);
1957 return (allocated);
1960 void
1961 isc_mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit) {
1962 REQUIRE(limit > 0);
1963 REQUIRE(VALID_MEMPOOL(mpctx));
1965 if (mpctx->lock != NULL)
1966 LOCK(mpctx->lock);
1968 mpctx->fillcount = limit;
1970 if (mpctx->lock != NULL)
1971 UNLOCK(mpctx->lock);
1974 unsigned int
1975 isc_mempool_getfillcount(isc_mempool_t *mpctx) {
1976 unsigned int fillcount;
1978 REQUIRE(VALID_MEMPOOL(mpctx));
1980 if (mpctx->lock != NULL)
1981 LOCK(mpctx->lock);
1983 fillcount = mpctx->fillcount;
1985 if (mpctx->lock != NULL)
1986 UNLOCK(mpctx->lock);
1988 return (fillcount);
1991 void
1992 isc_mem_printactive(isc_mem_t *ctx, FILE *file) {
1994 REQUIRE(VALID_CONTEXT(ctx));
1995 REQUIRE(file != NULL);
1997 #if !ISC_MEM_TRACKLINES
1998 UNUSED(ctx);
1999 UNUSED(file);
2000 #else
2001 print_active(ctx, file);
2002 #endif
2005 void
2006 isc_mem_printallactive(FILE *file) {
2007 #if !ISC_MEM_TRACKLINES
2008 UNUSED(file);
2009 #else
2010 isc_mem_t *ctx;
2012 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2014 LOCK(&lock);
2015 for (ctx = ISC_LIST_HEAD(contexts);
2016 ctx != NULL;
2017 ctx = ISC_LIST_NEXT(ctx, link)) {
2018 fprintf(file, "context: %p\n", ctx);
2019 print_active(ctx, file);
2021 UNLOCK(&lock);
2022 #endif
2025 void
2026 isc_mem_checkdestroyed(FILE *file) {
2028 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2030 LOCK(&lock);
2031 if (!ISC_LIST_EMPTY(contexts)) {
2032 #if ISC_MEM_TRACKLINES
2033 isc_mem_t *ctx;
2035 for (ctx = ISC_LIST_HEAD(contexts);
2036 ctx != NULL;
2037 ctx = ISC_LIST_NEXT(ctx, link)) {
2038 fprintf(file, "context: %p\n", ctx);
2039 print_active(ctx, file);
2041 fflush(file);
2042 #endif
2043 INSIST(0);
2045 UNLOCK(&lock);
2048 unsigned int
2049 isc_mem_references(isc_mem_t *ctx) {
2050 unsigned int references;
2051 REQUIRE(VALID_CONTEXT(ctx));
2053 MCTXLOCK(ctx, &ctx->lock);
2054 references = ctx->references;
2055 MCTXUNLOCK(ctx, &ctx->lock);
2057 return (references);
2060 #ifdef HAVE_LIBXML2
2062 typedef struct summarystat {
2063 isc_uint64_t total;
2064 isc_uint64_t inuse;
2065 isc_uint64_t blocksize;
2066 isc_uint64_t contextsize;
2067 } summarystat_t;
2069 static void
2070 renderctx(isc_mem_t *ctx, summarystat_t *summary, xmlTextWriterPtr writer) {
2071 REQUIRE(VALID_CONTEXT(ctx));
2073 xmlTextWriterStartElement(writer, ISC_XMLCHAR "context");
2075 xmlTextWriterStartElement(writer, ISC_XMLCHAR "id");
2076 xmlTextWriterWriteFormatString(writer, "%p", ctx);
2077 xmlTextWriterEndElement(writer); /* id */
2079 if (ctx->name[0] != 0) {
2080 xmlTextWriterStartElement(writer, ISC_XMLCHAR "name");
2081 xmlTextWriterWriteFormatString(writer, "%s", ctx->name);
2082 xmlTextWriterEndElement(writer); /* name */
2085 REQUIRE(VALID_CONTEXT(ctx));
2086 MCTXLOCK(ctx, &ctx->lock);
2088 summary->contextsize += sizeof(*ctx) +
2089 (ctx->max_size + 1) * sizeof(struct stats) +
2090 ctx->max_size * sizeof(element *) +
2091 ctx->basic_table_count * sizeof(char *);
2092 #if ISC_MEM_TRACKLINES
2093 if (ctx->debuglist != NULL) {
2094 summary->contextsize +=
2095 (ctx->max_size + 1) * sizeof(debuglist_t) +
2096 ctx->debuglistcnt * sizeof(debuglink_t);
2098 #endif
2099 xmlTextWriterStartElement(writer, ISC_XMLCHAR "references");
2100 xmlTextWriterWriteFormatString(writer, "%d", ctx->references);
2101 xmlTextWriterEndElement(writer); /* references */
2103 summary->total += ctx->total;
2104 xmlTextWriterStartElement(writer, ISC_XMLCHAR "total");
2105 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2106 (isc_uint64_t)ctx->total);
2107 xmlTextWriterEndElement(writer); /* total */
2109 summary->inuse += ctx->inuse;
2110 xmlTextWriterStartElement(writer, ISC_XMLCHAR "inuse");
2111 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2112 (isc_uint64_t)ctx->inuse);
2113 xmlTextWriterEndElement(writer); /* inuse */
2115 xmlTextWriterStartElement(writer, ISC_XMLCHAR "maxinuse");
2116 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2117 (isc_uint64_t)ctx->maxinuse);
2118 xmlTextWriterEndElement(writer); /* maxinuse */
2120 xmlTextWriterStartElement(writer, ISC_XMLCHAR "blocksize");
2121 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
2122 summary->blocksize += ctx->basic_table_count *
2123 NUM_BASIC_BLOCKS * ctx->mem_target;
2124 xmlTextWriterWriteFormatString(writer,
2125 "%" ISC_PRINT_QUADFORMAT "u",
2126 (isc_uint64_t)
2127 ctx->basic_table_count *
2128 NUM_BASIC_BLOCKS *
2129 ctx->mem_target);
2130 } else
2131 xmlTextWriterWriteFormatString(writer, "%s", "-");
2132 xmlTextWriterEndElement(writer); /* blocksize */
2134 xmlTextWriterStartElement(writer, ISC_XMLCHAR "pools");
2135 xmlTextWriterWriteFormatString(writer, "%u", ctx->poolcnt);
2136 xmlTextWriterEndElement(writer); /* pools */
2137 summary->contextsize += ctx->poolcnt * sizeof(isc_mempool_t);
2139 xmlTextWriterStartElement(writer, ISC_XMLCHAR "hiwater");
2140 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2141 (isc_uint64_t)ctx->hi_water);
2142 xmlTextWriterEndElement(writer); /* hiwater */
2144 xmlTextWriterStartElement(writer, ISC_XMLCHAR "lowater");
2145 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2146 (isc_uint64_t)ctx->lo_water);
2147 xmlTextWriterEndElement(writer); /* lowater */
2149 MCTXUNLOCK(ctx, &ctx->lock);
2151 xmlTextWriterEndElement(writer); /* context */
2154 void
2155 isc_mem_renderxml(xmlTextWriterPtr writer) {
2156 isc_mem_t *ctx;
2157 summarystat_t summary;
2158 isc_uint64_t lost;
2160 memset(&summary, 0, sizeof(summary));
2162 xmlTextWriterStartElement(writer, ISC_XMLCHAR "contexts");
2164 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2166 LOCK(&lock);
2167 lost = totallost;
2168 for (ctx = ISC_LIST_HEAD(contexts);
2169 ctx != NULL;
2170 ctx = ISC_LIST_NEXT(ctx, link)) {
2171 renderctx(ctx, &summary, writer);
2173 UNLOCK(&lock);
2175 xmlTextWriterEndElement(writer); /* contexts */
2177 xmlTextWriterStartElement(writer, ISC_XMLCHAR "summary");
2179 xmlTextWriterStartElement(writer, ISC_XMLCHAR "TotalUse");
2180 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2181 summary.total);
2182 xmlTextWriterEndElement(writer); /* TotalUse */
2184 xmlTextWriterStartElement(writer, ISC_XMLCHAR "InUse");
2185 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2186 summary.inuse);
2187 xmlTextWriterEndElement(writer); /* InUse */
2189 xmlTextWriterStartElement(writer, ISC_XMLCHAR "BlockSize");
2190 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2191 summary.blocksize);
2192 xmlTextWriterEndElement(writer); /* BlockSize */
2194 xmlTextWriterStartElement(writer, ISC_XMLCHAR "ContextSize");
2195 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2196 summary.contextsize);
2197 xmlTextWriterEndElement(writer); /* ContextSize */
2199 xmlTextWriterStartElement(writer, ISC_XMLCHAR "Lost");
2200 xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2201 lost);
2202 xmlTextWriterEndElement(writer); /* Lost */
2204 xmlTextWriterEndElement(writer); /* summary */
2207 #endif /* HAVE_LIBXML2 */