]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - contrib/bind9/lib/isc/mem.c
Update to 9.6-ESV-R8.
[FreeBSD/stable/8.git] / contrib / bind9 / lib / isc / mem.c
1 /*
2  * Copyright (C) 2004-2010, 2012  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1997-2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /* $Id$ */
19
20 /*! \file */
21
22 #include <config.h>
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <stddef.h>
27
28 #include <limits.h>
29
30 #include <isc/magic.h>
31 #include <isc/mem.h>
32 #include <isc/msgs.h>
33 #include <isc/once.h>
34 #include <isc/ondestroy.h>
35 #include <isc/string.h>
36 #include <isc/mutex.h>
37 #include <isc/print.h>
38 #include <isc/util.h>
39 #include <isc/xml.h>
40
41 #define MCTXLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) LOCK(l)
42 #define MCTXUNLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) UNLOCK(l)
43
44 #ifndef ISC_MEM_DEBUGGING
45 #define ISC_MEM_DEBUGGING 0
46 #endif
47 LIBISC_EXTERNAL_DATA unsigned int isc_mem_debugging = ISC_MEM_DEBUGGING;
48
49 /*
50  * Constants.
51  */
52
53 #define DEF_MAX_SIZE            1100
54 #define DEF_MEM_TARGET          4096
55 #define ALIGNMENT_SIZE          8U              /*%< must be a power of 2 */
56 #define NUM_BASIC_BLOCKS        64              /*%< must be > 1 */
57 #define TABLE_INCREMENT         1024
58 #define DEBUGLIST_COUNT         1024
59
60 /*
61  * Types.
62  */
63 #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                         if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
1409                                 INSIST(oldsize >= ALIGNMENT_SIZE);
1410                                 oldsize -= ALIGNMENT_SIZE;
1411                         }
1412                         copysize = (oldsize > size) ? size : oldsize;
1413                         memcpy(new_ptr, ptr, copysize);
1414                         isc__mem_free(ctx, ptr FLARG_PASS);
1415                 }
1416         } else if (ptr != NULL)
1417                 isc__mem_free(ctx, ptr FLARG_PASS);
1418
1419         return (new_ptr);
1420 }
1421
1422 void
1423 isc__mem_free(isc_mem_t *ctx, void *ptr FLARG) {
1424         size_info *si;
1425         size_t size;
1426         isc_boolean_t call_water= ISC_FALSE;
1427
1428         REQUIRE(VALID_CONTEXT(ctx));
1429         REQUIRE(ptr != NULL);
1430
1431         if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
1432                 si = &(((size_info *)ptr)[-2]);
1433                 REQUIRE(si->u.ctx == ctx);
1434                 size = si[1].u.size;
1435         } else {
1436                 si = &(((size_info *)ptr)[-1]);
1437                 size = si->u.size;
1438         }
1439
1440         if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1441                 MCTXLOCK(ctx, &ctx->lock);
1442                 mem_putunlocked(ctx, si, size);
1443         } else {
1444                 mem_put(ctx, si, size);
1445                 MCTXLOCK(ctx, &ctx->lock);
1446                 mem_putstats(ctx, si, size);
1447         }
1448
1449         DELETE_TRACE(ctx, ptr, size, file, line);
1450
1451         /*
1452          * The check against ctx->lo_water == 0 is for the condition
1453          * when the context was pushed over hi_water but then had
1454          * isc_mem_setwater() called with 0 for hi_water and lo_water.
1455          */
1456         if (ctx->is_overmem &&
1457             (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1458                 ctx->is_overmem = ISC_FALSE;
1459         }
1460
1461         if (ctx->hi_called &&
1462             (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1463                 ctx->hi_called = ISC_FALSE;
1464
1465                 if (ctx->water != NULL)
1466                         call_water = ISC_TRUE;
1467         }
1468         MCTXUNLOCK(ctx, &ctx->lock);
1469
1470         if (call_water)
1471                 (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
1472 }
1473
1474
1475 /*
1476  * Other useful things.
1477  */
1478
1479 char *
1480 isc__mem_strdup(isc_mem_t *mctx, const char *s FLARG) {
1481         size_t len;
1482         char *ns;
1483
1484         REQUIRE(VALID_CONTEXT(mctx));
1485         REQUIRE(s != NULL);
1486
1487         len = strlen(s);
1488
1489         ns = isc__mem_allocate(mctx, len + 1 FLARG_PASS);
1490
1491         if (ns != NULL)
1492                 strncpy(ns, s, len + 1);
1493
1494         return (ns);
1495 }
1496
1497 void
1498 isc_mem_setdestroycheck(isc_mem_t *ctx, isc_boolean_t flag) {
1499         REQUIRE(VALID_CONTEXT(ctx));
1500         MCTXLOCK(ctx, &ctx->lock);
1501
1502         ctx->checkfree = flag;
1503
1504         MCTXUNLOCK(ctx, &ctx->lock);
1505 }
1506
1507 /*
1508  * Quotas
1509  */
1510
1511 void
1512 isc_mem_setquota(isc_mem_t *ctx, size_t quota) {
1513         REQUIRE(VALID_CONTEXT(ctx));
1514         MCTXLOCK(ctx, &ctx->lock);
1515
1516         ctx->quota = quota;
1517
1518         MCTXUNLOCK(ctx, &ctx->lock);
1519 }
1520
1521 size_t
1522 isc_mem_getquota(isc_mem_t *ctx) {
1523         size_t quota;
1524
1525         REQUIRE(VALID_CONTEXT(ctx));
1526         MCTXLOCK(ctx, &ctx->lock);
1527
1528         quota = ctx->quota;
1529
1530         MCTXUNLOCK(ctx, &ctx->lock);
1531
1532         return (quota);
1533 }
1534
1535 size_t
1536 isc_mem_inuse(isc_mem_t *ctx) {
1537         size_t inuse;
1538
1539         REQUIRE(VALID_CONTEXT(ctx));
1540         MCTXLOCK(ctx, &ctx->lock);
1541
1542         inuse = ctx->inuse;
1543
1544         MCTXUNLOCK(ctx, &ctx->lock);
1545
1546         return (inuse);
1547 }
1548
1549 void
1550 isc_mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg,
1551                  size_t hiwater, size_t lowater)
1552 {
1553         isc_boolean_t callwater = ISC_FALSE;
1554         isc_mem_water_t oldwater;
1555         void *oldwater_arg;
1556
1557         REQUIRE(VALID_CONTEXT(ctx));
1558         REQUIRE(hiwater >= lowater);
1559
1560         MCTXLOCK(ctx, &ctx->lock);
1561         oldwater = ctx->water;
1562         oldwater_arg = ctx->water_arg;
1563         if (water == NULL) {
1564                 callwater = ctx->hi_called;
1565                 ctx->water = NULL;
1566                 ctx->water_arg = NULL;
1567                 ctx->hi_water = 0;
1568                 ctx->lo_water = 0;
1569                 ctx->hi_called = ISC_FALSE;
1570         } else {
1571                 if (ctx->hi_called &&
1572                     (ctx->water != water || ctx->water_arg != water_arg ||
1573                      ctx->inuse < lowater || lowater == 0U))
1574                         callwater = ISC_TRUE;
1575                 ctx->water = water;
1576                 ctx->water_arg = water_arg;
1577                 ctx->hi_water = hiwater;
1578                 ctx->lo_water = lowater;
1579                 ctx->hi_called = ISC_FALSE;
1580         }
1581         MCTXUNLOCK(ctx, &ctx->lock);
1582
1583         if (callwater && oldwater != NULL)
1584                 (oldwater)(oldwater_arg, ISC_MEM_LOWATER);
1585 }
1586
1587 isc_boolean_t
1588 isc_mem_isovermem(isc_mem_t *ctx) {
1589         REQUIRE(VALID_CONTEXT(ctx));
1590
1591         /*
1592          * We don't bother to lock the context because 100% accuracy isn't
1593          * necessary (and even if we locked the context the returned value
1594          * could be different from the actual state when it's used anyway)
1595          */
1596         return (ctx->is_overmem);
1597 }
1598
1599 void
1600 isc_mem_setname(isc_mem_t *ctx, const char *name, void *tag) {
1601         REQUIRE(VALID_CONTEXT(ctx));
1602
1603         LOCK(&ctx->lock);
1604         memset(ctx->name, 0, sizeof(ctx->name));
1605         strncpy(ctx->name, name, sizeof(ctx->name) - 1);
1606         ctx->tag = tag;
1607         UNLOCK(&ctx->lock);
1608 }
1609
1610 const char *
1611 isc_mem_getname(isc_mem_t *ctx) {
1612         REQUIRE(VALID_CONTEXT(ctx));
1613
1614         return (ctx->name);
1615 }
1616
1617 void *
1618 isc_mem_gettag(isc_mem_t *ctx) {
1619         REQUIRE(VALID_CONTEXT(ctx));
1620
1621         return (ctx->tag);
1622 }
1623
1624 /*
1625  * Memory pool stuff
1626  */
1627
1628 isc_result_t
1629 isc_mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp) {
1630         isc_mempool_t *mpctx;
1631
1632         REQUIRE(VALID_CONTEXT(mctx));
1633         REQUIRE(size > 0U);
1634         REQUIRE(mpctxp != NULL && *mpctxp == NULL);
1635
1636         /*
1637          * Allocate space for this pool, initialize values, and if all works
1638          * well, attach to the memory context.
1639          */
1640         mpctx = isc_mem_get(mctx, sizeof(isc_mempool_t));
1641         if (mpctx == NULL)
1642                 return (ISC_R_NOMEMORY);
1643
1644         mpctx->magic = MEMPOOL_MAGIC;
1645         mpctx->lock = NULL;
1646         mpctx->mctx = mctx;
1647         mpctx->size = size;
1648         mpctx->maxalloc = UINT_MAX;
1649         mpctx->allocated = 0;
1650         mpctx->freecount = 0;
1651         mpctx->freemax = 1;
1652         mpctx->fillcount = 1;
1653         mpctx->gets = 0;
1654 #if ISC_MEMPOOL_NAMES
1655         mpctx->name[0] = 0;
1656 #endif
1657         mpctx->items = NULL;
1658
1659         *mpctxp = mpctx;
1660
1661         MCTXLOCK(mctx, &mctx->lock);
1662         ISC_LIST_INITANDAPPEND(mctx->pools, mpctx, link);
1663         mctx->poolcnt++;
1664         MCTXUNLOCK(mctx, &mctx->lock);
1665
1666         return (ISC_R_SUCCESS);
1667 }
1668
1669 void
1670 isc_mempool_setname(isc_mempool_t *mpctx, const char *name) {
1671         REQUIRE(name != NULL);
1672
1673 #if ISC_MEMPOOL_NAMES
1674         if (mpctx->lock != NULL)
1675                 LOCK(mpctx->lock);
1676
1677         strncpy(mpctx->name, name, sizeof(mpctx->name) - 1);
1678         mpctx->name[sizeof(mpctx->name) - 1] = '\0';
1679
1680         if (mpctx->lock != NULL)
1681                 UNLOCK(mpctx->lock);
1682 #else
1683         UNUSED(mpctx);
1684         UNUSED(name);
1685 #endif
1686 }
1687
1688 void
1689 isc_mempool_destroy(isc_mempool_t **mpctxp) {
1690         isc_mempool_t *mpctx;
1691         isc_mem_t *mctx;
1692         isc_mutex_t *lock;
1693         element *item;
1694
1695         REQUIRE(mpctxp != NULL);
1696         mpctx = *mpctxp;
1697         REQUIRE(VALID_MEMPOOL(mpctx));
1698 #if ISC_MEMPOOL_NAMES
1699         if (mpctx->allocated > 0)
1700                 UNEXPECTED_ERROR(__FILE__, __LINE__,
1701                                  "isc_mempool_destroy(): mempool %s "
1702                                  "leaked memory",
1703                                  mpctx->name);
1704 #endif
1705         REQUIRE(mpctx->allocated == 0);
1706
1707         mctx = mpctx->mctx;
1708
1709         lock = mpctx->lock;
1710
1711         if (lock != NULL)
1712                 LOCK(lock);
1713
1714         /*
1715          * Return any items on the free list
1716          */
1717         MCTXLOCK(mctx, &mctx->lock);
1718         while (mpctx->items != NULL) {
1719                 INSIST(mpctx->freecount > 0);
1720                 mpctx->freecount--;
1721                 item = mpctx->items;
1722                 mpctx->items = item->next;
1723
1724                 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1725                         mem_putunlocked(mctx, item, mpctx->size);
1726                 } else {
1727                         mem_put(mctx, item, mpctx->size);
1728                         mem_putstats(mctx, item, mpctx->size);
1729                 }
1730         }
1731         MCTXUNLOCK(mctx, &mctx->lock);
1732
1733         /*
1734          * Remove our linked list entry from the memory context.
1735          */
1736         MCTXLOCK(mctx, &mctx->lock);
1737         ISC_LIST_UNLINK(mctx->pools, mpctx, link);
1738         mctx->poolcnt--;
1739         MCTXUNLOCK(mctx, &mctx->lock);
1740
1741         mpctx->magic = 0;
1742
1743         isc_mem_put(mpctx->mctx, mpctx, sizeof(isc_mempool_t));
1744
1745         if (lock != NULL)
1746                 UNLOCK(lock);
1747
1748         *mpctxp = NULL;
1749 }
1750
1751 void
1752 isc_mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock) {
1753         REQUIRE(VALID_MEMPOOL(mpctx));
1754         REQUIRE(mpctx->lock == NULL);
1755         REQUIRE(lock != NULL);
1756
1757         mpctx->lock = lock;
1758 }
1759
1760 void *
1761 isc__mempool_get(isc_mempool_t *mpctx FLARG) {
1762         element *item;
1763         isc_mem_t *mctx;
1764         unsigned int i;
1765
1766         REQUIRE(VALID_MEMPOOL(mpctx));
1767
1768         mctx = mpctx->mctx;
1769
1770         if (mpctx->lock != NULL)
1771                 LOCK(mpctx->lock);
1772
1773         /*
1774          * Don't let the caller go over quota
1775          */
1776         if (mpctx->allocated >= mpctx->maxalloc) {
1777                 item = NULL;
1778                 goto out;
1779         }
1780
1781         /*
1782          * if we have a free list item, return the first here
1783          */
1784         item = mpctx->items;
1785         if (item != NULL) {
1786                 mpctx->items = item->next;
1787                 INSIST(mpctx->freecount > 0);
1788                 mpctx->freecount--;
1789                 mpctx->gets++;
1790                 mpctx->allocated++;
1791                 goto out;
1792         }
1793
1794         /*
1795          * We need to dip into the well.  Lock the memory context here and
1796          * fill up our free list.
1797          */
1798         MCTXLOCK(mctx, &mctx->lock);
1799         for (i = 0; i < mpctx->fillcount; i++) {
1800                 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1801                         item = mem_getunlocked(mctx, mpctx->size);
1802                 } else {
1803                         item = mem_get(mctx, mpctx->size);
1804                         if (item != NULL)
1805                                 mem_getstats(mctx, mpctx->size);
1806                 }
1807                 if (item == NULL)
1808                         break;
1809                 item->next = mpctx->items;
1810                 mpctx->items = item;
1811                 mpctx->freecount++;
1812         }
1813         MCTXUNLOCK(mctx, &mctx->lock);
1814
1815         /*
1816          * If we didn't get any items, return NULL.
1817          */
1818         item = mpctx->items;
1819         if (item == NULL)
1820                 goto out;
1821
1822         mpctx->items = item->next;
1823         mpctx->freecount--;
1824         mpctx->gets++;
1825         mpctx->allocated++;
1826
1827  out:
1828         if (mpctx->lock != NULL)
1829                 UNLOCK(mpctx->lock);
1830
1831 #if ISC_MEM_TRACKLINES
1832         if (item != NULL) {
1833                 MCTXLOCK(mctx, &mctx->lock);
1834                 ADD_TRACE(mctx, item, mpctx->size, file, line);
1835                 MCTXUNLOCK(mctx, &mctx->lock);
1836         }
1837 #endif /* ISC_MEM_TRACKLINES */
1838
1839         return (item);
1840 }
1841
1842 void
1843 isc__mempool_put(isc_mempool_t *mpctx, void *mem FLARG) {
1844         isc_mem_t *mctx;
1845         element *item;
1846
1847         REQUIRE(VALID_MEMPOOL(mpctx));
1848         REQUIRE(mem != NULL);
1849
1850         mctx = mpctx->mctx;
1851
1852         if (mpctx->lock != NULL)
1853                 LOCK(mpctx->lock);
1854
1855         INSIST(mpctx->allocated > 0);
1856         mpctx->allocated--;
1857
1858 #if ISC_MEM_TRACKLINES
1859         MCTXLOCK(mctx, &mctx->lock);
1860         DELETE_TRACE(mctx, mem, mpctx->size, file, line);
1861         MCTXUNLOCK(mctx, &mctx->lock);
1862 #endif /* ISC_MEM_TRACKLINES */
1863
1864         /*
1865          * If our free list is full, return this to the mctx directly.
1866          */
1867         if (mpctx->freecount >= mpctx->freemax) {
1868                 if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1869                         MCTXLOCK(mctx, &mctx->lock);
1870                         mem_putunlocked(mctx, mem, mpctx->size);
1871                         MCTXUNLOCK(mctx, &mctx->lock);
1872                 } else {
1873                         mem_put(mctx, mem, mpctx->size);
1874                         MCTXLOCK(mctx, &mctx->lock);
1875                         mem_putstats(mctx, mem, mpctx->size);
1876                         MCTXUNLOCK(mctx, &mctx->lock);
1877                 }
1878                 if (mpctx->lock != NULL)
1879                         UNLOCK(mpctx->lock);
1880                 return;
1881         }
1882
1883         /*
1884          * Otherwise, attach it to our free list and bump the counter.
1885          */
1886         mpctx->freecount++;
1887         item = (element *)mem;
1888         item->next = mpctx->items;
1889         mpctx->items = item;
1890
1891         if (mpctx->lock != NULL)
1892                 UNLOCK(mpctx->lock);
1893 }
1894
1895 /*
1896  * Quotas
1897  */
1898
1899 void
1900 isc_mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit) {
1901         REQUIRE(VALID_MEMPOOL(mpctx));
1902
1903         if (mpctx->lock != NULL)
1904                 LOCK(mpctx->lock);
1905
1906         mpctx->freemax = limit;
1907
1908         if (mpctx->lock != NULL)
1909                 UNLOCK(mpctx->lock);
1910 }
1911
1912 unsigned int
1913 isc_mempool_getfreemax(isc_mempool_t *mpctx) {
1914         unsigned int freemax;
1915
1916         REQUIRE(VALID_MEMPOOL(mpctx));
1917
1918         if (mpctx->lock != NULL)
1919                 LOCK(mpctx->lock);
1920
1921         freemax = mpctx->freemax;
1922
1923         if (mpctx->lock != NULL)
1924                 UNLOCK(mpctx->lock);
1925
1926         return (freemax);
1927 }
1928
1929 unsigned int
1930 isc_mempool_getfreecount(isc_mempool_t *mpctx) {
1931         unsigned int freecount;
1932
1933         REQUIRE(VALID_MEMPOOL(mpctx));
1934
1935         if (mpctx->lock != NULL)
1936                 LOCK(mpctx->lock);
1937
1938         freecount = mpctx->freecount;
1939
1940         if (mpctx->lock != NULL)
1941                 UNLOCK(mpctx->lock);
1942
1943         return (freecount);
1944 }
1945
1946 void
1947 isc_mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit) {
1948         REQUIRE(limit > 0);
1949
1950         REQUIRE(VALID_MEMPOOL(mpctx));
1951
1952         if (mpctx->lock != NULL)
1953                 LOCK(mpctx->lock);
1954
1955         mpctx->maxalloc = limit;
1956
1957         if (mpctx->lock != NULL)
1958                 UNLOCK(mpctx->lock);
1959 }
1960
1961 unsigned int
1962 isc_mempool_getmaxalloc(isc_mempool_t *mpctx) {
1963         unsigned int maxalloc;
1964
1965         REQUIRE(VALID_MEMPOOL(mpctx));
1966
1967         if (mpctx->lock != NULL)
1968                 LOCK(mpctx->lock);
1969
1970         maxalloc = mpctx->maxalloc;
1971
1972         if (mpctx->lock != NULL)
1973                 UNLOCK(mpctx->lock);
1974
1975         return (maxalloc);
1976 }
1977
1978 unsigned int
1979 isc_mempool_getallocated(isc_mempool_t *mpctx) {
1980         unsigned int allocated;
1981
1982         REQUIRE(VALID_MEMPOOL(mpctx));
1983
1984         if (mpctx->lock != NULL)
1985                 LOCK(mpctx->lock);
1986
1987         allocated = mpctx->allocated;
1988
1989         if (mpctx->lock != NULL)
1990                 UNLOCK(mpctx->lock);
1991
1992         return (allocated);
1993 }
1994
1995 void
1996 isc_mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit) {
1997         REQUIRE(limit > 0);
1998         REQUIRE(VALID_MEMPOOL(mpctx));
1999
2000         if (mpctx->lock != NULL)
2001                 LOCK(mpctx->lock);
2002
2003         mpctx->fillcount = limit;
2004
2005         if (mpctx->lock != NULL)
2006                 UNLOCK(mpctx->lock);
2007 }
2008
2009 unsigned int
2010 isc_mempool_getfillcount(isc_mempool_t *mpctx) {
2011         unsigned int fillcount;
2012
2013         REQUIRE(VALID_MEMPOOL(mpctx));
2014
2015         if (mpctx->lock != NULL)
2016                 LOCK(mpctx->lock);
2017
2018         fillcount = mpctx->fillcount;
2019
2020         if (mpctx->lock != NULL)
2021                 UNLOCK(mpctx->lock);
2022
2023         return (fillcount);
2024 }
2025
2026 void
2027 isc_mem_printactive(isc_mem_t *ctx, FILE *file) {
2028
2029         REQUIRE(VALID_CONTEXT(ctx));
2030         REQUIRE(file != NULL);
2031
2032 #if !ISC_MEM_TRACKLINES
2033         UNUSED(ctx);
2034         UNUSED(file);
2035 #else
2036         print_active(ctx, file);
2037 #endif
2038 }
2039
2040 void
2041 isc_mem_printallactive(FILE *file) {
2042 #if !ISC_MEM_TRACKLINES
2043         UNUSED(file);
2044 #else
2045         isc_mem_t *ctx;
2046
2047         RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2048
2049         LOCK(&lock);
2050         for (ctx = ISC_LIST_HEAD(contexts);
2051              ctx != NULL;
2052              ctx = ISC_LIST_NEXT(ctx, link)) {
2053                 fprintf(file, "context: %p\n", ctx);
2054                 print_active(ctx, file);
2055         }
2056         UNLOCK(&lock);
2057 #endif
2058 }
2059
2060 void
2061 isc_mem_checkdestroyed(FILE *file) {
2062
2063         RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2064
2065         LOCK(&lock);
2066         if (!ISC_LIST_EMPTY(contexts))  {
2067 #if ISC_MEM_TRACKLINES
2068                 isc_mem_t *ctx;
2069
2070                 for (ctx = ISC_LIST_HEAD(contexts);
2071                      ctx != NULL;
2072                      ctx = ISC_LIST_NEXT(ctx, link)) {
2073                         fprintf(file, "context: %p\n", ctx);
2074                         print_active(ctx, file);
2075                 }
2076                 fflush(file);
2077 #endif
2078                 INSIST(0);
2079         }
2080         UNLOCK(&lock);
2081 }
2082
2083 unsigned int
2084 isc_mem_references(isc_mem_t *ctx) {
2085         unsigned int references;
2086         REQUIRE(VALID_CONTEXT(ctx));
2087
2088         MCTXLOCK(ctx, &ctx->lock);
2089         references = ctx->references;
2090         MCTXUNLOCK(ctx, &ctx->lock);
2091
2092         return (references);
2093 }
2094
2095 #ifdef HAVE_LIBXML2
2096
2097 typedef struct summarystat {
2098         isc_uint64_t    total;
2099         isc_uint64_t    inuse;
2100         isc_uint64_t    blocksize;
2101         isc_uint64_t    contextsize;
2102 } summarystat_t;
2103
2104 static void
2105 renderctx(isc_mem_t *ctx, summarystat_t *summary, xmlTextWriterPtr writer) {
2106         REQUIRE(VALID_CONTEXT(ctx));
2107
2108         xmlTextWriterStartElement(writer, ISC_XMLCHAR "context");
2109
2110         xmlTextWriterStartElement(writer, ISC_XMLCHAR "id");
2111         xmlTextWriterWriteFormatString(writer, "%p", ctx);
2112         xmlTextWriterEndElement(writer); /* id */
2113
2114         if (ctx->name[0] != 0) {
2115                 xmlTextWriterStartElement(writer, ISC_XMLCHAR "name");
2116                 xmlTextWriterWriteFormatString(writer, "%s", ctx->name);
2117                 xmlTextWriterEndElement(writer); /* name */
2118         }
2119
2120         REQUIRE(VALID_CONTEXT(ctx));
2121         MCTXLOCK(ctx, &ctx->lock);
2122
2123         summary->contextsize += sizeof(*ctx) +
2124                 (ctx->max_size + 1) * sizeof(struct stats) +
2125                 ctx->max_size * sizeof(element *) +
2126                 ctx->basic_table_count * sizeof(char *);
2127 #if ISC_MEM_TRACKLINES
2128         if (ctx->debuglist != NULL) {
2129                 summary->contextsize +=
2130                         (ctx->max_size + 1) * sizeof(debuglist_t) +
2131                         ctx->debuglistcnt * sizeof(debuglink_t);
2132         }
2133 #endif
2134         xmlTextWriterStartElement(writer, ISC_XMLCHAR "references");
2135         xmlTextWriterWriteFormatString(writer, "%d", ctx->references);
2136         xmlTextWriterEndElement(writer); /* references */
2137
2138         summary->total += ctx->total;
2139         xmlTextWriterStartElement(writer, ISC_XMLCHAR "total");
2140         xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2141                                        (isc_uint64_t)ctx->total);
2142         xmlTextWriterEndElement(writer); /* total */
2143
2144         summary->inuse += ctx->inuse;
2145         xmlTextWriterStartElement(writer, ISC_XMLCHAR "inuse");
2146         xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2147                                        (isc_uint64_t)ctx->inuse);
2148         xmlTextWriterEndElement(writer); /* inuse */
2149
2150         xmlTextWriterStartElement(writer, ISC_XMLCHAR "maxinuse");
2151         xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2152                                        (isc_uint64_t)ctx->maxinuse);
2153         xmlTextWriterEndElement(writer); /* maxinuse */
2154
2155         xmlTextWriterStartElement(writer, ISC_XMLCHAR "blocksize");
2156         if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
2157                 summary->blocksize += ctx->basic_table_count *
2158                         NUM_BASIC_BLOCKS * ctx->mem_target;
2159                 xmlTextWriterWriteFormatString(writer,
2160                                                "%" ISC_PRINT_QUADFORMAT "u",
2161                                                (isc_uint64_t)
2162                                                ctx->basic_table_count *
2163                                                NUM_BASIC_BLOCKS *
2164                                                ctx->mem_target);
2165         } else
2166                 xmlTextWriterWriteFormatString(writer, "%s", "-");
2167         xmlTextWriterEndElement(writer); /* blocksize */
2168
2169         xmlTextWriterStartElement(writer, ISC_XMLCHAR "pools");
2170         xmlTextWriterWriteFormatString(writer, "%u", ctx->poolcnt);
2171         xmlTextWriterEndElement(writer); /* pools */
2172         summary->contextsize += ctx->poolcnt * sizeof(isc_mempool_t);
2173
2174         xmlTextWriterStartElement(writer, ISC_XMLCHAR "hiwater");
2175         xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2176                                        (isc_uint64_t)ctx->hi_water);
2177         xmlTextWriterEndElement(writer); /* hiwater */
2178
2179         xmlTextWriterStartElement(writer, ISC_XMLCHAR "lowater");
2180         xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2181                                        (isc_uint64_t)ctx->lo_water);
2182         xmlTextWriterEndElement(writer); /* lowater */
2183
2184         MCTXUNLOCK(ctx, &ctx->lock);
2185
2186         xmlTextWriterEndElement(writer); /* context */
2187 }
2188
2189 void
2190 isc_mem_renderxml(xmlTextWriterPtr writer) {
2191         isc_mem_t *ctx;
2192         summarystat_t summary;
2193         isc_uint64_t lost;
2194
2195         memset(&summary, 0, sizeof(summary));
2196
2197         xmlTextWriterStartElement(writer, ISC_XMLCHAR "contexts");
2198
2199         RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2200
2201         LOCK(&lock);
2202         lost = totallost;
2203         for (ctx = ISC_LIST_HEAD(contexts);
2204              ctx != NULL;
2205              ctx = ISC_LIST_NEXT(ctx, link)) {
2206                 renderctx(ctx, &summary, writer);
2207         }
2208         UNLOCK(&lock);
2209
2210         xmlTextWriterEndElement(writer); /* contexts */
2211
2212         xmlTextWriterStartElement(writer, ISC_XMLCHAR "summary");
2213
2214         xmlTextWriterStartElement(writer, ISC_XMLCHAR "TotalUse");
2215         xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2216                                        summary.total);
2217         xmlTextWriterEndElement(writer); /* TotalUse */
2218
2219         xmlTextWriterStartElement(writer, ISC_XMLCHAR "InUse");
2220         xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2221                                        summary.inuse);
2222         xmlTextWriterEndElement(writer); /* InUse */
2223
2224         xmlTextWriterStartElement(writer, ISC_XMLCHAR "BlockSize");
2225         xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2226                                        summary.blocksize);
2227         xmlTextWriterEndElement(writer); /* BlockSize */
2228
2229         xmlTextWriterStartElement(writer, ISC_XMLCHAR "ContextSize");
2230         xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2231                                        summary.contextsize);
2232         xmlTextWriterEndElement(writer); /* ContextSize */
2233
2234         xmlTextWriterStartElement(writer, ISC_XMLCHAR "Lost");
2235         xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
2236                                        lost);
2237         xmlTextWriterEndElement(writer); /* Lost */
2238
2239         xmlTextWriterEndElement(writer); /* summary */
2240 }
2241
2242 #endif /* HAVE_LIBXML2 */