]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/bind9/lib/isc/mem.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / bind9 / lib / isc / mem.c
1 /*
2  * Copyright (C) 2004-2010, 2012  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1997-2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /* $Id$ */
19
20 /*! \file */
21
22 #include <config.h>
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <stddef.h>
27
28 #include <limits.h>
29
30 #include <isc/magic.h>
31 #include <isc/mem.h>
32 #include <isc/msgs.h>
33 #include <isc/once.h>
34 #include <isc/ondestroy.h>
35 #include <isc/string.h>
36 #include <isc/mutex.h>
37 #include <isc/print.h>
38 #include <isc/util.h>
39 #include <isc/xml.h>
40
41 #define MCTXLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) LOCK(l)
42 #define MCTXUNLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) UNLOCK(l)
43
44 #ifndef ISC_MEM_DEBUGGING
45 #define ISC_MEM_DEBUGGING 0
46 #endif
47 LIBISC_EXTERNAL_DATA unsigned int isc_mem_debugging = ISC_MEM_DEBUGGING;
48
49 /*
50  * Constants.
51  */
52
53 #define DEF_MAX_SIZE            1100
54 #define DEF_MEM_TARGET          4096
55 #define ALIGNMENT_SIZE          8U              /*%< must be a power of 2 */
56 #define NUM_BASIC_BLOCKS        64              /*%< must be > 1 */
57 #define TABLE_INCREMENT         1024
58 #define DEBUGLIST_COUNT         1024
59
60 /*
61  * Types.
62  */
63 typedef struct isc__mem isc__mem_t;
64 typedef struct isc__mempool isc__mempool_t;
65
66 #if ISC_MEM_TRACKLINES
67 typedef struct debuglink debuglink_t;
68 struct debuglink {
69         ISC_LINK(debuglink_t)   link;
70         const void             *ptr[DEBUGLIST_COUNT];
71         unsigned int            size[DEBUGLIST_COUNT];
72         const char             *file[DEBUGLIST_COUNT];
73         unsigned int            line[DEBUGLIST_COUNT];
74         unsigned int            count;
75 };
76
77 #define FLARG_PASS      , file, line
78 #define FLARG           , const char *file, unsigned int line
79 #else
80 #define FLARG_PASS
81 #define FLARG
82 #endif
83
84 typedef struct element element;
85 struct element {
86         element *               next;
87 };
88
89 typedef struct {
90         /*!
91          * This structure must be ALIGNMENT_SIZE bytes.
92          */
93         union {
94                 size_t          size;
95                 isc__mem_t      *ctx;
96                 char            bytes[ALIGNMENT_SIZE];
97         } u;
98 } size_info;
99
100 struct stats {
101         unsigned long           gets;
102         unsigned long           totalgets;
103         unsigned long           blocks;
104         unsigned long           freefrags;
105 };
106
107 #define MEM_MAGIC               ISC_MAGIC('M', 'e', 'm', 'C')
108 #define VALID_CONTEXT(c)        ISC_MAGIC_VALID(c, MEM_MAGIC)
109
110 #if ISC_MEM_TRACKLINES
111 typedef ISC_LIST(debuglink_t)   debuglist_t;
112 #endif
113
114 /* List of all active memory contexts. */
115
116 static ISC_LIST(isc__mem_t)     contexts;
117 static isc_once_t               once = ISC_ONCE_INIT;
118 static isc_mutex_t              lock;
119
120 /*%
121  * Total size of lost memory due to a bug of external library.
122  * Locked by the global lock.
123  */
124 static isc_uint64_t             totallost;
125
126 struct isc__mem {
127         isc_mem_t               common;
128         isc_ondestroy_t         ondestroy;
129         unsigned int            flags;
130         isc_mutex_t             lock;
131         isc_memalloc_t          memalloc;
132         isc_memfree_t           memfree;
133         void *                  arg;
134         size_t                  max_size;
135         isc_boolean_t           checkfree;
136         struct stats *          stats;
137         unsigned int            references;
138         char                    name[16];
139         void *                  tag;
140         size_t                  quota;
141         size_t                  total;
142         size_t                  inuse;
143         size_t                  maxinuse;
144         size_t                  hi_water;
145         size_t                  lo_water;
146         isc_boolean_t           hi_called;
147         isc_boolean_t           is_overmem;
148         isc_mem_water_t         water;
149         void *                  water_arg;
150         ISC_LIST(isc__mempool_t) pools;
151         unsigned int            poolcnt;
152
153         /*  ISC_MEMFLAG_INTERNAL */
154         size_t                  mem_target;
155         element **              freelists;
156         element *               basic_blocks;
157         unsigned char **        basic_table;
158         unsigned int            basic_table_count;
159         unsigned int            basic_table_size;
160         unsigned char *         lowest;
161         unsigned char *         highest;
162
163 #if ISC_MEM_TRACKLINES
164         debuglist_t *           debuglist;
165         unsigned int            debuglistcnt;
166 #endif
167
168         unsigned int            memalloc_failures;
169         ISC_LINK(isc__mem_t)    link;
170 };
171
172 #define MEMPOOL_MAGIC           ISC_MAGIC('M', 'E', 'M', 'p')
173 #define VALID_MEMPOOL(c)        ISC_MAGIC_VALID(c, MEMPOOL_MAGIC)
174
175 struct isc__mempool {
176         /* always unlocked */
177         isc_mempool_t   common;         /*%< common header of mempool's */
178         isc_mutex_t    *lock;           /*%< optional lock */
179         isc__mem_t      *mctx;          /*%< our memory context */
180         /*%< locked via the memory context's lock */
181         ISC_LINK(isc__mempool_t)        link;   /*%< next pool in this mem context */
182         /*%< optionally locked from here down */
183         element        *items;          /*%< low water item list */
184         size_t          size;           /*%< size of each item on this pool */
185         unsigned int    maxalloc;       /*%< max number of items allowed */
186         unsigned int    allocated;      /*%< # of items currently given out */
187         unsigned int    freecount;      /*%< # of items on reserved list */
188         unsigned int    freemax;        /*%< # of items allowed on free list */
189         unsigned int    fillcount;      /*%< # of items to fetch on each fill */
190         /*%< Stats only. */
191         unsigned int    gets;           /*%< # of requests to this pool */
192         /*%< Debugging only. */
193 #if ISC_MEMPOOL_NAMES
194         char            name[16];       /*%< printed name in stats reports */
195 #endif
196 };
197
198 /*
199  * Private Inline-able.
200  */
201
202 #if ! ISC_MEM_TRACKLINES
203 #define ADD_TRACE(a, b, c, d, e)
204 #define DELETE_TRACE(a, b, c, d, e)
205 #else
206 #define ADD_TRACE(a, b, c, d, e) \
207         do { \
208                 if ((isc_mem_debugging & (ISC_MEM_DEBUGTRACE | \
209                                           ISC_MEM_DEBUGRECORD)) != 0 && \
210                      b != NULL) \
211                          add_trace_entry(a, b, c, d, e); \
212         } while (0)
213 #define DELETE_TRACE(a, b, c, d, e)     delete_trace_entry(a, b, c, d, e)
214
215 static void
216 print_active(isc__mem_t *ctx, FILE *out);
217
218 /*%
219  * The following can be either static or public, depending on build environment.
220  */
221
222 #ifdef BIND9
223 #define ISC_MEMFUNC_SCOPE
224 #else
225 #define ISC_MEMFUNC_SCOPE static
226 #endif
227
228 ISC_MEMFUNC_SCOPE isc_result_t
229 isc__mem_createx(size_t init_max_size, size_t target_size,
230                  isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
231                  isc_mem_t **ctxp);
232 ISC_MEMFUNC_SCOPE isc_result_t
233 isc__mem_createx2(size_t init_max_size, size_t target_size,
234                   isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
235                   isc_mem_t **ctxp, unsigned int flags);
236 ISC_MEMFUNC_SCOPE isc_result_t
237 isc__mem_create(size_t init_max_size, size_t target_size, isc_mem_t **ctxp);
238 ISC_MEMFUNC_SCOPE isc_result_t
239 isc__mem_create2(size_t init_max_size, size_t target_size,
240                  isc_mem_t **ctxp, unsigned int flags);
241 ISC_MEMFUNC_SCOPE void
242 isc__mem_attach(isc_mem_t *source, isc_mem_t **targetp);
243 ISC_MEMFUNC_SCOPE void
244 isc__mem_detach(isc_mem_t **ctxp);
245 ISC_MEMFUNC_SCOPE void
246 isc___mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG);
247 ISC_MEMFUNC_SCOPE void
248 isc__mem_destroy(isc_mem_t **ctxp);
249 ISC_MEMFUNC_SCOPE isc_result_t
250 isc__mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event);
251 ISC_MEMFUNC_SCOPE void *
252 isc___mem_get(isc_mem_t *ctx, size_t size FLARG);
253 ISC_MEMFUNC_SCOPE void
254 isc___mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG);
255 ISC_MEMFUNC_SCOPE void
256 isc__mem_stats(isc_mem_t *ctx, FILE *out);
257 ISC_MEMFUNC_SCOPE void *
258 isc___mem_allocate(isc_mem_t *ctx, size_t size FLARG);
259 ISC_MEMFUNC_SCOPE void *
260 isc___mem_reallocate(isc_mem_t *ctx, void *ptr, size_t size FLARG);
261 ISC_MEMFUNC_SCOPE void
262 isc___mem_free(isc_mem_t *ctx, void *ptr FLARG);
263 ISC_MEMFUNC_SCOPE char *
264 isc___mem_strdup(isc_mem_t *mctx, const char *s FLARG);
265 ISC_MEMFUNC_SCOPE void
266 isc__mem_setdestroycheck(isc_mem_t *ctx, isc_boolean_t flag);
267 ISC_MEMFUNC_SCOPE void
268 isc__mem_setquota(isc_mem_t *ctx, size_t quota);
269 ISC_MEMFUNC_SCOPE size_t
270 isc__mem_getquota(isc_mem_t *ctx);
271 ISC_MEMFUNC_SCOPE size_t
272 isc__mem_inuse(isc_mem_t *ctx);
273 ISC_MEMFUNC_SCOPE isc_boolean_t
274 isc__mem_isovermem(isc_mem_t *ctx);
275 ISC_MEMFUNC_SCOPE void
276 isc__mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg,
277                   size_t hiwater, size_t lowater);
278 ISC_MEMFUNC_SCOPE void
279 isc__mem_waterack(isc_mem_t *ctx0, int flag);
280 ISC_MEMFUNC_SCOPE void
281 isc__mem_setname(isc_mem_t *ctx, const char *name, void *tag);
282 ISC_MEMFUNC_SCOPE const char *
283 isc__mem_getname(isc_mem_t *ctx);
284 ISC_MEMFUNC_SCOPE void *
285 isc__mem_gettag(isc_mem_t *ctx);
286 ISC_MEMFUNC_SCOPE isc_result_t
287 isc__mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp);
288 ISC_MEMFUNC_SCOPE void
289 isc__mempool_setname(isc_mempool_t *mpctx, const char *name);
290 ISC_MEMFUNC_SCOPE void
291 isc__mempool_destroy(isc_mempool_t **mpctxp);
292 ISC_MEMFUNC_SCOPE void
293 isc__mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock);
294 ISC_MEMFUNC_SCOPE void *
295 isc___mempool_get(isc_mempool_t *mpctx FLARG);
296 ISC_MEMFUNC_SCOPE void
297 isc___mempool_put(isc_mempool_t *mpctx, void *mem FLARG);
298 ISC_MEMFUNC_SCOPE void
299 isc__mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit);
300 ISC_MEMFUNC_SCOPE unsigned int
301 isc__mempool_getfreemax(isc_mempool_t *mpctx);
302 ISC_MEMFUNC_SCOPE unsigned int
303 isc__mempool_getfreecount(isc_mempool_t *mpctx);
304 ISC_MEMFUNC_SCOPE void
305 isc__mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit);
306 ISC_MEMFUNC_SCOPE unsigned int
307 isc__mempool_getmaxalloc(isc_mempool_t *mpctx);
308 ISC_MEMFUNC_SCOPE unsigned int
309 isc__mempool_getallocated(isc_mempool_t *mpctx);
310 ISC_MEMFUNC_SCOPE void
311 isc__mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit);
312 ISC_MEMFUNC_SCOPE unsigned int
313 isc__mempool_getfillcount(isc_mempool_t *mpctx);
314 #ifdef BIND9
315 ISC_MEMFUNC_SCOPE void
316 isc__mem_printactive(isc_mem_t *ctx0, FILE *file);
317 ISC_MEMFUNC_SCOPE void
318 isc__mem_printallactive(FILE *file);
319 ISC_MEMFUNC_SCOPE void
320 isc__mem_checkdestroyed(FILE *file);
321 ISC_MEMFUNC_SCOPE unsigned int
322 isc__mem_references(isc_mem_t *ctx0);
323 #endif
324
325 static struct isc__memmethods {
326         isc_memmethods_t methods;
327
328         /*%
329          * The following are defined just for avoiding unused static functions.
330          */
331 #ifndef BIND9
332         void *createx, *create, *create2, *ondestroy, *stats,
333                 *setquota, *getquota, *setname, *getname, *gettag;
334 #endif
335 } memmethods = {
336         {
337                 isc__mem_attach,
338                 isc__mem_detach,
339                 isc__mem_destroy,
340                 isc___mem_get,
341                 isc___mem_put,
342                 isc___mem_putanddetach,
343                 isc___mem_allocate,
344                 isc___mem_reallocate,
345                 isc___mem_strdup,
346                 isc___mem_free,
347                 isc__mem_setdestroycheck,
348                 isc__mem_setwater,
349                 isc__mem_waterack,
350                 isc__mem_inuse,
351                 isc__mem_isovermem,
352                 isc__mempool_create
353         }
354 #ifndef BIND9
355         ,
356         (void *)isc__mem_createx, (void *)isc__mem_create,
357         (void *)isc__mem_create2, (void *)isc__mem_ondestroy,
358         (void *)isc__mem_stats, (void *)isc__mem_setquota,
359         (void *)isc__mem_getquota, (void *)isc__mem_setname,
360         (void *)isc__mem_getname, (void *)isc__mem_gettag
361 #endif
362 };
363
364 static struct isc__mempoolmethods {
365         isc_mempoolmethods_t methods;
366
367         /*%
368          * The following are defined just for avoiding unused static functions.
369          */
370 #ifndef BIND9
371         void *getfreemax, *getfreecount, *getmaxalloc, *getfillcount;
372 #endif
373 } mempoolmethods = {
374         {
375                 isc__mempool_destroy,
376                 isc___mempool_get,
377                 isc___mempool_put,
378                 isc__mempool_getallocated,
379                 isc__mempool_setmaxalloc,
380                 isc__mempool_setfreemax,
381                 isc__mempool_setname,
382                 isc__mempool_associatelock,
383                 isc__mempool_setfillcount
384         }
385 #ifndef BIND9
386         ,
387         (void *)isc__mempool_getfreemax, (void *)isc__mempool_getfreecount,
388         (void *)isc__mempool_getmaxalloc, (void *)isc__mempool_getfillcount
389 #endif
390 };
391
392 /*!
393  * mctx must be locked.
394  */
395 static inline void
396 add_trace_entry(isc__mem_t *mctx, const void *ptr, unsigned int size
397                 FLARG)
398 {
399         debuglink_t *dl;
400         unsigned int i;
401         unsigned int mysize = size;
402
403         if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
404                 fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
405                                                ISC_MSG_ADDTRACE,
406                                                "add %p size %u "
407                                                "file %s line %u mctx %p\n"),
408                         ptr, size, file, line, mctx);
409
410         if (mctx->debuglist == NULL)
411                 return;
412
413         if (mysize > mctx->max_size)
414                 mysize = mctx->max_size;
415
416         dl = ISC_LIST_HEAD(mctx->debuglist[mysize]);
417         while (dl != NULL) {
418                 if (dl->count == DEBUGLIST_COUNT)
419                         goto next;
420                 for (i = 0; i < DEBUGLIST_COUNT; i++) {
421                         if (dl->ptr[i] == NULL) {
422                                 dl->ptr[i] = ptr;
423                                 dl->size[i] = size;
424                                 dl->file[i] = file;
425                                 dl->line[i] = line;
426                                 dl->count++;
427                                 return;
428                         }
429                 }
430         next:
431                 dl = ISC_LIST_NEXT(dl, link);
432         }
433
434         dl = malloc(sizeof(debuglink_t));
435         INSIST(dl != NULL);
436
437         ISC_LINK_INIT(dl, link);
438         for (i = 1; i < DEBUGLIST_COUNT; i++) {
439                 dl->ptr[i] = NULL;
440                 dl->size[i] = 0;
441                 dl->file[i] = NULL;
442                 dl->line[i] = 0;
443         }
444
445         dl->ptr[0] = ptr;
446         dl->size[0] = size;
447         dl->file[0] = file;
448         dl->line[0] = line;
449         dl->count = 1;
450
451         ISC_LIST_PREPEND(mctx->debuglist[mysize], dl, link);
452         mctx->debuglistcnt++;
453 }
454
455 static inline void
456 delete_trace_entry(isc__mem_t *mctx, const void *ptr, unsigned int size,
457                    const char *file, unsigned int line)
458 {
459         debuglink_t *dl;
460         unsigned int i;
461
462         if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
463                 fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
464                                                ISC_MSG_DELTRACE,
465                                                "del %p size %u "
466                                                "file %s line %u mctx %p\n"),
467                         ptr, size, file, line, mctx);
468
469         if (mctx->debuglist == NULL)
470                 return;
471
472         if (size > mctx->max_size)
473                 size = mctx->max_size;
474
475         dl = ISC_LIST_HEAD(mctx->debuglist[size]);
476         while (dl != NULL) {
477                 for (i = 0; i < DEBUGLIST_COUNT; i++) {
478                         if (dl->ptr[i] == ptr) {
479                                 dl->ptr[i] = NULL;
480                                 dl->size[i] = 0;
481                                 dl->file[i] = NULL;
482                                 dl->line[i] = 0;
483
484                                 INSIST(dl->count > 0);
485                                 dl->count--;
486                                 if (dl->count == 0) {
487                                         ISC_LIST_UNLINK(mctx->debuglist[size],
488                                                         dl, link);
489                                         free(dl);
490                                 }
491                                 return;
492                         }
493                 }
494                 dl = ISC_LIST_NEXT(dl, link);
495         }
496
497         /*
498          * If we get here, we didn't find the item on the list.  We're
499          * screwed.
500          */
501         INSIST(dl != NULL);
502 }
503 #endif /* ISC_MEM_TRACKLINES */
504
505 static inline size_t
506 rmsize(size_t size) {
507         /*
508          * round down to ALIGNMENT_SIZE
509          */
510         return (size & (~(ALIGNMENT_SIZE - 1)));
511 }
512
513 static inline size_t
514 quantize(size_t size) {
515         /*!
516          * Round up the result in order to get a size big
517          * enough to satisfy the request and be aligned on ALIGNMENT_SIZE
518          * byte boundaries.
519          */
520
521         if (size == 0U)
522                 return (ALIGNMENT_SIZE);
523         return ((size + ALIGNMENT_SIZE - 1) & (~(ALIGNMENT_SIZE - 1)));
524 }
525
526 static inline isc_boolean_t
527 more_basic_blocks(isc__mem_t *ctx) {
528         void *new;
529         unsigned char *curr, *next;
530         unsigned char *first, *last;
531         unsigned char **table;
532         unsigned int table_size;
533         size_t increment;
534         int i;
535
536         /* Require: we hold the context lock. */
537
538         /*
539          * Did we hit the quota for this context?
540          */
541         increment = NUM_BASIC_BLOCKS * ctx->mem_target;
542         if (ctx->quota != 0U && ctx->total + increment > ctx->quota)
543                 return (ISC_FALSE);
544
545         INSIST(ctx->basic_table_count <= ctx->basic_table_size);
546         if (ctx->basic_table_count == ctx->basic_table_size) {
547                 table_size = ctx->basic_table_size + TABLE_INCREMENT;
548                 table = (ctx->memalloc)(ctx->arg,
549                                         table_size * sizeof(unsigned char *));
550                 if (table == NULL) {
551                         ctx->memalloc_failures++;
552                         return (ISC_FALSE);
553                 }
554                 if (ctx->basic_table_size != 0) {
555                         memcpy(table, ctx->basic_table,
556                                ctx->basic_table_size *
557                                sizeof(unsigned char *));
558                         (ctx->memfree)(ctx->arg, ctx->basic_table);
559                 }
560                 ctx->basic_table = table;
561                 ctx->basic_table_size = table_size;
562         }
563
564         new = (ctx->memalloc)(ctx->arg, NUM_BASIC_BLOCKS * ctx->mem_target);
565         if (new == NULL) {
566                 ctx->memalloc_failures++;
567                 return (ISC_FALSE);
568         }
569         ctx->total += increment;
570         ctx->basic_table[ctx->basic_table_count] = new;
571         ctx->basic_table_count++;
572
573         curr = new;
574         next = curr + ctx->mem_target;
575         for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) {
576                 ((element *)curr)->next = (element *)next;
577                 curr = next;
578                 next += ctx->mem_target;
579         }
580         /*
581          * curr is now pointing at the last block in the
582          * array.
583          */
584         ((element *)curr)->next = NULL;
585         first = new;
586         last = first + NUM_BASIC_BLOCKS * ctx->mem_target - 1;
587         if (first < ctx->lowest || ctx->lowest == NULL)
588                 ctx->lowest = first;
589         if (last > ctx->highest)
590                 ctx->highest = last;
591         ctx->basic_blocks = new;
592
593         return (ISC_TRUE);
594 }
595
596 static inline isc_boolean_t
597 more_frags(isc__mem_t *ctx, size_t new_size) {
598         int i, frags;
599         size_t total_size;
600         void *new;
601         unsigned char *curr, *next;
602
603         /*!
604          * Try to get more fragments by chopping up a basic block.
605          */
606
607         if (ctx->basic_blocks == NULL) {
608                 if (!more_basic_blocks(ctx)) {
609                         /*
610                          * We can't get more memory from the OS, or we've
611                          * hit the quota for this context.
612                          */
613                         /*
614                          * XXXRTH  "At quota" notification here.
615                          */
616                         return (ISC_FALSE);
617                 }
618         }
619
620         total_size = ctx->mem_target;
621         new = ctx->basic_blocks;
622         ctx->basic_blocks = ctx->basic_blocks->next;
623         frags = total_size / new_size;
624         ctx->stats[new_size].blocks++;
625         ctx->stats[new_size].freefrags += frags;
626         /*
627          * Set up a linked-list of blocks of size
628          * "new_size".
629          */
630         curr = new;
631         next = curr + new_size;
632         total_size -= new_size;
633         for (i = 0; i < (frags - 1); i++) {
634                 ((element *)curr)->next = (element *)next;
635                 curr = next;
636                 next += new_size;
637                 total_size -= new_size;
638         }
639         /*
640          * Add the remaining fragment of the basic block to a free list.
641          */
642         total_size = rmsize(total_size);
643         if (total_size > 0U) {
644                 ((element *)next)->next = ctx->freelists[total_size];
645                 ctx->freelists[total_size] = (element *)next;
646                 ctx->stats[total_size].freefrags++;
647         }
648         /*
649          * curr is now pointing at the last block in the
650          * array.
651          */
652         ((element *)curr)->next = NULL;
653         ctx->freelists[new_size] = new;
654
655         return (ISC_TRUE);
656 }
657
658 static inline void *
659 mem_getunlocked(isc__mem_t *ctx, size_t size) {
660         size_t new_size = quantize(size);
661         void *ret;
662
663         if (size >= ctx->max_size || new_size >= ctx->max_size) {
664                 /*
665                  * memget() was called on something beyond our upper limit.
666                  */
667                 if (ctx->quota != 0U && ctx->total + size > ctx->quota) {
668                         ret = NULL;
669                         goto done;
670                 }
671                 ret = (ctx->memalloc)(ctx->arg, size);
672                 if (ret == NULL) {
673                         ctx->memalloc_failures++;
674                         goto done;
675                 }
676                 ctx->total += size;
677                 ctx->inuse += size;
678                 ctx->stats[ctx->max_size].gets++;
679                 ctx->stats[ctx->max_size].totalgets++;
680                 /*
681                  * If we don't set new_size to size, then the
682                  * ISC_MEM_FILL code might write over bytes we
683                  * don't own.
684                  */
685                 new_size = size;
686                 goto done;
687         }
688
689         /*
690          * If there are no blocks in the free list for this size, get a chunk
691          * of memory and then break it up into "new_size"-sized blocks, adding
692          * them to the free list.
693          */
694         if (ctx->freelists[new_size] == NULL && !more_frags(ctx, new_size))
695                 return (NULL);
696
697         /*
698          * The free list uses the "rounded-up" size "new_size".
699          */
700         ret = ctx->freelists[new_size];
701         ctx->freelists[new_size] = ctx->freelists[new_size]->next;
702
703         /*
704          * The stats[] uses the _actual_ "size" requested by the
705          * caller, with the caveat (in the code above) that "size" >= the
706          * max. size (max_size) ends up getting recorded as a call to
707          * max_size.
708          */
709         ctx->stats[size].gets++;
710         ctx->stats[size].totalgets++;
711         ctx->stats[new_size].freefrags--;
712         ctx->inuse += new_size;
713
714  done:
715
716 #if ISC_MEM_FILL
717         if (ret != NULL)
718                 memset(ret, 0xbe, new_size); /* Mnemonic for "beef". */
719 #endif
720
721         return (ret);
722 }
723
724 #if ISC_MEM_FILL && ISC_MEM_CHECKOVERRUN
725 static inline void
726 check_overrun(void *mem, size_t size, size_t new_size) {
727         unsigned char *cp;
728
729         cp = (unsigned char *)mem;
730         cp += size;
731         while (size < new_size) {
732                 INSIST(*cp == 0xbe);
733                 cp++;
734                 size++;
735         }
736 }
737 #endif
738
739 static inline void
740 mem_putunlocked(isc__mem_t *ctx, void *mem, size_t size) {
741         size_t new_size = quantize(size);
742
743         if (size == ctx->max_size || new_size >= ctx->max_size) {
744                 /*
745                  * memput() called on something beyond our upper limit.
746                  */
747 #if ISC_MEM_FILL
748                 memset(mem, 0xde, size); /* Mnemonic for "dead". */
749 #endif
750                 (ctx->memfree)(ctx->arg, mem);
751                 INSIST(ctx->stats[ctx->max_size].gets != 0U);
752                 ctx->stats[ctx->max_size].gets--;
753                 INSIST(size <= ctx->total);
754                 ctx->inuse -= size;
755                 ctx->total -= size;
756                 return;
757         }
758
759 #if ISC_MEM_FILL
760 #if ISC_MEM_CHECKOVERRUN
761         check_overrun(mem, size, new_size);
762 #endif
763         memset(mem, 0xde, new_size); /* Mnemonic for "dead". */
764 #endif
765
766         /*
767          * The free list uses the "rounded-up" size "new_size".
768          */
769         ((element *)mem)->next = ctx->freelists[new_size];
770         ctx->freelists[new_size] = (element *)mem;
771
772         /*
773          * The stats[] uses the _actual_ "size" requested by the
774          * caller, with the caveat (in the code above) that "size" >= the
775          * max. size (max_size) ends up getting recorded as a call to
776          * max_size.
777          */
778         INSIST(ctx->stats[size].gets != 0U);
779         ctx->stats[size].gets--;
780         ctx->stats[new_size].freefrags++;
781         ctx->inuse -= new_size;
782 }
783
784 /*!
785  * Perform a malloc, doing memory filling and overrun detection as necessary.
786  */
787 static inline void *
788 mem_get(isc__mem_t *ctx, size_t size) {
789         char *ret;
790
791 #if ISC_MEM_CHECKOVERRUN
792         size += 1;
793 #endif
794
795         ret = (ctx->memalloc)(ctx->arg, size);
796         if (ret == NULL)
797                 ctx->memalloc_failures++;
798
799 #if ISC_MEM_FILL
800         if (ret != NULL)
801                 memset(ret, 0xbe, size); /* Mnemonic for "beef". */
802 #else
803 #  if ISC_MEM_CHECKOVERRUN
804         if (ret != NULL)
805                 ret[size-1] = 0xbe;
806 #  endif
807 #endif
808
809         return (ret);
810 }
811
812 /*!
813  * Perform a free, doing memory filling and overrun detection as necessary.
814  */
815 static inline void
816 mem_put(isc__mem_t *ctx, void *mem, size_t size) {
817 #if ISC_MEM_CHECKOVERRUN
818         INSIST(((unsigned char *)mem)[size] == 0xbe);
819 #endif
820 #if ISC_MEM_FILL
821         memset(mem, 0xde, size); /* Mnemonic for "dead". */
822 #else
823         UNUSED(size);
824 #endif
825         (ctx->memfree)(ctx->arg, mem);
826 }
827
828 /*!
829  * Update internal counters after a memory get.
830  */
831 static inline void
832 mem_getstats(isc__mem_t *ctx, size_t size) {
833         ctx->total += size;
834         ctx->inuse += size;
835
836         if (size > ctx->max_size) {
837                 ctx->stats[ctx->max_size].gets++;
838                 ctx->stats[ctx->max_size].totalgets++;
839         } else {
840                 ctx->stats[size].gets++;
841                 ctx->stats[size].totalgets++;
842         }
843 }
844
845 /*!
846  * Update internal counters after a memory put.
847  */
848 static inline void
849 mem_putstats(isc__mem_t *ctx, void *ptr, size_t size) {
850         UNUSED(ptr);
851
852         INSIST(ctx->inuse >= size);
853         ctx->inuse -= size;
854
855         if (size > ctx->max_size) {
856                 INSIST(ctx->stats[ctx->max_size].gets > 0U);
857                 ctx->stats[ctx->max_size].gets--;
858         } else {
859                 INSIST(ctx->stats[size].gets > 0U);
860                 ctx->stats[size].gets--;
861         }
862 }
863
864 /*
865  * Private.
866  */
867
868 static void *
869 default_memalloc(void *arg, size_t size) {
870         UNUSED(arg);
871         if (size == 0U)
872                 size = 1;
873         return (malloc(size));
874 }
875
876 static void
877 default_memfree(void *arg, void *ptr) {
878         UNUSED(arg);
879         free(ptr);
880 }
881
882 static void
883 initialize_action(void) {
884         RUNTIME_CHECK(isc_mutex_init(&lock) == ISC_R_SUCCESS);
885         ISC_LIST_INIT(contexts);
886         totallost = 0;
887 }
888
889 /*
890  * Public.
891  */
892
893 ISC_MEMFUNC_SCOPE isc_result_t
894 isc__mem_createx(size_t init_max_size, size_t target_size,
895                  isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
896                  isc_mem_t **ctxp)
897 {
898         return (isc__mem_createx2(init_max_size, target_size, memalloc, memfree,
899                                   arg, ctxp, ISC_MEMFLAG_DEFAULT));
900
901 }
902
903 ISC_MEMFUNC_SCOPE isc_result_t
904 isc__mem_createx2(size_t init_max_size, size_t target_size,
905                   isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
906                   isc_mem_t **ctxp, unsigned int flags)
907 {
908         isc__mem_t *ctx;
909         isc_result_t result;
910
911         REQUIRE(ctxp != NULL && *ctxp == NULL);
912         REQUIRE(memalloc != NULL);
913         REQUIRE(memfree != NULL);
914
915         INSIST((ALIGNMENT_SIZE & (ALIGNMENT_SIZE - 1)) == 0);
916
917         RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
918
919         ctx = (memalloc)(arg, sizeof(*ctx));
920         if (ctx == NULL)
921                 return (ISC_R_NOMEMORY);
922
923         if ((flags & ISC_MEMFLAG_NOLOCK) == 0) {
924                 result = isc_mutex_init(&ctx->lock);
925                 if (result != ISC_R_SUCCESS) {
926                         (memfree)(arg, ctx);
927                         return (result);
928                 }
929         }
930
931         if (init_max_size == 0U)
932                 ctx->max_size = DEF_MAX_SIZE;
933         else
934                 ctx->max_size = init_max_size;
935         ctx->flags = flags;
936         ctx->references = 1;
937         memset(ctx->name, 0, sizeof(ctx->name));
938         ctx->tag = NULL;
939         ctx->quota = 0;
940         ctx->total = 0;
941         ctx->inuse = 0;
942         ctx->maxinuse = 0;
943         ctx->hi_water = 0;
944         ctx->lo_water = 0;
945         ctx->hi_called = ISC_FALSE;
946         ctx->is_overmem = ISC_FALSE;
947         ctx->water = NULL;
948         ctx->water_arg = NULL;
949         ctx->common.impmagic = MEM_MAGIC;
950         ctx->common.magic = ISCAPI_MCTX_MAGIC;
951         ctx->common.methods = (isc_memmethods_t *)&memmethods;
952         isc_ondestroy_init(&ctx->ondestroy);
953         ctx->memalloc = memalloc;
954         ctx->memfree = memfree;
955         ctx->arg = arg;
956         ctx->stats = NULL;
957         ctx->checkfree = ISC_TRUE;
958 #if ISC_MEM_TRACKLINES
959         ctx->debuglist = NULL;
960         ctx->debuglistcnt = 0;
961 #endif
962         ISC_LIST_INIT(ctx->pools);
963         ctx->poolcnt = 0;
964         ctx->freelists = NULL;
965         ctx->basic_blocks = NULL;
966         ctx->basic_table = NULL;
967         ctx->basic_table_count = 0;
968         ctx->basic_table_size = 0;
969         ctx->lowest = NULL;
970         ctx->highest = NULL;
971
972         ctx->stats = (memalloc)(arg,
973                                 (ctx->max_size+1) * sizeof(struct stats));
974         if (ctx->stats == NULL) {
975                 result = ISC_R_NOMEMORY;
976                 goto error;
977         }
978         memset(ctx->stats, 0, (ctx->max_size + 1) * sizeof(struct stats));
979
980         if ((flags & ISC_MEMFLAG_INTERNAL) != 0) {
981                 if (target_size == 0U)
982                         ctx->mem_target = DEF_MEM_TARGET;
983                 else
984                         ctx->mem_target = target_size;
985                 ctx->freelists = (memalloc)(arg, ctx->max_size *
986                                                  sizeof(element *));
987                 if (ctx->freelists == NULL) {
988                         result = ISC_R_NOMEMORY;
989                         goto error;
990                 }
991                 memset(ctx->freelists, 0,
992                        ctx->max_size * sizeof(element *));
993         }
994
995 #if ISC_MEM_TRACKLINES
996         if ((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0) {
997                 unsigned int i;
998
999                 ctx->debuglist = (memalloc)(arg,
1000                                       (ctx->max_size+1) * sizeof(debuglist_t));
1001                 if (ctx->debuglist == NULL) {
1002                         result = ISC_R_NOMEMORY;
1003                         goto error;
1004                 }
1005                 for (i = 0; i <= ctx->max_size; i++)
1006                         ISC_LIST_INIT(ctx->debuglist[i]);
1007         }
1008 #endif
1009
1010         ctx->memalloc_failures = 0;
1011
1012         LOCK(&lock);
1013         ISC_LIST_INITANDAPPEND(contexts, ctx, link);
1014         UNLOCK(&lock);
1015
1016         *ctxp = (isc_mem_t *)ctx;
1017         return (ISC_R_SUCCESS);
1018
1019   error:
1020         if (ctx != NULL) {
1021                 if (ctx->stats != NULL)
1022                         (memfree)(arg, ctx->stats);
1023                 if (ctx->freelists != NULL)
1024                         (memfree)(arg, ctx->freelists);
1025 #if ISC_MEM_TRACKLINES
1026                 if (ctx->debuglist != NULL)
1027                         (ctx->memfree)(ctx->arg, ctx->debuglist);
1028 #endif /* ISC_MEM_TRACKLINES */
1029                 if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
1030                         DESTROYLOCK(&ctx->lock);
1031                 (memfree)(arg, ctx);
1032         }
1033
1034         return (result);
1035 }
1036
1037 ISC_MEMFUNC_SCOPE isc_result_t
1038 isc__mem_create(size_t init_max_size, size_t target_size, isc_mem_t **ctxp) {
1039         return (isc__mem_createx2(init_max_size, target_size,
1040                                   default_memalloc, default_memfree, NULL,
1041                                   ctxp, ISC_MEMFLAG_DEFAULT));
1042 }
1043
1044 ISC_MEMFUNC_SCOPE isc_result_t
1045 isc__mem_create2(size_t init_max_size, size_t target_size,
1046                  isc_mem_t **ctxp, unsigned int flags)
1047 {
1048         return (isc__mem_createx2(init_max_size, target_size,
1049                                   default_memalloc, default_memfree, NULL,
1050                                   ctxp, flags));
1051 }
1052
1053 static void
1054 destroy(isc__mem_t *ctx) {
1055         unsigned int i;
1056         isc_ondestroy_t ondest;
1057
1058         LOCK(&lock);
1059         ISC_LIST_UNLINK(contexts, ctx, link);
1060         totallost += ctx->inuse;
1061         UNLOCK(&lock);
1062
1063         ctx->common.impmagic = 0;
1064         ctx->common.magic = 0;
1065
1066         INSIST(ISC_LIST_EMPTY(ctx->pools));
1067
1068 #if ISC_MEM_TRACKLINES
1069         if (ctx->debuglist != NULL) {
1070                 if (ctx->checkfree) {
1071                         for (i = 0; i <= ctx->max_size; i++) {
1072                                 if (!ISC_LIST_EMPTY(ctx->debuglist[i]))
1073                                         print_active(ctx, stderr);
1074                                 INSIST(ISC_LIST_EMPTY(ctx->debuglist[i]));
1075                         }
1076                 } else {
1077                         debuglink_t *dl;
1078
1079                         for (i = 0; i <= ctx->max_size; i++)
1080                                 for (dl = ISC_LIST_HEAD(ctx->debuglist[i]);
1081                                      dl != NULL;
1082                                      dl = ISC_LIST_HEAD(ctx->debuglist[i])) {
1083                                         ISC_LIST_UNLINK(ctx->debuglist[i],
1084                                                         dl, link);
1085                                         free(dl);
1086                                 }
1087                 }
1088                 (ctx->memfree)(ctx->arg, ctx->debuglist);
1089         }
1090 #endif
1091         INSIST(ctx->references == 0);
1092
1093         if (ctx->checkfree) {
1094                 for (i = 0; i <= ctx->max_size; i++) {
1095 #if ISC_MEM_TRACKLINES
1096                         if (ctx->stats[i].gets != 0U)
1097                                 print_active(ctx, stderr);
1098 #endif
1099                         INSIST(ctx->stats[i].gets == 0U);
1100                 }
1101         }
1102
1103         (ctx->memfree)(ctx->arg, ctx->stats);
1104
1105         if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1106                 for (i = 0; i < ctx->basic_table_count; i++)
1107                         (ctx->memfree)(ctx->arg, ctx->basic_table[i]);
1108                 (ctx->memfree)(ctx->arg, ctx->freelists);
1109                 if (ctx->basic_table != NULL)
1110                         (ctx->memfree)(ctx->arg, ctx->basic_table);
1111         }
1112
1113         ondest = ctx->ondestroy;
1114
1115         if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
1116                 DESTROYLOCK(&ctx->lock);
1117         (ctx->memfree)(ctx->arg, ctx);
1118
1119         isc_ondestroy_notify(&ondest, ctx);
1120 }
1121
1122 ISC_MEMFUNC_SCOPE void
1123 isc__mem_attach(isc_mem_t *source0, isc_mem_t **targetp) {
1124         isc__mem_t *source = (isc__mem_t *)source0;
1125
1126         REQUIRE(VALID_CONTEXT(source));
1127         REQUIRE(targetp != NULL && *targetp == NULL);
1128
1129         MCTXLOCK(source, &source->lock);
1130         source->references++;
1131         MCTXUNLOCK(source, &source->lock);
1132
1133         *targetp = (isc_mem_t *)source;
1134 }
1135
1136 ISC_MEMFUNC_SCOPE void
1137 isc__mem_detach(isc_mem_t **ctxp) {
1138         isc__mem_t *ctx;
1139         isc_boolean_t want_destroy = ISC_FALSE;
1140
1141         REQUIRE(ctxp != NULL);
1142         ctx = (isc__mem_t *)*ctxp;
1143         REQUIRE(VALID_CONTEXT(ctx));
1144
1145         MCTXLOCK(ctx, &ctx->lock);
1146         INSIST(ctx->references > 0);
1147         ctx->references--;
1148         if (ctx->references == 0)
1149                 want_destroy = ISC_TRUE;
1150         MCTXUNLOCK(ctx, &ctx->lock);
1151
1152         if (want_destroy)
1153                 destroy(ctx);
1154
1155         *ctxp = NULL;
1156 }
1157
1158 /*
1159  * isc_mem_putanddetach() is the equivalent of:
1160  *
1161  * mctx = NULL;
1162  * isc_mem_attach(ptr->mctx, &mctx);
1163  * isc_mem_detach(&ptr->mctx);
1164  * isc_mem_put(mctx, ptr, sizeof(*ptr);
1165  * isc_mem_detach(&mctx);
1166  */
1167
1168 ISC_MEMFUNC_SCOPE void
1169 isc___mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) {
1170         isc__mem_t *ctx;
1171         isc_boolean_t want_destroy = ISC_FALSE;
1172         size_info *si;
1173         size_t oldsize;
1174
1175         REQUIRE(ctxp != NULL);
1176         ctx = (isc__mem_t *)*ctxp;
1177         REQUIRE(VALID_CONTEXT(ctx));
1178         REQUIRE(ptr != NULL);
1179
1180         /*
1181          * Must be before mem_putunlocked() as ctxp is usually within
1182          * [ptr..ptr+size).
1183          */
1184         *ctxp = NULL;
1185
1186         if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) {
1187                 if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) {
1188                         si = &(((size_info *)ptr)[-1]);
1189                         oldsize = si->u.size - ALIGNMENT_SIZE;
1190                         if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
1191                                 oldsize -= ALIGNMENT_SIZE;
1192                         INSIST(oldsize == size);
1193                 }
1194                 isc__mem_free((isc_mem_t *)ctx, ptr FLARG_PASS);
1195
1196                 MCTXLOCK(ctx, &ctx->lock);
1197                 ctx->references--;
1198                 if (ctx->references == 0)
1199                         want_destroy = ISC_TRUE;
1200                 MCTXUNLOCK(ctx, &ctx->lock);
1201                 if (want_destroy)
1202                         destroy(ctx);
1203
1204                 return;
1205         }
1206
1207         if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1208                 MCTXLOCK(ctx, &ctx->lock);
1209                 mem_putunlocked(ctx, ptr, size);
1210         } else {
1211                 mem_put(ctx, ptr, size);
1212                 MCTXLOCK(ctx, &ctx->lock);
1213                 mem_putstats(ctx, ptr, size);
1214         }
1215
1216         DELETE_TRACE(ctx, ptr, size, file, line);
1217         INSIST(ctx->references > 0);
1218         ctx->references--;
1219         if (ctx->references == 0)
1220                 want_destroy = ISC_TRUE;
1221
1222         MCTXUNLOCK(ctx, &ctx->lock);
1223
1224         if (want_destroy)
1225                 destroy(ctx);
1226 }
1227
1228 ISC_MEMFUNC_SCOPE void
1229 isc__mem_destroy(isc_mem_t **ctxp) {
1230         isc__mem_t *ctx;
1231
1232         /*
1233          * This routine provides legacy support for callers who use mctxs
1234          * without attaching/detaching.
1235          */
1236
1237         REQUIRE(ctxp != NULL);
1238         ctx = (isc__mem_t *)*ctxp;
1239         REQUIRE(VALID_CONTEXT(ctx));
1240
1241         MCTXLOCK(ctx, &ctx->lock);
1242 #if ISC_MEM_TRACKLINES
1243         if (ctx->references != 1)
1244                 print_active(ctx, stderr);
1245 #endif
1246         REQUIRE(ctx->references == 1);
1247         ctx->references--;
1248         MCTXUNLOCK(ctx, &ctx->lock);
1249
1250         destroy(ctx);
1251
1252         *ctxp = NULL;
1253 }
1254
1255 ISC_MEMFUNC_SCOPE isc_result_t
1256 isc__mem_ondestroy(isc_mem_t *ctx0, isc_task_t *task, isc_event_t **event) {
1257         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1258         isc_result_t res;
1259
1260         MCTXLOCK(ctx, &ctx->lock);
1261         res = isc_ondestroy_register(&ctx->ondestroy, task, event);
1262         MCTXUNLOCK(ctx, &ctx->lock);
1263
1264         return (res);
1265 }
1266
1267 ISC_MEMFUNC_SCOPE void *
1268 isc___mem_get(isc_mem_t *ctx0, size_t size FLARG) {
1269         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1270         void *ptr;
1271         isc_boolean_t call_water = ISC_FALSE;
1272
1273         REQUIRE(VALID_CONTEXT(ctx));
1274
1275         if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0)
1276                 return (isc__mem_allocate(ctx0, size FLARG_PASS));
1277
1278         if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1279                 MCTXLOCK(ctx, &ctx->lock);
1280                 ptr = mem_getunlocked(ctx, size);
1281         } else {
1282                 ptr = mem_get(ctx, size);
1283                 MCTXLOCK(ctx, &ctx->lock);
1284                 if (ptr != NULL)
1285                         mem_getstats(ctx, size);
1286         }
1287
1288         ADD_TRACE(ctx, ptr, size, file, line);
1289         if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1290             !ctx->is_overmem) {
1291                 ctx->is_overmem = ISC_TRUE;
1292         }
1293         if (ctx->hi_water != 0U && !ctx->hi_called &&
1294             ctx->inuse > ctx->hi_water) {
1295                 call_water = ISC_TRUE;
1296         }
1297         if (ctx->inuse > ctx->maxinuse) {
1298                 ctx->maxinuse = ctx->inuse;
1299                 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1300                     (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
1301                         fprintf(stderr, "maxinuse = %lu\n",
1302                                 (unsigned long)ctx->inuse);
1303         }
1304         MCTXUNLOCK(ctx, &ctx->lock);
1305
1306         if (call_water)
1307                 (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
1308
1309         return (ptr);
1310 }
1311
1312 ISC_MEMFUNC_SCOPE void
1313 isc___mem_put(isc_mem_t *ctx0, void *ptr, size_t size FLARG) {
1314         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1315         isc_boolean_t call_water = ISC_FALSE;
1316         size_info *si;
1317         size_t oldsize;
1318
1319         REQUIRE(VALID_CONTEXT(ctx));
1320         REQUIRE(ptr != NULL);
1321
1322         if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) {
1323                 if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) {
1324                         si = &(((size_info *)ptr)[-1]);
1325                         oldsize = si->u.size - ALIGNMENT_SIZE;
1326                         if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
1327                                 oldsize -= ALIGNMENT_SIZE;
1328                         INSIST(oldsize == size);
1329                 }
1330                 isc__mem_free((isc_mem_t *)ctx, ptr FLARG_PASS);
1331                 return;
1332         }
1333
1334         if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1335                 MCTXLOCK(ctx, &ctx->lock);
1336                 mem_putunlocked(ctx, ptr, size);
1337         } else {
1338                 mem_put(ctx, ptr, size);
1339                 MCTXLOCK(ctx, &ctx->lock);
1340                 mem_putstats(ctx, ptr, size);
1341         }
1342
1343         DELETE_TRACE(ctx, ptr, size, file, line);
1344
1345         /*
1346          * The check against ctx->lo_water == 0 is for the condition
1347          * when the context was pushed over hi_water but then had
1348          * isc_mem_setwater() called with 0 for hi_water and lo_water.
1349          */
1350         if (ctx->is_overmem &&
1351             (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1352                 ctx->is_overmem = ISC_FALSE;
1353         }
1354         if (ctx->hi_called &&
1355             (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1356                 if (ctx->water != NULL)
1357                         call_water = ISC_TRUE;
1358         }
1359         MCTXUNLOCK(ctx, &ctx->lock);
1360
1361         if (call_water)
1362                 (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
1363 }
1364
1365 ISC_MEMFUNC_SCOPE void
1366 isc__mem_waterack(isc_mem_t *ctx0, int flag) {
1367         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1368
1369         REQUIRE(VALID_CONTEXT(ctx));
1370
1371         MCTXLOCK(ctx, &ctx->lock);
1372         if (flag == ISC_MEM_LOWATER)
1373                 ctx->hi_called = ISC_FALSE;
1374         else if (flag == ISC_MEM_HIWATER)
1375                 ctx->hi_called = ISC_TRUE;
1376         MCTXUNLOCK(ctx, &ctx->lock);
1377 }
1378
1379 #if ISC_MEM_TRACKLINES
1380 static void
1381 print_active(isc__mem_t *mctx, FILE *out) {
1382         if (mctx->debuglist != NULL) {
1383                 debuglink_t *dl;
1384                 unsigned int i, j;
1385                 const char *format;
1386                 isc_boolean_t found;
1387
1388                 fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1389                                             ISC_MSG_DUMPALLOC,
1390                                             "Dump of all outstanding "
1391                                             "memory allocations:\n"));
1392                 found = ISC_FALSE;
1393                 format = isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1394                                         ISC_MSG_PTRFILELINE,
1395                                         "\tptr %p size %u file %s line %u\n");
1396                 for (i = 0; i <= mctx->max_size; i++) {
1397                         dl = ISC_LIST_HEAD(mctx->debuglist[i]);
1398
1399                         if (dl != NULL)
1400                                 found = ISC_TRUE;
1401
1402                         while (dl != NULL) {
1403                                 for (j = 0; j < DEBUGLIST_COUNT; j++)
1404                                         if (dl->ptr[j] != NULL)
1405                                                 fprintf(out, format,
1406                                                         dl->ptr[j],
1407                                                         dl->size[j],
1408                                                         dl->file[j],
1409                                                         dl->line[j]);
1410                                 dl = ISC_LIST_NEXT(dl, link);
1411                         }
1412                 }
1413                 if (!found)
1414                         fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1415                                                     ISC_MSG_NONE, "\tNone.\n"));
1416         }
1417 }
1418 #endif
1419
1420 /*
1421  * Print the stats[] on the stream "out" with suitable formatting.
1422  */
1423 ISC_MEMFUNC_SCOPE void
1424 isc__mem_stats(isc_mem_t *ctx0, FILE *out) {
1425         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1426         size_t i;
1427         const struct stats *s;
1428         const isc__mempool_t *pool;
1429
1430         REQUIRE(VALID_CONTEXT(ctx));
1431         MCTXLOCK(ctx, &ctx->lock);
1432
1433         for (i = 0; i <= ctx->max_size; i++) {
1434                 s = &ctx->stats[i];
1435
1436                 if (s->totalgets == 0U && s->gets == 0U)
1437                         continue;
1438                 fprintf(out, "%s%5lu: %11lu gets, %11lu rem",
1439                         (i == ctx->max_size) ? ">=" : "  ",
1440                         (unsigned long) i, s->totalgets, s->gets);
1441                 if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0 &&
1442                     (s->blocks != 0U || s->freefrags != 0U))
1443                         fprintf(out, " (%lu bl, %lu ff)",
1444                                 s->blocks, s->freefrags);
1445                 fputc('\n', out);
1446         }
1447
1448         /*
1449          * Note that since a pool can be locked now, these stats might be
1450          * somewhat off if the pool is in active use at the time the stats
1451          * are dumped.  The link fields are protected by the isc_mem_t's
1452          * lock, however, so walking this list and extracting integers from
1453          * stats fields is always safe.
1454          */
1455         pool = ISC_LIST_HEAD(ctx->pools);
1456         if (pool != NULL) {
1457                 fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1458                                             ISC_MSG_POOLSTATS,
1459                                             "[Pool statistics]\n"));
1460                 fprintf(out, "%15s %10s %10s %10s %10s %10s %10s %10s %1s\n",
1461                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1462                                        ISC_MSG_POOLNAME, "name"),
1463                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1464                                        ISC_MSG_POOLSIZE, "size"),
1465                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1466                                        ISC_MSG_POOLMAXALLOC, "maxalloc"),
1467                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1468                                        ISC_MSG_POOLALLOCATED, "allocated"),
1469                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1470                                        ISC_MSG_POOLFREECOUNT, "freecount"),
1471                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1472                                        ISC_MSG_POOLFREEMAX, "freemax"),
1473                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1474                                        ISC_MSG_POOLFILLCOUNT, "fillcount"),
1475                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1476                                        ISC_MSG_POOLGETS, "gets"),
1477                         "L");
1478         }
1479         while (pool != NULL) {
1480                 fprintf(out, "%15s %10lu %10u %10u %10u %10u %10u %10u %s\n",
1481                         pool->name, (unsigned long) pool->size, pool->maxalloc,
1482                         pool->allocated, pool->freecount, pool->freemax,
1483                         pool->fillcount, pool->gets,
1484                         (pool->lock == NULL ? "N" : "Y"));
1485                 pool = ISC_LIST_NEXT(pool, link);
1486         }
1487
1488 #if ISC_MEM_TRACKLINES
1489         print_active(ctx, out);
1490 #endif
1491
1492         MCTXUNLOCK(ctx, &ctx->lock);
1493 }
1494
1495 /*
1496  * Replacements for malloc() and free() -- they implicitly remember the
1497  * size of the object allocated (with some additional overhead).
1498  */
1499
1500 static void *
1501 isc__mem_allocateunlocked(isc_mem_t *ctx0, size_t size) {
1502         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1503         size_info *si;
1504
1505         size += ALIGNMENT_SIZE;
1506         if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
1507                 size += ALIGNMENT_SIZE;
1508
1509         if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0)
1510                 si = mem_getunlocked(ctx, size);
1511         else
1512                 si = mem_get(ctx, size);
1513
1514         if (si == NULL)
1515                 return (NULL);
1516         if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
1517                 si->u.ctx = ctx;
1518                 si++;
1519         }
1520         si->u.size = size;
1521         return (&si[1]);
1522 }
1523
1524 ISC_MEMFUNC_SCOPE void *
1525 isc___mem_allocate(isc_mem_t *ctx0, size_t size FLARG) {
1526         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1527         size_info *si;
1528         isc_boolean_t call_water = ISC_FALSE;
1529
1530         REQUIRE(VALID_CONTEXT(ctx));
1531
1532         if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1533                 MCTXLOCK(ctx, &ctx->lock);
1534                 si = isc__mem_allocateunlocked((isc_mem_t *)ctx, size);
1535         } else {
1536                 si = isc__mem_allocateunlocked((isc_mem_t *)ctx, size);
1537                 MCTXLOCK(ctx, &ctx->lock);
1538                 if (si != NULL)
1539                         mem_getstats(ctx, si[-1].u.size);
1540         }
1541
1542 #if ISC_MEM_TRACKLINES
1543         ADD_TRACE(ctx, si, si[-1].u.size, file, line);
1544 #endif
1545         if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1546             !ctx->is_overmem) {
1547                 ctx->is_overmem = ISC_TRUE;
1548         }
1549
1550         if (ctx->hi_water != 0U && !ctx->hi_called &&
1551             ctx->inuse > ctx->hi_water) {
1552                 ctx->hi_called = ISC_TRUE;
1553                 call_water = ISC_TRUE;
1554         }
1555         if (ctx->inuse > ctx->maxinuse) {
1556                 ctx->maxinuse = ctx->inuse;
1557                 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1558                     (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
1559                         fprintf(stderr, "maxinuse = %lu\n",
1560                                 (unsigned long)ctx->inuse);
1561         }
1562         MCTXUNLOCK(ctx, &ctx->lock);
1563
1564         if (call_water)
1565                 (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
1566
1567         return (si);
1568 }
1569
1570 ISC_MEMFUNC_SCOPE void *
1571 isc___mem_reallocate(isc_mem_t *ctx0, void *ptr, size_t size FLARG) {
1572         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1573         void *new_ptr = NULL;
1574         size_t oldsize, copysize;
1575
1576         REQUIRE(VALID_CONTEXT(ctx));
1577
1578         /*
1579          * This function emulates the realloc(3) standard library function:
1580          * - if size > 0, allocate new memory; and if ptr is non NULL, copy
1581          *   as much of the old contents to the new buffer and free the old one.
1582          *   Note that when allocation fails the original pointer is intact;
1583          *   the caller must free it.
1584          * - if size is 0 and ptr is non NULL, simply free the given ptr.
1585          * - this function returns:
1586          *     pointer to the newly allocated memory, or
1587          *     NULL if allocation fails or doesn't happen.
1588          */
1589         if (size > 0U) {
1590                 new_ptr = isc__mem_allocate(ctx0, size FLARG_PASS);
1591                 if (new_ptr != NULL && ptr != NULL) {
1592                         oldsize = (((size_info *)ptr)[-1]).u.size;
1593                         INSIST(oldsize >= ALIGNMENT_SIZE);
1594                         oldsize -= ALIGNMENT_SIZE;
1595                         if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
1596                                 INSIST(oldsize >= ALIGNMENT_SIZE);
1597                                 oldsize -= ALIGNMENT_SIZE;
1598                         }
1599                         copysize = (oldsize > size) ? size : oldsize;
1600                         memcpy(new_ptr, ptr, copysize);
1601                         isc__mem_free(ctx0, ptr FLARG_PASS);
1602                 }
1603         } else if (ptr != NULL)
1604                 isc__mem_free(ctx0, ptr FLARG_PASS);
1605
1606         return (new_ptr);
1607 }
1608
1609 ISC_MEMFUNC_SCOPE void
1610 isc___mem_free(isc_mem_t *ctx0, void *ptr FLARG) {
1611         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1612         size_info *si;
1613         size_t size;
1614         isc_boolean_t call_water= ISC_FALSE;
1615
1616         REQUIRE(VALID_CONTEXT(ctx));
1617         REQUIRE(ptr != NULL);
1618
1619         if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
1620                 si = &(((size_info *)ptr)[-2]);
1621                 REQUIRE(si->u.ctx == ctx);
1622                 size = si[1].u.size;
1623         } else {
1624                 si = &(((size_info *)ptr)[-1]);
1625                 size = si->u.size;
1626         }
1627
1628         if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1629                 MCTXLOCK(ctx, &ctx->lock);
1630                 mem_putunlocked(ctx, si, size);
1631         } else {
1632                 mem_put(ctx, si, size);
1633                 MCTXLOCK(ctx, &ctx->lock);
1634                 mem_putstats(ctx, si, size);
1635         }
1636
1637         DELETE_TRACE(ctx, ptr, size, file, line);
1638
1639         /*
1640          * The check against ctx->lo_water == 0 is for the condition
1641          * when the context was pushed over hi_water but then had
1642          * isc_mem_setwater() called with 0 for hi_water and lo_water.
1643          */
1644         if (ctx->is_overmem &&
1645             (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1646                 ctx->is_overmem = ISC_FALSE;
1647         }
1648
1649         if (ctx->hi_called &&
1650             (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1651                 ctx->hi_called = ISC_FALSE;
1652
1653                 if (ctx->water != NULL)
1654                         call_water = ISC_TRUE;
1655         }
1656         MCTXUNLOCK(ctx, &ctx->lock);
1657
1658         if (call_water)
1659                 (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
1660 }
1661
1662
1663 /*
1664  * Other useful things.
1665  */
1666
1667 ISC_MEMFUNC_SCOPE char *
1668 isc___mem_strdup(isc_mem_t *mctx0, const char *s FLARG) {
1669         isc__mem_t *mctx = (isc__mem_t *)mctx0;
1670         size_t len;
1671         char *ns;
1672
1673         REQUIRE(VALID_CONTEXT(mctx));
1674         REQUIRE(s != NULL);
1675
1676         len = strlen(s);
1677
1678         ns = isc___mem_allocate((isc_mem_t *)mctx, len + 1 FLARG_PASS);
1679
1680         if (ns != NULL)
1681                 strncpy(ns, s, len + 1);
1682
1683         return (ns);
1684 }
1685
1686 ISC_MEMFUNC_SCOPE void
1687 isc__mem_setdestroycheck(isc_mem_t *ctx0, isc_boolean_t flag) {
1688         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1689
1690         REQUIRE(VALID_CONTEXT(ctx));
1691         MCTXLOCK(ctx, &ctx->lock);
1692
1693         ctx->checkfree = flag;
1694
1695         MCTXUNLOCK(ctx, &ctx->lock);
1696 }
1697
1698 /*
1699  * Quotas
1700  */
1701
1702 ISC_MEMFUNC_SCOPE void
1703 isc__mem_setquota(isc_mem_t *ctx0, size_t quota) {
1704         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1705
1706         REQUIRE(VALID_CONTEXT(ctx));
1707         MCTXLOCK(ctx, &ctx->lock);
1708
1709         ctx->quota = quota;
1710
1711         MCTXUNLOCK(ctx, &ctx->lock);
1712 }
1713
1714 ISC_MEMFUNC_SCOPE size_t
1715 isc__mem_getquota(isc_mem_t *ctx0) {
1716         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1717         size_t quota;
1718
1719         REQUIRE(VALID_CONTEXT(ctx));
1720         MCTXLOCK(ctx, &ctx->lock);
1721
1722         quota = ctx->quota;
1723
1724         MCTXUNLOCK(ctx, &ctx->lock);
1725
1726         return (quota);
1727 }
1728
1729 ISC_MEMFUNC_SCOPE size_t
1730 isc__mem_inuse(isc_mem_t *ctx0) {
1731         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1732         size_t inuse;
1733
1734         REQUIRE(VALID_CONTEXT(ctx));
1735         MCTXLOCK(ctx, &ctx->lock);
1736
1737         inuse = ctx->inuse;
1738
1739         MCTXUNLOCK(ctx, &ctx->lock);
1740
1741         return (inuse);
1742 }
1743
1744 ISC_MEMFUNC_SCOPE void
1745 isc__mem_setwater(isc_mem_t *ctx0, isc_mem_water_t water, void *water_arg,
1746                  size_t hiwater, size_t lowater)
1747 {
1748         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1749         isc_boolean_t callwater = ISC_FALSE;
1750         isc_mem_water_t oldwater;
1751         void *oldwater_arg;
1752
1753         REQUIRE(VALID_CONTEXT(ctx));
1754         REQUIRE(hiwater >= lowater);
1755
1756         MCTXLOCK(ctx, &ctx->lock);
1757         oldwater = ctx->water;
1758         oldwater_arg = ctx->water_arg;
1759         if (water == NULL) {
1760                 callwater = ctx->hi_called;
1761                 ctx->water = NULL;
1762                 ctx->water_arg = NULL;
1763                 ctx->hi_water = 0;
1764                 ctx->lo_water = 0;
1765                 ctx->hi_called = ISC_FALSE;
1766         } else {
1767                 if (ctx->hi_called &&
1768                     (ctx->water != water || ctx->water_arg != water_arg ||
1769                      ctx->inuse < lowater || lowater == 0U))
1770                         callwater = ISC_TRUE;
1771                 ctx->water = water;
1772                 ctx->water_arg = water_arg;
1773                 ctx->hi_water = hiwater;
1774                 ctx->lo_water = lowater;
1775                 ctx->hi_called = ISC_FALSE;
1776         }
1777         MCTXUNLOCK(ctx, &ctx->lock);
1778
1779         if (callwater && oldwater != NULL)
1780                 (oldwater)(oldwater_arg, ISC_MEM_LOWATER);
1781 }
1782
1783 ISC_MEMFUNC_SCOPE isc_boolean_t
1784 isc__mem_isovermem(isc_mem_t *ctx0) {
1785         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1786
1787         REQUIRE(VALID_CONTEXT(ctx));
1788
1789         /*
1790          * We don't bother to lock the context because 100% accuracy isn't
1791          * necessary (and even if we locked the context the returned value
1792          * could be different from the actual state when it's used anyway)
1793          */
1794         return (ctx->is_overmem);
1795 }
1796
1797 ISC_MEMFUNC_SCOPE void
1798 isc__mem_setname(isc_mem_t *ctx0, const char *name, void *tag) {
1799         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1800
1801         REQUIRE(VALID_CONTEXT(ctx));
1802
1803         LOCK(&ctx->lock);
1804         memset(ctx->name, 0, sizeof(ctx->name));
1805         strncpy(ctx->name, name, sizeof(ctx->name) - 1);
1806         ctx->tag = tag;
1807         UNLOCK(&ctx->lock);
1808 }
1809
1810 ISC_MEMFUNC_SCOPE const char *
1811 isc__mem_getname(isc_mem_t *ctx0) {
1812         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1813
1814         REQUIRE(VALID_CONTEXT(ctx));
1815
1816         return (ctx->name);
1817 }
1818
1819 ISC_MEMFUNC_SCOPE void *
1820 isc__mem_gettag(isc_mem_t *ctx0) {
1821         isc__mem_t *ctx = (isc__mem_t *)ctx0;
1822
1823         REQUIRE(VALID_CONTEXT(ctx));
1824
1825         return (ctx->tag);
1826 }
1827
1828 /*
1829  * Memory pool stuff
1830  */
1831
1832 ISC_MEMFUNC_SCOPE isc_result_t
1833 isc__mempool_create(isc_mem_t *mctx0, size_t size, isc_mempool_t **mpctxp) {
1834         isc__mem_t *mctx = (isc__mem_t *)mctx0;
1835         isc__mempool_t *mpctx;
1836
1837         REQUIRE(VALID_CONTEXT(mctx));
1838         REQUIRE(size > 0U);
1839         REQUIRE(mpctxp != NULL && *mpctxp == NULL);
1840
1841         /*
1842          * Allocate space for this pool, initialize values, and if all works
1843          * well, attach to the memory context.
1844          */
1845         mpctx = isc_mem_get((isc_mem_t *)mctx, sizeof(isc__mempool_t));
1846         if (mpctx == NULL)
1847                 return (ISC_R_NOMEMORY);
1848
1849         mpctx->common.methods = (isc_mempoolmethods_t *)&mempoolmethods;
1850         mpctx->common.impmagic = MEMPOOL_MAGIC;
1851         mpctx->common.magic = ISCAPI_MPOOL_MAGIC;
1852         mpctx->lock = NULL;
1853         mpctx->mctx = mctx;
1854         mpctx->size = size;
1855         mpctx->maxalloc = UINT_MAX;
1856         mpctx->allocated = 0;
1857         mpctx->freecount = 0;
1858         mpctx->freemax = 1;
1859         mpctx->fillcount = 1;
1860         mpctx->gets = 0;
1861 #if ISC_MEMPOOL_NAMES
1862         mpctx->name[0] = 0;
1863 #endif
1864         mpctx->items = NULL;
1865
1866         *mpctxp = (isc_mempool_t *)mpctx;
1867
1868         MCTXLOCK(mctx, &mctx->lock);
1869         ISC_LIST_INITANDAPPEND(mctx->pools, mpctx, link);
1870         mctx->poolcnt++;
1871         MCTXUNLOCK(mctx, &mctx->lock);
1872
1873         return (ISC_R_SUCCESS);
1874 }
1875
1876 ISC_MEMFUNC_SCOPE void
1877 isc__mempool_setname(isc_mempool_t *mpctx0, const char *name) {
1878         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
1879
1880         REQUIRE(name != NULL);
1881         REQUIRE(VALID_MEMPOOL(mpctx));
1882
1883 #if ISC_MEMPOOL_NAMES
1884         if (mpctx->lock != NULL)
1885                 LOCK(mpctx->lock);
1886
1887         strncpy(mpctx->name, name, sizeof(mpctx->name) - 1);
1888         mpctx->name[sizeof(mpctx->name) - 1] = '\0';
1889
1890         if (mpctx->lock != NULL)
1891                 UNLOCK(mpctx->lock);
1892 #else
1893         UNUSED(mpctx);
1894         UNUSED(name);
1895 #endif
1896 }
1897
1898 ISC_MEMFUNC_SCOPE void
1899 isc__mempool_destroy(isc_mempool_t **mpctxp) {
1900         isc__mempool_t *mpctx;
1901         isc__mem_t *mctx;
1902         isc_mutex_t *lock;
1903         element *item;
1904
1905         REQUIRE(mpctxp != NULL);
1906         mpctx = (isc__mempool_t *)*mpctxp;
1907         REQUIRE(VALID_MEMPOOL(mpctx));
1908 #if ISC_MEMPOOL_NAMES
1909         if (mpctx->allocated > 0)
1910                 UNEXPECTED_ERROR(__FILE__, __LINE__,
1911                                  "isc__mempool_destroy(): mempool %s "
1912                                  "leaked memory",
1913                                  mpctx->name);
1914 #endif
1915         REQUIRE(mpctx->allocated == 0);
1916
1917         mctx = mpctx->mctx;
1918
1919         lock = mpctx->lock;
1920
1921         if (lock != NULL)
1922                 LOCK(lock);
1923
1924         /*
1925          * Return any items on the free list
1926          */
1927         MCTXLOCK(mctx, &mctx->lock);
1928         while (mpctx->items != NULL) {
1929                 INSIST(mpctx->freecount > 0);
1930                 mpctx->freecount--;
1931                 item = mpctx->items;
1932                 mpctx->items = item->next;
1933
1934                 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1935                         mem_putunlocked(mctx, item, mpctx->size);
1936                 } else {
1937                         mem_put(mctx, item, mpctx->size);
1938                         mem_putstats(mctx, item, mpctx->size);
1939                 }
1940         }
1941         MCTXUNLOCK(mctx, &mctx->lock);
1942
1943         /*
1944          * Remove our linked list entry from the memory context.
1945          */
1946         MCTXLOCK(mctx, &mctx->lock);
1947         ISC_LIST_UNLINK(mctx->pools, mpctx, link);
1948         mctx->poolcnt--;
1949         MCTXUNLOCK(mctx, &mctx->lock);
1950
1951         mpctx->common.impmagic = 0;
1952         mpctx->common.magic = 0;
1953
1954         isc_mem_put((isc_mem_t *)mpctx->mctx, mpctx, sizeof(isc__mempool_t));
1955
1956         if (lock != NULL)
1957                 UNLOCK(lock);
1958
1959         *mpctxp = NULL;
1960 }
1961
1962 ISC_MEMFUNC_SCOPE void
1963 isc__mempool_associatelock(isc_mempool_t *mpctx0, isc_mutex_t *lock) {
1964         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
1965
1966         REQUIRE(VALID_MEMPOOL(mpctx));
1967         REQUIRE(mpctx->lock == NULL);
1968         REQUIRE(lock != NULL);
1969
1970         mpctx->lock = lock;
1971 }
1972
1973 ISC_MEMFUNC_SCOPE void *
1974 isc___mempool_get(isc_mempool_t *mpctx0 FLARG) {
1975         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
1976         element *item;
1977         isc__mem_t *mctx;
1978         unsigned int i;
1979
1980         REQUIRE(VALID_MEMPOOL(mpctx));
1981
1982         mctx = mpctx->mctx;
1983
1984         if (mpctx->lock != NULL)
1985                 LOCK(mpctx->lock);
1986
1987         /*
1988          * Don't let the caller go over quota
1989          */
1990         if (mpctx->allocated >= mpctx->maxalloc) {
1991                 item = NULL;
1992                 goto out;
1993         }
1994
1995         /*
1996          * if we have a free list item, return the first here
1997          */
1998         item = mpctx->items;
1999         if (item != NULL) {
2000                 mpctx->items = item->next;
2001                 INSIST(mpctx->freecount > 0);
2002                 mpctx->freecount--;
2003                 mpctx->gets++;
2004                 mpctx->allocated++;
2005                 goto out;
2006         }
2007
2008         /*
2009          * We need to dip into the well.  Lock the memory context here and
2010          * fill up our free list.
2011          */
2012         MCTXLOCK(mctx, &mctx->lock);
2013         for (i = 0; i < mpctx->fillcount; i++) {
2014                 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
2015                         item = mem_getunlocked(mctx, mpctx->size);
2016                 } else {
2017                         item = mem_get(mctx, mpctx->size);
2018                         if (item != NULL)
2019                                 mem_getstats(mctx, mpctx->size);
2020                 }
2021                 if (item == NULL)
2022                         break;
2023                 item->next = mpctx->items;
2024                 mpctx->items = item;
2025                 mpctx->freecount++;
2026         }
2027         MCTXUNLOCK(mctx, &mctx->lock);
2028
2029         /*
2030          * If we didn't get any items, return NULL.
2031          */
2032         item = mpctx->items;
2033         if (item == NULL)
2034                 goto out;
2035
2036         mpctx->items = item->next;
2037         mpctx->freecount--;
2038         mpctx->gets++;
2039         mpctx->allocated++;
2040
2041  out:
2042         if (mpctx->lock != NULL)
2043                 UNLOCK(mpctx->lock);
2044
2045 #if ISC_MEM_TRACKLINES
2046         if (item != NULL) {
2047                 MCTXLOCK(mctx, &mctx->lock);
2048                 ADD_TRACE(mctx, item, mpctx->size, file, line);
2049                 MCTXUNLOCK(mctx, &mctx->lock);
2050         }
2051 #endif /* ISC_MEM_TRACKLINES */
2052
2053         return (item);
2054 }
2055
2056 ISC_MEMFUNC_SCOPE void
2057 isc___mempool_put(isc_mempool_t *mpctx0, void *mem FLARG) {
2058         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2059         isc__mem_t *mctx;
2060         element *item;
2061
2062         REQUIRE(VALID_MEMPOOL(mpctx));
2063         REQUIRE(mem != NULL);
2064
2065         mctx = mpctx->mctx;
2066
2067         if (mpctx->lock != NULL)
2068                 LOCK(mpctx->lock);
2069
2070         INSIST(mpctx->allocated > 0);
2071         mpctx->allocated--;
2072
2073 #if ISC_MEM_TRACKLINES
2074         MCTXLOCK(mctx, &mctx->lock);
2075         DELETE_TRACE(mctx, mem, mpctx->size, file, line);
2076         MCTXUNLOCK(mctx, &mctx->lock);
2077 #endif /* ISC_MEM_TRACKLINES */
2078
2079         /*
2080          * If our free list is full, return this to the mctx directly.
2081          */
2082         if (mpctx->freecount >= mpctx->freemax) {
2083                 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
2084                         MCTXLOCK(mctx, &mctx->lock);
2085                         mem_putunlocked(mctx, mem, mpctx->size);
2086                         MCTXUNLOCK(mctx, &mctx->lock);
2087                 } else {
2088                         mem_put(mctx, mem, mpctx->size);
2089                         MCTXLOCK(mctx, &mctx->lock);
2090                         mem_putstats(mctx, mem, mpctx->size);
2091                         MCTXUNLOCK(mctx, &mctx->lock);
2092                 }
2093                 if (mpctx->lock != NULL)
2094                         UNLOCK(mpctx->lock);
2095                 return;
2096         }
2097
2098         /*
2099          * Otherwise, attach it to our free list and bump the counter.
2100          */
2101         mpctx->freecount++;
2102         item = (element *)mem;
2103         item->next = mpctx->items;
2104         mpctx->items = item;
2105
2106         if (mpctx->lock != NULL)
2107                 UNLOCK(mpctx->lock);
2108 }
2109
2110 /*
2111  * Quotas
2112  */
2113
2114 ISC_MEMFUNC_SCOPE void
2115 isc__mempool_setfreemax(isc_mempool_t *mpctx0, unsigned int limit) {
2116         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2117
2118         REQUIRE(VALID_MEMPOOL(mpctx));
2119
2120         if (mpctx->lock != NULL)
2121                 LOCK(mpctx->lock);
2122
2123         mpctx->freemax = limit;
2124
2125         if (mpctx->lock != NULL)
2126                 UNLOCK(mpctx->lock);
2127 }
2128
2129 ISC_MEMFUNC_SCOPE unsigned int
2130 isc__mempool_getfreemax(isc_mempool_t *mpctx0) {
2131         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2132         unsigned int freemax;
2133
2134         REQUIRE(VALID_MEMPOOL(mpctx));
2135
2136         if (mpctx->lock != NULL)
2137                 LOCK(mpctx->lock);
2138
2139         freemax = mpctx->freemax;
2140
2141         if (mpctx->lock != NULL)
2142                 UNLOCK(mpctx->lock);
2143
2144         return (freemax);
2145 }
2146
2147 ISC_MEMFUNC_SCOPE unsigned int
2148 isc__mempool_getfreecount(isc_mempool_t *mpctx0) {
2149         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2150         unsigned int freecount;
2151
2152         REQUIRE(VALID_MEMPOOL(mpctx));
2153
2154         if (mpctx->lock != NULL)
2155                 LOCK(mpctx->lock);
2156
2157         freecount = mpctx->freecount;
2158
2159         if (mpctx->lock != NULL)
2160                 UNLOCK(mpctx->lock);
2161
2162         return (freecount);
2163 }
2164
2165 ISC_MEMFUNC_SCOPE void
2166 isc__mempool_setmaxalloc(isc_mempool_t *mpctx0, unsigned int limit) {
2167         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2168
2169         REQUIRE(limit > 0);
2170
2171         REQUIRE(VALID_MEMPOOL(mpctx));
2172
2173         if (mpctx->lock != NULL)
2174                 LOCK(mpctx->lock);
2175
2176         mpctx->maxalloc = limit;
2177
2178         if (mpctx->lock != NULL)
2179                 UNLOCK(mpctx->lock);
2180 }
2181
2182 ISC_MEMFUNC_SCOPE unsigned int
2183 isc__mempool_getmaxalloc(isc_mempool_t *mpctx0) {
2184         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2185         unsigned int maxalloc;
2186
2187         REQUIRE(VALID_MEMPOOL(mpctx));
2188
2189         if (mpctx->lock != NULL)
2190                 LOCK(mpctx->lock);
2191
2192         maxalloc = mpctx->maxalloc;
2193
2194         if (mpctx->lock != NULL)
2195                 UNLOCK(mpctx->lock);
2196
2197         return (maxalloc);
2198 }
2199
2200 ISC_MEMFUNC_SCOPE unsigned int
2201 isc__mempool_getallocated(isc_mempool_t *mpctx0) {
2202         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2203         unsigned int allocated;
2204
2205         REQUIRE(VALID_MEMPOOL(mpctx));
2206
2207         if (mpctx->lock != NULL)
2208                 LOCK(mpctx->lock);
2209
2210         allocated = mpctx->allocated;
2211
2212         if (mpctx->lock != NULL)
2213                 UNLOCK(mpctx->lock);
2214
2215         return (allocated);
2216 }
2217
2218 ISC_MEMFUNC_SCOPE void
2219 isc__mempool_setfillcount(isc_mempool_t *mpctx0, unsigned int limit) {
2220         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2221
2222         REQUIRE(limit > 0);
2223         REQUIRE(VALID_MEMPOOL(mpctx));
2224
2225         if (mpctx->lock != NULL)
2226                 LOCK(mpctx->lock);
2227
2228         mpctx->fillcount = limit;
2229
2230         if (mpctx->lock != NULL)
2231                 UNLOCK(mpctx->lock);
2232 }
2233
2234 ISC_MEMFUNC_SCOPE unsigned int
2235 isc__mempool_getfillcount(isc_mempool_t *mpctx0) {
2236         isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2237
2238         unsigned int fillcount;
2239
2240         REQUIRE(VALID_MEMPOOL(mpctx));
2241
2242         if (mpctx->lock != NULL)
2243                 LOCK(mpctx->lock);
2244
2245         fillcount = mpctx->fillcount;
2246
2247         if (mpctx->lock != NULL)
2248                 UNLOCK(mpctx->lock);
2249
2250         return (fillcount);
2251 }
2252
2253 #ifdef USE_MEMIMPREGISTER
2254 isc_result_t
2255 isc__mem_register() {
2256         return (isc_mem_register(isc__mem_create2));
2257 }
2258 #endif
2259
2260 #ifdef BIND9
2261 ISC_MEMFUNC_SCOPE void
2262 isc__mem_printactive(isc_mem_t *ctx0, FILE *file) {
2263         isc__mem_t *ctx = (isc__mem_t *)ctx0;
2264
2265         REQUIRE(VALID_CONTEXT(ctx));
2266         REQUIRE(file != NULL);
2267
2268 #if !ISC_MEM_TRACKLINES
2269         UNUSED(ctx);
2270         UNUSED(file);
2271 #else
2272         print_active(ctx, file);
2273 #endif
2274 }
2275
2276 ISC_MEMFUNC_SCOPE void
2277 isc__mem_printallactive(FILE *file) {
2278 #if !ISC_MEM_TRACKLINES
2279         UNUSED(file);
2280 #else
2281         isc__mem_t *ctx;
2282
2283         RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2284
2285         LOCK(&lock);
2286         for (ctx = ISC_LIST_HEAD(contexts);
2287              ctx != NULL;
2288              ctx = ISC_LIST_NEXT(ctx, link)) {
2289                 fprintf(file, "context: %p\n", ctx);
2290                 print_active(ctx, file);
2291         }
2292         UNLOCK(&lock);
2293 #endif
2294 }
2295
2296 ISC_MEMFUNC_SCOPE void
2297 isc__mem_checkdestroyed(FILE *file) {
2298
2299         RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2300
2301         LOCK(&lock);
2302         if (!ISC_LIST_EMPTY(contexts))  {
2303 #if ISC_MEM_TRACKLINES
2304                 isc__mem_t *ctx;
2305
2306                 for (ctx = ISC_LIST_HEAD(contexts);
2307                      ctx != NULL;
2308                      ctx = ISC_LIST_NEXT(ctx, link)) {
2309                         fprintf(file, "context: %p\n", ctx);
2310                         print_active(ctx, file);
2311                 }
2312                 fflush(file);
2313 #endif
2314                 INSIST(0);
2315         }
2316         UNLOCK(&lock);
2317 }
2318
2319 ISC_MEMFUNC_SCOPE unsigned int
2320 isc_mem_references(isc_mem_t *ctx0) {
2321         isc__mem_t *ctx = (isc__mem_t *)ctx0;
2322         unsigned int references;
2323
2324         REQUIRE(VALID_CONTEXT(ctx));
2325
2326         MCTXLOCK(ctx, &ctx->lock);
2327         references = ctx->references;
2328         MCTXUNLOCK(ctx, &ctx->lock);
2329
2330         return (references);
2331 }
2332
2333 #ifdef HAVE_LIBXML2
2334
2335 typedef struct summarystat {
2336         isc_uint64_t    total;
2337         isc_uint64_t    inuse;
2338         isc_uint64_t    blocksize;
2339         isc_uint64_t    contextsize;
2340 } summarystat_t;
2341
2342 static void
2343 renderctx(isc__mem_t *ctx, summarystat_t *summary, xmlTextWriterPtr writer) {
2344         REQUIRE(VALID_CONTEXT(ctx));
2345
2346         xmlTextWriterStartElement(writer, ISC_XMLCHAR "context");
2347
2348         xmlTextWriterStartElement(writer, ISC_XMLCHAR "id");
2349         xmlTextWriterWriteFormatString(writer, "%p", ctx);
2350         xmlTextWriterEndElement(writer); /* id */
2351
2352         if (ctx->name[0] != 0) {
2353                 xmlTextWriterStartElement(writer, ISC_XMLCHAR "name");
2354                 xmlTextWriterWriteFormatString(writer, "%s", ctx->name);
2355                 xmlTextWriterEndElement(writer); /* name */
2356         }
2357
2358         REQUIRE(VALID_CONTEXT(ctx));
2359         MCTXLOCK(ctx, &ctx->lock);
2360
2361         summary->contextsize += sizeof(*ctx) +
2362                 (ctx->max_size + 1) * sizeof(struct stats) +
2363                 ctx->max_size * sizeof(element *) +
2364                 ctx->basic_table_count * sizeof(char *);
2365 #if ISC_MEM_TRACKLINES
2366         if (ctx->debuglist != NULL) {
2367                 summary->contextsize +=
2368                         (ctx->max_size + 1) * sizeof(debuglist_t) +
2369                         ctx->debuglistcnt * sizeof(debuglink_t);
2370         }
2371 #endif
2372         xmlTextWriterStartElement(writer, ISC_XMLCHAR "references");
2373         xmlTextWriterWriteFormatString(writer, "%d", ctx->references);
2374         xmlTextWriterEndElement(writer); /* references */
2375
2376         summary->total += ctx->total;
2377         xmlTextWriterStartElement(writer, ISC_XMLCHAR "total");
2378         xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2379                                        (isc_uint64_t)ctx->total);
2380         xmlTextWriterEndElement(writer); /* total */
2381
2382         summary->inuse += ctx->inuse;
2383         xmlTextWriterStartElement(writer, ISC_XMLCHAR "inuse");
2384         xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2385                                        (isc_uint64_t)ctx->inuse);
2386         xmlTextWriterEndElement(writer); /* inuse */
2387
2388         xmlTextWriterStartElement(writer, ISC_XMLCHAR "maxinuse");
2389         xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2390                                        (isc_uint64_t)ctx->maxinuse);
2391         xmlTextWriterEndElement(writer); /* maxinuse */
2392
2393         xmlTextWriterStartElement(writer, ISC_XMLCHAR "blocksize");
2394         if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
2395                 summary->blocksize += ctx->basic_table_count *
2396                         NUM_BASIC_BLOCKS * ctx->mem_target;
2397                 xmlTextWriterWriteFormatString(writer,
2398                                                "%" ISC_PRINT_QUADFORMAT "u",
2399                                                (isc_uint64_t)
2400                                                ctx->basic_table_count *
2401                                                NUM_BASIC_BLOCKS *
2402                                                ctx->mem_target);
2403         } else
2404                 xmlTextWriterWriteFormatString(writer, "%s", "-");
2405         xmlTextWriterEndElement(writer); /* blocksize */
2406
2407         xmlTextWriterStartElement(writer, ISC_XMLCHAR "pools");
2408         xmlTextWriterWriteFormatString(writer, "%u", ctx->poolcnt);
2409         xmlTextWriterEndElement(writer); /* pools */
2410         summary->contextsize += ctx->poolcnt * sizeof(isc_mempool_t);
2411
2412         xmlTextWriterStartElement(writer, ISC_XMLCHAR "hiwater");
2413         xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2414                                        (isc_uint64_t)ctx->hi_water);
2415         xmlTextWriterEndElement(writer); /* hiwater */
2416
2417         xmlTextWriterStartElement(writer, ISC_XMLCHAR "lowater");
2418         xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2419                                        (isc_uint64_t)ctx->lo_water);
2420         xmlTextWriterEndElement(writer); /* lowater */
2421
2422         MCTXUNLOCK(ctx, &ctx->lock);
2423
2424         xmlTextWriterEndElement(writer); /* context */
2425 }
2426
2427 void
2428 isc_mem_renderxml(xmlTextWriterPtr writer) {
2429         isc__mem_t *ctx;
2430         summarystat_t summary;
2431         isc_uint64_t lost;
2432
2433         memset(&summary, 0, sizeof(summary));
2434
2435         xmlTextWriterStartElement(writer, ISC_XMLCHAR "contexts");
2436
2437         RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2438
2439         LOCK(&lock);
2440         lost = totallost;
2441         for (ctx = ISC_LIST_HEAD(contexts);
2442              ctx != NULL;
2443              ctx = ISC_LIST_NEXT(ctx, link)) {
2444                 renderctx(ctx, &summary, writer);
2445         }
2446         UNLOCK(&lock);
2447
2448         xmlTextWriterEndElement(writer); /* contexts */
2449
2450         xmlTextWriterStartElement(writer, ISC_XMLCHAR "summary");
2451
2452         xmlTextWriterStartElement(writer, ISC_XMLCHAR "TotalUse");
2453         xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2454                                        summary.total);
2455         xmlTextWriterEndElement(writer); /* TotalUse */
2456
2457         xmlTextWriterStartElement(writer, ISC_XMLCHAR "InUse");
2458         xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2459                                        summary.inuse);
2460         xmlTextWriterEndElement(writer); /* InUse */
2461
2462         xmlTextWriterStartElement(writer, ISC_XMLCHAR "BlockSize");
2463         xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2464                                        summary.blocksize);
2465         xmlTextWriterEndElement(writer); /* BlockSize */
2466
2467         xmlTextWriterStartElement(writer, ISC_XMLCHAR "ContextSize");
2468         xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2469                                        summary.contextsize);
2470         xmlTextWriterEndElement(writer); /* ContextSize */
2471
2472         xmlTextWriterStartElement(writer, ISC_XMLCHAR "Lost");
2473         xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2474                                        lost);
2475         xmlTextWriterEndElement(writer); /* Lost */
2476
2477         xmlTextWriterEndElement(writer); /* summary */
2478 }
2479
2480 #endif /* HAVE_LIBXML2 */
2481 #endif /* BIND9 */