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