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