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