Annotation of embedaddon/ntp/lib/isc/mem.c, revision 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>