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