File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / lib / isc / mem.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:38 2012 UTC (12 years, 7 months ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    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.1.1.1 2012/05/29 12:08:38 misho 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>