mem.c revision 186462
1/*
2 * Copyright (C) 2004-2008  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1997-2003  Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/* $Id: mem.c,v 1.116.18.21 2008/02/07 23:45:56 tbox Exp $ */
19
20/*! \file */
21
22#include <config.h>
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <stddef.h>
27
28#include <limits.h>
29
30#include <isc/magic.h>
31#include <isc/mem.h>
32#include <isc/msgs.h>
33#include <isc/once.h>
34#include <isc/ondestroy.h>
35#include <isc/string.h>
36
37#include <isc/mutex.h>
38#include <isc/util.h>
39
40#define MCTXLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) LOCK(l)
41#define MCTXUNLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) UNLOCK(l)
42
43#ifndef ISC_MEM_DEBUGGING
44#define ISC_MEM_DEBUGGING 0
45#endif
46LIBISC_EXTERNAL_DATA unsigned int isc_mem_debugging = ISC_MEM_DEBUGGING;
47
48/*
49 * Constants.
50 */
51
52#define DEF_MAX_SIZE		1100
53#define DEF_MEM_TARGET		4096
54#define ALIGNMENT_SIZE		8		/*%< must be a power of 2 */
55#define NUM_BASIC_BLOCKS	64		/*%< must be > 1 */
56#define TABLE_INCREMENT		1024
57#define DEBUGLIST_COUNT		1024
58
59/*
60 * Types.
61 */
62#if ISC_MEM_TRACKLINES
63typedef struct debuglink debuglink_t;
64struct debuglink {
65	ISC_LINK(debuglink_t)	link;
66	const void	       *ptr[DEBUGLIST_COUNT];
67	unsigned int		size[DEBUGLIST_COUNT];
68	const char	       *file[DEBUGLIST_COUNT];
69	unsigned int		line[DEBUGLIST_COUNT];
70	unsigned int		count;
71};
72
73#define FLARG_PASS	, file, line
74#define FLARG		, const char *file, int line
75#else
76#define FLARG_PASS
77#define FLARG
78#endif
79
80typedef struct element element;
81struct element {
82	element *		next;
83};
84
85typedef struct {
86	/*!
87	 * This structure must be ALIGNMENT_SIZE bytes.
88	 */
89	union {
90		size_t		size;
91		isc_mem_t	*ctx;
92		char		bytes[ALIGNMENT_SIZE];
93	} u;
94} size_info;
95
96struct stats {
97	unsigned long		gets;
98	unsigned long		totalgets;
99	unsigned long		blocks;
100	unsigned long		freefrags;
101};
102
103#define MEM_MAGIC		ISC_MAGIC('M', 'e', 'm', 'C')
104#define VALID_CONTEXT(c)	ISC_MAGIC_VALID(c, MEM_MAGIC)
105
106#if ISC_MEM_TRACKLINES
107typedef ISC_LIST(debuglink_t)	debuglist_t;
108#endif
109
110/* List of all active memory contexts. */
111
112static ISC_LIST(isc_mem_t)	contexts;
113static isc_once_t		once = ISC_ONCE_INIT;
114static isc_mutex_t		lock;
115
116struct isc_mem {
117	unsigned int		magic;
118	isc_ondestroy_t		ondestroy;
119	unsigned int		flags;
120	isc_mutex_t		lock;
121	isc_memalloc_t		memalloc;
122	isc_memfree_t		memfree;
123	void *			arg;
124	size_t			max_size;
125	isc_boolean_t		checkfree;
126	struct stats *		stats;
127	unsigned int		references;
128	size_t			quota;
129	size_t			total;
130	size_t			inuse;
131	size_t			maxinuse;
132	size_t			hi_water;
133	size_t			lo_water;
134	isc_boolean_t		hi_called;
135	isc_mem_water_t		water;
136	void *			water_arg;
137	ISC_LIST(isc_mempool_t)	pools;
138
139	/*  ISC_MEMFLAG_INTERNAL */
140	size_t			mem_target;
141	element **		freelists;
142	element *		basic_blocks;
143	unsigned char **	basic_table;
144	unsigned int		basic_table_count;
145	unsigned int		basic_table_size;
146	unsigned char *		lowest;
147	unsigned char *		highest;
148
149#if ISC_MEM_TRACKLINES
150	debuglist_t *	 	debuglist;
151#endif
152
153	unsigned int		memalloc_failures;
154	ISC_LINK(isc_mem_t)	link;
155};
156
157#define MEMPOOL_MAGIC		ISC_MAGIC('M', 'E', 'M', 'p')
158#define VALID_MEMPOOL(c)	ISC_MAGIC_VALID(c, MEMPOOL_MAGIC)
159
160struct isc_mempool {
161	/* always unlocked */
162	unsigned int	magic;		/*%< magic number */
163	isc_mutex_t    *lock;		/*%< optional lock */
164	isc_mem_t      *mctx;		/*%< our memory context */
165	/*%< locked via the memory context's lock */
166	ISC_LINK(isc_mempool_t)	link;	/*%< next pool in this mem context */
167	/*%< optionally locked from here down */
168	element	       *items;		/*%< low water item list */
169	size_t		size;		/*%< size of each item on this pool */
170	unsigned int	maxalloc;	/*%< max number of items allowed */
171	unsigned int	allocated;	/*%< # of items currently given out */
172	unsigned int	freecount;	/*%< # of items on reserved list */
173	unsigned int	freemax;	/*%< # of items allowed on free list */
174	unsigned int	fillcount;	/*%< # of items to fetch on each fill */
175	/*%< Stats only. */
176	unsigned int	gets;		/*%< # of requests to this pool */
177	/*%< Debugging only. */
178#if ISC_MEMPOOL_NAMES
179	char		name[16];	/*%< printed name in stats reports */
180#endif
181};
182
183/*
184 * Private Inline-able.
185 */
186
187#if ! ISC_MEM_TRACKLINES
188#define ADD_TRACE(a, b, c, d, e)
189#define DELETE_TRACE(a, b, c, d, e)
190#else
191#define ADD_TRACE(a, b, c, d, e) \
192	do { \
193		if ((isc_mem_debugging & (ISC_MEM_DEBUGTRACE | \
194					  ISC_MEM_DEBUGRECORD)) != 0 && \
195		     b != NULL) \
196			 add_trace_entry(a, b, c, d, e); \
197	} while (0)
198#define DELETE_TRACE(a, b, c, d, e)	delete_trace_entry(a, b, c, d, e)
199
200static void
201print_active(isc_mem_t *ctx, FILE *out);
202
203/*!
204 * mctx must be locked.
205 */
206static inline void
207add_trace_entry(isc_mem_t *mctx, const void *ptr, unsigned int size
208		FLARG)
209{
210	debuglink_t *dl;
211	unsigned int i;
212
213	if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
214		fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
215					       ISC_MSG_ADDTRACE,
216					       "add %p size %u "
217					       "file %s line %u mctx %p\n"),
218			ptr, size, file, line, mctx);
219
220	if (mctx->debuglist == NULL)
221		return;
222
223	if (size > mctx->max_size)
224		size = mctx->max_size;
225
226	dl = ISC_LIST_HEAD(mctx->debuglist[size]);
227	while (dl != NULL) {
228		if (dl->count == DEBUGLIST_COUNT)
229			goto next;
230		for (i = 0; i < DEBUGLIST_COUNT; i++) {
231			if (dl->ptr[i] == NULL) {
232				dl->ptr[i] = ptr;
233				dl->size[i] = size;
234				dl->file[i] = file;
235				dl->line[i] = line;
236				dl->count++;
237				return;
238			}
239		}
240	next:
241		dl = ISC_LIST_NEXT(dl, link);
242	}
243
244	dl = malloc(sizeof(debuglink_t));
245	INSIST(dl != NULL);
246
247	ISC_LINK_INIT(dl, link);
248	for (i = 1; i < DEBUGLIST_COUNT; i++) {
249		dl->ptr[i] = NULL;
250		dl->size[i] = 0;
251		dl->file[i] = NULL;
252		dl->line[i] = 0;
253	}
254
255	dl->ptr[0] = ptr;
256	dl->size[0] = size;
257	dl->file[0] = file;
258	dl->line[0] = line;
259	dl->count = 1;
260
261	ISC_LIST_PREPEND(mctx->debuglist[size], dl, link);
262}
263
264static inline void
265delete_trace_entry(isc_mem_t *mctx, const void *ptr, unsigned int size,
266		   const char *file, unsigned int line)
267{
268	debuglink_t *dl;
269	unsigned int i;
270
271	if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
272		fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
273					       ISC_MSG_DELTRACE,
274					       "del %p size %u "
275					       "file %s line %u mctx %p\n"),
276			ptr, size, file, line, mctx);
277
278	if (mctx->debuglist == NULL)
279		return;
280
281	if (size > mctx->max_size)
282		size = mctx->max_size;
283
284	dl = ISC_LIST_HEAD(mctx->debuglist[size]);
285	while (dl != NULL) {
286		for (i = 0; i < DEBUGLIST_COUNT; i++) {
287			if (dl->ptr[i] == ptr) {
288				dl->ptr[i] = NULL;
289				dl->size[i] = 0;
290				dl->file[i] = NULL;
291				dl->line[i] = 0;
292
293				INSIST(dl->count > 0);
294				dl->count--;
295				if (dl->count == 0) {
296					ISC_LIST_UNLINK(mctx->debuglist[size],
297							dl, link);
298					free(dl);
299				}
300				return;
301			}
302		}
303		dl = ISC_LIST_NEXT(dl, link);
304	}
305
306	/*
307	 * If we get here, we didn't find the item on the list.  We're
308	 * screwed.
309	 */
310	INSIST(dl != NULL);
311}
312#endif /* ISC_MEM_TRACKLINES */
313
314static inline size_t
315rmsize(size_t size) {
316	/*
317	 * round down to ALIGNMENT_SIZE
318	 */
319	return (size & (~(ALIGNMENT_SIZE - 1)));
320}
321
322static inline size_t
323quantize(size_t size) {
324	/*!
325	 * Round up the result in order to get a size big
326	 * enough to satisfy the request and be aligned on ALIGNMENT_SIZE
327	 * byte boundaries.
328	 */
329
330	if (size == 0U)
331		return (ALIGNMENT_SIZE);
332	return ((size + ALIGNMENT_SIZE - 1) & (~(ALIGNMENT_SIZE - 1)));
333}
334
335static inline isc_boolean_t
336more_basic_blocks(isc_mem_t *ctx) {
337	void *new;
338	unsigned char *curr, *next;
339	unsigned char *first, *last;
340	unsigned char **table;
341	unsigned int table_size;
342	size_t increment;
343	int i;
344
345	/* Require: we hold the context lock. */
346
347	/*
348	 * Did we hit the quota for this context?
349	 */
350	increment = NUM_BASIC_BLOCKS * ctx->mem_target;
351	if (ctx->quota != 0U && ctx->total + increment > ctx->quota)
352		return (ISC_FALSE);
353
354	INSIST(ctx->basic_table_count <= ctx->basic_table_size);
355	if (ctx->basic_table_count == ctx->basic_table_size) {
356		table_size = ctx->basic_table_size + TABLE_INCREMENT;
357		table = (ctx->memalloc)(ctx->arg,
358					table_size * sizeof(unsigned char *));
359		if (table == NULL) {
360			ctx->memalloc_failures++;
361			return (ISC_FALSE);
362		}
363		if (ctx->basic_table_size != 0) {
364			memcpy(table, ctx->basic_table,
365			       ctx->basic_table_size *
366			       sizeof(unsigned char *));
367			(ctx->memfree)(ctx->arg, ctx->basic_table);
368		}
369		ctx->basic_table = table;
370		ctx->basic_table_size = table_size;
371	}
372
373	new = (ctx->memalloc)(ctx->arg, NUM_BASIC_BLOCKS * ctx->mem_target);
374	if (new == NULL) {
375		ctx->memalloc_failures++;
376		return (ISC_FALSE);
377	}
378	ctx->total += increment;
379	ctx->basic_table[ctx->basic_table_count] = new;
380	ctx->basic_table_count++;
381
382	curr = new;
383	next = curr + ctx->mem_target;
384	for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) {
385		((element *)curr)->next = (element *)next;
386		curr = next;
387		next += ctx->mem_target;
388	}
389	/*
390	 * curr is now pointing at the last block in the
391	 * array.
392	 */
393	((element *)curr)->next = NULL;
394	first = new;
395	last = first + NUM_BASIC_BLOCKS * ctx->mem_target - 1;
396	if (first < ctx->lowest || ctx->lowest == NULL)
397		ctx->lowest = first;
398	if (last > ctx->highest)
399		ctx->highest = last;
400	ctx->basic_blocks = new;
401
402	return (ISC_TRUE);
403}
404
405static inline isc_boolean_t
406more_frags(isc_mem_t *ctx, size_t new_size) {
407	int i, frags;
408	size_t total_size;
409	void *new;
410	unsigned char *curr, *next;
411
412	/*!
413	 * Try to get more fragments by chopping up a basic block.
414	 */
415
416	if (ctx->basic_blocks == NULL) {
417		if (!more_basic_blocks(ctx)) {
418			/*
419			 * We can't get more memory from the OS, or we've
420			 * hit the quota for this context.
421			 */
422			/*
423			 * XXXRTH  "At quota" notification here.
424			 */
425			return (ISC_FALSE);
426		}
427	}
428
429	total_size = ctx->mem_target;
430	new = ctx->basic_blocks;
431	ctx->basic_blocks = ctx->basic_blocks->next;
432	frags = total_size / new_size;
433	ctx->stats[new_size].blocks++;
434	ctx->stats[new_size].freefrags += frags;
435	/*
436	 * Set up a linked-list of blocks of size
437	 * "new_size".
438	 */
439	curr = new;
440	next = curr + new_size;
441	total_size -= new_size;
442	for (i = 0; i < (frags - 1); i++) {
443		((element *)curr)->next = (element *)next;
444		curr = next;
445		next += new_size;
446		total_size -= new_size;
447	}
448	/*
449	 * Add the remaining fragment of the basic block to a free list.
450	 */
451	total_size = rmsize(total_size);
452	if (total_size > 0U) {
453		((element *)next)->next = ctx->freelists[total_size];
454		ctx->freelists[total_size] = (element *)next;
455		ctx->stats[total_size].freefrags++;
456	}
457	/*
458	 * curr is now pointing at the last block in the
459	 * array.
460	 */
461	((element *)curr)->next = NULL;
462	ctx->freelists[new_size] = new;
463
464	return (ISC_TRUE);
465}
466
467static inline void *
468mem_getunlocked(isc_mem_t *ctx, size_t size) {
469	size_t new_size = quantize(size);
470	void *ret;
471
472	if (size >= ctx->max_size || new_size >= ctx->max_size) {
473		/*
474		 * memget() was called on something beyond our upper limit.
475		 */
476		if (ctx->quota != 0U && ctx->total + size > ctx->quota) {
477			ret = NULL;
478			goto done;
479		}
480		ret = (ctx->memalloc)(ctx->arg, size);
481		if (ret == NULL) {
482			ctx->memalloc_failures++;
483			goto done;
484		}
485		ctx->total += size;
486		ctx->inuse += size;
487		ctx->stats[ctx->max_size].gets++;
488		ctx->stats[ctx->max_size].totalgets++;
489		/*
490		 * If we don't set new_size to size, then the
491		 * ISC_MEM_FILL code might write over bytes we
492		 * don't own.
493		 */
494		new_size = size;
495		goto done;
496	}
497
498	/*
499	 * If there are no blocks in the free list for this size, get a chunk
500	 * of memory and then break it up into "new_size"-sized blocks, adding
501	 * them to the free list.
502	 */
503	if (ctx->freelists[new_size] == NULL && !more_frags(ctx, new_size))
504		return (NULL);
505
506	/*
507	 * The free list uses the "rounded-up" size "new_size".
508	 */
509	ret = ctx->freelists[new_size];
510	ctx->freelists[new_size] = ctx->freelists[new_size]->next;
511
512	/*
513	 * The stats[] uses the _actual_ "size" requested by the
514	 * caller, with the caveat (in the code above) that "size" >= the
515	 * max. size (max_size) ends up getting recorded as a call to
516	 * max_size.
517	 */
518	ctx->stats[size].gets++;
519	ctx->stats[size].totalgets++;
520	ctx->stats[new_size].freefrags--;
521	ctx->inuse += new_size;
522
523 done:
524
525#if ISC_MEM_FILL
526	if (ret != NULL)
527		memset(ret, 0xbe, new_size); /* Mnemonic for "beef". */
528#endif
529
530	return (ret);
531}
532
533#if ISC_MEM_FILL && ISC_MEM_CHECKOVERRUN
534static inline void
535check_overrun(void *mem, size_t size, size_t new_size) {
536	unsigned char *cp;
537
538	cp = (unsigned char *)mem;
539	cp += size;
540	while (size < new_size) {
541		INSIST(*cp == 0xbe);
542		cp++;
543		size++;
544	}
545}
546#endif
547
548static inline void
549mem_putunlocked(isc_mem_t *ctx, void *mem, size_t size) {
550	size_t new_size = quantize(size);
551
552	if (size == ctx->max_size || new_size >= ctx->max_size) {
553		/*
554		 * memput() called on something beyond our upper limit.
555		 */
556#if ISC_MEM_FILL
557		memset(mem, 0xde, size); /* Mnemonic for "dead". */
558#endif
559		(ctx->memfree)(ctx->arg, mem);
560		INSIST(ctx->stats[ctx->max_size].gets != 0U);
561		ctx->stats[ctx->max_size].gets--;
562		INSIST(size <= ctx->total);
563		ctx->inuse -= size;
564		ctx->total -= size;
565		return;
566	}
567
568#if ISC_MEM_FILL
569#if ISC_MEM_CHECKOVERRUN
570	check_overrun(mem, size, new_size);
571#endif
572	memset(mem, 0xde, new_size); /* Mnemonic for "dead". */
573#endif
574
575	/*
576	 * The free list uses the "rounded-up" size "new_size".
577	 */
578	((element *)mem)->next = ctx->freelists[new_size];
579	ctx->freelists[new_size] = (element *)mem;
580
581	/*
582	 * The stats[] uses the _actual_ "size" requested by the
583	 * caller, with the caveat (in the code above) that "size" >= the
584	 * max. size (max_size) ends up getting recorded as a call to
585	 * max_size.
586	 */
587	INSIST(ctx->stats[size].gets != 0U);
588	ctx->stats[size].gets--;
589	ctx->stats[new_size].freefrags++;
590	ctx->inuse -= new_size;
591}
592
593/*!
594 * Perform a malloc, doing memory filling and overrun detection as necessary.
595 */
596static inline void *
597mem_get(isc_mem_t *ctx, size_t size) {
598	char *ret;
599
600#if ISC_MEM_CHECKOVERRUN
601	size += 1;
602#endif
603
604	ret = (ctx->memalloc)(ctx->arg, size);
605	if (ret == NULL)
606		ctx->memalloc_failures++;
607
608#if ISC_MEM_FILL
609	if (ret != NULL)
610		memset(ret, 0xbe, size); /* Mnemonic for "beef". */
611#else
612#  if ISC_MEM_CHECKOVERRUN
613	if (ret != NULL)
614		ret[size-1] = 0xbe;
615#  endif
616#endif
617
618	return (ret);
619}
620
621/*!
622 * Perform a free, doing memory filling and overrun detection as necessary.
623 */
624static inline void
625mem_put(isc_mem_t *ctx, void *mem, size_t size) {
626#if ISC_MEM_CHECKOVERRUN
627	INSIST(((unsigned char *)mem)[size] == 0xbe);
628#endif
629#if ISC_MEM_FILL
630	memset(mem, 0xde, size); /* Mnemonic for "dead". */
631#else
632	UNUSED(size);
633#endif
634	(ctx->memfree)(ctx->arg, mem);
635}
636
637/*!
638 * Update internal counters after a memory get.
639 */
640static inline void
641mem_getstats(isc_mem_t *ctx, size_t size) {
642	ctx->total += size;
643	ctx->inuse += size;
644
645	if (size > ctx->max_size) {
646		ctx->stats[ctx->max_size].gets++;
647		ctx->stats[ctx->max_size].totalgets++;
648	} else {
649		ctx->stats[size].gets++;
650		ctx->stats[size].totalgets++;
651	}
652}
653
654/*!
655 * Update internal counters after a memory put.
656 */
657static inline void
658mem_putstats(isc_mem_t *ctx, void *ptr, size_t size) {
659	UNUSED(ptr);
660
661	INSIST(ctx->inuse >= size);
662	ctx->inuse -= size;
663
664	if (size > ctx->max_size) {
665		INSIST(ctx->stats[ctx->max_size].gets > 0U);
666		ctx->stats[ctx->max_size].gets--;
667	} else {
668		INSIST(ctx->stats[size].gets > 0U);
669		ctx->stats[size].gets--;
670	}
671}
672
673/*
674 * Private.
675 */
676
677static void *
678default_memalloc(void *arg, size_t size) {
679	UNUSED(arg);
680	if (size == 0U)
681		size = 1;
682	return (malloc(size));
683}
684
685static void
686default_memfree(void *arg, void *ptr) {
687	UNUSED(arg);
688	free(ptr);
689}
690
691static void
692initialize_action(void) {
693	RUNTIME_CHECK(isc_mutex_init(&lock) == ISC_R_SUCCESS);
694	ISC_LIST_INIT(contexts);
695}
696
697/*
698 * Public.
699 */
700
701isc_result_t
702isc_mem_createx(size_t init_max_size, size_t target_size,
703		isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
704		isc_mem_t **ctxp)
705{
706	return (isc_mem_createx2(init_max_size, target_size, memalloc, memfree,
707				 arg, ctxp, ISC_MEMFLAG_DEFAULT));
708
709}
710
711isc_result_t
712isc_mem_createx2(size_t init_max_size, size_t target_size,
713		 isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
714		 isc_mem_t **ctxp, unsigned int flags)
715{
716	isc_mem_t *ctx;
717	isc_result_t result;
718
719	REQUIRE(ctxp != NULL && *ctxp == NULL);
720	REQUIRE(memalloc != NULL);
721	REQUIRE(memfree != NULL);
722
723	INSIST((ALIGNMENT_SIZE & (ALIGNMENT_SIZE - 1)) == 0);
724
725	RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
726
727	ctx = (memalloc)(arg, sizeof(*ctx));
728	if (ctx == NULL)
729		return (ISC_R_NOMEMORY);
730
731	if ((flags & ISC_MEMFLAG_NOLOCK) == 0) {
732		result = isc_mutex_init(&ctx->lock);
733		if (result != ISC_R_SUCCESS) {
734			(memfree)(arg, ctx);
735			return (result);
736		}
737	}
738
739	if (init_max_size == 0U)
740		ctx->max_size = DEF_MAX_SIZE;
741	else
742		ctx->max_size = init_max_size;
743	ctx->flags = flags;
744	ctx->references = 1;
745	ctx->quota = 0;
746	ctx->total = 0;
747	ctx->inuse = 0;
748	ctx->maxinuse = 0;
749	ctx->hi_water = 0;
750	ctx->lo_water = 0;
751	ctx->hi_called = ISC_FALSE;
752	ctx->water = NULL;
753	ctx->water_arg = NULL;
754	ctx->magic = MEM_MAGIC;
755	isc_ondestroy_init(&ctx->ondestroy);
756	ctx->memalloc = memalloc;
757	ctx->memfree = memfree;
758	ctx->arg = arg;
759	ctx->stats = NULL;
760	ctx->checkfree = ISC_TRUE;
761#if ISC_MEM_TRACKLINES
762	ctx->debuglist = NULL;
763#endif
764	ISC_LIST_INIT(ctx->pools);
765	ctx->freelists = NULL;
766	ctx->basic_blocks = NULL;
767	ctx->basic_table = NULL;
768	ctx->basic_table_count = 0;
769	ctx->basic_table_size = 0;
770	ctx->lowest = NULL;
771	ctx->highest = NULL;
772
773	ctx->stats = (memalloc)(arg,
774				(ctx->max_size+1) * sizeof(struct stats));
775	if (ctx->stats == NULL) {
776		result = ISC_R_NOMEMORY;
777		goto error;
778	}
779	memset(ctx->stats, 0, (ctx->max_size + 1) * sizeof(struct stats));
780
781	if ((flags & ISC_MEMFLAG_INTERNAL) != 0) {
782		if (target_size == 0U)
783			ctx->mem_target = DEF_MEM_TARGET;
784		else
785			ctx->mem_target = target_size;
786		ctx->freelists = (memalloc)(arg, ctx->max_size *
787						 sizeof(element *));
788		if (ctx->freelists == NULL) {
789			result = ISC_R_NOMEMORY;
790			goto error;
791		}
792		memset(ctx->freelists, 0,
793		       ctx->max_size * sizeof(element *));
794	}
795
796#if ISC_MEM_TRACKLINES
797	if ((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0) {
798		unsigned int i;
799
800		ctx->debuglist = (memalloc)(arg,
801				      (ctx->max_size+1) * sizeof(debuglist_t));
802		if (ctx->debuglist == NULL) {
803			result = ISC_R_NOMEMORY;
804			goto error;
805		}
806		for (i = 0; i <= ctx->max_size; i++)
807			ISC_LIST_INIT(ctx->debuglist[i]);
808	}
809#endif
810
811	ctx->memalloc_failures = 0;
812
813	LOCK(&lock);
814	ISC_LIST_INITANDAPPEND(contexts, ctx, link);
815	UNLOCK(&lock);
816
817	*ctxp = ctx;
818	return (ISC_R_SUCCESS);
819
820  error:
821	if (ctx != NULL) {
822		if (ctx->stats != NULL)
823			(memfree)(arg, ctx->stats);
824		if (ctx->freelists != NULL)
825			(memfree)(arg, ctx->freelists);
826#if ISC_MEM_TRACKLINES
827		if (ctx->debuglist != NULL)
828			(ctx->memfree)(ctx->arg, ctx->debuglist);
829#endif /* ISC_MEM_TRACKLINES */
830		if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
831			DESTROYLOCK(&ctx->lock);
832		(memfree)(arg, ctx);
833	}
834
835	return (result);
836}
837
838isc_result_t
839isc_mem_create(size_t init_max_size, size_t target_size,
840	       isc_mem_t **ctxp)
841{
842	return (isc_mem_createx2(init_max_size, target_size,
843				 default_memalloc, default_memfree, NULL,
844				 ctxp, ISC_MEMFLAG_DEFAULT));
845}
846
847isc_result_t
848isc_mem_create2(size_t init_max_size, size_t target_size,
849		isc_mem_t **ctxp, unsigned int flags)
850{
851	return (isc_mem_createx2(init_max_size, target_size,
852				 default_memalloc, default_memfree, NULL,
853				 ctxp, flags));
854}
855
856static void
857destroy(isc_mem_t *ctx) {
858	unsigned int i;
859	isc_ondestroy_t ondest;
860
861	ctx->magic = 0;
862
863	LOCK(&lock);
864	ISC_LIST_UNLINK(contexts, ctx, link);
865	UNLOCK(&lock);
866
867	INSIST(ISC_LIST_EMPTY(ctx->pools));
868
869#if ISC_MEM_TRACKLINES
870	if (ctx->debuglist != NULL) {
871		if (ctx->checkfree) {
872			for (i = 0; i <= ctx->max_size; i++) {
873				if (!ISC_LIST_EMPTY(ctx->debuglist[i]))
874					print_active(ctx, stderr);
875				INSIST(ISC_LIST_EMPTY(ctx->debuglist[i]));
876			}
877		} else {
878			debuglink_t *dl;
879
880			for (i = 0; i <= ctx->max_size; i++)
881				for (dl = ISC_LIST_HEAD(ctx->debuglist[i]);
882				     dl != NULL;
883				     dl = ISC_LIST_HEAD(ctx->debuglist[i])) {
884					ISC_LIST_UNLINK(ctx->debuglist[i],
885							dl, link);
886					free(dl);
887				}
888		}
889		(ctx->memfree)(ctx->arg, ctx->debuglist);
890	}
891#endif
892	INSIST(ctx->references == 0);
893
894	if (ctx->checkfree) {
895		for (i = 0; i <= ctx->max_size; i++) {
896#if ISC_MEM_TRACKLINES
897			if (ctx->stats[i].gets != 0U)
898				print_active(ctx, stderr);
899#endif
900			INSIST(ctx->stats[i].gets == 0U);
901		}
902	}
903
904	(ctx->memfree)(ctx->arg, ctx->stats);
905
906	if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
907		for (i = 0; i < ctx->basic_table_count; i++)
908			(ctx->memfree)(ctx->arg, ctx->basic_table[i]);
909		(ctx->memfree)(ctx->arg, ctx->freelists);
910		if (ctx->basic_table != NULL)
911			(ctx->memfree)(ctx->arg, ctx->basic_table);
912	}
913
914	ondest = ctx->ondestroy;
915
916	if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
917		DESTROYLOCK(&ctx->lock);
918	(ctx->memfree)(ctx->arg, ctx);
919
920	isc_ondestroy_notify(&ondest, ctx);
921}
922
923void
924isc_mem_attach(isc_mem_t *source, isc_mem_t **targetp) {
925	REQUIRE(VALID_CONTEXT(source));
926	REQUIRE(targetp != NULL && *targetp == NULL);
927
928	MCTXLOCK(source, &source->lock);
929	source->references++;
930	MCTXUNLOCK(source, &source->lock);
931
932	*targetp = source;
933}
934
935void
936isc_mem_detach(isc_mem_t **ctxp) {
937	isc_mem_t *ctx;
938	isc_boolean_t want_destroy = ISC_FALSE;
939
940	REQUIRE(ctxp != NULL);
941	ctx = *ctxp;
942	REQUIRE(VALID_CONTEXT(ctx));
943
944	MCTXLOCK(ctx, &ctx->lock);
945	INSIST(ctx->references > 0);
946	ctx->references--;
947	if (ctx->references == 0)
948		want_destroy = ISC_TRUE;
949	MCTXUNLOCK(ctx, &ctx->lock);
950
951	if (want_destroy)
952		destroy(ctx);
953
954	*ctxp = NULL;
955}
956
957/*
958 * isc_mem_putanddetach() is the equivalent of:
959 *
960 * mctx = NULL;
961 * isc_mem_attach(ptr->mctx, &mctx);
962 * isc_mem_detach(&ptr->mctx);
963 * isc_mem_put(mctx, ptr, sizeof(*ptr);
964 * isc_mem_detach(&mctx);
965 */
966
967void
968isc__mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) {
969	isc_mem_t *ctx;
970	isc_boolean_t want_destroy = ISC_FALSE;
971	size_info *si;
972	size_t oldsize;
973
974	REQUIRE(ctxp != NULL);
975	ctx = *ctxp;
976	REQUIRE(VALID_CONTEXT(ctx));
977	REQUIRE(ptr != NULL);
978
979	/*
980	 * Must be before mem_putunlocked() as ctxp is usually within
981	 * [ptr..ptr+size).
982	 */
983	*ctxp = NULL;
984
985	if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) {
986		if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) {
987			si = &(((size_info *)ptr)[-1]);
988			oldsize = si->u.size - ALIGNMENT_SIZE;
989			if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
990				oldsize -= ALIGNMENT_SIZE;
991			INSIST(oldsize == size);
992		}
993		isc__mem_free(ctx, ptr FLARG_PASS);
994
995		MCTXLOCK(ctx, &ctx->lock);
996		ctx->references--;
997		if (ctx->references == 0)
998			want_destroy = ISC_TRUE;
999		MCTXUNLOCK(ctx, &ctx->lock);
1000		if (want_destroy)
1001			destroy(ctx);
1002
1003		return;
1004	}
1005
1006	if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1007		MCTXLOCK(ctx, &ctx->lock);
1008		mem_putunlocked(ctx, ptr, size);
1009	} else {
1010		mem_put(ctx, ptr, size);
1011		MCTXLOCK(ctx, &ctx->lock);
1012		mem_putstats(ctx, ptr, size);
1013	}
1014
1015	DELETE_TRACE(ctx, ptr, size, file, line);
1016	INSIST(ctx->references > 0);
1017	ctx->references--;
1018	if (ctx->references == 0)
1019		want_destroy = ISC_TRUE;
1020
1021	MCTXUNLOCK(ctx, &ctx->lock);
1022
1023	if (want_destroy)
1024		destroy(ctx);
1025}
1026
1027void
1028isc_mem_destroy(isc_mem_t **ctxp) {
1029	isc_mem_t *ctx;
1030
1031	/*
1032	 * This routine provides legacy support for callers who use mctxs
1033	 * without attaching/detaching.
1034	 */
1035
1036	REQUIRE(ctxp != NULL);
1037	ctx = *ctxp;
1038	REQUIRE(VALID_CONTEXT(ctx));
1039
1040	MCTXLOCK(ctx, &ctx->lock);
1041#if ISC_MEM_TRACKLINES
1042	if (ctx->references != 1)
1043		print_active(ctx, stderr);
1044#endif
1045	REQUIRE(ctx->references == 1);
1046	ctx->references--;
1047	MCTXUNLOCK(ctx, &ctx->lock);
1048
1049	destroy(ctx);
1050
1051	*ctxp = NULL;
1052}
1053
1054isc_result_t
1055isc_mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event) {
1056	isc_result_t res;
1057
1058	MCTXLOCK(ctx, &ctx->lock);
1059	res = isc_ondestroy_register(&ctx->ondestroy, task, event);
1060	MCTXUNLOCK(ctx, &ctx->lock);
1061
1062	return (res);
1063}
1064
1065
1066void *
1067isc__mem_get(isc_mem_t *ctx, size_t size FLARG) {
1068	void *ptr;
1069	isc_boolean_t call_water = ISC_FALSE;
1070
1071	REQUIRE(VALID_CONTEXT(ctx));
1072
1073	if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0)
1074		return (isc__mem_allocate(ctx, size FLARG_PASS));
1075
1076	if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1077		MCTXLOCK(ctx, &ctx->lock);
1078		ptr = mem_getunlocked(ctx, size);
1079	} else {
1080		ptr = mem_get(ctx, size);
1081		MCTXLOCK(ctx, &ctx->lock);
1082		if (ptr != NULL)
1083			mem_getstats(ctx, size);
1084	}
1085
1086	ADD_TRACE(ctx, ptr, size, file, line);
1087	if (ctx->hi_water != 0U && !ctx->hi_called &&
1088	    ctx->inuse > ctx->hi_water) {
1089		call_water = ISC_TRUE;
1090	}
1091	if (ctx->inuse > ctx->maxinuse) {
1092		ctx->maxinuse = ctx->inuse;
1093		if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1094		    (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
1095			fprintf(stderr, "maxinuse = %lu\n",
1096				(unsigned long)ctx->inuse);
1097	}
1098	MCTXUNLOCK(ctx, &ctx->lock);
1099
1100	if (call_water)
1101		(ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
1102
1103	return (ptr);
1104}
1105
1106void
1107isc__mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG)
1108{
1109	isc_boolean_t call_water = ISC_FALSE;
1110	size_info *si;
1111	size_t oldsize;
1112
1113	REQUIRE(VALID_CONTEXT(ctx));
1114	REQUIRE(ptr != NULL);
1115
1116	if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) {
1117		if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) {
1118			si = &(((size_info *)ptr)[-1]);
1119			oldsize = si->u.size - ALIGNMENT_SIZE;
1120			if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
1121				oldsize -= ALIGNMENT_SIZE;
1122			INSIST(oldsize == size);
1123		}
1124		isc__mem_free(ctx, ptr FLARG_PASS);
1125		return;
1126	}
1127
1128	if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1129		MCTXLOCK(ctx, &ctx->lock);
1130		mem_putunlocked(ctx, ptr, size);
1131	} else {
1132		mem_put(ctx, ptr, size);
1133		MCTXLOCK(ctx, &ctx->lock);
1134		mem_putstats(ctx, ptr, size);
1135	}
1136
1137	DELETE_TRACE(ctx, ptr, size, file, line);
1138
1139	/*
1140	 * The check against ctx->lo_water == 0 is for the condition
1141	 * when the context was pushed over hi_water but then had
1142	 * isc_mem_setwater() called with 0 for hi_water and lo_water.
1143	 */
1144	if (ctx->hi_called &&
1145	    (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1146		if (ctx->water != NULL)
1147			call_water = ISC_TRUE;
1148	}
1149	MCTXUNLOCK(ctx, &ctx->lock);
1150
1151	if (call_water)
1152		(ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
1153}
1154
1155void
1156isc_mem_waterack(isc_mem_t *ctx, int flag) {
1157	REQUIRE(VALID_CONTEXT(ctx));
1158
1159	MCTXLOCK(ctx, &ctx->lock);
1160	if (flag == ISC_MEM_LOWATER)
1161		ctx->hi_called = ISC_FALSE;
1162	else if (flag == ISC_MEM_HIWATER)
1163		ctx->hi_called = ISC_TRUE;
1164	MCTXUNLOCK(ctx, &ctx->lock);
1165}
1166
1167#if ISC_MEM_TRACKLINES
1168static void
1169print_active(isc_mem_t *mctx, FILE *out) {
1170	if (mctx->debuglist != NULL) {
1171		debuglink_t *dl;
1172		unsigned int i, j;
1173		const char *format;
1174		isc_boolean_t found;
1175
1176		fprintf(out, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1177					    ISC_MSG_DUMPALLOC,
1178					    "Dump of all outstanding "
1179					    "memory allocations:\n"));
1180		found = ISC_FALSE;
1181		format = isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1182					ISC_MSG_PTRFILELINE,
1183					"\tptr %p size %u file %s line %u\n");
1184		for (i = 0; i <= mctx->max_size; i++) {
1185			dl = ISC_LIST_HEAD(mctx->debuglist[i]);
1186
1187			if (dl != NULL)
1188				found = ISC_TRUE;
1189
1190			while (dl != NULL) {
1191				for (j = 0; j < DEBUGLIST_COUNT; j++)
1192					if (dl->ptr[j] != NULL)
1193						fprintf(out, format,
1194							dl->ptr[j],
1195							dl->size[j],
1196							dl->file[j],
1197							dl->line[j]);
1198				dl = ISC_LIST_NEXT(dl, link);
1199			}
1200		}
1201		if (!found)
1202			fprintf(out, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1203						    ISC_MSG_NONE, "\tNone.\n"));
1204	}
1205}
1206#endif
1207
1208/*
1209 * Print the stats[] on the stream "out" with suitable formatting.
1210 */
1211void
1212isc_mem_stats(isc_mem_t *ctx, FILE *out) {
1213	size_t i;
1214	const struct stats *s;
1215	const isc_mempool_t *pool;
1216
1217	REQUIRE(VALID_CONTEXT(ctx));
1218	MCTXLOCK(ctx, &ctx->lock);
1219
1220	for (i = 0; i <= ctx->max_size; i++) {
1221		s = &ctx->stats[i];
1222
1223		if (s->totalgets == 0U && s->gets == 0U)
1224			continue;
1225		fprintf(out, "%s%5lu: %11lu gets, %11lu rem",
1226			(i == ctx->max_size) ? ">=" : "  ",
1227			(unsigned long) i, s->totalgets, s->gets);
1228		if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0 &&
1229		    (s->blocks != 0U || s->freefrags != 0U))
1230			fprintf(out, " (%lu bl, %lu ff)",
1231				s->blocks, s->freefrags);
1232		fputc('\n', out);
1233	}
1234
1235	/*
1236	 * Note that since a pool can be locked now, these stats might be
1237	 * somewhat off if the pool is in active use at the time the stats
1238	 * are dumped.  The link fields are protected by the isc_mem_t's
1239	 * lock, however, so walking this list and extracting integers from
1240	 * stats fields is always safe.
1241	 */
1242	pool = ISC_LIST_HEAD(ctx->pools);
1243	if (pool != NULL) {
1244		fprintf(out, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1245					    ISC_MSG_POOLSTATS,
1246					    "[Pool statistics]\n"));
1247		fprintf(out, "%15s %10s %10s %10s %10s %10s %10s %10s %1s\n",
1248			isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1249				       ISC_MSG_POOLNAME, "name"),
1250			isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1251				       ISC_MSG_POOLSIZE, "size"),
1252			isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1253				       ISC_MSG_POOLMAXALLOC, "maxalloc"),
1254			isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1255				       ISC_MSG_POOLALLOCATED, "allocated"),
1256			isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1257				       ISC_MSG_POOLFREECOUNT, "freecount"),
1258			isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1259				       ISC_MSG_POOLFREEMAX, "freemax"),
1260			isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1261				       ISC_MSG_POOLFILLCOUNT, "fillcount"),
1262			isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1263				       ISC_MSG_POOLGETS, "gets"),
1264			"L");
1265	}
1266	while (pool != NULL) {
1267		fprintf(out, "%15s %10lu %10u %10u %10u %10u %10u %10u %s\n",
1268			pool->name, (unsigned long) pool->size, pool->maxalloc,
1269			pool->allocated, pool->freecount, pool->freemax,
1270			pool->fillcount, pool->gets,
1271			(pool->lock == NULL ? "N" : "Y"));
1272		pool = ISC_LIST_NEXT(pool, link);
1273	}
1274
1275#if ISC_MEM_TRACKLINES
1276	print_active(ctx, out);
1277#endif
1278
1279	MCTXUNLOCK(ctx, &ctx->lock);
1280}
1281
1282/*
1283 * Replacements for malloc() and free() -- they implicitly remember the
1284 * size of the object allocated (with some additional overhead).
1285 */
1286
1287static void *
1288isc__mem_allocateunlocked(isc_mem_t *ctx, size_t size) {
1289	size_info *si;
1290
1291	size += ALIGNMENT_SIZE;
1292	if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
1293		size += ALIGNMENT_SIZE;
1294
1295	if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0)
1296		si = mem_getunlocked(ctx, size);
1297	else
1298		si = mem_get(ctx, size);
1299
1300	if (si == NULL)
1301		return (NULL);
1302	if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
1303		si->u.ctx = ctx;
1304		si++;
1305	}
1306	si->u.size = size;
1307	return (&si[1]);
1308}
1309
1310void *
1311isc__mem_allocate(isc_mem_t *ctx, size_t size FLARG) {
1312	size_info *si;
1313	isc_boolean_t call_water = ISC_FALSE;
1314
1315	REQUIRE(VALID_CONTEXT(ctx));
1316
1317	if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1318		MCTXLOCK(ctx, &ctx->lock);
1319		si = isc__mem_allocateunlocked(ctx, size);
1320	} else {
1321		si = isc__mem_allocateunlocked(ctx, size);
1322		MCTXLOCK(ctx, &ctx->lock);
1323		if (si != NULL)
1324			mem_getstats(ctx, si[-1].u.size);
1325	}
1326
1327#if ISC_MEM_TRACKLINES
1328	ADD_TRACE(ctx, si, si[-1].u.size, file, line);
1329#endif
1330	if (ctx->hi_water != 0U && !ctx->hi_called &&
1331	    ctx->inuse > ctx->hi_water) {
1332		ctx->hi_called = ISC_TRUE;
1333		call_water = ISC_TRUE;
1334	}
1335	if (ctx->inuse > ctx->maxinuse) {
1336		ctx->maxinuse = ctx->inuse;
1337		if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1338		    (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
1339			fprintf(stderr, "maxinuse = %lu\n",
1340				(unsigned long)ctx->inuse);
1341	}
1342	MCTXUNLOCK(ctx, &ctx->lock);
1343
1344	if (call_water)
1345		(ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
1346
1347	return (si);
1348}
1349
1350void
1351isc__mem_free(isc_mem_t *ctx, void *ptr FLARG) {
1352	size_info *si;
1353	size_t size;
1354	isc_boolean_t call_water= ISC_FALSE;
1355
1356	REQUIRE(VALID_CONTEXT(ctx));
1357	REQUIRE(ptr != NULL);
1358
1359	if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
1360		si = &(((size_info *)ptr)[-2]);
1361		REQUIRE(si->u.ctx == ctx);
1362		size = si[1].u.size;
1363	} else {
1364		si = &(((size_info *)ptr)[-1]);
1365		size = si->u.size;
1366	}
1367
1368	if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1369		MCTXLOCK(ctx, &ctx->lock);
1370		mem_putunlocked(ctx, si, size);
1371	} else {
1372		mem_put(ctx, si, size);
1373		MCTXLOCK(ctx, &ctx->lock);
1374		mem_putstats(ctx, si, size);
1375	}
1376
1377	DELETE_TRACE(ctx, ptr, size, file, line);
1378
1379	/*
1380	 * The check against ctx->lo_water == 0 is for the condition
1381	 * when the context was pushed over hi_water but then had
1382	 * isc_mem_setwater() called with 0 for hi_water and lo_water.
1383	 */
1384	if (ctx->hi_called &&
1385	    (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1386		ctx->hi_called = ISC_FALSE;
1387
1388		if (ctx->water != NULL)
1389			call_water = ISC_TRUE;
1390	}
1391	MCTXUNLOCK(ctx, &ctx->lock);
1392
1393	if (call_water)
1394		(ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
1395}
1396
1397
1398/*
1399 * Other useful things.
1400 */
1401
1402char *
1403isc__mem_strdup(isc_mem_t *mctx, const char *s FLARG) {
1404	size_t len;
1405	char *ns;
1406
1407	REQUIRE(VALID_CONTEXT(mctx));
1408	REQUIRE(s != NULL);
1409
1410	len = strlen(s);
1411
1412	ns = isc__mem_allocate(mctx, len + 1 FLARG_PASS);
1413
1414	if (ns != NULL)
1415		strncpy(ns, s, len + 1);
1416
1417	return (ns);
1418}
1419
1420void
1421isc_mem_setdestroycheck(isc_mem_t *ctx, isc_boolean_t flag) {
1422	REQUIRE(VALID_CONTEXT(ctx));
1423	MCTXLOCK(ctx, &ctx->lock);
1424
1425	ctx->checkfree = flag;
1426
1427	MCTXUNLOCK(ctx, &ctx->lock);
1428}
1429
1430/*
1431 * Quotas
1432 */
1433
1434void
1435isc_mem_setquota(isc_mem_t *ctx, size_t quota) {
1436	REQUIRE(VALID_CONTEXT(ctx));
1437	MCTXLOCK(ctx, &ctx->lock);
1438
1439	ctx->quota = quota;
1440
1441	MCTXUNLOCK(ctx, &ctx->lock);
1442}
1443
1444size_t
1445isc_mem_getquota(isc_mem_t *ctx) {
1446	size_t quota;
1447
1448	REQUIRE(VALID_CONTEXT(ctx));
1449	MCTXLOCK(ctx, &ctx->lock);
1450
1451	quota = ctx->quota;
1452
1453	MCTXUNLOCK(ctx, &ctx->lock);
1454
1455	return (quota);
1456}
1457
1458size_t
1459isc_mem_inuse(isc_mem_t *ctx) {
1460	size_t inuse;
1461
1462	REQUIRE(VALID_CONTEXT(ctx));
1463	MCTXLOCK(ctx, &ctx->lock);
1464
1465	inuse = ctx->inuse;
1466
1467	MCTXUNLOCK(ctx, &ctx->lock);
1468
1469	return (inuse);
1470}
1471
1472void
1473isc_mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg,
1474		 size_t hiwater, size_t lowater)
1475{
1476	isc_boolean_t callwater = ISC_FALSE;
1477	isc_mem_water_t oldwater;
1478	void *oldwater_arg;
1479
1480	REQUIRE(VALID_CONTEXT(ctx));
1481	REQUIRE(hiwater >= lowater);
1482
1483	MCTXLOCK(ctx, &ctx->lock);
1484	oldwater = ctx->water;
1485	oldwater_arg = ctx->water_arg;
1486	if (water == NULL) {
1487		callwater = ctx->hi_called;
1488		ctx->water = NULL;
1489		ctx->water_arg = NULL;
1490		ctx->hi_water = 0;
1491		ctx->lo_water = 0;
1492		ctx->hi_called = ISC_FALSE;
1493	} else {
1494		if (ctx->hi_called &&
1495		    (ctx->water != water || ctx->water_arg != water_arg ||
1496		     ctx->inuse < lowater || lowater == 0U))
1497			callwater = ISC_TRUE;
1498		ctx->water = water;
1499		ctx->water_arg = water_arg;
1500		ctx->hi_water = hiwater;
1501		ctx->lo_water = lowater;
1502		ctx->hi_called = ISC_FALSE;
1503	}
1504	MCTXUNLOCK(ctx, &ctx->lock);
1505
1506	if (callwater && oldwater != NULL)
1507		(oldwater)(oldwater_arg, ISC_MEM_LOWATER);
1508}
1509
1510/*
1511 * Memory pool stuff
1512 */
1513
1514isc_result_t
1515isc_mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp) {
1516	isc_mempool_t *mpctx;
1517
1518	REQUIRE(VALID_CONTEXT(mctx));
1519	REQUIRE(size > 0U);
1520	REQUIRE(mpctxp != NULL && *mpctxp == NULL);
1521
1522	/*
1523	 * Allocate space for this pool, initialize values, and if all works
1524	 * well, attach to the memory context.
1525	 */
1526	mpctx = isc_mem_get(mctx, sizeof(isc_mempool_t));
1527	if (mpctx == NULL)
1528		return (ISC_R_NOMEMORY);
1529
1530	mpctx->magic = MEMPOOL_MAGIC;
1531	mpctx->lock = NULL;
1532	mpctx->mctx = mctx;
1533	mpctx->size = size;
1534	mpctx->maxalloc = UINT_MAX;
1535	mpctx->allocated = 0;
1536	mpctx->freecount = 0;
1537	mpctx->freemax = 1;
1538	mpctx->fillcount = 1;
1539	mpctx->gets = 0;
1540#if ISC_MEMPOOL_NAMES
1541	mpctx->name[0] = 0;
1542#endif
1543	mpctx->items = NULL;
1544
1545	*mpctxp = mpctx;
1546
1547	MCTXLOCK(mctx, &mctx->lock);
1548	ISC_LIST_INITANDAPPEND(mctx->pools, mpctx, link);
1549	MCTXUNLOCK(mctx, &mctx->lock);
1550
1551	return (ISC_R_SUCCESS);
1552}
1553
1554void
1555isc_mempool_setname(isc_mempool_t *mpctx, const char *name) {
1556	REQUIRE(name != NULL);
1557
1558#if ISC_MEMPOOL_NAMES
1559	if (mpctx->lock != NULL)
1560		LOCK(mpctx->lock);
1561
1562	strncpy(mpctx->name, name, sizeof(mpctx->name) - 1);
1563	mpctx->name[sizeof(mpctx->name) - 1] = '\0';
1564
1565	if (mpctx->lock != NULL)
1566		UNLOCK(mpctx->lock);
1567#else
1568	UNUSED(mpctx);
1569	UNUSED(name);
1570#endif
1571}
1572
1573void
1574isc_mempool_destroy(isc_mempool_t **mpctxp) {
1575	isc_mempool_t *mpctx;
1576	isc_mem_t *mctx;
1577	isc_mutex_t *lock;
1578	element *item;
1579
1580	REQUIRE(mpctxp != NULL);
1581	mpctx = *mpctxp;
1582	REQUIRE(VALID_MEMPOOL(mpctx));
1583#if ISC_MEMPOOL_NAMES
1584	if (mpctx->allocated > 0)
1585		UNEXPECTED_ERROR(__FILE__, __LINE__,
1586				 "isc_mempool_destroy(): mempool %s "
1587				 "leaked memory",
1588				 mpctx->name);
1589#endif
1590	REQUIRE(mpctx->allocated == 0);
1591
1592	mctx = mpctx->mctx;
1593
1594	lock = mpctx->lock;
1595
1596	if (lock != NULL)
1597		LOCK(lock);
1598
1599	/*
1600	 * Return any items on the free list
1601	 */
1602	MCTXLOCK(mctx, &mctx->lock);
1603	while (mpctx->items != NULL) {
1604		INSIST(mpctx->freecount > 0);
1605		mpctx->freecount--;
1606		item = mpctx->items;
1607		mpctx->items = item->next;
1608
1609		if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1610			mem_putunlocked(mctx, item, mpctx->size);
1611		} else {
1612			mem_put(mctx, item, mpctx->size);
1613			mem_putstats(mctx, item, mpctx->size);
1614		}
1615	}
1616	MCTXUNLOCK(mctx, &mctx->lock);
1617
1618	/*
1619	 * Remove our linked list entry from the memory context.
1620	 */
1621	MCTXLOCK(mctx, &mctx->lock);
1622	ISC_LIST_UNLINK(mctx->pools, mpctx, link);
1623	MCTXUNLOCK(mctx, &mctx->lock);
1624
1625	mpctx->magic = 0;
1626
1627	isc_mem_put(mpctx->mctx, mpctx, sizeof(isc_mempool_t));
1628
1629	if (lock != NULL)
1630		UNLOCK(lock);
1631
1632	*mpctxp = NULL;
1633}
1634
1635void
1636isc_mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock) {
1637	REQUIRE(VALID_MEMPOOL(mpctx));
1638	REQUIRE(mpctx->lock == NULL);
1639	REQUIRE(lock != NULL);
1640
1641	mpctx->lock = lock;
1642}
1643
1644void *
1645isc__mempool_get(isc_mempool_t *mpctx FLARG) {
1646	element *item;
1647	isc_mem_t *mctx;
1648	unsigned int i;
1649
1650	REQUIRE(VALID_MEMPOOL(mpctx));
1651
1652	mctx = mpctx->mctx;
1653
1654	if (mpctx->lock != NULL)
1655		LOCK(mpctx->lock);
1656
1657	/*
1658	 * Don't let the caller go over quota
1659	 */
1660	if (mpctx->allocated >= mpctx->maxalloc) {
1661		item = NULL;
1662		goto out;
1663	}
1664
1665	/*
1666	 * if we have a free list item, return the first here
1667	 */
1668	item = mpctx->items;
1669	if (item != NULL) {
1670		mpctx->items = item->next;
1671		INSIST(mpctx->freecount > 0);
1672		mpctx->freecount--;
1673		mpctx->gets++;
1674		mpctx->allocated++;
1675		goto out;
1676	}
1677
1678	/*
1679	 * We need to dip into the well.  Lock the memory context here and
1680	 * fill up our free list.
1681	 */
1682	MCTXLOCK(mctx, &mctx->lock);
1683	for (i = 0; i < mpctx->fillcount; i++) {
1684		if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1685			item = mem_getunlocked(mctx, mpctx->size);
1686		} else {
1687			item = mem_get(mctx, mpctx->size);
1688			if (item != NULL)
1689				mem_getstats(mctx, mpctx->size);
1690		}
1691		if (item == NULL)
1692			break;
1693		item->next = mpctx->items;
1694		mpctx->items = item;
1695		mpctx->freecount++;
1696	}
1697	MCTXUNLOCK(mctx, &mctx->lock);
1698
1699	/*
1700	 * If we didn't get any items, return NULL.
1701	 */
1702	item = mpctx->items;
1703	if (item == NULL)
1704		goto out;
1705
1706	mpctx->items = item->next;
1707	mpctx->freecount--;
1708	mpctx->gets++;
1709	mpctx->allocated++;
1710
1711 out:
1712	if (mpctx->lock != NULL)
1713		UNLOCK(mpctx->lock);
1714
1715#if ISC_MEM_TRACKLINES
1716	if (item != NULL) {
1717		MCTXLOCK(mctx, &mctx->lock);
1718		ADD_TRACE(mctx, item, mpctx->size, file, line);
1719		MCTXUNLOCK(mctx, &mctx->lock);
1720	}
1721#endif /* ISC_MEM_TRACKLINES */
1722
1723	return (item);
1724}
1725
1726void
1727isc__mempool_put(isc_mempool_t *mpctx, void *mem FLARG) {
1728	isc_mem_t *mctx;
1729	element *item;
1730
1731	REQUIRE(VALID_MEMPOOL(mpctx));
1732	REQUIRE(mem != NULL);
1733
1734	mctx = mpctx->mctx;
1735
1736	if (mpctx->lock != NULL)
1737		LOCK(mpctx->lock);
1738
1739	INSIST(mpctx->allocated > 0);
1740	mpctx->allocated--;
1741
1742#if ISC_MEM_TRACKLINES
1743	MCTXLOCK(mctx, &mctx->lock);
1744	DELETE_TRACE(mctx, mem, mpctx->size, file, line);
1745	MCTXUNLOCK(mctx, &mctx->lock);
1746#endif /* ISC_MEM_TRACKLINES */
1747
1748	/*
1749	 * If our free list is full, return this to the mctx directly.
1750	 */
1751	if (mpctx->freecount >= mpctx->freemax) {
1752		if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1753			MCTXLOCK(mctx, &mctx->lock);
1754			mem_putunlocked(mctx, mem, mpctx->size);
1755			MCTXUNLOCK(mctx, &mctx->lock);
1756		} else {
1757			mem_put(mctx, mem, mpctx->size);
1758			MCTXLOCK(mctx, &mctx->lock);
1759			mem_putstats(mctx, mem, mpctx->size);
1760			MCTXUNLOCK(mctx, &mctx->lock);
1761		}
1762		if (mpctx->lock != NULL)
1763			UNLOCK(mpctx->lock);
1764		return;
1765	}
1766
1767	/*
1768	 * Otherwise, attach it to our free list and bump the counter.
1769	 */
1770	mpctx->freecount++;
1771	item = (element *)mem;
1772	item->next = mpctx->items;
1773	mpctx->items = item;
1774
1775	if (mpctx->lock != NULL)
1776		UNLOCK(mpctx->lock);
1777}
1778
1779/*
1780 * Quotas
1781 */
1782
1783void
1784isc_mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit) {
1785	REQUIRE(VALID_MEMPOOL(mpctx));
1786
1787	if (mpctx->lock != NULL)
1788		LOCK(mpctx->lock);
1789
1790	mpctx->freemax = limit;
1791
1792	if (mpctx->lock != NULL)
1793		UNLOCK(mpctx->lock);
1794}
1795
1796unsigned int
1797isc_mempool_getfreemax(isc_mempool_t *mpctx) {
1798	unsigned int freemax;
1799
1800	REQUIRE(VALID_MEMPOOL(mpctx));
1801
1802	if (mpctx->lock != NULL)
1803		LOCK(mpctx->lock);
1804
1805	freemax = mpctx->freemax;
1806
1807	if (mpctx->lock != NULL)
1808		UNLOCK(mpctx->lock);
1809
1810	return (freemax);
1811}
1812
1813unsigned int
1814isc_mempool_getfreecount(isc_mempool_t *mpctx) {
1815	unsigned int freecount;
1816
1817	REQUIRE(VALID_MEMPOOL(mpctx));
1818
1819	if (mpctx->lock != NULL)
1820		LOCK(mpctx->lock);
1821
1822	freecount = mpctx->freecount;
1823
1824	if (mpctx->lock != NULL)
1825		UNLOCK(mpctx->lock);
1826
1827	return (freecount);
1828}
1829
1830void
1831isc_mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit) {
1832	REQUIRE(limit > 0);
1833
1834	REQUIRE(VALID_MEMPOOL(mpctx));
1835
1836	if (mpctx->lock != NULL)
1837		LOCK(mpctx->lock);
1838
1839	mpctx->maxalloc = limit;
1840
1841	if (mpctx->lock != NULL)
1842		UNLOCK(mpctx->lock);
1843}
1844
1845unsigned int
1846isc_mempool_getmaxalloc(isc_mempool_t *mpctx) {
1847	unsigned int maxalloc;
1848
1849	REQUIRE(VALID_MEMPOOL(mpctx));
1850
1851	if (mpctx->lock != NULL)
1852		LOCK(mpctx->lock);
1853
1854	maxalloc = mpctx->maxalloc;
1855
1856	if (mpctx->lock != NULL)
1857		UNLOCK(mpctx->lock);
1858
1859	return (maxalloc);
1860}
1861
1862unsigned int
1863isc_mempool_getallocated(isc_mempool_t *mpctx) {
1864	unsigned int allocated;
1865
1866	REQUIRE(VALID_MEMPOOL(mpctx));
1867
1868	if (mpctx->lock != NULL)
1869		LOCK(mpctx->lock);
1870
1871	allocated = mpctx->allocated;
1872
1873	if (mpctx->lock != NULL)
1874		UNLOCK(mpctx->lock);
1875
1876	return (allocated);
1877}
1878
1879void
1880isc_mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit) {
1881	REQUIRE(limit > 0);
1882	REQUIRE(VALID_MEMPOOL(mpctx));
1883
1884	if (mpctx->lock != NULL)
1885		LOCK(mpctx->lock);
1886
1887	mpctx->fillcount = limit;
1888
1889	if (mpctx->lock != NULL)
1890		UNLOCK(mpctx->lock);
1891}
1892
1893unsigned int
1894isc_mempool_getfillcount(isc_mempool_t *mpctx) {
1895	unsigned int fillcount;
1896
1897	REQUIRE(VALID_MEMPOOL(mpctx));
1898
1899	if (mpctx->lock != NULL)
1900		LOCK(mpctx->lock);
1901
1902	fillcount = mpctx->fillcount;
1903
1904	if (mpctx->lock != NULL)
1905		UNLOCK(mpctx->lock);
1906
1907	return (fillcount);
1908}
1909
1910void
1911isc_mem_printactive(isc_mem_t *ctx, FILE *file) {
1912
1913	REQUIRE(VALID_CONTEXT(ctx));
1914	REQUIRE(file != NULL);
1915
1916#if !ISC_MEM_TRACKLINES
1917	UNUSED(ctx);
1918	UNUSED(file);
1919#else
1920	print_active(ctx, file);
1921#endif
1922}
1923
1924void
1925isc_mem_printallactive(FILE *file) {
1926#if !ISC_MEM_TRACKLINES
1927	UNUSED(file);
1928#else
1929	isc_mem_t *ctx;
1930
1931	RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
1932
1933	LOCK(&lock);
1934	for (ctx = ISC_LIST_HEAD(contexts);
1935	     ctx != NULL;
1936	     ctx = ISC_LIST_NEXT(ctx, link)) {
1937		fprintf(file, "context: %p\n", ctx);
1938		print_active(ctx, file);
1939	}
1940	UNLOCK(&lock);
1941#endif
1942}
1943
1944void
1945isc_mem_checkdestroyed(FILE *file) {
1946
1947	RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
1948
1949	LOCK(&lock);
1950	if (!ISC_LIST_EMPTY(contexts))  {
1951#if ISC_MEM_TRACKLINES
1952		isc_mem_t *ctx;
1953
1954		for (ctx = ISC_LIST_HEAD(contexts);
1955		     ctx != NULL;
1956		     ctx = ISC_LIST_NEXT(ctx, link)) {
1957			fprintf(file, "context: %p\n", ctx);
1958			print_active(ctx, file);
1959		}
1960		fflush(file);
1961#endif
1962		INSIST(0);
1963	}
1964	UNLOCK(&lock);
1965}
1966