Annotation of embedaddon/ntp/lib/isc/mem.c, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>