diff options
Diffstat (limited to 'contrib/bind9/lib/isc/mem.c')
-rw-r--r-- | contrib/bind9/lib/isc/mem.c | 601 |
1 files changed, 389 insertions, 212 deletions
diff --git a/contrib/bind9/lib/isc/mem.c b/contrib/bind9/lib/isc/mem.c index f5069fb..35918dc 100644 --- a/contrib/bind9/lib/isc/mem.c +++ b/contrib/bind9/lib/isc/mem.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1997-2003 Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any @@ -15,7 +15,9 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: mem.c,v 1.98.2.7.2.7 2005/03/17 03:58:32 marka Exp $ */ +/* $Id: mem.c,v 1.116.18.12 2006/12/08 05:07:59 marka Exp $ */ + +/*! \file */ #include <config.h> @@ -28,35 +30,29 @@ #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; /* - * Define ISC_MEM_USE_INTERNAL_MALLOC=1 to use the internal malloc() - * implementation in preference to the system one. The internal malloc() - * is very space-efficient, and quite fast on uniprocessor systems. It - * performs poorly on multiprocessor machines. - */ -#ifndef ISC_MEM_USE_INTERNAL_MALLOC -#define ISC_MEM_USE_INTERNAL_MALLOC 0 -#endif - -/* * 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 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 @@ -87,11 +83,12 @@ struct element { }; typedef struct { - /* + /*! * This structure must be ALIGNMENT_SIZE bytes. */ union { size_t size; + isc_mem_t *ctx; char bytes[ALIGNMENT_SIZE]; } u; } size_info; @@ -99,10 +96,8 @@ typedef struct { struct stats { unsigned long gets; unsigned long totalgets; -#if ISC_MEM_USE_INTERNAL_MALLOC unsigned long blocks; unsigned long freefrags; -#endif /* ISC_MEM_USE_INTERNAL_MALLOC */ }; #define MEM_MAGIC ISC_MAGIC('M', 'e', 'm', 'C') @@ -112,9 +107,16 @@ struct stats { 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; @@ -134,7 +136,7 @@ struct isc_mem { void * water_arg; ISC_LIST(isc_mempool_t) pools; -#if ISC_MEM_USE_INTERNAL_MALLOC + /* ISC_MEMFLAG_INTERNAL */ size_t mem_target; element ** freelists; element * basic_blocks; @@ -143,13 +145,13 @@ struct isc_mem { unsigned int basic_table_size; unsigned char * lowest; unsigned char * highest; -#endif /* ISC_MEM_USE_INTERNAL_MALLOC */ #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') @@ -157,24 +159,24 @@ struct isc_mem { 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. */ + 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 */ + char name[16]; /*%< printed name in stats reports */ #endif }; @@ -198,7 +200,7 @@ struct isc_mempool { static void print_active(isc_mem_t *ctx, FILE *out); -/* +/*! * mctx must be locked. */ static inline void @@ -309,7 +311,6 @@ delete_trace_entry(isc_mem_t *mctx, const void *ptr, unsigned int size, } #endif /* ISC_MEM_TRACKLINES */ -#if ISC_MEM_USE_INTERNAL_MALLOC static inline size_t rmsize(size_t size) { /* @@ -320,13 +321,13 @@ rmsize(size_t size) { 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 == 0) + if (size == 0U) return (ALIGNMENT_SIZE); return ((size + ALIGNMENT_SIZE - 1) & (~(ALIGNMENT_SIZE - 1))); } @@ -347,7 +348,7 @@ more_basic_blocks(isc_mem_t *ctx) { * Did we hit the quota for this context? */ increment = NUM_BASIC_BLOCKS * ctx->mem_target; - if (ctx->quota != 0 && ctx->total + increment > ctx->quota) + if (ctx->quota != 0U && ctx->total + increment > ctx->quota) return (ISC_FALSE); INSIST(ctx->basic_table_count <= ctx->basic_table_size); @@ -408,7 +409,7 @@ more_frags(isc_mem_t *ctx, size_t new_size) { void *new; unsigned char *curr, *next; - /* + /*! * Try to get more fragments by chopping up a basic block. */ @@ -448,7 +449,7 @@ more_frags(isc_mem_t *ctx, size_t new_size) { * Add the remaining fragment of the basic block to a free list. */ total_size = rmsize(total_size); - if (total_size > 0) { + if (total_size > 0U) { ((element *)next)->next = ctx->freelists[total_size]; ctx->freelists[total_size] = (element *)next; ctx->stats[total_size].freefrags++; @@ -472,7 +473,7 @@ mem_getunlocked(isc_mem_t *ctx, size_t size) { /* * memget() was called on something beyond our upper limit. */ - if (ctx->quota != 0 && ctx->total + size > ctx->quota) { + if (ctx->quota != 0U && ctx->total + size > ctx->quota) { ret = NULL; goto done; } @@ -556,7 +557,7 @@ mem_putunlocked(isc_mem_t *ctx, void *mem, size_t size) { memset(mem, 0xde, size); /* Mnemonic for "dead". */ #endif (ctx->memfree)(ctx->arg, mem); - INSIST(ctx->stats[ctx->max_size].gets != 0); + INSIST(ctx->stats[ctx->max_size].gets != 0U); ctx->stats[ctx->max_size].gets--; INSIST(size <= ctx->total); ctx->inuse -= size; @@ -583,15 +584,13 @@ mem_putunlocked(isc_mem_t *ctx, void *mem, size_t size) { * max. size (max_size) ends up getting recorded as a call to * max_size. */ - INSIST(ctx->stats[size].gets != 0); + INSIST(ctx->stats[size].gets != 0U); ctx->stats[size].gets--; ctx->stats[new_size].freefrags++; ctx->inuse -= new_size; } -#else /* ISC_MEM_USE_INTERNAL_MALLOC */ - -/* +/*! * Perform a malloc, doing memory filling and overrun detection as necessary. */ static inline void * @@ -619,7 +618,7 @@ mem_get(isc_mem_t *ctx, size_t size) { return (ret); } -/* +/*! * Perform a free, doing memory filling and overrun detection as necessary. */ static inline void @@ -635,7 +634,7 @@ mem_put(isc_mem_t *ctx, void *mem, size_t size) { (ctx->memfree)(ctx->arg, mem); } -/* +/*! * Update internal counters after a memory get. */ static inline void @@ -652,7 +651,7 @@ mem_getstats(isc_mem_t *ctx, size_t size) { } } -/* +/*! * Update internal counters after a memory put. */ static inline void @@ -671,8 +670,6 @@ mem_putstats(isc_mem_t *ctx, void *ptr, size_t size) { } } -#endif /* ISC_MEM_USE_INTERNAL_MALLOC */ - /* * Private. */ @@ -691,6 +688,11 @@ default_memfree(void *arg, void *ptr) { free(ptr); } +static void +initialize_action(void) { + RUNTIME_CHECK(isc_mutex_init(&lock) == ISC_R_SUCCESS); +} + /* * Public. */ @@ -700,6 +702,16 @@ 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; @@ -709,27 +721,25 @@ isc_mem_createx(size_t init_max_size, size_t target_size, INSIST((ALIGNMENT_SIZE & (ALIGNMENT_SIZE - 1)) == 0); -#if !ISC_MEM_USE_INTERNAL_MALLOC - UNUSED(target_size); -#endif + RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); ctx = (memalloc)(arg, sizeof(*ctx)); if (ctx == NULL) return (ISC_R_NOMEMORY); - if (isc_mutex_init(&ctx->lock) != ISC_R_SUCCESS) { - UNEXPECTED_ERROR(__FILE__, __LINE__, - "isc_mutex_init() %s", - isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, - ISC_MSG_FAILED, "failed")); - (memfree)(arg, ctx); - return (ISC_R_UNEXPECTED); + 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; @@ -751,10 +761,13 @@ isc_mem_createx(size_t init_max_size, size_t target_size, ctx->debuglist = NULL; #endif ISC_LIST_INIT(ctx->pools); - -#if ISC_MEM_USE_INTERNAL_MALLOC ctx->freelists = NULL; -#endif /* ISC_MEM_USE_INTERNAL_MALLOC */ + 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)); @@ -764,25 +777,20 @@ isc_mem_createx(size_t init_max_size, size_t target_size, } memset(ctx->stats, 0, (ctx->max_size + 1) * sizeof(struct stats)); -#if ISC_MEM_USE_INTERNAL_MALLOC - if (target_size == 0) - 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; + 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 *)); } - memset(ctx->freelists, 0, - ctx->max_size * sizeof(element *)); - ctx->basic_blocks = NULL; - ctx->basic_table = NULL; - ctx->basic_table_count = 0; - ctx->basic_table_size = 0; - ctx->lowest = NULL; - ctx->highest = NULL; -#endif /* ISC_MEM_USE_INTERNAL_MALLOC */ #if ISC_MEM_TRACKLINES if ((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0) { @@ -801,6 +809,10 @@ isc_mem_createx(size_t init_max_size, size_t target_size, ctx->memalloc_failures = 0; + LOCK(&lock); + ISC_LIST_INITANDAPPEND(contexts, ctx, link); + UNLOCK(&lock); + *ctxp = ctx; return (ISC_R_SUCCESS); @@ -808,15 +820,14 @@ isc_mem_createx(size_t init_max_size, size_t target_size, if (ctx != NULL) { if (ctx->stats != NULL) (memfree)(arg, ctx->stats); -#if ISC_MEM_USE_INTERNAL_MALLOC if (ctx->freelists != NULL) (memfree)(arg, ctx->freelists); -#endif /* ISC_MEM_USE_INTERNAL_MALLOC */ #if ISC_MEM_TRACKLINES if (ctx->debuglist != NULL) (ctx->memfree)(ctx->arg, ctx->debuglist); #endif /* ISC_MEM_TRACKLINES */ - DESTROYLOCK(&ctx->lock); + if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0) + DESTROYLOCK(&ctx->lock); (memfree)(arg, ctx); } @@ -827,9 +838,18 @@ isc_result_t isc_mem_create(size_t init_max_size, size_t target_size, isc_mem_t **ctxp) { - return (isc_mem_createx(init_max_size, target_size, - default_memalloc, default_memfree, NULL, - 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 @@ -839,9 +859,11 @@ destroy(isc_mem_t *ctx) { ctx->magic = 0; -#if ISC_MEM_USE_INTERNAL_MALLOC + LOCK(&lock); + ISC_LIST_UNLINK(contexts, ctx, link); + UNLOCK(&lock); + INSIST(ISC_LIST_EMPTY(ctx->pools)); -#endif /* ISC_MEM_USE_INTERNAL_MALLOC */ #if ISC_MEM_TRACKLINES if (ctx->debuglist != NULL) { @@ -880,16 +902,17 @@ destroy(isc_mem_t *ctx) { (ctx->memfree)(ctx->arg, ctx->stats); -#if ISC_MEM_USE_INTERNAL_MALLOC - 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); -#endif /* ISC_MEM_USE_INTERNAL_MALLOC */ + 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; - DESTROYLOCK(&ctx->lock); + if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0) + DESTROYLOCK(&ctx->lock); (ctx->memfree)(ctx->arg, ctx); isc_ondestroy_notify(&ondest, ctx); @@ -900,9 +923,9 @@ isc_mem_attach(isc_mem_t *source, isc_mem_t **targetp) { REQUIRE(VALID_CONTEXT(source)); REQUIRE(targetp != NULL && *targetp == NULL); - LOCK(&source->lock); + MCTXLOCK(source, &source->lock); source->references++; - UNLOCK(&source->lock); + MCTXUNLOCK(source, &source->lock); *targetp = source; } @@ -916,12 +939,12 @@ isc_mem_detach(isc_mem_t **ctxp) { ctx = *ctxp; REQUIRE(VALID_CONTEXT(ctx)); - LOCK(&ctx->lock); + MCTXLOCK(ctx, &ctx->lock); INSIST(ctx->references > 0); ctx->references--; if (ctx->references == 0) want_destroy = ISC_TRUE; - UNLOCK(&ctx->lock); + MCTXUNLOCK(ctx, &ctx->lock); if (want_destroy) destroy(ctx); @@ -943,6 +966,8 @@ 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; @@ -955,14 +980,35 @@ isc__mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) { */ *ctxp = NULL; -#if ISC_MEM_USE_INTERNAL_MALLOC - LOCK(&ctx->lock); - mem_putunlocked(ctx, ptr, size); -#else /* ISC_MEM_USE_INTERNAL_MALLOC */ - mem_put(ctx, ptr, size); - LOCK(&ctx->lock); - mem_putstats(ctx, ptr, size); -#endif /* ISC_MEM_USE_INTERNAL_MALLOC */ + 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); @@ -970,7 +1016,7 @@ isc__mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) { if (ctx->references == 0) want_destroy = ISC_TRUE; - UNLOCK(&ctx->lock); + MCTXUNLOCK(ctx, &ctx->lock); if (want_destroy) destroy(ctx); @@ -989,14 +1035,14 @@ isc_mem_destroy(isc_mem_t **ctxp) { ctx = *ctxp; REQUIRE(VALID_CONTEXT(ctx)); - LOCK(&ctx->lock); + MCTXLOCK(ctx, &ctx->lock); #if ISC_MEM_TRACKLINES if (ctx->references != 1) print_active(ctx, stderr); #endif REQUIRE(ctx->references == 1); ctx->references--; - UNLOCK(&ctx->lock); + MCTXUNLOCK(ctx, &ctx->lock); destroy(ctx); @@ -1007,9 +1053,9 @@ isc_result_t isc_mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event) { isc_result_t res; - LOCK(&ctx->lock); + MCTXLOCK(ctx, &ctx->lock); res = isc_ondestroy_register(&ctx->ondestroy, task, event); - UNLOCK(&ctx->lock); + MCTXUNLOCK(ctx, &ctx->lock); return (res); } @@ -1022,15 +1068,18 @@ isc__mem_get(isc_mem_t *ctx, size_t size FLARG) { REQUIRE(VALID_CONTEXT(ctx)); -#if ISC_MEM_USE_INTERNAL_MALLOC - LOCK(&ctx->lock); - ptr = mem_getunlocked(ctx, size); -#else /* ISC_MEM_USE_INTERNAL_MALLOC */ - ptr = mem_get(ctx, size); - LOCK(&ctx->lock); - if (ptr != NULL) - mem_getstats(ctx, size); -#endif /* ISC_MEM_USE_INTERNAL_MALLOC */ + 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 && @@ -1045,7 +1094,7 @@ isc__mem_get(isc_mem_t *ctx, size_t size FLARG) { fprintf(stderr, "maxinuse = %lu\n", (unsigned long)ctx->inuse); } - UNLOCK(&ctx->lock); + MCTXUNLOCK(ctx, &ctx->lock); if (call_water) (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER); @@ -1057,18 +1106,32 @@ 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_USE_INTERNAL_MALLOC - LOCK(&ctx->lock); - mem_putunlocked(ctx, ptr, size); -#else /* ISC_MEM_USE_INTERNAL_MALLOC */ - mem_put(ctx, ptr, size); - LOCK(&ctx->lock); - mem_putstats(ctx, ptr, size); -#endif /* ISC_MEM_USE_INTERNAL_MALLOC */ + 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); @@ -1084,7 +1147,7 @@ isc__mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG) if (ctx->water != NULL) call_water = ISC_TRUE; } - UNLOCK(&ctx->lock); + MCTXUNLOCK(ctx, &ctx->lock); if (call_water) (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER); @@ -1141,7 +1204,7 @@ isc_mem_stats(isc_mem_t *ctx, FILE *out) { const isc_mempool_t *pool; REQUIRE(VALID_CONTEXT(ctx)); - LOCK(&ctx->lock); + MCTXLOCK(ctx, &ctx->lock); for (i = 0; i <= ctx->max_size; i++) { s = &ctx->stats[i]; @@ -1151,11 +1214,10 @@ isc_mem_stats(isc_mem_t *ctx, FILE *out) { fprintf(out, "%s%5lu: %11lu gets, %11lu rem", (i == ctx->max_size) ? ">=" : " ", (unsigned long) i, s->totalgets, s->gets); -#if ISC_MEM_USE_INTERNAL_MALLOC - if (s->blocks != 0 || s->freefrags != 0) + if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0 && + (s->blocks != 0U || s->freefrags != 0U)) fprintf(out, " (%lu bl, %lu ff)", s->blocks, s->freefrags); -#endif /* ISC_MEM_USE_INTERNAL_MALLOC */ fputc('\n', out); } @@ -1203,7 +1265,7 @@ isc_mem_stats(isc_mem_t *ctx, FILE *out) { print_active(ctx, out); #endif - UNLOCK(&ctx->lock); + MCTXUNLOCK(ctx, &ctx->lock); } /* @@ -1216,13 +1278,20 @@ isc__mem_allocateunlocked(isc_mem_t *ctx, size_t size) { size_info *si; size += ALIGNMENT_SIZE; -#if ISC_MEM_USE_INTERNAL_MALLOC - si = mem_getunlocked(ctx, size); -#else /* ISC_MEM_USE_INTERNAL_MALLOC */ - si = mem_get(ctx, size); -#endif /* ISC_MEM_USE_INTERNAL_MALLOC */ + 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]); } @@ -1230,24 +1299,39 @@ isc__mem_allocateunlocked(isc_mem_t *ctx, size_t size) { 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 ISC_MEM_USE_INTERNAL_MALLOC - LOCK(&ctx->lock); - si = isc__mem_allocateunlocked(ctx, size); -#else /* ISC_MEM_USE_INTERNAL_MALLOC */ - si = isc__mem_allocateunlocked(ctx, size); - LOCK(&ctx->lock); - if (si != NULL) - mem_getstats(ctx, si[-1].u.size); -#endif /* ISC_MEM_USE_INTERNAL_MALLOC */ + 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); - UNLOCK(&ctx->lock); + if (call_water) + (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER); return (si); } @@ -1256,25 +1340,47 @@ 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); - si = &(((size_info *)ptr)[-1]); - size = si->u.size; + 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 ISC_MEM_USE_INTERNAL_MALLOC - LOCK(&ctx->lock); - mem_putunlocked(ctx, si, size); -#else /* ISC_MEM_USE_INTERNAL_MALLOC */ - mem_put(ctx, si, size); - LOCK(&ctx->lock); - mem_putstats(ctx, si, size); -#endif /* ISC_MEM_USE_INTERNAL_MALLOC */ + 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); - UNLOCK(&ctx->lock); + /* + * 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); } @@ -1303,11 +1409,11 @@ isc__mem_strdup(isc_mem_t *mctx, const char *s FLARG) { void isc_mem_setdestroycheck(isc_mem_t *ctx, isc_boolean_t flag) { REQUIRE(VALID_CONTEXT(ctx)); - LOCK(&ctx->lock); + MCTXLOCK(ctx, &ctx->lock); ctx->checkfree = flag; - UNLOCK(&ctx->lock); + MCTXUNLOCK(ctx, &ctx->lock); } /* @@ -1317,11 +1423,11 @@ isc_mem_setdestroycheck(isc_mem_t *ctx, isc_boolean_t flag) { void isc_mem_setquota(isc_mem_t *ctx, size_t quota) { REQUIRE(VALID_CONTEXT(ctx)); - LOCK(&ctx->lock); + MCTXLOCK(ctx, &ctx->lock); ctx->quota = quota; - UNLOCK(&ctx->lock); + MCTXUNLOCK(ctx, &ctx->lock); } size_t @@ -1329,11 +1435,11 @@ isc_mem_getquota(isc_mem_t *ctx) { size_t quota; REQUIRE(VALID_CONTEXT(ctx)); - LOCK(&ctx->lock); + MCTXLOCK(ctx, &ctx->lock); quota = ctx->quota; - UNLOCK(&ctx->lock); + MCTXUNLOCK(ctx, &ctx->lock); return (quota); } @@ -1343,11 +1449,11 @@ isc_mem_inuse(isc_mem_t *ctx) { size_t inuse; REQUIRE(VALID_CONTEXT(ctx)); - LOCK(&ctx->lock); + MCTXLOCK(ctx, &ctx->lock); inuse = ctx->inuse; - UNLOCK(&ctx->lock); + MCTXUNLOCK(ctx, &ctx->lock); return (inuse); } @@ -1356,24 +1462,38 @@ 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); - LOCK(&ctx->lock); + 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; } - UNLOCK(&ctx->lock); + MCTXUNLOCK(ctx, &ctx->lock); + + if (callwater && oldwater != NULL) + (oldwater)(oldwater_arg, ISC_MEM_LOWATER); } /* @@ -1413,9 +1533,9 @@ isc_mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp) { *mpctxp = mpctx; - LOCK(&mctx->lock); + MCTXLOCK(mctx, &mctx->lock); ISC_LIST_INITANDAPPEND(mctx->pools, mpctx, link); - UNLOCK(&mctx->lock); + MCTXUNLOCK(mctx, &mctx->lock); return (ISC_R_SUCCESS); } @@ -1468,28 +1588,28 @@ isc_mempool_destroy(isc_mempool_t **mpctxp) { /* * Return any items on the free list */ - LOCK(&mctx->lock); + MCTXLOCK(mctx, &mctx->lock); while (mpctx->items != NULL) { INSIST(mpctx->freecount > 0); mpctx->freecount--; item = mpctx->items; mpctx->items = item->next; -#if ISC_MEM_USE_INTERNAL_MALLOC - mem_putunlocked(mctx, item, mpctx->size); -#else /* ISC_MEM_USE_INTERNAL_MALLOC */ - mem_put(mctx, item, mpctx->size); - mem_putstats(mctx, item, mpctx->size); -#endif /* ISC_MEM_USE_INTERNAL_MALLOC */ + 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); + } } - UNLOCK(&mctx->lock); + MCTXUNLOCK(mctx, &mctx->lock); /* * Remove our linked list entry from the memory context. */ - LOCK(&mctx->lock); + MCTXLOCK(mctx, &mctx->lock); ISC_LIST_UNLINK(mctx->pools, mpctx, link); - UNLOCK(&mctx->lock); + MCTXUNLOCK(mctx, &mctx->lock); mpctx->magic = 0; @@ -1548,22 +1668,22 @@ isc__mempool_get(isc_mempool_t *mpctx FLARG) { * We need to dip into the well. Lock the memory context here and * fill up our free list. */ - LOCK(&mctx->lock); + MCTXLOCK(mctx, &mctx->lock); for (i = 0; i < mpctx->fillcount; i++) { -#if ISC_MEM_USE_INTERNAL_MALLOC - item = mem_getunlocked(mctx, mpctx->size); -#else /* ISC_MEM_USE_INTERNAL_MALLOC */ - item = mem_get(mctx, mpctx->size); - if (item != NULL) - mem_getstats(mctx, mpctx->size); -#endif /* ISC_MEM_USE_INTERNAL_MALLOC */ + 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++; } - UNLOCK(&mctx->lock); + MCTXUNLOCK(mctx, &mctx->lock); /* * If we didn't get any items, return NULL. @@ -1583,9 +1703,9 @@ isc__mempool_get(isc_mempool_t *mpctx FLARG) { #if ISC_MEM_TRACKLINES if (item != NULL) { - LOCK(&mctx->lock); + MCTXLOCK(mctx, &mctx->lock); ADD_TRACE(mctx, item, mpctx->size, file, line); - UNLOCK(&mctx->lock); + MCTXUNLOCK(mctx, &mctx->lock); } #endif /* ISC_MEM_TRACKLINES */ @@ -1609,25 +1729,25 @@ isc__mempool_put(isc_mempool_t *mpctx, void *mem FLARG) { mpctx->allocated--; #if ISC_MEM_TRACKLINES - LOCK(&mctx->lock); + MCTXLOCK(mctx, &mctx->lock); DELETE_TRACE(mctx, mem, mpctx->size, file, line); - UNLOCK(&mctx->lock); + 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 ISC_MEM_USE_INTERNAL_MALLOC - LOCK(&mctx->lock); - mem_putunlocked(mctx, mem, mpctx->size); - UNLOCK(&mctx->lock); -#else /* ISC_MEM_USE_INTERNAL_MALLOC */ - mem_put(mctx, mem, mpctx->size); - LOCK(&mctx->lock); - mem_putstats(mctx, mem, mpctx->size); - UNLOCK(&mctx->lock); -#endif /* ISC_MEM_USE_INTERNAL_MALLOC */ + 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; @@ -1775,3 +1895,60 @@ isc_mempool_getfillcount(isc_mempool_t *mpctx) { 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(1); + } + UNLOCK(&lock); +} |