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