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