diff options
Diffstat (limited to 'contrib/bind9/lib/isc/mem.c')
-rw-r--r-- | contrib/bind9/lib/isc/mem.c | 1955 |
1 files changed, 0 insertions, 1955 deletions
diff --git a/contrib/bind9/lib/isc/mem.c b/contrib/bind9/lib/isc/mem.c deleted file mode 100644 index aec6118..0000000 --- a/contrib/bind9/lib/isc/mem.c +++ /dev/null @@ -1,1955 +0,0 @@ -/* - * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") - * Copyright (C) 1997-2003 Internet Software Consortium. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH - * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, - * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE - * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -/* $Id: mem.c,v 1.116.18.18 2007/10/30 23:31:43 marka Exp $ */ - -/*! \file */ - -#include <config.h> - -#include <stdio.h> -#include <stdlib.h> -#include <stddef.h> - -#include <limits.h> - -#include <isc/magic.h> -#include <isc/mem.h> -#include <isc/msgs.h> -#include <isc/once.h> -#include <isc/ondestroy.h> -#include <isc/string.h> - -#include <isc/mutex.h> -#include <isc/util.h> - -#define MCTXLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) LOCK(l) -#define MCTXUNLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) UNLOCK(l) - -#ifndef ISC_MEM_DEBUGGING -#define ISC_MEM_DEBUGGING 0 -#endif -LIBISC_EXTERNAL_DATA unsigned int isc_mem_debugging = ISC_MEM_DEBUGGING; - -/* - * Constants. - */ - -#define DEF_MAX_SIZE 1100 -#define DEF_MEM_TARGET 4096 -#define ALIGNMENT_SIZE 8 /*%< must be a power of 2 */ -#define NUM_BASIC_BLOCKS 64 /*%< must be > 1 */ -#define TABLE_INCREMENT 1024 -#define DEBUGLIST_COUNT 1024 - -/* - * Types. - */ -#if ISC_MEM_TRACKLINES -typedef struct debuglink debuglink_t; -struct debuglink { - ISC_LINK(debuglink_t) link; - const void *ptr[DEBUGLIST_COUNT]; - unsigned int size[DEBUGLIST_COUNT]; - const char *file[DEBUGLIST_COUNT]; - unsigned int line[DEBUGLIST_COUNT]; - unsigned int count; -}; - -#define FLARG_PASS , file, line -#define FLARG , const char *file, int line -#else -#define FLARG_PASS -#define FLARG -#endif - -typedef struct element element; -struct element { - element * next; -}; - -typedef struct { - /*! - * This structure must be ALIGNMENT_SIZE bytes. - */ - union { - size_t size; - isc_mem_t *ctx; - char bytes[ALIGNMENT_SIZE]; - } u; -} size_info; - -struct stats { - unsigned long gets; - unsigned long totalgets; - unsigned long blocks; - unsigned long freefrags; -}; - -#define MEM_MAGIC ISC_MAGIC('M', 'e', 'm', 'C') -#define VALID_CONTEXT(c) ISC_MAGIC_VALID(c, MEM_MAGIC) - -#if ISC_MEM_TRACKLINES -typedef ISC_LIST(debuglink_t) debuglist_t; -#endif - -/* List of all active memory contexts. */ - -static ISC_LIST(isc_mem_t) contexts; -static isc_once_t once = ISC_ONCE_INIT; -static isc_mutex_t lock; - -struct isc_mem { - unsigned int magic; - isc_ondestroy_t ondestroy; - unsigned int flags; - isc_mutex_t lock; - isc_memalloc_t memalloc; - isc_memfree_t memfree; - void * arg; - size_t max_size; - isc_boolean_t checkfree; - struct stats * stats; - unsigned int references; - size_t quota; - size_t total; - size_t inuse; - size_t maxinuse; - size_t hi_water; - size_t lo_water; - isc_boolean_t hi_called; - isc_mem_water_t water; - void * water_arg; - ISC_LIST(isc_mempool_t) pools; - - /* ISC_MEMFLAG_INTERNAL */ - size_t mem_target; - element ** freelists; - element * basic_blocks; - unsigned char ** basic_table; - unsigned int basic_table_count; - unsigned int basic_table_size; - unsigned char * lowest; - unsigned char * highest; - -#if ISC_MEM_TRACKLINES - debuglist_t * debuglist; -#endif - - unsigned int memalloc_failures; - ISC_LINK(isc_mem_t) link; -}; - -#define MEMPOOL_MAGIC ISC_MAGIC('M', 'E', 'M', 'p') -#define VALID_MEMPOOL(c) ISC_MAGIC_VALID(c, MEMPOOL_MAGIC) - -struct isc_mempool { - /* always unlocked */ - unsigned int magic; /*%< magic number */ - isc_mutex_t *lock; /*%< optional lock */ - isc_mem_t *mctx; /*%< our memory context */ - /*%< locked via the memory context's lock */ - ISC_LINK(isc_mempool_t) link; /*%< next pool in this mem context */ - /*%< optionally locked from here down */ - element *items; /*%< low water item list */ - size_t size; /*%< size of each item on this pool */ - unsigned int maxalloc; /*%< max number of items allowed */ - unsigned int allocated; /*%< # of items currently given out */ - unsigned int freecount; /*%< # of items on reserved list */ - unsigned int freemax; /*%< # of items allowed on free list */ - unsigned int fillcount; /*%< # of items to fetch on each fill */ - /*%< Stats only. */ - unsigned int gets; /*%< # of requests to this pool */ - /*%< Debugging only. */ -#if ISC_MEMPOOL_NAMES - char name[16]; /*%< printed name in stats reports */ -#endif -}; - -/* - * Private Inline-able. - */ - -#if ! ISC_MEM_TRACKLINES -#define ADD_TRACE(a, b, c, d, e) -#define DELETE_TRACE(a, b, c, d, e) -#else -#define ADD_TRACE(a, b, c, d, e) \ - do { \ - if ((isc_mem_debugging & (ISC_MEM_DEBUGTRACE | \ - ISC_MEM_DEBUGRECORD)) != 0 && \ - b != NULL) \ - add_trace_entry(a, b, c, d, e); \ - } while (0) -#define DELETE_TRACE(a, b, c, d, e) delete_trace_entry(a, b, c, d, e) - -static void -print_active(isc_mem_t *ctx, FILE *out); - -/*! - * mctx must be locked. - */ -static inline void -add_trace_entry(isc_mem_t *mctx, const void *ptr, unsigned int size - FLARG) -{ - debuglink_t *dl; - unsigned int i; - - if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0) - fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, - ISC_MSG_ADDTRACE, - "add %p size %u " - "file %s line %u mctx %p\n"), - ptr, size, file, line, mctx); - - if (mctx->debuglist == NULL) - return; - - if (size > mctx->max_size) - size = mctx->max_size; - - dl = ISC_LIST_HEAD(mctx->debuglist[size]); - while (dl != NULL) { - if (dl->count == DEBUGLIST_COUNT) - goto next; - for (i = 0; i < DEBUGLIST_COUNT; i++) { - if (dl->ptr[i] == NULL) { - dl->ptr[i] = ptr; - dl->size[i] = size; - dl->file[i] = file; - dl->line[i] = line; - dl->count++; - return; - } - } - next: - dl = ISC_LIST_NEXT(dl, link); - } - - dl = malloc(sizeof(debuglink_t)); - INSIST(dl != NULL); - - ISC_LINK_INIT(dl, link); - for (i = 1; i < DEBUGLIST_COUNT; i++) { - dl->ptr[i] = NULL; - dl->size[i] = 0; - dl->file[i] = NULL; - dl->line[i] = 0; - } - - dl->ptr[0] = ptr; - dl->size[0] = size; - dl->file[0] = file; - dl->line[0] = line; - dl->count = 1; - - ISC_LIST_PREPEND(mctx->debuglist[size], dl, link); -} - -static inline void -delete_trace_entry(isc_mem_t *mctx, const void *ptr, unsigned int size, - const char *file, unsigned int line) -{ - debuglink_t *dl; - unsigned int i; - - if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0) - fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, - ISC_MSG_DELTRACE, - "del %p size %u " - "file %s line %u mctx %p\n"), - ptr, size, file, line, mctx); - - if (mctx->debuglist == NULL) - return; - - if (size > mctx->max_size) - size = mctx->max_size; - - dl = ISC_LIST_HEAD(mctx->debuglist[size]); - while (dl != NULL) { - for (i = 0; i < DEBUGLIST_COUNT; i++) { - if (dl->ptr[i] == ptr) { - dl->ptr[i] = NULL; - dl->size[i] = 0; - dl->file[i] = NULL; - dl->line[i] = 0; - - INSIST(dl->count > 0); - dl->count--; - if (dl->count == 0) { - ISC_LIST_UNLINK(mctx->debuglist[size], - dl, link); - free(dl); - } - return; - } - } - dl = ISC_LIST_NEXT(dl, link); - } - - /* - * If we get here, we didn't find the item on the list. We're - * screwed. - */ - INSIST(dl != NULL); -} -#endif /* ISC_MEM_TRACKLINES */ - -static inline size_t -rmsize(size_t size) { - /* - * round down to ALIGNMENT_SIZE - */ - return (size & (~(ALIGNMENT_SIZE - 1))); -} - -static inline size_t -quantize(size_t size) { - /*! - * Round up the result in order to get a size big - * enough to satisfy the request and be aligned on ALIGNMENT_SIZE - * byte boundaries. - */ - - if (size == 0U) - return (ALIGNMENT_SIZE); - return ((size + ALIGNMENT_SIZE - 1) & (~(ALIGNMENT_SIZE - 1))); -} - -static inline isc_boolean_t -more_basic_blocks(isc_mem_t *ctx) { - void *new; - unsigned char *curr, *next; - unsigned char *first, *last; - unsigned char **table; - unsigned int table_size; - size_t increment; - int i; - - /* Require: we hold the context lock. */ - - /* - * Did we hit the quota for this context? - */ - increment = NUM_BASIC_BLOCKS * ctx->mem_target; - if (ctx->quota != 0U && ctx->total + increment > ctx->quota) - return (ISC_FALSE); - - INSIST(ctx->basic_table_count <= ctx->basic_table_size); - if (ctx->basic_table_count == ctx->basic_table_size) { - table_size = ctx->basic_table_size + TABLE_INCREMENT; - table = (ctx->memalloc)(ctx->arg, - table_size * sizeof(unsigned char *)); - if (table == NULL) { - ctx->memalloc_failures++; - return (ISC_FALSE); - } - if (ctx->basic_table_size != 0) { - memcpy(table, ctx->basic_table, - ctx->basic_table_size * - sizeof(unsigned char *)); - (ctx->memfree)(ctx->arg, ctx->basic_table); - } - ctx->basic_table = table; - ctx->basic_table_size = table_size; - } - - new = (ctx->memalloc)(ctx->arg, NUM_BASIC_BLOCKS * ctx->mem_target); - if (new == NULL) { - ctx->memalloc_failures++; - return (ISC_FALSE); - } - ctx->total += increment; - ctx->basic_table[ctx->basic_table_count] = new; - ctx->basic_table_count++; - - curr = new; - next = curr + ctx->mem_target; - for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) { - ((element *)curr)->next = (element *)next; - curr = next; - next += ctx->mem_target; - } - /* - * curr is now pointing at the last block in the - * array. - */ - ((element *)curr)->next = NULL; - first = new; - last = first + NUM_BASIC_BLOCKS * ctx->mem_target - 1; - if (first < ctx->lowest || ctx->lowest == NULL) - ctx->lowest = first; - if (last > ctx->highest) - ctx->highest = last; - ctx->basic_blocks = new; - - return (ISC_TRUE); -} - -static inline isc_boolean_t -more_frags(isc_mem_t *ctx, size_t new_size) { - int i, frags; - size_t total_size; - void *new; - unsigned char *curr, *next; - - /*! - * Try to get more fragments by chopping up a basic block. - */ - - if (ctx->basic_blocks == NULL) { - if (!more_basic_blocks(ctx)) { - /* - * We can't get more memory from the OS, or we've - * hit the quota for this context. - */ - /* - * XXXRTH "At quota" notification here. - */ - return (ISC_FALSE); - } - } - - total_size = ctx->mem_target; - new = ctx->basic_blocks; - ctx->basic_blocks = ctx->basic_blocks->next; - frags = total_size / new_size; - ctx->stats[new_size].blocks++; - ctx->stats[new_size].freefrags += frags; - /* - * Set up a linked-list of blocks of size - * "new_size". - */ - curr = new; - next = curr + new_size; - total_size -= new_size; - for (i = 0; i < (frags - 1); i++) { - ((element *)curr)->next = (element *)next; - curr = next; - next += new_size; - total_size -= new_size; - } - /* - * Add the remaining fragment of the basic block to a free list. - */ - total_size = rmsize(total_size); - if (total_size > 0U) { - ((element *)next)->next = ctx->freelists[total_size]; - ctx->freelists[total_size] = (element *)next; - ctx->stats[total_size].freefrags++; - } - /* - * curr is now pointing at the last block in the - * array. - */ - ((element *)curr)->next = NULL; - ctx->freelists[new_size] = new; - - return (ISC_TRUE); -} - -static inline void * -mem_getunlocked(isc_mem_t *ctx, size_t size) { - size_t new_size = quantize(size); - void *ret; - - if (size >= ctx->max_size || new_size >= ctx->max_size) { - /* - * memget() was called on something beyond our upper limit. - */ - if (ctx->quota != 0U && ctx->total + size > ctx->quota) { - ret = NULL; - goto done; - } - ret = (ctx->memalloc)(ctx->arg, size); - if (ret == NULL) { - ctx->memalloc_failures++; - goto done; - } - ctx->total += size; - ctx->inuse += size; - ctx->stats[ctx->max_size].gets++; - ctx->stats[ctx->max_size].totalgets++; - /* - * If we don't set new_size to size, then the - * ISC_MEM_FILL code might write over bytes we - * don't own. - */ - new_size = size; - goto done; - } - - /* - * If there are no blocks in the free list for this size, get a chunk - * of memory and then break it up into "new_size"-sized blocks, adding - * them to the free list. - */ - if (ctx->freelists[new_size] == NULL && !more_frags(ctx, new_size)) - return (NULL); - - /* - * The free list uses the "rounded-up" size "new_size". - */ - ret = ctx->freelists[new_size]; - ctx->freelists[new_size] = ctx->freelists[new_size]->next; - - /* - * The stats[] uses the _actual_ "size" requested by the - * caller, with the caveat (in the code above) that "size" >= the - * max. size (max_size) ends up getting recorded as a call to - * max_size. - */ - ctx->stats[size].gets++; - ctx->stats[size].totalgets++; - ctx->stats[new_size].freefrags--; - ctx->inuse += new_size; - - done: - -#if ISC_MEM_FILL - if (ret != NULL) - memset(ret, 0xbe, new_size); /* Mnemonic for "beef". */ -#endif - - return (ret); -} - -#if ISC_MEM_FILL && ISC_MEM_CHECKOVERRUN -static inline void -check_overrun(void *mem, size_t size, size_t new_size) { - unsigned char *cp; - - cp = (unsigned char *)mem; - cp += size; - while (size < new_size) { - INSIST(*cp == 0xbe); - cp++; - size++; - } -} -#endif - -static inline void -mem_putunlocked(isc_mem_t *ctx, void *mem, size_t size) { - size_t new_size = quantize(size); - - if (size == ctx->max_size || new_size >= ctx->max_size) { - /* - * memput() called on something beyond our upper limit. - */ -#if ISC_MEM_FILL - memset(mem, 0xde, size); /* Mnemonic for "dead". */ -#endif - (ctx->memfree)(ctx->arg, mem); - INSIST(ctx->stats[ctx->max_size].gets != 0U); - ctx->stats[ctx->max_size].gets--; - INSIST(size <= ctx->total); - ctx->inuse -= size; - ctx->total -= size; - return; - } - -#if ISC_MEM_FILL -#if ISC_MEM_CHECKOVERRUN - check_overrun(mem, size, new_size); -#endif - memset(mem, 0xde, new_size); /* Mnemonic for "dead". */ -#endif - - /* - * The free list uses the "rounded-up" size "new_size". - */ - ((element *)mem)->next = ctx->freelists[new_size]; - ctx->freelists[new_size] = (element *)mem; - - /* - * The stats[] uses the _actual_ "size" requested by the - * caller, with the caveat (in the code above) that "size" >= the - * max. size (max_size) ends up getting recorded as a call to - * max_size. - */ - INSIST(ctx->stats[size].gets != 0U); - ctx->stats[size].gets--; - ctx->stats[new_size].freefrags++; - ctx->inuse -= new_size; -} - -/*! - * Perform a malloc, doing memory filling and overrun detection as necessary. - */ -static inline void * -mem_get(isc_mem_t *ctx, size_t size) { - char *ret; - -#if ISC_MEM_CHECKOVERRUN - size += 1; -#endif - - ret = (ctx->memalloc)(ctx->arg, size); - if (ret == NULL) - ctx->memalloc_failures++; - -#if ISC_MEM_FILL - if (ret != NULL) - memset(ret, 0xbe, size); /* Mnemonic for "beef". */ -#else -# if ISC_MEM_CHECKOVERRUN - if (ret != NULL) - ret[size-1] = 0xbe; -# endif -#endif - - return (ret); -} - -/*! - * Perform a free, doing memory filling and overrun detection as necessary. - */ -static inline void -mem_put(isc_mem_t *ctx, void *mem, size_t size) { -#if ISC_MEM_CHECKOVERRUN - INSIST(((unsigned char *)mem)[size] == 0xbe); -#endif -#if ISC_MEM_FILL - memset(mem, 0xde, size); /* Mnemonic for "dead". */ -#else - UNUSED(size); -#endif - (ctx->memfree)(ctx->arg, mem); -} - -/*! - * Update internal counters after a memory get. - */ -static inline void -mem_getstats(isc_mem_t *ctx, size_t size) { - ctx->total += size; - ctx->inuse += size; - - if (size > ctx->max_size) { - ctx->stats[ctx->max_size].gets++; - ctx->stats[ctx->max_size].totalgets++; - } else { - ctx->stats[size].gets++; - ctx->stats[size].totalgets++; - } -} - -/*! - * Update internal counters after a memory put. - */ -static inline void -mem_putstats(isc_mem_t *ctx, void *ptr, size_t size) { - UNUSED(ptr); - - INSIST(ctx->inuse >= size); - ctx->inuse -= size; - - if (size > ctx->max_size) { - INSIST(ctx->stats[ctx->max_size].gets > 0U); - ctx->stats[ctx->max_size].gets--; - } else { - INSIST(ctx->stats[size].gets > 0U); - ctx->stats[size].gets--; - } -} - -/* - * Private. - */ - -static void * -default_memalloc(void *arg, size_t size) { - UNUSED(arg); - if (size == 0U) - size = 1; - return (malloc(size)); -} - -static void -default_memfree(void *arg, void *ptr) { - UNUSED(arg); - free(ptr); -} - -static void -initialize_action(void) { - RUNTIME_CHECK(isc_mutex_init(&lock) == ISC_R_SUCCESS); - ISC_LIST_INIT(contexts); -} - -/* - * Public. - */ - -isc_result_t -isc_mem_createx(size_t init_max_size, size_t target_size, - isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg, - isc_mem_t **ctxp) -{ - return (isc_mem_createx2(init_max_size, target_size, memalloc, memfree, - arg, ctxp, ISC_MEMFLAG_DEFAULT)); - -} - -isc_result_t -isc_mem_createx2(size_t init_max_size, size_t target_size, - isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg, - isc_mem_t **ctxp, unsigned int flags) -{ - isc_mem_t *ctx; - isc_result_t result; - - REQUIRE(ctxp != NULL && *ctxp == NULL); - REQUIRE(memalloc != NULL); - REQUIRE(memfree != NULL); - - INSIST((ALIGNMENT_SIZE & (ALIGNMENT_SIZE - 1)) == 0); - - RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); - - ctx = (memalloc)(arg, sizeof(*ctx)); - if (ctx == NULL) - return (ISC_R_NOMEMORY); - - if ((flags & ISC_MEMFLAG_NOLOCK) == 0) { - result = isc_mutex_init(&ctx->lock); - if (result != ISC_R_SUCCESS) { - (memfree)(arg, ctx); - return (result); - } - } - - if (init_max_size == 0U) - ctx->max_size = DEF_MAX_SIZE; - else - ctx->max_size = init_max_size; - ctx->flags = flags; - ctx->references = 1; - ctx->quota = 0; - ctx->total = 0; - ctx->inuse = 0; - ctx->maxinuse = 0; - ctx->hi_water = 0; - ctx->lo_water = 0; - ctx->hi_called = ISC_FALSE; - ctx->water = NULL; - ctx->water_arg = NULL; - ctx->magic = MEM_MAGIC; - isc_ondestroy_init(&ctx->ondestroy); - ctx->memalloc = memalloc; - ctx->memfree = memfree; - ctx->arg = arg; - ctx->stats = NULL; - ctx->checkfree = ISC_TRUE; -#if ISC_MEM_TRACKLINES - ctx->debuglist = NULL; -#endif - ISC_LIST_INIT(ctx->pools); - ctx->freelists = NULL; - ctx->basic_blocks = NULL; - ctx->basic_table = NULL; - ctx->basic_table_count = 0; - ctx->basic_table_size = 0; - ctx->lowest = NULL; - ctx->highest = NULL; - - ctx->stats = (memalloc)(arg, - (ctx->max_size+1) * sizeof(struct stats)); - if (ctx->stats == NULL) { - result = ISC_R_NOMEMORY; - goto error; - } - memset(ctx->stats, 0, (ctx->max_size + 1) * sizeof(struct stats)); - - if ((flags & ISC_MEMFLAG_INTERNAL) != 0) { - if (target_size == 0U) - ctx->mem_target = DEF_MEM_TARGET; - else - ctx->mem_target = target_size; - ctx->freelists = (memalloc)(arg, ctx->max_size * - sizeof(element *)); - if (ctx->freelists == NULL) { - result = ISC_R_NOMEMORY; - goto error; - } - memset(ctx->freelists, 0, - ctx->max_size * sizeof(element *)); - } - -#if ISC_MEM_TRACKLINES - if ((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0) { - unsigned int i; - - ctx->debuglist = (memalloc)(arg, - (ctx->max_size+1) * sizeof(debuglist_t)); - if (ctx->debuglist == NULL) { - result = ISC_R_NOMEMORY; - goto error; - } - for (i = 0; i <= ctx->max_size; i++) - ISC_LIST_INIT(ctx->debuglist[i]); - } -#endif - - ctx->memalloc_failures = 0; - - LOCK(&lock); - ISC_LIST_INITANDAPPEND(contexts, ctx, link); - UNLOCK(&lock); - - *ctxp = ctx; - return (ISC_R_SUCCESS); - - error: - if (ctx != NULL) { - if (ctx->stats != NULL) - (memfree)(arg, ctx->stats); - if (ctx->freelists != NULL) - (memfree)(arg, ctx->freelists); -#if ISC_MEM_TRACKLINES - if (ctx->debuglist != NULL) - (ctx->memfree)(ctx->arg, ctx->debuglist); -#endif /* ISC_MEM_TRACKLINES */ - if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0) - DESTROYLOCK(&ctx->lock); - (memfree)(arg, ctx); - } - - return (result); -} - -isc_result_t -isc_mem_create(size_t init_max_size, size_t target_size, - isc_mem_t **ctxp) -{ - return (isc_mem_createx2(init_max_size, target_size, - default_memalloc, default_memfree, NULL, - ctxp, ISC_MEMFLAG_DEFAULT)); -} - -isc_result_t -isc_mem_create2(size_t init_max_size, size_t target_size, - isc_mem_t **ctxp, unsigned int flags) -{ - return (isc_mem_createx2(init_max_size, target_size, - default_memalloc, default_memfree, NULL, - ctxp, flags)); -} - -static void -destroy(isc_mem_t *ctx) { - unsigned int i; - isc_ondestroy_t ondest; - - ctx->magic = 0; - - LOCK(&lock); - ISC_LIST_UNLINK(contexts, ctx, link); - UNLOCK(&lock); - - INSIST(ISC_LIST_EMPTY(ctx->pools)); - -#if ISC_MEM_TRACKLINES - if (ctx->debuglist != NULL) { - if (ctx->checkfree) { - for (i = 0; i <= ctx->max_size; i++) { - if (!ISC_LIST_EMPTY(ctx->debuglist[i])) - print_active(ctx, stderr); - INSIST(ISC_LIST_EMPTY(ctx->debuglist[i])); - } - } else { - debuglink_t *dl; - - for (i = 0; i <= ctx->max_size; i++) - for (dl = ISC_LIST_HEAD(ctx->debuglist[i]); - dl != NULL; - dl = ISC_LIST_HEAD(ctx->debuglist[i])) { - ISC_LIST_UNLINK(ctx->debuglist[i], - dl, link); - free(dl); - } - } - (ctx->memfree)(ctx->arg, ctx->debuglist); - } -#endif - INSIST(ctx->references == 0); - - if (ctx->checkfree) { - for (i = 0; i <= ctx->max_size; i++) { -#if ISC_MEM_TRACKLINES - if (ctx->stats[i].gets != 0U) - print_active(ctx, stderr); -#endif - INSIST(ctx->stats[i].gets == 0U); - } - } - - (ctx->memfree)(ctx->arg, ctx->stats); - - if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { - for (i = 0; i < ctx->basic_table_count; i++) - (ctx->memfree)(ctx->arg, ctx->basic_table[i]); - (ctx->memfree)(ctx->arg, ctx->freelists); - (ctx->memfree)(ctx->arg, ctx->basic_table); - } - - ondest = ctx->ondestroy; - - if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0) - DESTROYLOCK(&ctx->lock); - (ctx->memfree)(ctx->arg, ctx); - - isc_ondestroy_notify(&ondest, ctx); -} - -void -isc_mem_attach(isc_mem_t *source, isc_mem_t **targetp) { - REQUIRE(VALID_CONTEXT(source)); - REQUIRE(targetp != NULL && *targetp == NULL); - - MCTXLOCK(source, &source->lock); - source->references++; - MCTXUNLOCK(source, &source->lock); - - *targetp = source; -} - -void -isc_mem_detach(isc_mem_t **ctxp) { - isc_mem_t *ctx; - isc_boolean_t want_destroy = ISC_FALSE; - - REQUIRE(ctxp != NULL); - ctx = *ctxp; - REQUIRE(VALID_CONTEXT(ctx)); - - MCTXLOCK(ctx, &ctx->lock); - INSIST(ctx->references > 0); - ctx->references--; - if (ctx->references == 0) - want_destroy = ISC_TRUE; - MCTXUNLOCK(ctx, &ctx->lock); - - if (want_destroy) - destroy(ctx); - - *ctxp = NULL; -} - -/* - * isc_mem_putanddetach() is the equivalent of: - * - * mctx = NULL; - * isc_mem_attach(ptr->mctx, &mctx); - * isc_mem_detach(&ptr->mctx); - * isc_mem_put(mctx, ptr, sizeof(*ptr); - * isc_mem_detach(&mctx); - */ - -void -isc__mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) { - isc_mem_t *ctx; - isc_boolean_t want_destroy = ISC_FALSE; - size_info *si; - size_t oldsize; - - REQUIRE(ctxp != NULL); - ctx = *ctxp; - REQUIRE(VALID_CONTEXT(ctx)); - REQUIRE(ptr != NULL); - - /* - * Must be before mem_putunlocked() as ctxp is usually within - * [ptr..ptr+size). - */ - *ctxp = NULL; - - if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) { - if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) { - si = &(((size_info *)ptr)[-1]); - oldsize = si->u.size - ALIGNMENT_SIZE; - if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) - oldsize -= ALIGNMENT_SIZE; - INSIST(oldsize == size); - } - isc__mem_free(ctx, ptr FLARG_PASS); - - MCTXLOCK(ctx, &ctx->lock); - ctx->references--; - if (ctx->references == 0) - want_destroy = ISC_TRUE; - MCTXUNLOCK(ctx, &ctx->lock); - if (want_destroy) - destroy(ctx); - - return; - } - - if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { - MCTXLOCK(ctx, &ctx->lock); - mem_putunlocked(ctx, ptr, size); - } else { - mem_put(ctx, ptr, size); - MCTXLOCK(ctx, &ctx->lock); - mem_putstats(ctx, ptr, size); - } - - DELETE_TRACE(ctx, ptr, size, file, line); - INSIST(ctx->references > 0); - ctx->references--; - if (ctx->references == 0) - want_destroy = ISC_TRUE; - - MCTXUNLOCK(ctx, &ctx->lock); - - if (want_destroy) - destroy(ctx); -} - -void -isc_mem_destroy(isc_mem_t **ctxp) { - isc_mem_t *ctx; - - /* - * This routine provides legacy support for callers who use mctxs - * without attaching/detaching. - */ - - REQUIRE(ctxp != NULL); - ctx = *ctxp; - REQUIRE(VALID_CONTEXT(ctx)); - - MCTXLOCK(ctx, &ctx->lock); -#if ISC_MEM_TRACKLINES - if (ctx->references != 1) - print_active(ctx, stderr); -#endif - REQUIRE(ctx->references == 1); - ctx->references--; - MCTXUNLOCK(ctx, &ctx->lock); - - destroy(ctx); - - *ctxp = NULL; -} - -isc_result_t -isc_mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event) { - isc_result_t res; - - MCTXLOCK(ctx, &ctx->lock); - res = isc_ondestroy_register(&ctx->ondestroy, task, event); - MCTXUNLOCK(ctx, &ctx->lock); - - return (res); -} - - -void * -isc__mem_get(isc_mem_t *ctx, size_t size FLARG) { - void *ptr; - isc_boolean_t call_water = ISC_FALSE; - - REQUIRE(VALID_CONTEXT(ctx)); - - if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) - return (isc__mem_allocate(ctx, size FLARG_PASS)); - - if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { - MCTXLOCK(ctx, &ctx->lock); - ptr = mem_getunlocked(ctx, size); - } else { - ptr = mem_get(ctx, size); - MCTXLOCK(ctx, &ctx->lock); - if (ptr != NULL) - mem_getstats(ctx, size); - } - - ADD_TRACE(ctx, ptr, size, file, line); - if (ctx->hi_water != 0U && !ctx->hi_called && - ctx->inuse > ctx->hi_water) { - ctx->hi_called = ISC_TRUE; - call_water = ISC_TRUE; - } - if (ctx->inuse > ctx->maxinuse) { - ctx->maxinuse = ctx->inuse; - if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water && - (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0) - fprintf(stderr, "maxinuse = %lu\n", - (unsigned long)ctx->inuse); - } - MCTXUNLOCK(ctx, &ctx->lock); - - if (call_water) - (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER); - - return (ptr); -} - -void -isc__mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG) -{ - isc_boolean_t call_water = ISC_FALSE; - size_info *si; - size_t oldsize; - - REQUIRE(VALID_CONTEXT(ctx)); - REQUIRE(ptr != NULL); - - if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) { - if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) { - si = &(((size_info *)ptr)[-1]); - oldsize = si->u.size - ALIGNMENT_SIZE; - if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) - oldsize -= ALIGNMENT_SIZE; - INSIST(oldsize == size); - } - isc__mem_free(ctx, ptr FLARG_PASS); - return; - } - - if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { - MCTXLOCK(ctx, &ctx->lock); - mem_putunlocked(ctx, ptr, size); - } else { - mem_put(ctx, ptr, size); - MCTXLOCK(ctx, &ctx->lock); - mem_putstats(ctx, ptr, size); - } - - DELETE_TRACE(ctx, ptr, size, file, line); - - /* - * The check against ctx->lo_water == 0 is for the condition - * when the context was pushed over hi_water but then had - * isc_mem_setwater() called with 0 for hi_water and lo_water. - */ - if (ctx->hi_called && - (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) { - ctx->hi_called = ISC_FALSE; - - if (ctx->water != NULL) - call_water = ISC_TRUE; - } - MCTXUNLOCK(ctx, &ctx->lock); - - if (call_water) - (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER); -} - -#if ISC_MEM_TRACKLINES -static void -print_active(isc_mem_t *mctx, FILE *out) { - if (mctx->debuglist != NULL) { - debuglink_t *dl; - unsigned int i, j; - const char *format; - isc_boolean_t found; - - fprintf(out, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, - ISC_MSG_DUMPALLOC, - "Dump of all outstanding " - "memory allocations:\n")); - found = ISC_FALSE; - format = isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, - ISC_MSG_PTRFILELINE, - "\tptr %p size %u file %s line %u\n"); - for (i = 0; i <= mctx->max_size; i++) { - dl = ISC_LIST_HEAD(mctx->debuglist[i]); - - if (dl != NULL) - found = ISC_TRUE; - - while (dl != NULL) { - for (j = 0; j < DEBUGLIST_COUNT; j++) - if (dl->ptr[j] != NULL) - fprintf(out, format, - dl->ptr[j], - dl->size[j], - dl->file[j], - dl->line[j]); - dl = ISC_LIST_NEXT(dl, link); - } - } - if (!found) - fprintf(out, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, - ISC_MSG_NONE, "\tNone.\n")); - } -} -#endif - -/* - * Print the stats[] on the stream "out" with suitable formatting. - */ -void -isc_mem_stats(isc_mem_t *ctx, FILE *out) { - size_t i; - const struct stats *s; - const isc_mempool_t *pool; - - REQUIRE(VALID_CONTEXT(ctx)); - MCTXLOCK(ctx, &ctx->lock); - - for (i = 0; i <= ctx->max_size; i++) { - s = &ctx->stats[i]; - - if (s->totalgets == 0U && s->gets == 0U) - continue; - fprintf(out, "%s%5lu: %11lu gets, %11lu rem", - (i == ctx->max_size) ? ">=" : " ", - (unsigned long) i, s->totalgets, s->gets); - if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0 && - (s->blocks != 0U || s->freefrags != 0U)) - fprintf(out, " (%lu bl, %lu ff)", - s->blocks, s->freefrags); - fputc('\n', out); - } - - /* - * Note that since a pool can be locked now, these stats might be - * somewhat off if the pool is in active use at the time the stats - * are dumped. The link fields are protected by the isc_mem_t's - * lock, however, so walking this list and extracting integers from - * stats fields is always safe. - */ - pool = ISC_LIST_HEAD(ctx->pools); - if (pool != NULL) { - fprintf(out, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, - ISC_MSG_POOLSTATS, - "[Pool statistics]\n")); - fprintf(out, "%15s %10s %10s %10s %10s %10s %10s %10s %1s\n", - isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, - ISC_MSG_POOLNAME, "name"), - isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, - ISC_MSG_POOLSIZE, "size"), - isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, - ISC_MSG_POOLMAXALLOC, "maxalloc"), - isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, - ISC_MSG_POOLALLOCATED, "allocated"), - isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, - ISC_MSG_POOLFREECOUNT, "freecount"), - isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, - ISC_MSG_POOLFREEMAX, "freemax"), - isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, - ISC_MSG_POOLFILLCOUNT, "fillcount"), - isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, - ISC_MSG_POOLGETS, "gets"), - "L"); - } - while (pool != NULL) { - fprintf(out, "%15s %10lu %10u %10u %10u %10u %10u %10u %s\n", - pool->name, (unsigned long) pool->size, pool->maxalloc, - pool->allocated, pool->freecount, pool->freemax, - pool->fillcount, pool->gets, - (pool->lock == NULL ? "N" : "Y")); - pool = ISC_LIST_NEXT(pool, link); - } - -#if ISC_MEM_TRACKLINES - print_active(ctx, out); -#endif - - MCTXUNLOCK(ctx, &ctx->lock); -} - -/* - * Replacements for malloc() and free() -- they implicitly remember the - * size of the object allocated (with some additional overhead). - */ - -static void * -isc__mem_allocateunlocked(isc_mem_t *ctx, size_t size) { - size_info *si; - - size += ALIGNMENT_SIZE; - if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) - size += ALIGNMENT_SIZE; - - if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) - si = mem_getunlocked(ctx, size); - else - si = mem_get(ctx, size); - - if (si == NULL) - return (NULL); - if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) { - si->u.ctx = ctx; - si++; - } - si->u.size = size; - return (&si[1]); -} - -void * -isc__mem_allocate(isc_mem_t *ctx, size_t size FLARG) { - size_info *si; - isc_boolean_t call_water = ISC_FALSE; - - REQUIRE(VALID_CONTEXT(ctx)); - - if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { - MCTXLOCK(ctx, &ctx->lock); - si = isc__mem_allocateunlocked(ctx, size); - } else { - si = isc__mem_allocateunlocked(ctx, size); - MCTXLOCK(ctx, &ctx->lock); - if (si != NULL) - mem_getstats(ctx, si[-1].u.size); - } - -#if ISC_MEM_TRACKLINES - ADD_TRACE(ctx, si, si[-1].u.size, file, line); -#endif - if (ctx->hi_water != 0U && !ctx->hi_called && - ctx->inuse > ctx->hi_water) { - ctx->hi_called = ISC_TRUE; - call_water = ISC_TRUE; - } - if (ctx->inuse > ctx->maxinuse) { - ctx->maxinuse = ctx->inuse; - if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water && - (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0) - fprintf(stderr, "maxinuse = %lu\n", - (unsigned long)ctx->inuse); - } - MCTXUNLOCK(ctx, &ctx->lock); - - if (call_water) - (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER); - - return (si); -} - -void -isc__mem_free(isc_mem_t *ctx, void *ptr FLARG) { - size_info *si; - size_t size; - isc_boolean_t call_water= ISC_FALSE; - - REQUIRE(VALID_CONTEXT(ctx)); - REQUIRE(ptr != NULL); - - if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) { - si = &(((size_info *)ptr)[-2]); - REQUIRE(si->u.ctx == ctx); - size = si[1].u.size; - } else { - si = &(((size_info *)ptr)[-1]); - size = si->u.size; - } - - if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { - MCTXLOCK(ctx, &ctx->lock); - mem_putunlocked(ctx, si, size); - } else { - mem_put(ctx, si, size); - MCTXLOCK(ctx, &ctx->lock); - mem_putstats(ctx, si, size); - } - - DELETE_TRACE(ctx, ptr, size, file, line); - - /* - * The check against ctx->lo_water == 0 is for the condition - * when the context was pushed over hi_water but then had - * isc_mem_setwater() called with 0 for hi_water and lo_water. - */ - if (ctx->hi_called && - (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) { - ctx->hi_called = ISC_FALSE; - - if (ctx->water != NULL) - call_water = ISC_TRUE; - } - MCTXUNLOCK(ctx, &ctx->lock); - - if (call_water) - (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER); -} - - -/* - * Other useful things. - */ - -char * -isc__mem_strdup(isc_mem_t *mctx, const char *s FLARG) { - size_t len; - char *ns; - - REQUIRE(VALID_CONTEXT(mctx)); - REQUIRE(s != NULL); - - len = strlen(s); - - ns = isc__mem_allocate(mctx, len + 1 FLARG_PASS); - - if (ns != NULL) - strncpy(ns, s, len + 1); - - return (ns); -} - -void -isc_mem_setdestroycheck(isc_mem_t *ctx, isc_boolean_t flag) { - REQUIRE(VALID_CONTEXT(ctx)); - MCTXLOCK(ctx, &ctx->lock); - - ctx->checkfree = flag; - - MCTXUNLOCK(ctx, &ctx->lock); -} - -/* - * Quotas - */ - -void -isc_mem_setquota(isc_mem_t *ctx, size_t quota) { - REQUIRE(VALID_CONTEXT(ctx)); - MCTXLOCK(ctx, &ctx->lock); - - ctx->quota = quota; - - MCTXUNLOCK(ctx, &ctx->lock); -} - -size_t -isc_mem_getquota(isc_mem_t *ctx) { - size_t quota; - - REQUIRE(VALID_CONTEXT(ctx)); - MCTXLOCK(ctx, &ctx->lock); - - quota = ctx->quota; - - MCTXUNLOCK(ctx, &ctx->lock); - - return (quota); -} - -size_t -isc_mem_inuse(isc_mem_t *ctx) { - size_t inuse; - - REQUIRE(VALID_CONTEXT(ctx)); - MCTXLOCK(ctx, &ctx->lock); - - inuse = ctx->inuse; - - MCTXUNLOCK(ctx, &ctx->lock); - - return (inuse); -} - -void -isc_mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg, - size_t hiwater, size_t lowater) -{ - isc_boolean_t callwater = ISC_FALSE; - isc_mem_water_t oldwater; - void *oldwater_arg; - - REQUIRE(VALID_CONTEXT(ctx)); - REQUIRE(hiwater >= lowater); - - MCTXLOCK(ctx, &ctx->lock); - oldwater = ctx->water; - oldwater_arg = ctx->water_arg; - if (water == NULL) { - callwater = ctx->hi_called; - ctx->water = NULL; - ctx->water_arg = NULL; - ctx->hi_water = 0; - ctx->lo_water = 0; - ctx->hi_called = ISC_FALSE; - } else { - if (ctx->hi_called && - (ctx->water != water || ctx->water_arg != water_arg || - ctx->inuse < lowater || lowater == 0U)) - callwater = ISC_TRUE; - ctx->water = water; - ctx->water_arg = water_arg; - ctx->hi_water = hiwater; - ctx->lo_water = lowater; - ctx->hi_called = ISC_FALSE; - } - MCTXUNLOCK(ctx, &ctx->lock); - - if (callwater && oldwater != NULL) - (oldwater)(oldwater_arg, ISC_MEM_LOWATER); -} - -/* - * Memory pool stuff - */ - -isc_result_t -isc_mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp) { - isc_mempool_t *mpctx; - - REQUIRE(VALID_CONTEXT(mctx)); - REQUIRE(size > 0U); - REQUIRE(mpctxp != NULL && *mpctxp == NULL); - - /* - * Allocate space for this pool, initialize values, and if all works - * well, attach to the memory context. - */ - mpctx = isc_mem_get(mctx, sizeof(isc_mempool_t)); - if (mpctx == NULL) - return (ISC_R_NOMEMORY); - - mpctx->magic = MEMPOOL_MAGIC; - mpctx->lock = NULL; - mpctx->mctx = mctx; - mpctx->size = size; - mpctx->maxalloc = UINT_MAX; - mpctx->allocated = 0; - mpctx->freecount = 0; - mpctx->freemax = 1; - mpctx->fillcount = 1; - mpctx->gets = 0; -#if ISC_MEMPOOL_NAMES - mpctx->name[0] = 0; -#endif - mpctx->items = NULL; - - *mpctxp = mpctx; - - MCTXLOCK(mctx, &mctx->lock); - ISC_LIST_INITANDAPPEND(mctx->pools, mpctx, link); - MCTXUNLOCK(mctx, &mctx->lock); - - return (ISC_R_SUCCESS); -} - -void -isc_mempool_setname(isc_mempool_t *mpctx, const char *name) { - REQUIRE(name != NULL); - -#if ISC_MEMPOOL_NAMES - if (mpctx->lock != NULL) - LOCK(mpctx->lock); - - strncpy(mpctx->name, name, sizeof(mpctx->name) - 1); - mpctx->name[sizeof(mpctx->name) - 1] = '\0'; - - if (mpctx->lock != NULL) - UNLOCK(mpctx->lock); -#else - UNUSED(mpctx); - UNUSED(name); -#endif -} - -void -isc_mempool_destroy(isc_mempool_t **mpctxp) { - isc_mempool_t *mpctx; - isc_mem_t *mctx; - isc_mutex_t *lock; - element *item; - - REQUIRE(mpctxp != NULL); - mpctx = *mpctxp; - REQUIRE(VALID_MEMPOOL(mpctx)); -#if ISC_MEMPOOL_NAMES - if (mpctx->allocated > 0) - UNEXPECTED_ERROR(__FILE__, __LINE__, - "isc_mempool_destroy(): mempool %s " - "leaked memory", - mpctx->name); -#endif - REQUIRE(mpctx->allocated == 0); - - mctx = mpctx->mctx; - - lock = mpctx->lock; - - if (lock != NULL) - LOCK(lock); - - /* - * Return any items on the free list - */ - MCTXLOCK(mctx, &mctx->lock); - while (mpctx->items != NULL) { - INSIST(mpctx->freecount > 0); - mpctx->freecount--; - item = mpctx->items; - mpctx->items = item->next; - - if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { - mem_putunlocked(mctx, item, mpctx->size); - } else { - mem_put(mctx, item, mpctx->size); - mem_putstats(mctx, item, mpctx->size); - } - } - MCTXUNLOCK(mctx, &mctx->lock); - - /* - * Remove our linked list entry from the memory context. - */ - MCTXLOCK(mctx, &mctx->lock); - ISC_LIST_UNLINK(mctx->pools, mpctx, link); - MCTXUNLOCK(mctx, &mctx->lock); - - mpctx->magic = 0; - - isc_mem_put(mpctx->mctx, mpctx, sizeof(isc_mempool_t)); - - if (lock != NULL) - UNLOCK(lock); - - *mpctxp = NULL; -} - -void -isc_mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock) { - REQUIRE(VALID_MEMPOOL(mpctx)); - REQUIRE(mpctx->lock == NULL); - REQUIRE(lock != NULL); - - mpctx->lock = lock; -} - -void * -isc__mempool_get(isc_mempool_t *mpctx FLARG) { - element *item; - isc_mem_t *mctx; - unsigned int i; - - REQUIRE(VALID_MEMPOOL(mpctx)); - - mctx = mpctx->mctx; - - if (mpctx->lock != NULL) - LOCK(mpctx->lock); - - /* - * Don't let the caller go over quota - */ - if (mpctx->allocated >= mpctx->maxalloc) { - item = NULL; - goto out; - } - - /* - * if we have a free list item, return the first here - */ - item = mpctx->items; - if (item != NULL) { - mpctx->items = item->next; - INSIST(mpctx->freecount > 0); - mpctx->freecount--; - mpctx->gets++; - mpctx->allocated++; - goto out; - } - - /* - * We need to dip into the well. Lock the memory context here and - * fill up our free list. - */ - MCTXLOCK(mctx, &mctx->lock); - for (i = 0; i < mpctx->fillcount; i++) { - if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { - item = mem_getunlocked(mctx, mpctx->size); - } else { - item = mem_get(mctx, mpctx->size); - if (item != NULL) - mem_getstats(mctx, mpctx->size); - } - if (item == NULL) - break; - item->next = mpctx->items; - mpctx->items = item; - mpctx->freecount++; - } - MCTXUNLOCK(mctx, &mctx->lock); - - /* - * If we didn't get any items, return NULL. - */ - item = mpctx->items; - if (item == NULL) - goto out; - - mpctx->items = item->next; - mpctx->freecount--; - mpctx->gets++; - mpctx->allocated++; - - out: - if (mpctx->lock != NULL) - UNLOCK(mpctx->lock); - -#if ISC_MEM_TRACKLINES - if (item != NULL) { - MCTXLOCK(mctx, &mctx->lock); - ADD_TRACE(mctx, item, mpctx->size, file, line); - MCTXUNLOCK(mctx, &mctx->lock); - } -#endif /* ISC_MEM_TRACKLINES */ - - return (item); -} - -void -isc__mempool_put(isc_mempool_t *mpctx, void *mem FLARG) { - isc_mem_t *mctx; - element *item; - - REQUIRE(VALID_MEMPOOL(mpctx)); - REQUIRE(mem != NULL); - - mctx = mpctx->mctx; - - if (mpctx->lock != NULL) - LOCK(mpctx->lock); - - INSIST(mpctx->allocated > 0); - mpctx->allocated--; - -#if ISC_MEM_TRACKLINES - MCTXLOCK(mctx, &mctx->lock); - DELETE_TRACE(mctx, mem, mpctx->size, file, line); - MCTXUNLOCK(mctx, &mctx->lock); -#endif /* ISC_MEM_TRACKLINES */ - - /* - * If our free list is full, return this to the mctx directly. - */ - if (mpctx->freecount >= mpctx->freemax) { - if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { - MCTXLOCK(mctx, &mctx->lock); - mem_putunlocked(mctx, mem, mpctx->size); - MCTXUNLOCK(mctx, &mctx->lock); - } else { - mem_put(mctx, mem, mpctx->size); - MCTXLOCK(mctx, &mctx->lock); - mem_putstats(mctx, mem, mpctx->size); - MCTXUNLOCK(mctx, &mctx->lock); - } - if (mpctx->lock != NULL) - UNLOCK(mpctx->lock); - return; - } - - /* - * Otherwise, attach it to our free list and bump the counter. - */ - mpctx->freecount++; - item = (element *)mem; - item->next = mpctx->items; - mpctx->items = item; - - if (mpctx->lock != NULL) - UNLOCK(mpctx->lock); -} - -/* - * Quotas - */ - -void -isc_mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit) { - REQUIRE(VALID_MEMPOOL(mpctx)); - - if (mpctx->lock != NULL) - LOCK(mpctx->lock); - - mpctx->freemax = limit; - - if (mpctx->lock != NULL) - UNLOCK(mpctx->lock); -} - -unsigned int -isc_mempool_getfreemax(isc_mempool_t *mpctx) { - unsigned int freemax; - - REQUIRE(VALID_MEMPOOL(mpctx)); - - if (mpctx->lock != NULL) - LOCK(mpctx->lock); - - freemax = mpctx->freemax; - - if (mpctx->lock != NULL) - UNLOCK(mpctx->lock); - - return (freemax); -} - -unsigned int -isc_mempool_getfreecount(isc_mempool_t *mpctx) { - unsigned int freecount; - - REQUIRE(VALID_MEMPOOL(mpctx)); - - if (mpctx->lock != NULL) - LOCK(mpctx->lock); - - freecount = mpctx->freecount; - - if (mpctx->lock != NULL) - UNLOCK(mpctx->lock); - - return (freecount); -} - -void -isc_mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit) { - REQUIRE(limit > 0); - - REQUIRE(VALID_MEMPOOL(mpctx)); - - if (mpctx->lock != NULL) - LOCK(mpctx->lock); - - mpctx->maxalloc = limit; - - if (mpctx->lock != NULL) - UNLOCK(mpctx->lock); -} - -unsigned int -isc_mempool_getmaxalloc(isc_mempool_t *mpctx) { - unsigned int maxalloc; - - REQUIRE(VALID_MEMPOOL(mpctx)); - - if (mpctx->lock != NULL) - LOCK(mpctx->lock); - - maxalloc = mpctx->maxalloc; - - if (mpctx->lock != NULL) - UNLOCK(mpctx->lock); - - return (maxalloc); -} - -unsigned int -isc_mempool_getallocated(isc_mempool_t *mpctx) { - unsigned int allocated; - - REQUIRE(VALID_MEMPOOL(mpctx)); - - if (mpctx->lock != NULL) - LOCK(mpctx->lock); - - allocated = mpctx->allocated; - - if (mpctx->lock != NULL) - UNLOCK(mpctx->lock); - - return (allocated); -} - -void -isc_mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit) { - REQUIRE(limit > 0); - REQUIRE(VALID_MEMPOOL(mpctx)); - - if (mpctx->lock != NULL) - LOCK(mpctx->lock); - - mpctx->fillcount = limit; - - if (mpctx->lock != NULL) - UNLOCK(mpctx->lock); -} - -unsigned int -isc_mempool_getfillcount(isc_mempool_t *mpctx) { - unsigned int fillcount; - - REQUIRE(VALID_MEMPOOL(mpctx)); - - if (mpctx->lock != NULL) - LOCK(mpctx->lock); - - fillcount = mpctx->fillcount; - - if (mpctx->lock != NULL) - UNLOCK(mpctx->lock); - - return (fillcount); -} - -void -isc_mem_printactive(isc_mem_t *ctx, FILE *file) { - - REQUIRE(VALID_CONTEXT(ctx)); - REQUIRE(file != NULL); - -#if !ISC_MEM_TRACKLINES - UNUSED(ctx); - UNUSED(file); -#else - print_active(ctx, file); -#endif -} - -void -isc_mem_printallactive(FILE *file) { -#if !ISC_MEM_TRACKLINES - UNUSED(file); -#else - isc_mem_t *ctx; - - RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); - - LOCK(&lock); - for (ctx = ISC_LIST_HEAD(contexts); - ctx != NULL; - ctx = ISC_LIST_NEXT(ctx, link)) { - fprintf(file, "context: %p\n", ctx); - print_active(ctx, file); - } - UNLOCK(&lock); -#endif -} - -void -isc_mem_checkdestroyed(FILE *file) { - - RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); - - LOCK(&lock); - if (!ISC_LIST_EMPTY(contexts)) { -#if ISC_MEM_TRACKLINES - isc_mem_t *ctx; - - for (ctx = ISC_LIST_HEAD(contexts); - ctx != NULL; - ctx = ISC_LIST_NEXT(ctx, link)) { - fprintf(file, "context: %p\n", ctx); - print_active(ctx, file); - } - fflush(file); -#endif - INSIST(0); - } - UNLOCK(&lock); -} |