]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/bind9/lib/isc/mem.c
Update BIND to 9.9.8
[FreeBSD/stable/9.git] / contrib / bind9 / lib / isc / mem.c
1 /*
2  * Copyright (C) 2004-2010, 2012-2015  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 (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(void) {
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 #if ISC_MEM_TRACKLINES
2264         isc__mem_t *ctx = (isc__mem_t *)ctx0;
2265
2266         REQUIRE(VALID_CONTEXT(ctx));
2267         REQUIRE(file != NULL);
2268
2269         print_active(ctx, file);
2270 #else
2271         UNUSED(ctx0);
2272         UNUSED(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(&contextslock);
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(&contextslock);
2293 #endif
2294 }
2295
2296 ISC_MEMFUNC_SCOPE void
2297 isc__mem_checkdestroyed(FILE *file) {
2298 #if !ISC_MEM_TRACKLINES
2299         UNUSED(file);
2300 #endif
2301
2302         RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2303
2304         LOCK(&contextslock);
2305         if (!ISC_LIST_EMPTY(contexts))  {
2306 #if ISC_MEM_TRACKLINES
2307                 isc__mem_t *ctx;
2308
2309                 for (ctx = ISC_LIST_HEAD(contexts);
2310                      ctx != NULL;
2311                      ctx = ISC_LIST_NEXT(ctx, link)) {
2312                         fprintf(file, "context: %p\n", ctx);
2313                         print_active(ctx, file);
2314                 }
2315                 fflush(file);
2316 #endif
2317                 INSIST(0);
2318         }
2319         UNLOCK(&contextslock);
2320 }
2321
2322 ISC_MEMFUNC_SCOPE unsigned int
2323 isc_mem_references(isc_mem_t *ctx0) {
2324         isc__mem_t *ctx = (isc__mem_t *)ctx0;
2325         unsigned int references;
2326
2327         REQUIRE(VALID_CONTEXT(ctx));
2328
2329         MCTXLOCK(ctx, &ctx->lock);
2330         references = ctx->references;
2331         MCTXUNLOCK(ctx, &ctx->lock);
2332
2333         return (references);
2334 }
2335
2336 #ifdef HAVE_LIBXML2
2337
2338 typedef struct summarystat {
2339         isc_uint64_t    total;
2340         isc_uint64_t    inuse;
2341         isc_uint64_t    blocksize;
2342         isc_uint64_t    contextsize;
2343 } summarystat_t;
2344
2345 #define TRY0(a) do { xmlrc = (a); if (xmlrc < 0) goto error; } while(0)
2346 static int
2347 renderctx(isc__mem_t *ctx, summarystat_t *summary, xmlTextWriterPtr writer) {
2348         int xmlrc;
2349
2350         REQUIRE(VALID_CONTEXT(ctx));
2351
2352         MCTXLOCK(ctx, &ctx->lock);
2353
2354         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "context"));
2355
2356         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "id"));
2357         TRY0(xmlTextWriterWriteFormatString(writer, "%p", ctx));
2358         TRY0(xmlTextWriterEndElement(writer)); /* id */
2359
2360         if (ctx->name[0] != 0) {
2361                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"));
2362                 TRY0(xmlTextWriterWriteFormatString(writer, "%s", ctx->name));
2363                 TRY0(xmlTextWriterEndElement(writer)); /* name */
2364         }
2365
2366         summary->contextsize += sizeof(*ctx) +
2367                 (ctx->max_size + 1) * sizeof(struct stats) +
2368                 ctx->max_size * sizeof(element *) +
2369                 ctx->basic_table_count * sizeof(char *);
2370 #if ISC_MEM_TRACKLINES
2371         if (ctx->debuglist != NULL) {
2372                 summary->contextsize +=
2373                         (ctx->max_size + 1) * sizeof(debuglist_t) +
2374                         ctx->debuglistcnt * sizeof(debuglink_t);
2375         }
2376 #endif
2377         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "references"));
2378         TRY0(xmlTextWriterWriteFormatString(writer, "%d", ctx->references));
2379         TRY0(xmlTextWriterEndElement(writer)); /* references */
2380
2381         summary->total += ctx->total;
2382         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "total"));
2383         TRY0(xmlTextWriterWriteFormatString(writer,
2384                                             "%" ISC_PRINT_QUADFORMAT "u",
2385                                             (isc_uint64_t)ctx->total));
2386         TRY0(xmlTextWriterEndElement(writer)); /* total */
2387
2388         summary->inuse += ctx->inuse;
2389         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "inuse"));
2390         TRY0(xmlTextWriterWriteFormatString(writer,
2391                                             "%" ISC_PRINT_QUADFORMAT "u",
2392                                             (isc_uint64_t)ctx->inuse));
2393         TRY0(xmlTextWriterEndElement(writer)); /* inuse */
2394
2395         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "maxinuse"));
2396         TRY0(xmlTextWriterWriteFormatString(writer,
2397                                             "%" ISC_PRINT_QUADFORMAT "u",
2398                                             (isc_uint64_t)ctx->maxinuse));
2399         TRY0(xmlTextWriterEndElement(writer)); /* maxinuse */
2400
2401         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "blocksize"));
2402         if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
2403                 summary->blocksize += ctx->basic_table_count *
2404                         NUM_BASIC_BLOCKS * ctx->mem_target;
2405                 TRY0(xmlTextWriterWriteFormatString(writer,
2406                                                "%" ISC_PRINT_QUADFORMAT "u",
2407                                                (isc_uint64_t)
2408                                                ctx->basic_table_count *
2409                                                NUM_BASIC_BLOCKS *
2410                                                ctx->mem_target));
2411         } else
2412                 TRY0(xmlTextWriterWriteFormatString(writer, "%s", "-"));
2413         TRY0(xmlTextWriterEndElement(writer)); /* blocksize */
2414
2415         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "pools"));
2416         TRY0(xmlTextWriterWriteFormatString(writer, "%u", ctx->poolcnt));
2417         TRY0(xmlTextWriterEndElement(writer)); /* pools */
2418         summary->contextsize += ctx->poolcnt * sizeof(isc_mempool_t);
2419
2420         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "hiwater"));
2421         TRY0(xmlTextWriterWriteFormatString(writer,
2422                                             "%" ISC_PRINT_QUADFORMAT "u",
2423                                             (isc_uint64_t)ctx->hi_water));
2424         TRY0(xmlTextWriterEndElement(writer)); /* hiwater */
2425
2426         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "lowater"));
2427         TRY0(xmlTextWriterWriteFormatString(writer,
2428                                             "%" ISC_PRINT_QUADFORMAT "u",
2429                                             (isc_uint64_t)ctx->lo_water));
2430         TRY0(xmlTextWriterEndElement(writer)); /* lowater */
2431
2432         TRY0(xmlTextWriterEndElement(writer)); /* context */
2433
2434  error:
2435         MCTXUNLOCK(ctx, &ctx->lock);
2436
2437         return (xmlrc);
2438 }
2439
2440 int
2441 isc_mem_renderxml(xmlTextWriterPtr writer) {
2442         isc__mem_t *ctx;
2443         summarystat_t summary;
2444         isc_uint64_t lost;
2445         int xmlrc;
2446
2447         memset(&summary, 0, sizeof(summary));
2448
2449         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "contexts"));
2450
2451         RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2452
2453         LOCK(&contextslock);
2454         lost = totallost;
2455         for (ctx = ISC_LIST_HEAD(contexts);
2456              ctx != NULL;
2457              ctx = ISC_LIST_NEXT(ctx, link)) {
2458                 xmlrc = renderctx(ctx, &summary, writer);
2459                 if (xmlrc < 0) {
2460                         UNLOCK(&contextslock);
2461                         goto error;
2462                 }
2463         }
2464         UNLOCK(&contextslock);
2465
2466         TRY0(xmlTextWriterEndElement(writer)); /* contexts */
2467
2468         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "summary"));
2469
2470         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "TotalUse"));
2471         TRY0(xmlTextWriterWriteFormatString(writer,
2472                                             "%" ISC_PRINT_QUADFORMAT "u",
2473                                             summary.total));
2474         TRY0(xmlTextWriterEndElement(writer)); /* TotalUse */
2475
2476         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "InUse"));
2477         TRY0(xmlTextWriterWriteFormatString(writer,
2478                                             "%" ISC_PRINT_QUADFORMAT "u",
2479                                             summary.inuse));
2480         TRY0(xmlTextWriterEndElement(writer)); /* InUse */
2481
2482         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "BlockSize"));
2483         TRY0(xmlTextWriterWriteFormatString(writer,
2484                                             "%" ISC_PRINT_QUADFORMAT "u",
2485                                             summary.blocksize));
2486         TRY0(xmlTextWriterEndElement(writer)); /* BlockSize */
2487
2488         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "ContextSize"));
2489         TRY0(xmlTextWriterWriteFormatString(writer,
2490                                             "%" ISC_PRINT_QUADFORMAT "u",
2491                                             summary.contextsize));
2492         TRY0(xmlTextWriterEndElement(writer)); /* ContextSize */
2493
2494         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "Lost"));
2495         TRY0(xmlTextWriterWriteFormatString(writer,
2496                                             "%" ISC_PRINT_QUADFORMAT "u",
2497                                             lost));
2498         TRY0(xmlTextWriterEndElement(writer)); /* Lost */
2499
2500         TRY0(xmlTextWriterEndElement(writer)); /* summary */
2501  error:
2502         return (xmlrc);
2503 }
2504
2505 #endif /* HAVE_LIBXML2 */
2506 #endif /* BIND9 */