Merge from vendor branch OPENPAM:
[dragonfly.git] / contrib / bind-9.2.4rc7 / lib / isc / mem.c
1 /*
2  * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1997-2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and 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.98.2.9 2004/03/09 06:11:48 marka Exp $ */
19
20 #include <config.h>
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stddef.h>
25
26 #include <limits.h>
27
28 #include <isc/magic.h>
29 #include <isc/mem.h>
30 #include <isc/msgs.h>
31 #include <isc/ondestroy.h>
32 #include <isc/string.h>
33
34 #include <isc/mutex.h>
35 #include <isc/util.h>
36
37 #ifndef ISC_MEM_DEBUGGING
38 #define ISC_MEM_DEBUGGING 0
39 #endif
40 LIBISC_EXTERNAL_DATA unsigned int isc_mem_debugging = ISC_MEM_DEBUGGING;
41
42 /*
43  * Define ISC_MEM_USE_INTERNAL_MALLOC=1 to use the internal malloc()
44  * implementation in preference to the system one.  The internal malloc()
45  * is very space-efficient, and quite fast on uniprocessor systems.  It
46  * performs poorly on multiprocessor machines.
47  */
48 #ifndef ISC_MEM_USE_INTERNAL_MALLOC
49 #define ISC_MEM_USE_INTERNAL_MALLOC 0
50 #endif
51
52 /*
53  * Constants.
54  */
55
56 #define DEF_MAX_SIZE            1100
57 #define DEF_MEM_TARGET          4096
58 #define ALIGNMENT_SIZE          8               /* must be a power of 2 */
59 #define NUM_BASIC_BLOCKS        64              /* must be > 1 */
60 #define TABLE_INCREMENT         1024
61 #define DEBUGLIST_COUNT         1024
62
63 /*
64  * Types.
65  */
66 #if ISC_MEM_TRACKLINES
67 typedef struct debuglink debuglink_t;
68 struct debuglink {
69         ISC_LINK(debuglink_t)   link;
70         const void             *ptr[DEBUGLIST_COUNT];
71         const char             *file[DEBUGLIST_COUNT];
72         unsigned int            line[DEBUGLIST_COUNT];
73         unsigned int            count;
74 };
75
76 #define FLARG_PASS      , file, line
77 #define FLARG           , const char *file, int line
78 #else
79 #define FLARG_PASS
80 #define FLARG
81 #endif
82
83 typedef struct element element;
84 struct element {
85         element *               next;
86 };
87
88 typedef struct {
89         /*
90          * This structure must be ALIGNMENT_SIZE bytes.
91          */
92         union {
93                 size_t          size;
94                 char            bytes[ALIGNMENT_SIZE];
95         } u;
96 } size_info;
97
98 struct stats {
99         unsigned long           gets;
100         unsigned long           totalgets;
101 #if ISC_MEM_USE_INTERNAL_MALLOC
102         unsigned long           blocks;
103         unsigned long           freefrags;
104 #endif /* ISC_MEM_USE_INTERNAL_MALLOC */
105 };
106
107 #define MEM_MAGIC               ISC_MAGIC('M', 'e', 'm', 'C')
108 #define VALID_CONTEXT(c)        ISC_MAGIC_VALID(c, MEM_MAGIC)
109
110 struct isc_mem {
111         unsigned int            magic;
112         isc_ondestroy_t         ondestroy;
113         isc_mutex_t             lock;
114         isc_memalloc_t          memalloc;
115         isc_memfree_t           memfree;
116         void *                  arg;
117         size_t                  max_size;
118         isc_boolean_t           checkfree;
119         struct stats *          stats;
120         unsigned int            references;
121         size_t                  quota;
122         size_t                  total;
123         size_t                  inuse;
124         size_t                  maxinuse;
125         size_t                  hi_water;
126         size_t                  lo_water;
127         isc_boolean_t           hi_called;
128         isc_mem_water_t         water;
129         void *                  water_arg;
130         ISC_LIST(isc_mempool_t) pools;
131
132 #if ISC_MEM_USE_INTERNAL_MALLOC
133         size_t                  mem_target;
134         element **              freelists;
135         element *               basic_blocks;
136         unsigned char **        basic_table;
137         unsigned int            basic_table_count;
138         unsigned int            basic_table_size;
139         unsigned char *         lowest;
140         unsigned char *         highest;
141 #endif /* ISC_MEM_USE_INTERNAL_MALLOC */
142
143 #if ISC_MEM_TRACKLINES
144         ISC_LIST(debuglink_t)   debuglist;
145         unsigned int            debugging;
146 #endif
147
148         unsigned int            memalloc_failures;
149 };
150
151 #define MEMPOOL_MAGIC           ISC_MAGIC('M', 'E', 'M', 'p')
152 #define VALID_MEMPOOL(c)        ISC_MAGIC_VALID(c, MEMPOOL_MAGIC)
153
154 struct isc_mempool {
155         /* always unlocked */
156         unsigned int    magic;          /* magic number */
157         isc_mutex_t    *lock;           /* optional lock */
158         isc_mem_t      *mctx;           /* our memory context */
159         /* locked via the memory context's lock */
160         ISC_LINK(isc_mempool_t) link;   /* next pool in this mem context */
161         /* optionally locked from here down */
162         element        *items;          /* low water item list */
163         size_t          size;           /* size of each item on this pool */
164         unsigned int    maxalloc;       /* max number of items allowed */
165         unsigned int    allocated;      /* # of items currently given out */
166         unsigned int    freecount;      /* # of items on reserved list */
167         unsigned int    freemax;        /* # of items allowed on free list */
168         unsigned int    fillcount;      /* # of items to fetch on each fill */
169         /* Stats only. */
170         unsigned int    gets;           /* # of requests to this pool */
171         /* Debugging only. */
172 #if ISC_MEMPOOL_NAMES
173         char            name[16];       /* printed name in stats reports */
174 #endif
175 };
176
177 /*
178  * Private Inline-able.
179  */
180
181 #if ! ISC_MEM_TRACKLINES
182 #define ADD_TRACE(a, b, c, d, e)
183 #define DELETE_TRACE(a, b, c, d, e)
184 #else
185 #define ADD_TRACE(a, b, c, d, e) \
186         do { if (b != NULL) add_trace_entry(a, b, c, d, e); } while (0)
187 #define DELETE_TRACE(a, b, c, d, e)     delete_trace_entry(a, b, c, d, e)
188
189 #define MEM_TRACE       ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
190 #define MEM_RECORD      ((mctx->debugging & ISC_MEM_DEBUGRECORD) != 0)
191
192 static void
193 print_active(isc_mem_t *ctx, FILE *out);
194
195 /*
196  * mctx must be locked.
197  */
198 static inline void
199 add_trace_entry(isc_mem_t *mctx, const void *ptr, unsigned int size
200                 FLARG)
201 {
202         debuglink_t *dl;
203         unsigned int i;
204
205         if (MEM_TRACE)
206                 fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
207                                                ISC_MSG_ADDTRACE,
208                                                "add %p size %u "
209                                                "file %s line %u mctx %p\n"),
210                         ptr, size, file, line, mctx);
211
212         if (!MEM_RECORD)
213                 return;
214
215         dl = ISC_LIST_HEAD(mctx->debuglist);
216         while (dl != NULL) {
217                 if (dl->count == DEBUGLIST_COUNT)
218                         goto next;
219                 for (i = 0 ; i < DEBUGLIST_COUNT ; i++) {
220                         if (dl->ptr[i] == NULL) {
221                                 dl->ptr[i] = ptr;
222                                 dl->file[i] = file;
223                                 dl->line[i] = line;
224                                 dl->count++;
225                                 return;
226                         }
227                 }
228         next:
229                 dl = ISC_LIST_NEXT(dl, link);
230         }
231
232         dl = malloc(sizeof(debuglink_t));
233         INSIST(dl != NULL);
234
235         ISC_LINK_INIT(dl, link);
236         for (i = 1 ; i < DEBUGLIST_COUNT ; i++) {
237                 dl->ptr[i] = NULL;
238                 dl->file[i] = NULL;
239                 dl->line[i] = 0;
240         }
241
242         dl->ptr[0] = ptr;
243         dl->file[0] = file;
244         dl->line[0] = line;
245         dl->count = 1;
246
247         ISC_LIST_PREPEND(mctx->debuglist, dl, link);
248 }
249
250 static inline void
251 delete_trace_entry(isc_mem_t *mctx, const void *ptr, unsigned int size,
252                    const char *file, unsigned int line)
253 {
254         debuglink_t *dl;
255         unsigned int i;
256
257         if (MEM_TRACE)
258                 fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
259                                                ISC_MSG_DELTRACE,
260                                                "del %p size %u "
261                                                "file %s line %u mctx %p\n"),
262                         ptr, size, file, line, mctx);
263
264         if (!MEM_RECORD)
265                 return;
266
267         dl = ISC_LIST_HEAD(mctx->debuglist);
268         while (dl != NULL) {
269                 for (i = 0 ; i < DEBUGLIST_COUNT ; i++) {
270                         if (dl->ptr[i] == ptr) {
271                                 dl->ptr[i] = NULL;
272                                 dl->file[i] = NULL;
273                                 dl->line[i] = 0;
274
275                                 INSIST(dl->count > 0);
276                                 dl->count--;
277                                 if (dl->count == 0) {
278                                         ISC_LIST_UNLINK(mctx->debuglist,
279                                                         dl, link);
280                                         free(dl);
281                                 }
282                                 return;
283                         }
284                 }
285                 dl = ISC_LIST_NEXT(dl, link);
286         }
287
288         /*
289          * If we get here, we didn't find the item on the list.  We're
290          * screwed.
291          */
292         INSIST(dl != NULL);
293 }
294 #endif /* ISC_MEM_TRACKLINES */
295
296 #if ISC_MEM_USE_INTERNAL_MALLOC
297 static inline size_t
298 rmsize(size_t size) {
299         /*
300          * round down to ALIGNMENT_SIZE
301          */
302         return (size & (~(ALIGNMENT_SIZE - 1)));
303 }
304
305 static inline size_t
306 quantize(size_t size) {
307         /*
308          * Round up the result in order to get a size big
309          * enough to satisfy the request and be aligned on ALIGNMENT_SIZE
310          * byte boundaries.
311          */
312
313         if (size == 0)
314                 return (ALIGNMENT_SIZE);
315         return ((size + ALIGNMENT_SIZE - 1) & (~(ALIGNMENT_SIZE - 1)));
316 }
317
318 static inline isc_boolean_t
319 more_basic_blocks(isc_mem_t *ctx) {
320         void *new;
321         unsigned char *curr, *next;
322         unsigned char *first, *last;
323         unsigned char **table;
324         unsigned int table_size;
325         size_t increment;
326         int i;
327
328         /* Require: we hold the context lock. */
329
330         /*
331          * Did we hit the quota for this context?
332          */
333         increment = NUM_BASIC_BLOCKS * ctx->mem_target;
334         if (ctx->quota != 0 && ctx->total + increment > ctx->quota)
335                 return (ISC_FALSE);
336
337         INSIST(ctx->basic_table_count <= ctx->basic_table_size);
338         if (ctx->basic_table_count == ctx->basic_table_size) {
339                 table_size = ctx->basic_table_size + TABLE_INCREMENT;
340                 table = (ctx->memalloc)(ctx->arg,
341                                         table_size * sizeof (unsigned char *));
342                 if (table == NULL) {
343                         ctx->memalloc_failures++;
344                         return (ISC_FALSE);
345                 }
346                 if (ctx->basic_table_size != 0) {
347                         memcpy(table, ctx->basic_table,
348                                ctx->basic_table_size *
349                                sizeof (unsigned char *));
350                         (ctx->memfree)(ctx->arg, ctx->basic_table);
351                 }
352                 ctx->basic_table = table;
353                 ctx->basic_table_size = table_size;
354         }
355
356         new = (ctx->memalloc)(ctx->arg, NUM_BASIC_BLOCKS * ctx->mem_target);
357         if (new == NULL) {
358                 ctx->memalloc_failures++;
359                 return (ISC_FALSE);
360         }
361         ctx->total += increment;
362         ctx->basic_table[ctx->basic_table_count] = new;
363         ctx->basic_table_count++;
364
365         curr = new;
366         next = curr + ctx->mem_target;
367         for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) {
368                 ((element *)curr)->next = (element *)next;
369                 curr = next;
370                 next += ctx->mem_target;
371         }
372         /*
373          * curr is now pointing at the last block in the
374          * array.
375          */
376         ((element *)curr)->next = NULL;
377         first = new;
378         last = first + NUM_BASIC_BLOCKS * ctx->mem_target - 1;
379         if (first < ctx->lowest || ctx->lowest == NULL)
380                 ctx->lowest = first;
381         if (last > ctx->highest)
382                 ctx->highest = last;
383         ctx->basic_blocks = new;
384
385         return (ISC_TRUE);
386 }
387
388 static inline isc_boolean_t
389 more_frags(isc_mem_t *ctx, size_t new_size) {
390         int i, frags;
391         size_t total_size;
392         void *new;
393         unsigned char *curr, *next;
394
395         /*
396          * Try to get more fragments by chopping up a basic block.
397          */
398
399         if (ctx->basic_blocks == NULL) {
400                 if (!more_basic_blocks(ctx)) {
401                         /*
402                          * We can't get more memory from the OS, or we've
403                          * hit the quota for this context.
404                          */
405                         /*
406                          * XXXRTH  "At quota" notification here.
407                          */
408                         return (ISC_FALSE);
409                 }
410         }
411
412         total_size = ctx->mem_target;
413         new = ctx->basic_blocks;
414         ctx->basic_blocks = ctx->basic_blocks->next;
415         frags = total_size / new_size;
416         ctx->stats[new_size].blocks++;
417         ctx->stats[new_size].freefrags += frags;
418         /*
419          * Set up a linked-list of blocks of size
420          * "new_size".
421          */
422         curr = new;
423         next = curr + new_size;
424         total_size -= new_size;
425         for (i = 0; i < (frags - 1); i++) {
426                 ((element *)curr)->next = (element *)next;
427                 curr = next;
428                 next += new_size;
429                 total_size -= new_size;
430         }
431         /*
432          * Add the remaining fragment of the basic block to a free list.
433          */
434         total_size = rmsize(total_size);
435         if (total_size > 0) {
436                 ((element *)next)->next = ctx->freelists[total_size];
437                 ctx->freelists[total_size] = (element *)next;
438                 ctx->stats[total_size].freefrags++;
439         }
440         /*
441          * curr is now pointing at the last block in the
442          * array.
443          */
444         ((element *)curr)->next = NULL;
445         ctx->freelists[new_size] = new;
446
447         return (ISC_TRUE);
448 }
449
450 static inline void *
451 mem_getunlocked(isc_mem_t *ctx, size_t size) {
452         size_t new_size = quantize(size);
453         void *ret;
454
455         if (size >= ctx->max_size || new_size >= ctx->max_size) {
456                 /*
457                  * memget() was called on something beyond our upper limit.
458                  */
459                 if (ctx->quota != 0 && ctx->total + size > ctx->quota) {
460                         ret = NULL;
461                         goto done;
462                 }
463                 ret = (ctx->memalloc)(ctx->arg, size);
464                 if (ret == NULL) {
465                         ctx->memalloc_failures++;
466                         goto done;
467                 }
468                 ctx->total += size;
469                 ctx->inuse += size;
470                 ctx->stats[ctx->max_size].gets++;
471                 ctx->stats[ctx->max_size].totalgets++;
472                 /*
473                  * If we don't set new_size to size, then the
474                  * ISC_MEM_FILL code might write over bytes we
475                  * don't own.
476                  */
477                 new_size = size;
478                 goto done;
479         }
480
481         /*
482          * If there are no blocks in the free list for this size, get a chunk
483          * of memory and then break it up into "new_size"-sized blocks, adding
484          * them to the free list.
485          */
486         if (ctx->freelists[new_size] == NULL && !more_frags(ctx, new_size))
487                 return (NULL);
488
489         /*
490          * The free list uses the "rounded-up" size "new_size".
491          */
492         ret = ctx->freelists[new_size];
493         ctx->freelists[new_size] = ctx->freelists[new_size]->next;
494
495         /*
496          * The stats[] uses the _actual_ "size" requested by the
497          * caller, with the caveat (in the code above) that "size" >= the
498          * max. size (max_size) ends up getting recorded as a call to
499          * max_size.
500          */
501         ctx->stats[size].gets++;
502         ctx->stats[size].totalgets++;
503         ctx->stats[new_size].freefrags--;
504         ctx->inuse += new_size;
505
506  done:
507
508 #if ISC_MEM_FILL
509         if (ret != NULL)
510                 memset(ret, 0xbe, new_size); /* Mnemonic for "beef". */
511 #endif
512
513         return (ret);
514 }
515
516 #if ISC_MEM_FILL && ISC_MEM_CHECKOVERRUN
517 static inline void
518 check_overrun(void *mem, size_t size, size_t new_size) {
519         unsigned char *cp;
520
521         cp = (unsigned char *)mem;
522         cp += size;
523         while (size < new_size) {
524                 INSIST(*cp == 0xbe);
525                 cp++;
526                 size++;
527         }
528 }
529 #endif
530
531 static inline void
532 mem_putunlocked(isc_mem_t *ctx, void *mem, size_t size) {
533         size_t new_size = quantize(size);
534
535         if (size == ctx->max_size || new_size >= ctx->max_size) {
536                 /*
537                  * memput() called on something beyond our upper limit.
538                  */
539 #if ISC_MEM_FILL
540                 memset(mem, 0xde, size); /* Mnemonic for "dead". */
541 #endif
542                 (ctx->memfree)(ctx->arg, mem);
543                 INSIST(ctx->stats[ctx->max_size].gets != 0);
544                 ctx->stats[ctx->max_size].gets--;
545                 INSIST(size <= ctx->total);
546                 ctx->inuse -= size;
547                 ctx->total -= size;
548                 return;
549         }
550
551 #if ISC_MEM_FILL
552 #if ISC_MEM_CHECKOVERRUN
553         check_overrun(mem, size, new_size);
554 #endif
555         memset(mem, 0xde, new_size); /* Mnemonic for "dead". */
556 #endif
557
558         /*
559          * The free list uses the "rounded-up" size "new_size".
560          */
561         ((element *)mem)->next = ctx->freelists[new_size];
562         ctx->freelists[new_size] = (element *)mem;
563
564         /*
565          * The stats[] uses the _actual_ "size" requested by the
566          * caller, with the caveat (in the code above) that "size" >= the
567          * max. size (max_size) ends up getting recorded as a call to
568          * max_size.
569          */
570         INSIST(ctx->stats[size].gets != 0);
571         ctx->stats[size].gets--;
572         ctx->stats[new_size].freefrags++;
573         ctx->inuse -= new_size;
574 }
575
576 #else /* ISC_MEM_USE_INTERNAL_MALLOC */
577
578 /*
579  * Perform a malloc, doing memory filling and overrun detection as necessary.
580  */
581 static inline void *
582 mem_get(isc_mem_t *ctx, size_t size) {
583         char *ret;
584
585 #if ISC_MEM_CHECKOVERRUN
586         size += 1;
587 #endif
588
589         ret = (ctx->memalloc)(ctx->arg, size);
590         if (ret == NULL)
591                 ctx->memalloc_failures++;       
592
593 #if ISC_MEM_FILL
594         if (ret != NULL)
595                 memset(ret, 0xbe, size); /* Mnemonic for "beef". */
596 #else
597 #  if ISC_MEM_CHECKOVERRUN
598         if (ret != NULL)
599                 ret[size-1] = 0xbe;
600 #  endif
601 #endif
602
603         return (ret);
604 }
605
606 /*
607  * Perform a free, doing memory filling and overrun detection as necessary.
608  */
609 static inline void
610 mem_put(isc_mem_t *ctx, void *mem, size_t size) {
611 #if ISC_MEM_CHECKOVERRUN
612         INSIST(((unsigned char *)mem)[size] == 0xbe);
613 #endif
614 #if ISC_MEM_FILL
615         memset(mem, 0xde, size); /* Mnemonic for "dead". */
616 #else
617         UNUSED(size);
618 #endif
619         (ctx->memfree)(ctx->arg, mem);
620 }
621
622 /*
623  * Update internal counters after a memory get.
624  */
625 static inline void
626 mem_getstats(isc_mem_t *ctx, size_t size) {
627         ctx->total += size;
628         ctx->inuse += size;
629
630         if (size > ctx->max_size) {
631                 ctx->stats[ctx->max_size].gets++;
632                 ctx->stats[ctx->max_size].totalgets++;
633         } else {
634                 ctx->stats[size].gets++;
635                 ctx->stats[size].totalgets++;
636         }
637 }
638
639 /*
640  * Update internal counters after a memory put.
641  */
642 static inline void
643 mem_putstats(isc_mem_t *ctx, void *ptr, size_t size) {
644         UNUSED(ptr);
645
646         INSIST(ctx->inuse >= size);
647         ctx->inuse -= size;
648
649         if (size > ctx->max_size) {
650                 INSIST(ctx->stats[ctx->max_size].gets > 0U);
651                 ctx->stats[ctx->max_size].gets--;
652         } else {
653                 INSIST(ctx->stats[size].gets > 0U);
654                 ctx->stats[size].gets--;
655         }
656 }
657
658 #endif /* ISC_MEM_USE_INTERNAL_MALLOC */
659
660 /*
661  * Private.
662  */
663
664 static void *
665 default_memalloc(void *arg, size_t size) {
666         UNUSED(arg);
667         if (size == 0U)
668                 size = 1;
669         return (malloc(size));
670 }
671
672 static void
673 default_memfree(void *arg, void *ptr) {
674         UNUSED(arg);
675         free(ptr);
676 }
677
678 /*
679  * Public.
680  */
681
682 isc_result_t
683 isc_mem_createx(size_t init_max_size, size_t target_size,
684                 isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
685                 isc_mem_t **ctxp)
686 {
687         isc_mem_t *ctx;
688         isc_result_t result;
689
690         REQUIRE(ctxp != NULL && *ctxp == NULL);
691         REQUIRE(memalloc != NULL);
692         REQUIRE(memfree != NULL);
693
694         INSIST((ALIGNMENT_SIZE & (ALIGNMENT_SIZE - 1)) == 0);
695
696 #if !ISC_MEM_USE_INTERNAL_MALLOC
697         UNUSED(target_size);
698 #endif
699
700         ctx = (memalloc)(arg, sizeof *ctx);
701         if (ctx == NULL)
702                 return (ISC_R_NOMEMORY);
703
704         if (init_max_size == 0U)
705                 ctx->max_size = DEF_MAX_SIZE;
706         else
707                 ctx->max_size = init_max_size;
708         ctx->references = 1;
709         ctx->quota = 0;
710         ctx->total = 0;
711         ctx->inuse = 0;
712         ctx->maxinuse = 0;
713         ctx->hi_water = 0;
714         ctx->lo_water = 0;
715         ctx->hi_called = ISC_FALSE;
716         ctx->water = NULL;
717         ctx->water_arg = NULL;
718         ctx->magic = MEM_MAGIC;
719         isc_ondestroy_init(&ctx->ondestroy);
720         ctx->memalloc = memalloc;
721         ctx->memfree = memfree;
722         ctx->arg = arg;
723         ctx->stats = NULL;
724         ctx->checkfree = ISC_TRUE;
725         ISC_LIST_INIT(ctx->pools);
726
727 #if ISC_MEM_USE_INTERNAL_MALLOC
728         ctx->freelists = NULL;
729 #endif /* ISC_MEM_USE_INTERNAL_MALLOC */
730
731         ctx->stats = (memalloc)(arg,
732                                 (ctx->max_size+1) * sizeof (struct stats));
733         if (ctx->stats == NULL) {
734                 result = ISC_R_NOMEMORY;
735                 goto error;
736         }
737         memset(ctx->stats, 0, (ctx->max_size + 1) * sizeof (struct stats));
738
739 #if ISC_MEM_USE_INTERNAL_MALLOC
740         if (target_size == 0)
741                 ctx->mem_target = DEF_MEM_TARGET;
742         else
743                 ctx->mem_target = target_size;
744         ctx->freelists = (memalloc)(arg, ctx->max_size * sizeof (element *));
745         if (ctx->freelists == NULL) {
746                 result = ISC_R_NOMEMORY;
747                 goto error;
748         }
749         memset(ctx->freelists, 0,
750                ctx->max_size * sizeof (element *));
751         ctx->basic_blocks = NULL;
752         ctx->basic_table = NULL;
753         ctx->basic_table_count = 0;
754         ctx->basic_table_size = 0;
755         ctx->lowest = NULL;
756         ctx->highest = NULL;
757 #endif /* ISC_MEM_USE_INTERNAL_MALLOC */
758
759         if (isc_mutex_init(&ctx->lock) != ISC_R_SUCCESS) {
760                 UNEXPECTED_ERROR(__FILE__, __LINE__,
761                                  "isc_mutex_init() %s",
762                                  isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
763                                                 ISC_MSG_FAILED, "failed"));
764                 result = ISC_R_UNEXPECTED;
765                 goto error;
766         }
767
768 #if ISC_MEM_TRACKLINES
769         ISC_LIST_INIT(ctx->debuglist);
770         ctx->debugging = isc_mem_debugging;
771 #endif
772
773         ctx->memalloc_failures = 0;
774
775         *ctxp = ctx;
776         return (ISC_R_SUCCESS);
777
778   error:
779         if (ctx) {
780                 if (ctx->stats)
781                         (memfree)(arg, ctx->stats);
782 #if ISC_MEM_USE_INTERNAL_MALLOC
783                 if (ctx->freelists)
784                         (memfree)(arg, ctx->freelists);
785 #endif /* ISC_MEM_USE_INTERNAL_MALLOC */
786                 (memfree)(arg, ctx);
787         }
788
789         return (result);
790 }
791
792 isc_result_t
793 isc_mem_create(size_t init_max_size, size_t target_size,
794                isc_mem_t **ctxp)
795 {
796         return (isc_mem_createx(init_max_size, target_size,
797                                 default_memalloc, default_memfree, NULL,
798                                 ctxp));
799 }
800
801 static void
802 destroy(isc_mem_t *ctx) {
803         unsigned int i;
804         isc_ondestroy_t ondest;
805
806         ctx->magic = 0;
807
808 #if ISC_MEM_USE_INTERNAL_MALLOC
809         INSIST(ISC_LIST_EMPTY(ctx->pools));
810 #endif /* ISC_MEM_USE_INTERNAL_MALLOC */
811
812 #if ISC_MEM_TRACKLINES
813         if (ctx->checkfree) {
814                 if (!ISC_LIST_EMPTY(ctx->debuglist))
815                         print_active(ctx, stderr);
816                 INSIST(ISC_LIST_EMPTY(ctx->debuglist));
817         } else {
818                 debuglink_t *dl;
819
820                 for (dl = ISC_LIST_HEAD(ctx->debuglist);
821                      dl != NULL;
822                      dl = ISC_LIST_HEAD(ctx->debuglist)) {
823                         ISC_LIST_UNLINK(ctx->debuglist, dl, link);
824                         free(dl);
825                 }
826         }
827 #endif
828         INSIST(ctx->references == 0);
829
830         if (ctx->checkfree) {
831                 for (i = 0; i <= ctx->max_size; i++) {
832 #if ISC_MEM_TRACKLINES
833                         if (ctx->stats[i].gets != 0)
834                                 print_active(ctx, stderr);
835 #endif
836                         INSIST(ctx->stats[i].gets == 0U);
837                 }
838         }
839
840         (ctx->memfree)(ctx->arg, ctx->stats);
841
842 #if ISC_MEM_USE_INTERNAL_MALLOC
843         for (i = 0; i < ctx->basic_table_count; i++)
844                 (ctx->memfree)(ctx->arg, ctx->basic_table[i]);
845         (ctx->memfree)(ctx->arg, ctx->freelists);
846         (ctx->memfree)(ctx->arg, ctx->basic_table);
847 #endif /* ISC_MEM_USE_INTERNAL_MALLOC */
848
849         ondest = ctx->ondestroy;
850
851         DESTROYLOCK(&ctx->lock);
852         (ctx->memfree)(ctx->arg, ctx);
853
854         isc_ondestroy_notify(&ondest, ctx);
855 }
856
857 void
858 isc_mem_attach(isc_mem_t *source, isc_mem_t **targetp) {
859         REQUIRE(VALID_CONTEXT(source));
860         REQUIRE(targetp != NULL && *targetp == NULL);
861
862         LOCK(&source->lock);
863         source->references++;
864         UNLOCK(&source->lock);
865
866         *targetp = source;
867 }
868
869 void
870 isc_mem_detach(isc_mem_t **ctxp) {
871         isc_mem_t *ctx;
872         isc_boolean_t want_destroy = ISC_FALSE;
873
874         REQUIRE(ctxp != NULL);
875         ctx = *ctxp;
876         REQUIRE(VALID_CONTEXT(ctx));
877
878         LOCK(&ctx->lock);
879         INSIST(ctx->references > 0);
880         ctx->references--;
881         if (ctx->references == 0)
882                 want_destroy = ISC_TRUE;
883         UNLOCK(&ctx->lock);
884
885         if (want_destroy)
886                 destroy(ctx);
887
888         *ctxp = NULL;
889 }
890
891 /*
892  * isc_mem_putanddetach() is the equivalent of:
893  *
894  * mctx = NULL;
895  * isc_mem_attach(ptr->mctx, &mctx);
896  * isc_mem_detach(&ptr->mctx);
897  * isc_mem_put(mctx, ptr, sizeof(*ptr);
898  * isc_mem_detach(&mctx);
899  */
900
901 void
902 isc__mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) {
903         isc_mem_t *ctx;
904         isc_boolean_t want_destroy = ISC_FALSE;
905
906         REQUIRE(ctxp != NULL);
907         ctx = *ctxp;
908         REQUIRE(VALID_CONTEXT(ctx));
909         REQUIRE(ptr != NULL);
910
911         /*
912          * Must be before mem_putunlocked() as ctxp is usually within
913          * [ptr..ptr+size).
914          */
915         *ctxp = NULL;
916
917 #if ISC_MEM_USE_INTERNAL_MALLOC
918         LOCK(&ctx->lock);
919         mem_putunlocked(ctx, ptr, size);
920 #else /* ISC_MEM_USE_INTERNAL_MALLOC */
921         mem_put(ctx, ptr, size);
922         LOCK(&ctx->lock);
923         mem_putstats(ctx, ptr, size);
924 #endif /* ISC_MEM_USE_INTERNAL_MALLOC */
925
926         DELETE_TRACE(ctx, ptr, size, file, line);
927         INSIST(ctx->references > 0);
928         ctx->references--;
929         if (ctx->references == 0)
930                 want_destroy = ISC_TRUE;
931
932         UNLOCK(&ctx->lock);
933
934         if (want_destroy)
935                 destroy(ctx);
936 }
937
938 void
939 isc_mem_destroy(isc_mem_t **ctxp) {
940         isc_mem_t *ctx;
941
942         /*
943          * This routine provides legacy support for callers who use mctxs
944          * without attaching/detaching.
945          */
946
947         REQUIRE(ctxp != NULL);
948         ctx = *ctxp;
949         REQUIRE(VALID_CONTEXT(ctx));
950
951         LOCK(&ctx->lock);
952 #if ISC_MEM_TRACKLINES
953         if (ctx->references != 1)
954                 print_active(ctx, stderr);
955 #endif
956         REQUIRE(ctx->references == 1);
957         ctx->references--;
958         UNLOCK(&ctx->lock);
959
960         destroy(ctx);
961
962         *ctxp = NULL;
963 }
964
965 isc_result_t
966 isc_mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event) {
967         isc_result_t res;
968
969         LOCK(&ctx->lock);
970         res = isc_ondestroy_register(&ctx->ondestroy, task, event);
971         UNLOCK(&ctx->lock);
972
973         return (res);
974 }
975
976
977 void *
978 isc__mem_get(isc_mem_t *ctx, size_t size FLARG) {
979         void *ptr;
980         isc_boolean_t call_water = ISC_FALSE;
981
982         REQUIRE(VALID_CONTEXT(ctx));
983
984 #if ISC_MEM_USE_INTERNAL_MALLOC
985         LOCK(&ctx->lock);
986         ptr = mem_getunlocked(ctx, size);
987 #else /* ISC_MEM_USE_INTERNAL_MALLOC */
988         ptr = mem_get(ctx, size);
989         LOCK(&ctx->lock);
990         if (ptr)
991                 mem_getstats(ctx, size);
992 #endif /* ISC_MEM_USE_INTERNAL_MALLOC */
993
994         ADD_TRACE(ctx, ptr, size, file, line);
995         if (ctx->hi_water != 0U && !ctx->hi_called &&
996             ctx->inuse > ctx->hi_water) {
997                 ctx->hi_called = ISC_TRUE;
998                 call_water = ISC_TRUE;
999         }
1000         if (ctx->inuse > ctx->maxinuse) {
1001                 ctx->maxinuse = ctx->inuse;
1002                 if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1003                     (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
1004                         fprintf(stderr, "maxinuse = %lu\n",
1005                                 (unsigned long)ctx->inuse);
1006         }
1007         UNLOCK(&ctx->lock);
1008
1009         if (call_water) {
1010                 (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
1011         }
1012
1013         return (ptr);
1014 }
1015
1016 void
1017 isc__mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG)
1018 {
1019         isc_boolean_t call_water = ISC_FALSE;
1020
1021         REQUIRE(VALID_CONTEXT(ctx));
1022         REQUIRE(ptr != NULL);
1023
1024 #if ISC_MEM_USE_INTERNAL_MALLOC
1025         LOCK(&ctx->lock);
1026         mem_putunlocked(ctx, ptr, size);
1027 #else /* ISC_MEM_USE_INTERNAL_MALLOC */
1028         mem_put(ctx, ptr, size);
1029         LOCK(&ctx->lock);
1030         mem_putstats(ctx, ptr, size);
1031 #endif /* ISC_MEM_USE_INTERNAL_MALLOC */
1032
1033         DELETE_TRACE(ctx, ptr, size, file, line);
1034
1035         /*
1036          * The check against ctx->lo_water == 0 is for the condition
1037          * when the context was pushed over hi_water but then had
1038          * isc_mem_setwater() called with 0 for hi_water and lo_water.
1039          */
1040         if (ctx->hi_called && 
1041             (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1042                 ctx->hi_called = ISC_FALSE;
1043
1044                 if (ctx->water != NULL)
1045                         call_water = ISC_TRUE;
1046         }
1047         UNLOCK(&ctx->lock);
1048
1049         if (call_water) {
1050                 (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
1051         }
1052 }
1053
1054 #if ISC_MEM_TRACKLINES
1055 static void
1056 print_active(isc_mem_t *mctx, FILE *out) {
1057         if (MEM_RECORD) {
1058                 debuglink_t *dl;
1059                 unsigned int i;
1060
1061                 fprintf(out, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1062                                             ISC_MSG_DUMPALLOC,
1063                                             "Dump of all outstanding "
1064                                             "memory allocations:\n"));
1065                 dl = ISC_LIST_HEAD(mctx->debuglist);
1066                 if (dl == NULL)
1067                         fprintf(out, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1068                                                     ISC_MSG_NONE,
1069                                                     "\tNone.\n"));
1070                 while (dl != NULL) {
1071                         for (i = 0 ; i < DEBUGLIST_COUNT ; i++)
1072                                 if (dl->ptr[i] != NULL)
1073                                         fprintf(out,
1074                                                 isc_msgcat_get(isc_msgcat,
1075                                                            ISC_MSGSET_MEM,
1076                                                            ISC_MSG_PTRFILELINE,
1077                                                            "\tptr %p "
1078                                                            "file %s "
1079                                                            "line %u\n"),
1080                                                 dl->ptr[i], dl->file[i],
1081                                                 dl->line[i]);
1082                         dl = ISC_LIST_NEXT(dl, link);
1083                 }
1084         }
1085 }
1086 #endif
1087
1088 /*
1089  * Print the stats[] on the stream "out" with suitable formatting.
1090  */
1091 void
1092 isc_mem_stats(isc_mem_t *ctx, FILE *out) {
1093         size_t i;
1094         const struct stats *s;
1095         const isc_mempool_t *pool;
1096
1097         REQUIRE(VALID_CONTEXT(ctx));
1098         LOCK(&ctx->lock);
1099
1100         for (i = 0; i <= ctx->max_size; i++) {
1101                 s = &ctx->stats[i];
1102
1103                 if (s->totalgets == 0U && s->gets == 0U)
1104                         continue;
1105                 fprintf(out, "%s%5lu: %11lu gets, %11lu rem",
1106                         (i == ctx->max_size) ? ">=" : "  ",
1107                         (unsigned long) i, s->totalgets, s->gets);
1108 #if ISC_MEM_USE_INTERNAL_MALLOC
1109                 if (s->blocks != 0 || s->freefrags != 0)
1110                         fprintf(out, " (%lu bl, %lu ff)",
1111                                 s->blocks, s->freefrags);
1112 #endif /* ISC_MEM_USE_INTERNAL_MALLOC */
1113                 fputc('\n', out);
1114         }
1115
1116         /*
1117          * Note that since a pool can be locked now, these stats might be
1118          * somewhat off if the pool is in active use at the time the stats
1119          * are dumped.  The link fields are protected by the isc_mem_t's
1120          * lock, however, so walking this list and extracting integers from
1121          * stats fields is always safe.
1122          */
1123         pool = ISC_LIST_HEAD(ctx->pools);
1124         if (pool != NULL) {
1125                 fprintf(out, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1126                                             ISC_MSG_POOLSTATS,
1127                                             "[Pool statistics]\n"));
1128                 fprintf(out, "%15s %10s %10s %10s %10s %10s %10s %10s %1s\n",
1129                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1130                                        ISC_MSG_POOLNAME, "name"),
1131                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1132                                        ISC_MSG_POOLSIZE, "size"),
1133                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1134                                        ISC_MSG_POOLMAXALLOC, "maxalloc"),
1135                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1136                                        ISC_MSG_POOLALLOCATED, "allocated"),
1137                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1138                                        ISC_MSG_POOLFREECOUNT, "freecount"),
1139                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1140                                        ISC_MSG_POOLFREEMAX, "freemax"),
1141                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1142                                        ISC_MSG_POOLFILLCOUNT, "fillcount"),
1143                         isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1144                                        ISC_MSG_POOLGETS, "gets"),
1145                         "L");
1146         }
1147         while (pool != NULL) {
1148                 fprintf(out, "%15s %10lu %10u %10u %10u %10u %10u %10u %s\n",
1149                         pool->name, (unsigned long) pool->size, pool->maxalloc,
1150                         pool->allocated, pool->freecount, pool->freemax,
1151                         pool->fillcount, pool->gets,
1152                         (pool->lock == NULL ? "N" : "Y"));
1153                 pool = ISC_LIST_NEXT(pool, link);
1154         }
1155
1156 #if ISC_MEM_TRACKLINES
1157         print_active(ctx, out);
1158 #endif
1159
1160         UNLOCK(&ctx->lock);
1161 }
1162
1163 /*
1164  * Replacements for malloc() and free() -- they implicitly remember the
1165  * size of the object allocated (with some additional overhead).
1166  */
1167
1168 static void *
1169 isc__mem_allocateunlocked(isc_mem_t *ctx, size_t size) {
1170         size_info *si;
1171
1172         size += ALIGNMENT_SIZE;
1173 #if ISC_MEM_USE_INTERNAL_MALLOC
1174         si = mem_getunlocked(ctx, size);
1175 #else /* ISC_MEM_USE_INTERNAL_MALLOC */
1176         si = mem_get(ctx, size);
1177 #endif /* ISC_MEM_USE_INTERNAL_MALLOC */
1178         if (si == NULL)
1179                 return (NULL);
1180         si->u.size = size;
1181         return (&si[1]);
1182 }
1183
1184 void *
1185 isc__mem_allocate(isc_mem_t *ctx, size_t size FLARG) {
1186         size_info *si;
1187
1188         REQUIRE(VALID_CONTEXT(ctx));
1189
1190 #if ISC_MEM_USE_INTERNAL_MALLOC
1191         LOCK(&ctx->lock);
1192         si = isc__mem_allocateunlocked(ctx, size);
1193 #else /* ISC_MEM_USE_INTERNAL_MALLOC */
1194         si = isc__mem_allocateunlocked(ctx, size);
1195         LOCK(&ctx->lock);
1196         if (si != NULL)
1197                 mem_getstats(ctx, si[-1].u.size);
1198 #endif /* ISC_MEM_USE_INTERNAL_MALLOC */
1199
1200 #if ISC_MEM_TRACKLINES
1201         if (si != NULL)
1202                 ADD_TRACE(ctx, si, si[-1].u.size, file, line);
1203 #endif
1204
1205         UNLOCK(&ctx->lock);
1206
1207         return (si);
1208 }
1209
1210 void
1211 isc__mem_free(isc_mem_t *ctx, void *ptr FLARG) {
1212         size_info *si;
1213         size_t size;
1214
1215         REQUIRE(VALID_CONTEXT(ctx));
1216         REQUIRE(ptr != NULL);
1217
1218         si = &(((size_info *)ptr)[-1]);
1219         size = si->u.size;
1220
1221 #if ISC_MEM_USE_INTERNAL_MALLOC
1222         LOCK(&ctx->lock);
1223         mem_putunlocked(ctx, si, size);
1224 #else /* ISC_MEM_USE_INTERNAL_MALLOC */
1225         mem_put(ctx, si, size);
1226         LOCK(&ctx->lock);
1227         mem_putstats(ctx, si, size);
1228 #endif /* ISC_MEM_USE_INTERNAL_MALLOC */
1229
1230         DELETE_TRACE(ctx, ptr, size, file, line);
1231
1232         UNLOCK(&ctx->lock);
1233 }
1234
1235
1236 /*
1237  * Other useful things.
1238  */
1239
1240 char *
1241 isc__mem_strdup(isc_mem_t *mctx, const char *s FLARG) {
1242         size_t len;
1243         char *ns;
1244
1245         REQUIRE(VALID_CONTEXT(mctx));
1246         REQUIRE(s != NULL);
1247
1248         len = strlen(s);
1249
1250         ns = isc__mem_allocate(mctx, len + 1 FLARG_PASS);
1251
1252         if (ns != NULL)
1253                 strncpy(ns, s, len + 1);
1254
1255         return (ns);
1256 }
1257
1258 void
1259 isc_mem_setdestroycheck(isc_mem_t *ctx, isc_boolean_t flag) {
1260         REQUIRE(VALID_CONTEXT(ctx));
1261         LOCK(&ctx->lock);
1262
1263         ctx->checkfree = flag;
1264
1265         UNLOCK(&ctx->lock);
1266 }
1267
1268 /*
1269  * Quotas
1270  */
1271
1272 void
1273 isc_mem_setquota(isc_mem_t *ctx, size_t quota) {
1274         REQUIRE(VALID_CONTEXT(ctx));
1275         LOCK(&ctx->lock);
1276
1277         ctx->quota = quota;
1278
1279         UNLOCK(&ctx->lock);
1280 }
1281
1282 size_t
1283 isc_mem_getquota(isc_mem_t *ctx) {
1284         size_t quota;
1285
1286         REQUIRE(VALID_CONTEXT(ctx));
1287         LOCK(&ctx->lock);
1288
1289         quota = ctx->quota;
1290
1291         UNLOCK(&ctx->lock);
1292
1293         return (quota);
1294 }
1295
1296 size_t
1297 isc_mem_inuse(isc_mem_t *ctx) {
1298         size_t inuse;
1299
1300         REQUIRE(VALID_CONTEXT(ctx));
1301         LOCK(&ctx->lock);
1302
1303         inuse = ctx->inuse;
1304
1305         UNLOCK(&ctx->lock);
1306
1307         return (inuse);
1308 }
1309
1310 void
1311 isc_mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg,
1312                  size_t hiwater, size_t lowater)
1313 {
1314         REQUIRE(VALID_CONTEXT(ctx));
1315         REQUIRE(hiwater >= lowater);
1316
1317         LOCK(&ctx->lock);
1318         if (water == NULL) {
1319                 ctx->water = NULL;
1320                 ctx->water_arg = NULL;
1321                 ctx->hi_water = 0;
1322                 ctx->lo_water = 0;
1323                 ctx->hi_called = ISC_FALSE;
1324         } else {
1325                 ctx->water = water;
1326                 ctx->water_arg = water_arg;
1327                 ctx->hi_water = hiwater;
1328                 ctx->lo_water = lowater;
1329                 ctx->hi_called = ISC_FALSE;
1330         }
1331         UNLOCK(&ctx->lock);
1332 }
1333
1334 /*
1335  * Memory pool stuff
1336  */
1337
1338 isc_result_t
1339 isc_mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp) {
1340         isc_mempool_t *mpctx;
1341
1342         REQUIRE(VALID_CONTEXT(mctx));
1343         REQUIRE(size > 0U);
1344         REQUIRE(mpctxp != NULL && *mpctxp == NULL);
1345
1346         /*
1347          * Allocate space for this pool, initialize values, and if all works
1348          * well, attach to the memory context.
1349          */
1350         mpctx = isc_mem_get(mctx, sizeof(isc_mempool_t));
1351         if (mpctx == NULL)
1352                 return (ISC_R_NOMEMORY);
1353
1354         mpctx->magic = MEMPOOL_MAGIC;
1355         mpctx->lock = NULL;
1356         mpctx->mctx = mctx;
1357         mpctx->size = size;
1358         mpctx->maxalloc = UINT_MAX;
1359         mpctx->allocated = 0;
1360         mpctx->freecount = 0;
1361         mpctx->freemax = 1;
1362         mpctx->fillcount = 1;
1363         mpctx->gets = 0;
1364 #if ISC_MEMPOOL_NAMES
1365         mpctx->name[0] = 0;
1366 #endif
1367         mpctx->items = NULL;
1368
1369         *mpctxp = mpctx;
1370
1371         LOCK(&mctx->lock);
1372         ISC_LIST_INITANDAPPEND(mctx->pools, mpctx, link);
1373         UNLOCK(&mctx->lock);
1374
1375         return (ISC_R_SUCCESS);
1376 }
1377
1378 void
1379 isc_mempool_setname(isc_mempool_t *mpctx, const char *name) {
1380         REQUIRE(name != NULL);
1381
1382 #if ISC_MEMPOOL_NAMES
1383         if (mpctx->lock != NULL)
1384                 LOCK(mpctx->lock);
1385
1386         strncpy(mpctx->name, name, sizeof(mpctx->name) - 1);
1387         mpctx->name[sizeof(mpctx->name) - 1] = '\0';
1388
1389         if (mpctx->lock != NULL)
1390                 UNLOCK(mpctx->lock);
1391 #else
1392         UNUSED(mpctx);
1393         UNUSED(name);
1394 #endif
1395 }
1396
1397 void
1398 isc_mempool_destroy(isc_mempool_t **mpctxp) {
1399         isc_mempool_t *mpctx;
1400         isc_mem_t *mctx;
1401         isc_mutex_t *lock;
1402         element *item;
1403
1404         REQUIRE(mpctxp != NULL);
1405         mpctx = *mpctxp;
1406         REQUIRE(VALID_MEMPOOL(mpctx));
1407 #if ISC_MEMPOOL_NAMES
1408         if (mpctx->allocated > 0)
1409                 UNEXPECTED_ERROR(__FILE__, __LINE__,
1410                                  "isc_mempool_destroy(): mempool %s "
1411                                  "leaked memory",
1412                                  mpctx->name);
1413 #endif
1414         REQUIRE(mpctx->allocated == 0);
1415
1416         mctx = mpctx->mctx;
1417
1418         lock = mpctx->lock;
1419
1420         if (lock != NULL)
1421                 LOCK(lock);
1422
1423         /*
1424          * Return any items on the free list
1425          */
1426         while (mpctx->items != NULL) {
1427                 INSIST(mpctx->freecount > 0);
1428                 mpctx->freecount--;
1429                 item = mpctx->items;
1430                 mpctx->items = item->next;
1431
1432 #if ISC_MEM_USE_INTERNAL_MALLOC
1433                 LOCK(&mctx->lock);
1434                 mem_putunlocked(mctx, item, mpctx->size);
1435                 UNLOCK(&mctx->lock);
1436 #else /* ISC_MEM_USE_INTERNAL_MALLOC */
1437                 mem_put(mctx, item, mpctx->size);
1438 #endif /* ISC_MEM_USE_INTERNAL_MALLOC */
1439         }
1440
1441         /*
1442          * Remove our linked list entry from the memory context.
1443          */
1444         LOCK(&mctx->lock);
1445         ISC_LIST_UNLINK(mctx->pools, mpctx, link);
1446         UNLOCK(&mctx->lock);
1447
1448         mpctx->magic = 0;
1449
1450         isc_mem_put(mpctx->mctx, mpctx, sizeof(isc_mempool_t));
1451
1452         if (lock != NULL)
1453                 UNLOCK(lock);
1454
1455         *mpctxp = NULL;
1456 }
1457
1458 void
1459 isc_mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock) {
1460         REQUIRE(VALID_MEMPOOL(mpctx));
1461         REQUIRE(mpctx->lock == NULL);
1462         REQUIRE(lock != NULL);
1463
1464         mpctx->lock = lock;
1465 }
1466
1467 void *
1468 isc__mempool_get(isc_mempool_t *mpctx FLARG) {
1469         element *item;
1470         isc_mem_t *mctx;
1471         unsigned int i;
1472
1473         REQUIRE(VALID_MEMPOOL(mpctx));
1474
1475         mctx = mpctx->mctx;
1476
1477         if (mpctx->lock != NULL)
1478                 LOCK(mpctx->lock);
1479
1480         /*
1481          * Don't let the caller go over quota
1482          */
1483         if (mpctx->allocated >= mpctx->maxalloc) {
1484                 item = NULL;
1485                 goto out;
1486         }
1487
1488         /*
1489          * if we have a free list item, return the first here
1490          */
1491         item = mpctx->items;
1492         if (item != NULL) {
1493                 mpctx->items = item->next;
1494                 INSIST(mpctx->freecount > 0);
1495                 mpctx->freecount--;
1496                 mpctx->gets++;
1497                 mpctx->allocated++;
1498                 goto out;
1499         }
1500
1501         /*
1502          * We need to dip into the well.  Lock the memory context here and
1503          * fill up our free list.
1504          */
1505         for (i = 0 ; i < mpctx->fillcount ; i++) {
1506 #if ISC_MEM_USE_INTERNAL_MALLOC
1507                 LOCK(&mctx->lock);
1508                 item = mem_getunlocked(mctx, mpctx->size);
1509                 UNLOCK(&mctx->lock);
1510 #else /* ISC_MEM_USE_INTERNAL_MALLOC */
1511                 item = mem_get(mctx, mpctx->size);
1512 #endif /* ISC_MEM_USE_INTERNAL_MALLOC */
1513                 if (item == NULL)
1514                         break;
1515                 item->next = mpctx->items;
1516                 mpctx->items = item;
1517                 mpctx->freecount++;
1518         }
1519
1520         /*
1521          * If we didn't get any items, return NULL.
1522          */
1523         item = mpctx->items;
1524         if (item == NULL)
1525                 goto out;
1526
1527         mpctx->items = item->next;
1528         mpctx->freecount--;
1529         mpctx->gets++;
1530         mpctx->allocated++;
1531
1532  out:
1533         if (mpctx->lock != NULL)
1534                 UNLOCK(mpctx->lock);
1535
1536 #if ISC_MEM_TRACKLINES
1537         if (item != NULL) {
1538                 LOCK(&mctx->lock);
1539                 ADD_TRACE(mctx, item, mpctx->size, file, line);
1540                 UNLOCK(&mctx->lock);
1541         }
1542 #endif /* ISC_MEM_TRACKLINES */
1543
1544         return (item);
1545 }
1546
1547 void
1548 isc__mempool_put(isc_mempool_t *mpctx, void *mem FLARG) {
1549         isc_mem_t *mctx;
1550         element *item;
1551
1552         REQUIRE(VALID_MEMPOOL(mpctx));
1553         REQUIRE(mem != NULL);
1554
1555         mctx = mpctx->mctx;
1556
1557         if (mpctx->lock != NULL)
1558                 LOCK(mpctx->lock);
1559
1560         INSIST(mpctx->allocated > 0);
1561         mpctx->allocated--;
1562
1563 #if ISC_MEM_TRACKLINES
1564         LOCK(&mctx->lock);
1565         DELETE_TRACE(mctx, mem, mpctx->size, file, line);
1566         UNLOCK(&mctx->lock);
1567 #endif /* ISC_MEM_TRACKLINES */
1568
1569         /*
1570          * If our free list is full, return this to the mctx directly.
1571          */
1572         if (mpctx->freecount >= mpctx->freemax) {
1573 #if ISC_MEM_USE_INTERNAL_MALLOC
1574                 LOCK(&mctx->lock);
1575                 mem_putunlocked(mctx, mem, mpctx->size);
1576                 UNLOCK(&mctx->lock);
1577 #else /* ISC_MEM_USE_INTERNAL_MALLOC */
1578                 mem_put(mctx, mem, mpctx->size);
1579 #endif /* ISC_MEM_USE_INTERNAL_MALLOC */
1580                 if (mpctx->lock != NULL)
1581                         UNLOCK(mpctx->lock);
1582                 return;
1583         }
1584
1585         /*
1586          * Otherwise, attach it to our free list and bump the counter.
1587          */
1588         mpctx->freecount++;
1589         item = (element *)mem;
1590         item->next = mpctx->items;
1591         mpctx->items = item;
1592
1593         if (mpctx->lock != NULL)
1594                 UNLOCK(mpctx->lock);
1595 }
1596
1597 /*
1598  * Quotas
1599  */
1600
1601 void
1602 isc_mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit) {
1603         REQUIRE(VALID_MEMPOOL(mpctx));
1604
1605         if (mpctx->lock != NULL)
1606                 LOCK(mpctx->lock);
1607
1608         mpctx->freemax = limit;
1609
1610         if (mpctx->lock != NULL)
1611                 UNLOCK(mpctx->lock);
1612 }
1613
1614 unsigned int
1615 isc_mempool_getfreemax(isc_mempool_t *mpctx) {
1616         unsigned int freemax;
1617
1618         REQUIRE(VALID_MEMPOOL(mpctx));
1619
1620         if (mpctx->lock != NULL)
1621                 LOCK(mpctx->lock);
1622
1623         freemax = mpctx->freemax;
1624
1625         if (mpctx->lock != NULL)
1626                 UNLOCK(mpctx->lock);
1627
1628         return (freemax);
1629 }
1630
1631 unsigned int
1632 isc_mempool_getfreecount(isc_mempool_t *mpctx) {
1633         unsigned int freecount;
1634
1635         REQUIRE(VALID_MEMPOOL(mpctx));
1636
1637         if (mpctx->lock != NULL)
1638                 LOCK(mpctx->lock);
1639
1640         freecount = mpctx->freecount;
1641
1642         if (mpctx->lock != NULL)
1643                 UNLOCK(mpctx->lock);
1644
1645         return (freecount);
1646 }
1647
1648 void
1649 isc_mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit) {
1650         REQUIRE(limit > 0);
1651
1652         REQUIRE(VALID_MEMPOOL(mpctx));
1653
1654         if (mpctx->lock != NULL)
1655                 LOCK(mpctx->lock);
1656
1657         mpctx->maxalloc = limit;
1658
1659         if (mpctx->lock != NULL)
1660                 UNLOCK(mpctx->lock);
1661 }
1662
1663 unsigned int
1664 isc_mempool_getmaxalloc(isc_mempool_t *mpctx) {
1665         unsigned int maxalloc;
1666
1667         REQUIRE(VALID_MEMPOOL(mpctx));
1668
1669         if (mpctx->lock != NULL)
1670                 LOCK(mpctx->lock);
1671
1672         maxalloc = mpctx->maxalloc;
1673
1674         if (mpctx->lock != NULL)
1675                 UNLOCK(mpctx->lock);
1676
1677         return (maxalloc);
1678 }
1679
1680 unsigned int
1681 isc_mempool_getallocated(isc_mempool_t *mpctx) {
1682         unsigned int allocated;
1683
1684         REQUIRE(VALID_MEMPOOL(mpctx));
1685
1686         if (mpctx->lock != NULL)
1687                 LOCK(mpctx->lock);
1688
1689         allocated = mpctx->allocated;
1690
1691         if (mpctx->lock != NULL)
1692                 UNLOCK(mpctx->lock);
1693
1694         return (allocated);
1695 }
1696
1697 void
1698 isc_mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit) {
1699         REQUIRE(limit > 0);
1700         REQUIRE(VALID_MEMPOOL(mpctx));
1701
1702         if (mpctx->lock != NULL)
1703                 LOCK(mpctx->lock);
1704
1705         mpctx->fillcount = limit;
1706
1707         if (mpctx->lock != NULL)
1708                 UNLOCK(mpctx->lock);
1709 }
1710
1711 unsigned int
1712 isc_mempool_getfillcount(isc_mempool_t *mpctx) {
1713         unsigned int fillcount;
1714
1715         REQUIRE(VALID_MEMPOOL(mpctx));
1716
1717         if (mpctx->lock != NULL)
1718                 LOCK(mpctx->lock);
1719
1720         fillcount = mpctx->fillcount;
1721
1722         if (mpctx->lock != NULL)
1723                 UNLOCK(mpctx->lock);
1724
1725         return (fillcount);
1726 }