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