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