mem.c 37.5 KB
Newer Older
Bob Halley's avatar
base  
Bob Halley committed
1
/*
Brian Wellington's avatar
Brian Wellington committed
2
 * Copyright (C) 1997-2001  Internet Software Consortium.
3
 *
Bob Halley's avatar
base  
Bob Halley committed
4
5
6
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
7
 *
8
9
10
11
12
13
14
15
 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
 * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Bob Halley's avatar
base  
Bob Halley committed
16
17
 */

18
/* $Id: mem.c,v 1.103 2001/10/12 00:35:11 gson Exp $ */
David Lawrence's avatar
David Lawrence committed
19

Bob Halley's avatar
Bob Halley committed
20
#include <config.h>
Bob Halley's avatar
base  
Bob Halley committed
21
22
23

#include <stdio.h>
#include <stdlib.h>
Bob Halley's avatar
Bob Halley committed
24
#include <stddef.h>
Bob Halley's avatar
base  
Bob Halley committed
25

Michael Graff's avatar
Michael Graff committed
26
27
#include <limits.h>

28
#include <isc/magic.h>
Bob Halley's avatar
Bob Halley committed
29
#include <isc/mem.h>
30
#include <isc/msgs.h>
31
#include <isc/ondestroy.h>
32
#include <isc/string.h>
Bob Halley's avatar
Bob Halley committed
33

Bob Halley's avatar
update    
Bob Halley committed
34
#include <isc/mutex.h>
Michael Graff's avatar
Michael Graff committed
35
#include <isc/util.h>
Bob Halley's avatar
update    
Bob Halley committed
36

37
38
39
#ifndef ISC_MEM_DEBUGGING
#define ISC_MEM_DEBUGGING 0
#endif
40
LIBISC_EXTERNAL_DATA unsigned int isc_mem_debugging = ISC_MEM_DEBUGGING;
41

42
43
44
45
46
47
48
49
50
51
/*
 * Define ISC_MEM_USE_INTERNAL_MALLOC=1 to use the internal malloc()
 * implementation in preference to the system one.  The internal malloc()
 * is very space-efficient, and quite fast on uniprocessor systems.  It
 * performs poorly on multiprocessor machines.
 */
#ifndef ISC_MEM_USE_INTERNAL_MALLOC
#define ISC_MEM_USE_INTERNAL_MALLOC 0
#endif

52
53
54
55
56
57
/*
 * Constants.
 */

#define DEF_MAX_SIZE		1100
#define DEF_MEM_TARGET		4096
58
59
#define ALIGNMENT_SIZE		8		/* must be a power of 2 */
#define NUM_BASIC_BLOCKS	64		/* must be > 1 */
60
#define TABLE_INCREMENT		1024
Michael Graff's avatar
Michael Graff committed
61
#define DEBUGLIST_COUNT		1024
62

Bob Halley's avatar
base  
Bob Halley committed
63
64
65
/*
 * Types.
 */
66
#if ISC_MEM_TRACKLINES
Michael Graff's avatar
Michael Graff committed
67
68
69
70
71
72
73
74
typedef struct debuglink debuglink_t;
struct debuglink {
	ISC_LINK(debuglink_t)	link;
	const void	       *ptr[DEBUGLIST_COUNT];
	const char	       *file[DEBUGLIST_COUNT];
	unsigned int		line[DEBUGLIST_COUNT];
	unsigned int		count;
};
Bob Halley's avatar
base  
Bob Halley committed
75

Michael Graff's avatar
Michael Graff committed
76
77
78
79
80
81
#define FLARG_PASS	, file, line
#define FLARG		, const char *file, int line
#else
#define FLARG_PASS
#define FLARG
#endif
82

Michael Graff's avatar
Michael Graff committed
83
typedef struct element element;
84
85
86
struct element {
	element *		next;
};
Bob Halley's avatar
base  
Bob Halley committed
87
88
89
90
91

typedef struct {
	/*
	 * This structure must be ALIGNMENT_SIZE bytes.
	 */
92
93
94
95
	union {
		size_t		size;
		char		bytes[ALIGNMENT_SIZE];
	} u;
Bob Halley's avatar
Bob Halley committed
96
} size_info;
Bob Halley's avatar
base  
Bob Halley committed
97
98

struct stats {
Bob Halley's avatar
Bob Halley committed
99
100
	unsigned long		gets;
	unsigned long		totalgets;
101
#if ISC_MEM_USE_INTERNAL_MALLOC
Bob Halley's avatar
Bob Halley committed
102
103
	unsigned long		blocks;
	unsigned long		freefrags;
104
#endif /* ISC_MEM_USE_INTERNAL_MALLOC */
Bob Halley's avatar
base  
Bob Halley committed
105
106
};

107
108
#define MEM_MAGIC		ISC_MAGIC('M', 'e', 'm', 'C')
#define VALID_CONTEXT(c)	ISC_MAGIC_VALID(c, MEM_MAGIC)
Bob Halley's avatar
Bob Halley committed
109

110
#if ISC_MEM_TRACKLINES
111
typedef ISC_LIST(debuglink_t)	debuglist_t;
112
#endif
113

114
struct isc_mem {
Bob Halley's avatar
Bob Halley committed
115
	unsigned int		magic;
116
	isc_ondestroy_t		ondestroy;
Bob Halley's avatar
Bob Halley committed
117
	isc_mutex_t		lock;
118
119
120
	isc_memalloc_t		memalloc;
	isc_memfree_t		memfree;
	void *			arg;
Bob Halley's avatar
base  
Bob Halley committed
121
	size_t			max_size;
122
	isc_boolean_t		checkfree;
Bob Halley's avatar
base  
Bob Halley committed
123
	struct stats *		stats;
124
	unsigned int		references;
125
	size_t			quota;
Bob Halley's avatar
Bob Halley committed
126
	size_t			total;
127
	size_t			inuse;
128
	size_t			maxinuse;
129
130
131
132
133
	size_t			hi_water;
	size_t			lo_water;
	isc_boolean_t		hi_called;
	isc_mem_water_t		water;
	void *			water_arg;
Michael Graff's avatar
Michael Graff committed
134
	ISC_LIST(isc_mempool_t)	pools;
135
136
137
138
139
140
141
142
143
144
145
146

#if ISC_MEM_USE_INTERNAL_MALLOC
	size_t			mem_target;
	element **		freelists;
	element *		basic_blocks;
	unsigned char **	basic_table;
	unsigned int		basic_table_count;
	unsigned int		basic_table_size;
	unsigned char *		lowest;
	unsigned char *		highest;
#endif /* ISC_MEM_USE_INTERNAL_MALLOC */

147
#if ISC_MEM_TRACKLINES
148
	debuglist_t *	 	debuglist;
Michael Graff's avatar
Michael Graff committed
149
#endif
150
151

	unsigned int		memalloc_failures;
Michael Graff's avatar
Michael Graff committed
152
153
};

154
155
#define MEMPOOL_MAGIC		ISC_MAGIC('M', 'E', 'M', 'p')
#define VALID_MEMPOOL(c)	ISC_MAGIC_VALID(c, MEMPOOL_MAGIC)
Michael Graff's avatar
Michael Graff committed
156
157

struct isc_mempool {
Michael Graff's avatar
Michael Graff committed
158
	/* always unlocked */
Michael Graff's avatar
Michael Graff committed
159
	unsigned int	magic;		/* magic number */
Michael Graff's avatar
Michael Graff committed
160
	isc_mutex_t    *lock;		/* optional lock */
Michael Graff's avatar
Michael Graff committed
161
	isc_mem_t      *mctx;		/* our memory context */
Michael Graff's avatar
Michael Graff committed
162
163
164
	/* locked via the memory context's lock */
	ISC_LINK(isc_mempool_t)	link;	/* next pool in this mem context */
	/* optionally locked from here down */
Michael Graff's avatar
Michael Graff committed
165
166
167
168
169
170
171
172
173
	element	       *items;		/* low water item list */
	size_t		size;		/* size of each item on this pool */
	unsigned int	maxalloc;	/* max number of items allowed */
	unsigned int	allocated;	/* # of items currently given out */
	unsigned int	freecount;	/* # of items on reserved list */
	unsigned int	freemax;	/* # of items allowed on free list */
	unsigned int	fillcount;	/* # of items to fetch on each fill */
	/* Stats only. */
	unsigned int	gets;		/* # of requests to this pool */
Michael Graff's avatar
Michael Graff committed
174
	/* Debugging only. */
175
#if ISC_MEMPOOL_NAMES
Michael Graff's avatar
Michael Graff committed
176
177
	char		name[16];	/* printed name in stats reports */
#endif
Bob Halley's avatar
base  
Bob Halley committed
178
179
};

180
181
182
/*
 * Private Inline-able.
 */
Bob Halley's avatar
base  
Bob Halley committed
183

184
#if ! ISC_MEM_TRACKLINES
Michael Graff's avatar
Michael Graff committed
185
186
187
#define ADD_TRACE(a, b, c, d, e)
#define DELETE_TRACE(a, b, c, d, e)
#else
188
#define ADD_TRACE(a, b, c, d, e) \
189
190
191
192
193
194
	do { \
		if ((isc_mem_debugging & (ISC_MEM_DEBUGTRACE | \
					  ISC_MEM_DEBUGRECORD)) != 0 && \
		     b != NULL) \
		         add_trace_entry(a, b, c, d, e); \
	} while (0)
Michael Graff's avatar
Michael Graff committed
195
196
#define DELETE_TRACE(a, b, c, d, e)	delete_trace_entry(a, b, c, d, e)

197
198
199
static void
print_active(isc_mem_t *ctx, FILE *out);

Michael Graff's avatar
Michael Graff committed
200
201
202
203
204
/*
 * mctx must be locked.
 */
static inline void
add_trace_entry(isc_mem_t *mctx, const void *ptr, unsigned int size
Michael Graff's avatar
pasto    
Michael Graff committed
205
		FLARG)
Michael Graff's avatar
Michael Graff committed
206
207
208
209
{
	debuglink_t *dl;
	unsigned int i;

210
	if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
211
212
213
214
		fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
					       ISC_MSG_ADDTRACE,
					       "add %p size %u "
					       "file %s line %u mctx %p\n"),
215
			ptr, size, file, line, mctx);
Michael Graff's avatar
Michael Graff committed
216

217
	if (mctx->debuglist == NULL)
Michael Graff's avatar
Michael Graff committed
218
219
		return;

220
221
222
223
	if (size > mctx->max_size)
		size = mctx->max_size;

	dl = ISC_LIST_HEAD(mctx->debuglist[size]);
Michael Graff's avatar
Michael Graff committed
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
	while (dl != NULL) {
		if (dl->count == DEBUGLIST_COUNT)
			goto next;
		for (i = 0 ; i < DEBUGLIST_COUNT ; i++) {
			if (dl->ptr[i] == NULL) {
				dl->ptr[i] = ptr;
				dl->file[i] = file;
				dl->line[i] = line;
				dl->count++;
				return;
			}
		}
	next:
		dl = ISC_LIST_NEXT(dl, link);
	}

	dl = malloc(sizeof(debuglink_t));
	INSIST(dl != NULL);

	ISC_LINK_INIT(dl, link);
	for (i = 1 ; i < DEBUGLIST_COUNT ; i++) {
		dl->ptr[i] = NULL;
		dl->file[i] = NULL;
		dl->line[i] = 0;
	}

	dl->ptr[0] = ptr;
	dl->file[0] = file;
	dl->line[0] = line;
	dl->count = 1;

255
	ISC_LIST_PREPEND(mctx->debuglist[size], dl, link);
Michael Graff's avatar
Michael Graff committed
256
257
258
259
260
261
262
263
264
}

static inline void
delete_trace_entry(isc_mem_t *mctx, const void *ptr, unsigned int size,
		   const char *file, unsigned int line)
{
	debuglink_t *dl;
	unsigned int i;

265
	if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
266
267
268
269
		fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
					       ISC_MSG_DELTRACE,
					       "del %p size %u "
					       "file %s line %u mctx %p\n"),
270
			ptr, size, file, line, mctx);
Michael Graff's avatar
Michael Graff committed
271

272
	if (mctx->debuglist == NULL)
Michael Graff's avatar
Michael Graff committed
273
274
		return;

275
276
277
278
	if (size > mctx->max_size)
		size = mctx->max_size;

	dl = ISC_LIST_HEAD(mctx->debuglist[size]);
Michael Graff's avatar
Michael Graff committed
279
280
281
282
283
284
285
286
287
288
	while (dl != NULL) {
		for (i = 0 ; i < DEBUGLIST_COUNT ; i++) {
			if (dl->ptr[i] == ptr) {
				dl->ptr[i] = NULL;
				dl->file[i] = NULL;
				dl->line[i] = 0;

				INSIST(dl->count > 0);
				dl->count--;
				if (dl->count == 0) {
289
					ISC_LIST_UNLINK(mctx->debuglist[size],
Michael Graff's avatar
Michael Graff committed
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
							dl, link);
					free(dl);
				}
				return;
			}
		}
		dl = ISC_LIST_NEXT(dl, link);
	}

	/*
	 * If we get here, we didn't find the item on the list.  We're
	 * screwed.
	 */
	INSIST(dl != NULL);
}
#endif /* ISC_MEM_TRACKLINES */

307
#if ISC_MEM_USE_INTERNAL_MALLOC
308
309
310
311
312
static inline size_t
rmsize(size_t size) {
	/*
 	 * round down to ALIGNMENT_SIZE
	 */
313
	return (size & (~(ALIGNMENT_SIZE - 1)));
314
315
}

316
static inline size_t
Bob Halley's avatar
base  
Bob Halley committed
317
318
quantize(size_t size) {
	/*
319
	 * Round up the result in order to get a size big
Bob Halley's avatar
base  
Bob Halley committed
320
321
322
	 * enough to satisfy the request and be aligned on ALIGNMENT_SIZE
	 * byte boundaries.
	 */
323

324
325
	if (size == 0)
		return (ALIGNMENT_SIZE);
326
	return ((size + ALIGNMENT_SIZE - 1) & (~(ALIGNMENT_SIZE - 1)));
Bob Halley's avatar
base  
Bob Halley committed
327
328
}

329
static inline isc_boolean_t
330
more_basic_blocks(isc_mem_t *ctx) {
331
332
333
334
335
	void *new;
	unsigned char *curr, *next;
	unsigned char *first, *last;
	unsigned char **table;
	unsigned int table_size;
Bob Halley's avatar
Bob Halley committed
336
	size_t increment;
337
338
339
340
	int i;

	/* Require: we hold the context lock. */

341
342
343
	/*
	 * Did we hit the quota for this context?
	 */
Bob Halley's avatar
Bob Halley committed
344
345
	increment = NUM_BASIC_BLOCKS * ctx->mem_target;
	if (ctx->quota != 0 && ctx->total + increment > ctx->quota)
346
		return (ISC_FALSE);
347
348
349

	INSIST(ctx->basic_table_count <= ctx->basic_table_size);
	if (ctx->basic_table_count == ctx->basic_table_size) {
350
		table_size = ctx->basic_table_size + TABLE_INCREMENT;
351
352
		table = (ctx->memalloc)(ctx->arg,
					table_size * sizeof (unsigned char *));
353
354
		if (table == NULL) {
			ctx->memalloc_failures++;
355
			return (ISC_FALSE);
356
		}
357
358
359
360
		if (ctx->basic_table_size != 0) {
			memcpy(table, ctx->basic_table,
			       ctx->basic_table_size *
			       sizeof (unsigned char *));
361
			(ctx->memfree)(ctx->arg, ctx->basic_table);
362
		}
363
364
		ctx->basic_table = table;
		ctx->basic_table_size = table_size;
365
	}
366

367
	new = (ctx->memalloc)(ctx->arg, NUM_BASIC_BLOCKS * ctx->mem_target);
368
369
	if (new == NULL) {
		ctx->memalloc_failures++;
370
		return (ISC_FALSE);
371
	}
Bob Halley's avatar
Bob Halley committed
372
	ctx->total += increment;
373
374
	ctx->basic_table[ctx->basic_table_count] = new;
	ctx->basic_table_count++;
375

376
377
378
	curr = new;
	next = curr + ctx->mem_target;
	for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) {
379
		((element *)curr)->next = (element *)next;
380
381
382
383
384
385
386
		curr = next;
		next += ctx->mem_target;
	}
	/*
	 * curr is now pointing at the last block in the
	 * array.
	 */
Bob Halley's avatar
Bob Halley committed
387
	((element *)curr)->next = NULL;
388
389
390
391
392
393
394
	first = new;
	last = first + NUM_BASIC_BLOCKS * ctx->mem_target - 1;
	if (first < ctx->lowest || ctx->lowest == NULL)
		ctx->lowest = first;
	if (last > ctx->highest)
		ctx->highest = last;
	ctx->basic_blocks = new;
395
396

	return (ISC_TRUE);
397
398
}

399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
static inline isc_boolean_t
more_frags(isc_mem_t *ctx, size_t new_size) {
	int i, frags;
	size_t total_size;
	void *new;
	unsigned char *curr, *next;

	/*
	 * Try to get more fragments by chopping up a basic block.
	 */

	if (ctx->basic_blocks == NULL) {
		if (!more_basic_blocks(ctx)) {
			/*
			 * We can't get more memory from the OS, or we've
			 * hit the quota for this context.
			 */
			/*
417
			 * XXXRTH  "At quota" notification here.
418
			 */
419
			return (ISC_FALSE);
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
		}
	}

	total_size = ctx->mem_target;
	new = ctx->basic_blocks;
	ctx->basic_blocks = ctx->basic_blocks->next;
	frags = total_size / new_size;
	ctx->stats[new_size].blocks++;
	ctx->stats[new_size].freefrags += frags;
	/*
	 * Set up a linked-list of blocks of size
	 * "new_size".
	 */
	curr = new;
	next = curr + new_size;
435
	total_size -= new_size;
436
437
438
439
	for (i = 0; i < (frags - 1); i++) {
		((element *)curr)->next = (element *)next;
		curr = next;
		next += new_size;
440
441
442
443
444
445
446
447
448
449
		total_size -= new_size;
	}
	/*
	 * Add the remaining fragment of the basic block to a free list.
	 */
	total_size = rmsize(total_size);
	if (total_size > 0) {
		((element *)next)->next = ctx->freelists[total_size];
		ctx->freelists[total_size] = (element *)next;
		ctx->stats[total_size].freefrags++;
450
451
452
453
454
455
456
457
458
459
460
	}
	/*
	 * curr is now pointing at the last block in the
	 * array.
	 */
	((element *)curr)->next = NULL;
	ctx->freelists[new_size] = new;

	return (ISC_TRUE);
}

Michael Graff's avatar
Michael Graff committed
461
static inline void *
462
mem_getunlocked(isc_mem_t *ctx, size_t size) {
Michael Graff's avatar
Michael Graff committed
463
464
	size_t new_size = quantize(size);
	void *ret;
Bob Halley's avatar
base  
Bob Halley committed
465
466

	if (size >= ctx->max_size || new_size >= ctx->max_size) {
467
468
469
		/*
		 * memget() was called on something beyond our upper limit.
		 */
Bob Halley's avatar
Bob Halley committed
470
471
472
473
		if (ctx->quota != 0 && ctx->total + size > ctx->quota) {
			ret = NULL;
			goto done;
		}
Mark Andrews's avatar
Mark Andrews committed
474
		ret = (ctx->memalloc)(ctx->arg, size);
475
476
477
		if (ret == NULL) {
			ctx->memalloc_failures++;
			goto done;
Bob Halley's avatar
base  
Bob Halley committed
478
		}
479
480
481
482
483
484
485
486
487
488
		ctx->total += size;
		ctx->inuse += size;
		ctx->stats[ctx->max_size].gets++;
		ctx->stats[ctx->max_size].totalgets++;
		/*
		 * If we don't set new_size to size, then the
		 * ISC_MEM_FILL code might write over bytes we
		 * don't own.
		 */
		new_size = size;
489
		goto done;
Bob Halley's avatar
base  
Bob Halley committed
490
491
	}

492
	/*
Bob Halley's avatar
base  
Bob Halley committed
493
494
495
496
	 * If there are no blocks in the free list for this size, get a chunk
	 * of memory and then break it up into "new_size"-sized blocks, adding
	 * them to the free list.
	 */
497
498
	if (ctx->freelists[new_size] == NULL && !more_frags(ctx, new_size))
		return (NULL);
Bob Halley's avatar
base  
Bob Halley committed
499

500
501
502
	/*
	 * The free list uses the "rounded-up" size "new_size".
	 */
Bob Halley's avatar
base  
Bob Halley committed
503
504
505
	ret = ctx->freelists[new_size];
	ctx->freelists[new_size] = ctx->freelists[new_size]->next;

506
	/*
Bob Halley's avatar
base  
Bob Halley committed
507
508
509
510
511
512
513
514
	 * The stats[] uses the _actual_ "size" requested by the
	 * caller, with the caveat (in the code above) that "size" >= the
	 * max. size (max_size) ends up getting recorded as a call to
	 * max_size.
	 */
	ctx->stats[size].gets++;
	ctx->stats[size].totalgets++;
	ctx->stats[new_size].freefrags--;
515
	ctx->inuse += new_size;
Bob Halley's avatar
base  
Bob Halley committed
516
517
518

 done:

519
#if ISC_MEM_FILL
520
521
	if (ret != NULL)
		memset(ret, 0xbe, new_size); /* Mnemonic for "beef". */
David Lawrence's avatar
David Lawrence committed
522
523
524
#endif

	return (ret);
Michael Graff's avatar
Michael Graff committed
525
526
}

527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
#if ISC_MEM_FILL && ISC_MEM_CHECKOVERRUN
static inline void
check_overrun(void *mem, size_t size, size_t new_size) {
	unsigned char *cp;

	cp = (unsigned char *)mem;
	cp += size;
	while (size < new_size) {
		INSIST(*cp == 0xbe);
		cp++;
		size++;
	}
}
#endif

Michael Graff's avatar
Michael Graff committed
542
static inline void
543
mem_putunlocked(isc_mem_t *ctx, void *mem, size_t size) {
Michael Graff's avatar
Michael Graff committed
544
	size_t new_size = quantize(size);
Bob Halley's avatar
base  
Bob Halley committed
545

546
	if (size == ctx->max_size || new_size >= ctx->max_size) {
547
548
549
		/*
		 * memput() called on something beyond our upper limit.
		 */
550
#if ISC_MEM_FILL
Mark Andrews's avatar
Mark Andrews committed
551
552
		memset(mem, 0xde, size); /* Mnemonic for "dead". */
#endif
553
		(ctx->memfree)(ctx->arg, mem);
Bob Halley's avatar
base  
Bob Halley committed
554
555
		INSIST(ctx->stats[ctx->max_size].gets != 0);
		ctx->stats[ctx->max_size].gets--;
Bob Halley's avatar
Bob Halley committed
556
		INSIST(size <= ctx->total);
557
		ctx->inuse -= size;
Bob Halley's avatar
Bob Halley committed
558
		ctx->total -= size;
Michael Graff's avatar
Michael Graff committed
559
		return;
Bob Halley's avatar
base  
Bob Halley committed
560
561
	}

562
563
#if ISC_MEM_FILL
#if ISC_MEM_CHECKOVERRUN
564
565
	check_overrun(mem, size, new_size);
#endif
Mark Andrews's avatar
Mark Andrews committed
566
567
	memset(mem, 0xde, new_size); /* Mnemonic for "dead". */
#endif
568

569
570
571
	/*
	 * The free list uses the "rounded-up" size "new_size".
	 */
Mark Andrews's avatar
Mark Andrews committed
572
573
	((element *)mem)->next = ctx->freelists[new_size];
	ctx->freelists[new_size] = (element *)mem;
Bob Halley's avatar
base  
Bob Halley committed
574

575
	/*
Bob Halley's avatar
base  
Bob Halley committed
576
577
578
579
580
581
582
583
	 * The stats[] uses the _actual_ "size" requested by the
	 * caller, with the caveat (in the code above) that "size" >= the
	 * max. size (max_size) ends up getting recorded as a call to
	 * max_size.
	 */
	INSIST(ctx->stats[size].gets != 0);
	ctx->stats[size].gets--;
	ctx->stats[new_size].freefrags++;
584
	ctx->inuse -= new_size;
Bob Halley's avatar
base  
Bob Halley committed
585
586
}

587
588
589
590
591
592
593
594
595
596
597
598
599
600
#else /* ISC_MEM_USE_INTERNAL_MALLOC */

/*
 * Perform a malloc, doing memory filling and overrun detection as necessary.
 */
static inline void *
mem_get(isc_mem_t *ctx, size_t size) {
	char *ret;

#if ISC_MEM_CHECKOVERRUN
	size += 1;
#endif

	ret = (ctx->memalloc)(ctx->arg, size);
601
602
	if (ret == NULL)
		ctx->memalloc_failures++;	
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622

#if ISC_MEM_FILL
	if (ret != NULL)
		memset(ret, 0xbe, size); /* Mnemonic for "beef". */
#else
#  if ISC_MEM_CHECKOVERRUN
	if (ret != NULL)
		ret[size-1] = 0xbe;
#  endif
#endif

	return (ret);
}

/*
 * Perform a free, doing memory filling and overrun detection as necessary.
 */
static inline void
mem_put(isc_mem_t *ctx, void *mem, size_t size) {
#if ISC_MEM_CHECKOVERRUN
623
	INSIST(((unsigned char *)mem)[size] == 0xbe);
624
625
626
#endif
#if ISC_MEM_FILL
	memset(mem, 0xde, size); /* Mnemonic for "dead". */
Andreas Gustafsson's avatar
Andreas Gustafsson committed
627
628
#else
	UNUSED(size);
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
#endif
	(ctx->memfree)(ctx->arg, mem);
}

/*
 * Update internal counters after a memory get.
 */
static inline void
mem_getstats(isc_mem_t *ctx, size_t size) {
	ctx->total += size;
	ctx->inuse += size;

	if (size > ctx->max_size) {
		ctx->stats[ctx->max_size].gets++;
		ctx->stats[ctx->max_size].totalgets++;
	} else {
		ctx->stats[size].gets++;
		ctx->stats[size].totalgets++;
	}
}

/*
 * Update internal counters after a memory put.
 */
static inline void
mem_putstats(isc_mem_t *ctx, void *ptr, size_t size) {
	UNUSED(ptr);

	INSIST(ctx->inuse >= size);
	ctx->inuse -= size;

	if (size > ctx->max_size) {
		INSIST(ctx->stats[ctx->max_size].gets > 0);
		ctx->stats[ctx->max_size].gets--;
	} else {
		INSIST(ctx->stats[size].gets > 0);
		ctx->stats[size].gets--;
	}
}

#endif /* ISC_MEM_USE_INTERNAL_MALLOC */

David Lawrence's avatar
David Lawrence committed
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
/*
 * Private.
 */

static void *
default_memalloc(void *arg, size_t size) {
	UNUSED(arg);
	return (malloc(size));
}

static void
default_memfree(void *arg, void *ptr) {
	UNUSED(arg);
	free(ptr);
}

/*
 * Public.
 */

isc_result_t
isc_mem_createx(size_t init_max_size, size_t target_size,
		isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
		isc_mem_t **ctxp)
{
	isc_mem_t *ctx;
697
	isc_result_t result;
David Lawrence's avatar
David Lawrence committed
698
699
700
701
702

	REQUIRE(ctxp != NULL && *ctxp == NULL);
	REQUIRE(memalloc != NULL);
	REQUIRE(memfree != NULL);

703
704
	INSIST((ALIGNMENT_SIZE & (ALIGNMENT_SIZE - 1)) == 0);

705
706
707
708
#if !ISC_MEM_USE_INTERNAL_MALLOC
	UNUSED(target_size);
#endif

David Lawrence's avatar
David Lawrence committed
709
710
711
712
713
714
715
716
	ctx = (memalloc)(arg, sizeof *ctx);
	if (ctx == NULL)
		return (ISC_R_NOMEMORY);

	if (init_max_size == 0)
		ctx->max_size = DEF_MAX_SIZE;
	else
		ctx->max_size = init_max_size;
717
718
719
720
	ctx->references = 1;
	ctx->quota = 0;
	ctx->total = 0;
	ctx->inuse = 0;
721
	ctx->maxinuse = 0;
722
723
724
725
726
727
728
729
730
731
732
	ctx->hi_water = 0;
	ctx->lo_water = 0;
	ctx->hi_called = ISC_FALSE;
	ctx->water = NULL;
	ctx->water_arg = NULL;
	ctx->magic = MEM_MAGIC;
	isc_ondestroy_init(&ctx->ondestroy);
	ctx->memalloc = memalloc;
	ctx->memfree = memfree;
	ctx->arg = arg;
	ctx->stats = NULL;
733
	ctx->checkfree = ISC_TRUE;
734
#if ISC_MEM_TRACKLINES
735
	ctx->debuglist = NULL;
736
#endif
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
	ISC_LIST_INIT(ctx->pools);

#if ISC_MEM_USE_INTERNAL_MALLOC
	ctx->freelists = NULL;
#endif /* ISC_MEM_USE_INTERNAL_MALLOC */

	ctx->stats = (memalloc)(arg,
				(ctx->max_size+1) * sizeof (struct stats));
	if (ctx->stats == NULL) {
		result = ISC_R_NOMEMORY;
		goto error;
	}
	memset(ctx->stats, 0, (ctx->max_size + 1) * sizeof (struct stats));

#if ISC_MEM_USE_INTERNAL_MALLOC
David Lawrence's avatar
David Lawrence committed
752
753
754
755
756
757
	if (target_size == 0)
		ctx->mem_target = DEF_MEM_TARGET;
	else
		ctx->mem_target = target_size;
	ctx->freelists = (memalloc)(arg, ctx->max_size * sizeof (element *));
	if (ctx->freelists == NULL) {
758
759
		result = ISC_R_NOMEMORY;
		goto error;
David Lawrence's avatar
David Lawrence committed
760
761
762
763
764
765
766
767
768
	}
	memset(ctx->freelists, 0,
	       ctx->max_size * sizeof (element *));
	ctx->basic_blocks = NULL;
	ctx->basic_table = NULL;
	ctx->basic_table_count = 0;
	ctx->basic_table_size = 0;
	ctx->lowest = NULL;
	ctx->highest = NULL;
769
770
#endif /* ISC_MEM_USE_INTERNAL_MALLOC */

David Lawrence's avatar
David Lawrence committed
771
772
	if (isc_mutex_init(&ctx->lock) != ISC_R_SUCCESS) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
773
774
775
				 "isc_mutex_init() %s",
				 isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
						ISC_MSG_FAILED, "failed"));
776
777
		result = ISC_R_UNEXPECTED;
		goto error;
David Lawrence's avatar
David Lawrence committed
778
	}
779

780
#if ISC_MEM_TRACKLINES
781
782
783
784
785
786
787
788
789
790
791
792
	if ((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0) {
		unsigned int i;

		ctx->debuglist = (memalloc)(arg,
				      (ctx->max_size+1) * sizeof (debuglist_t));
		if (ctx->debuglist == NULL) {
			result = ISC_R_NOMEMORY;
			goto error;
		}
		for (i = 0; i <= ctx->max_size; i++)
			ISC_LIST_INIT(ctx->debuglist[i]);
	}
Michael Graff's avatar
Michael Graff committed
793
#endif
David Lawrence's avatar
David Lawrence committed
794

795
796
	ctx->memalloc_failures = 0;

David Lawrence's avatar
David Lawrence committed
797
798
	*ctxp = ctx;
	return (ISC_R_SUCCESS);
799
800
801
802
803
804
805
806
807

  error:
	if (ctx) {
		if (ctx->stats)
			(memfree)(arg, ctx->stats);
#if ISC_MEM_USE_INTERNAL_MALLOC
		if (ctx->freelists)
			(memfree)(arg, ctx->freelists);
#endif /* ISC_MEM_USE_INTERNAL_MALLOC */
808
809
810
811
#if ISC_MEM_TRACKLINES
		if (ctx->debuglist)
			(ctx->memfree)(ctx->arg, ctx->debuglist);
#endif /* ISC_MEM_TRACKLINES */
812
813
814
815
		(memfree)(arg, ctx);
	}

	return (result);
David Lawrence's avatar
David Lawrence committed
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
}

isc_result_t
isc_mem_create(size_t init_max_size, size_t target_size,
	       isc_mem_t **ctxp)
{
	return (isc_mem_createx(init_max_size, target_size,
				default_memalloc, default_memfree, NULL,
				ctxp));
}

static void
destroy(isc_mem_t *ctx) {
	unsigned int i;
	isc_ondestroy_t ondest;

	ctx->magic = 0;

834
#if ISC_MEM_USE_INTERNAL_MALLOC
David Lawrence's avatar
David Lawrence committed
835
	INSIST(ISC_LIST_EMPTY(ctx->pools));
836
837
#endif /* ISC_MEM_USE_INTERNAL_MALLOC */

838
#if ISC_MEM_TRACKLINES
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
	if (ctx->debuglist != NULL) {
		if (ctx->checkfree) {
			for (i = 0; i <= ctx->max_size; i++) {
				if (!ISC_LIST_EMPTY(ctx->debuglist[i]))
					print_active(ctx, stderr);
				INSIST(ISC_LIST_EMPTY(ctx->debuglist[i]));
			}
		} else {
			debuglink_t *dl;

			for (i = 0; i <= ctx->max_size; i++)
				for (dl = ISC_LIST_HEAD(ctx->debuglist[i]);
				     dl != NULL;
				     dl = ISC_LIST_HEAD(ctx->debuglist[i])) {
					ISC_LIST_UNLINK(ctx->debuglist[i],
						 	dl, link);
					free(dl);
				}
857
		}
858
		(ctx->memfree)(ctx->arg, ctx->debuglist);
859
	}
Michael Graff's avatar
Michael Graff committed
860
#endif
David Lawrence's avatar
David Lawrence committed
861
862
863
	INSIST(ctx->references == 0);

	if (ctx->checkfree) {
864
865
866
867
868
		for (i = 0; i <= ctx->max_size; i++) {
#if ISC_MEM_TRACKLINES
			if (ctx->stats[i].gets != 0)
				print_active(ctx, stderr);
#endif
David Lawrence's avatar
David Lawrence committed
869
			INSIST(ctx->stats[i].gets == 0);
870
		}
David Lawrence's avatar
David Lawrence committed
871
872
	}

873
	(ctx->memfree)(ctx->arg, ctx->stats);
David Lawrence's avatar
David Lawrence committed
874

875
#if ISC_MEM_USE_INTERNAL_MALLOC
David Lawrence's avatar
David Lawrence committed
876
877
878
879
	for (i = 0; i < ctx->basic_table_count; i++)
		(ctx->memfree)(ctx->arg, ctx->basic_table[i]);
	(ctx->memfree)(ctx->arg, ctx->freelists);
	(ctx->memfree)(ctx->arg, ctx->basic_table);
880
#endif /* ISC_MEM_USE_INTERNAL_MALLOC */
David Lawrence's avatar
David Lawrence committed
881
882
883

	ondest = ctx->ondestroy;

884
	DESTROYLOCK(&ctx->lock);
David Lawrence's avatar
David Lawrence committed
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
	(ctx->memfree)(ctx->arg, ctx);

	isc_ondestroy_notify(&ondest, ctx);
}

void
isc_mem_attach(isc_mem_t *source, isc_mem_t **targetp) {
	REQUIRE(VALID_CONTEXT(source));
	REQUIRE(targetp != NULL && *targetp == NULL);

	LOCK(&source->lock);
	source->references++;
	UNLOCK(&source->lock);

	*targetp = source;
}

void
isc_mem_detach(isc_mem_t **ctxp) {
	isc_mem_t *ctx;
	isc_boolean_t want_destroy = ISC_FALSE;

	REQUIRE(ctxp != NULL);
	ctx = *ctxp;
	REQUIRE(VALID_CONTEXT(ctx));

	LOCK(&ctx->lock);
	INSIST(ctx->references > 0);
	ctx->references--;
	if (ctx->references == 0)
		want_destroy = ISC_TRUE;
	UNLOCK(&ctx->lock);

	if (want_destroy)
		destroy(ctx);

	*ctxp = NULL;
}

924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
/*
 * isc_mem_putanddetach() is the equivalent of:
 *
 * mctx = NULL;
 * isc_mem_attach(ptr->mctx, &mctx);
 * isc_mem_detach(&ptr->mctx);
 * isc_mem_put(mctx, ptr, sizeof(*ptr);
 * isc_mem_detach(&mctx);
 */

void
isc__mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) {
	isc_mem_t *ctx;
	isc_boolean_t want_destroy = ISC_FALSE;

	REQUIRE(ctxp != NULL);
	ctx = *ctxp;
	REQUIRE(VALID_CONTEXT(ctx));
	REQUIRE(ptr != NULL);

	/*
	 * Must be before mem_putunlocked() as ctxp is usually within
	 * [ptr..ptr+size).
	 */
	*ctxp = NULL;

950
#if ISC_MEM_USE_INTERNAL_MALLOC
951
952
	LOCK(&ctx->lock);
	mem_putunlocked(ctx, ptr, size);
953
954
955
956
957
958
959
#else /* ISC_MEM_USE_INTERNAL_MALLOC */
	mem_put(ctx, ptr, size);
	LOCK(&ctx->lock);
	mem_putstats(ctx, ptr, size);
#endif /* ISC_MEM_USE_INTERNAL_MALLOC */

	DELETE_TRACE(ctx, ptr, size, file, line);
960
961
962
963
	INSIST(ctx->references > 0);
	ctx->references--;
	if (ctx->references == 0)
		want_destroy = ISC_TRUE;
964

965
966
967
968
969
970
	UNLOCK(&ctx->lock);

	if (want_destroy)
		destroy(ctx);
}

David Lawrence's avatar
David Lawrence committed
971
972
973
974
975
976
977
978
979
980
981
982
983
984
void
isc_mem_destroy(isc_mem_t **ctxp) {
	isc_mem_t *ctx;

	/*
	 * This routine provides legacy support for callers who use mctxs
	 * without attaching/detaching.
	 */

	REQUIRE(ctxp != NULL);
	ctx = *ctxp;
	REQUIRE(VALID_CONTEXT(ctx));

	LOCK(&ctx->lock);
985
#if ISC_MEM_TRACKLINES
986
987
988
	if (ctx->references != 1)
		print_active(ctx, stderr);
#endif
David Lawrence's avatar
David Lawrence committed
989
990
991
992
	REQUIRE(ctx->references == 1);
	ctx->references--;
	UNLOCK(&ctx->lock);

Brian Wellington's avatar
Brian Wellington committed
993
	destroy(ctx);
David Lawrence's avatar
David Lawrence committed
994
995
996
997
998
999
1000

	*ctxp = NULL;
}

isc_result_t
isc_mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event) {
	isc_result_t res;
1001

David Lawrence's avatar
David Lawrence committed
1002
1003
1004
1005
1006
1007
1008
1009
	LOCK(&ctx->lock);
	res = isc_ondestroy_register(&ctx->ondestroy, task, event);
	UNLOCK(&ctx->lock);

	return (res);
}


Michael Graff's avatar
Michael Graff committed
1010
1011
1012
void *
isc__mem_get(isc_mem_t *ctx, size_t size FLARG) {
	void *ptr;
1013
	isc_boolean_t call_water = ISC_FALSE;
Michael Graff's avatar
Michael Graff committed
1014

David Lawrence's avatar
David Lawrence committed
1015
1016
	REQUIRE(VALID_CONTEXT(ctx));

1017
#if ISC_MEM_USE_INTERNAL_MALLOC
David Lawrence's avatar
David Lawrence committed
1018
	LOCK(&ctx->lock);
Michael Graff's avatar
Michael Graff committed
1019
	ptr = mem_getunlocked(ctx, size);
1020
1021
1022
#else /* ISC_MEM_USE_INTERNAL_MALLOC */
	ptr = mem_get(ctx, size);
	LOCK(&ctx->lock);
1023
1024
	if (ptr)
		mem_getstats(ctx, size);
1025
1026
#endif /* ISC_MEM_USE_INTERNAL_MALLOC */

Michael Graff's avatar
Michael Graff committed
1027
	ADD_TRACE(ctx, ptr, size, file, line);
1028
1029
1030
1031
1032
	if (ctx->hi_water != 0 && !ctx->hi_called &&
	    ctx->inuse > ctx->hi_water) {
		ctx->hi_called = ISC_TRUE;
		call_water = ISC_TRUE;
	}
1033
1034
1035
1036
1037
1038
	if (ctx->inuse > ctx->maxinuse) {
		ctx->maxinuse = ctx->inuse;
		if (ctx->hi_water != 0 && ctx->inuse > ctx->hi_water &&
		    (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
			fprintf(stderr, "maxinuse = %d\n", ctx->inuse);
	}
David Lawrence's avatar
David Lawrence committed
1039
	UNLOCK(&ctx->lock);
1040
1041
1042
1043
1044

	if (call_water) {
		(ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
	}

Bob Halley's avatar
base  
Bob Halley committed
1045
1046
1047
1048
	return (ptr);
}

void
Michael Graff's avatar
Michael Graff committed
1049
isc__mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG)
Bob Halley's avatar
base  
Bob Halley committed
1050
{
1051
1052
	isc_boolean_t call_water = ISC_FALSE;

Michael Graff's avatar
Michael Graff committed
1053
1054
1055
	REQUIRE(VALID_CONTEXT(ctx));
	REQUIRE(ptr != NULL);

1056
#if ISC_MEM_USE_INTERNAL_MALLOC
Michael Graff's avatar
Michael Graff committed
1057
1058
	LOCK(&ctx->lock);
	mem_putunlocked(ctx, ptr, size);
1059
1060
1061
1062
1063
1064
1065
#else /* ISC_MEM_USE_INTERNAL_MALLOC */
	mem_put(ctx, ptr, size);
	LOCK(&ctx->lock);
	mem_putstats(ctx, ptr, size);
#endif /* ISC_MEM_USE_INTERNAL_MALLOC */

	DELETE_TRACE(ctx, ptr, size, file, line);
1066
1067
1068
1069
1070
1071
1072
1073

	/*
	 * The check against ctx->lo_water == 0 is for the condition
	 * when the context was pushed over hi_water but then had
	 * isc_mem_setwater() called with 0 for hi_water and lo_water.
	 */
	if (ctx->hi_called && 
	    (ctx->inuse < ctx->lo_water || ctx->lo_water == 0)) {
1074
		ctx->hi_called = ISC_FALSE;
1075
1076
1077

		if (ctx->water != NULL)
			call_water = ISC_TRUE;
1078
	}
Michael Graff's avatar
Michael Graff committed
1079
	UNLOCK(&ctx->lock);
1080
1081
1082
1083

	if (call_water) {
		(ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
	}
Bob Halley's avatar
base  
Bob Halley committed
1084
1085
}

1086
#if ISC_MEM_TRACKLINES
1087
static void
1088
print_active(isc_mem_t *mctx, FILE *out) {
1089
	if (mctx->debuglist != NULL) {
1090
		debuglink_t *dl;
1091
1092
1093
		unsigned int i, j;
		const char *format;
		isc_boolean_t found;
1094
1095
1096

		fprintf(out, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
					    ISC_MSG_DUMPALLOC,
Andreas Gustafsson's avatar
Andreas Gustafsson committed
1097
1098
					    "Dump of all outstanding "
					    "memory allocations:\n"));
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
		found = ISC_FALSE;
		format = isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
				        ISC_MSG_PTRFILELINE,
					"\tptr %p file %s line %u\n");
		for (i = 0; i <= mctx->max_size; i++) {
			dl = ISC_LIST_HEAD(mctx->debuglist[i]);
			
			if (dl != NULL)
				found = ISC_TRUE;

			while (dl != NULL) {
				for (j = 0 ; j < DEBUGLIST_COUNT ; j++)
					if (dl->ptr[j] != NULL)
						fprintf(out, format,
							dl->ptr[j], dl->file[j],
							dl->line[j]);
				dl = ISC_LIST_NEXT(dl, link);
			}
1117
		}
1118
1119
1120
		if (!found)
			fprintf(out, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
						    ISC_MSG_NONE, "\tNone.\n"));
1121
1122
1123
1124
1125
1126
1127
	}
}
#endif

/*
 * Print the stats[] on the stream "out" with suitable formatting.
 */
Bob Halley's avatar
base  
Bob Halley committed
1128
void
1129
isc_mem_stats(isc_mem_t *ctx, FILE *out) {
Bob Halley's avatar
base  
Bob Halley committed
1130
	size_t i;
Michael Graff's avatar
Michael Graff committed
1131
1132
	const struct stats *s;
	const isc_mempool_t *pool;
Bob Halley's avatar
base  
Bob Halley committed
1133

Bob Halley's avatar
Bob Halley committed
1134
1135
	REQUIRE(VALID_CONTEXT(ctx));
	LOCK(&ctx->lock);
Bob Halley's avatar
base  
Bob Halley committed
1136

1137
1138
	for (i = 0; i <= ctx->max_size; i++) {
		s = &ctx->stats[i];
Michael Graff's avatar
Michael Graff committed
1139

1140
1141
1142
1143
1144
		if (s->totalgets == 0 && s->gets == 0)
			continue;
		fprintf(out, "%s%5lu: %11lu gets, %11lu rem",
			(i == ctx->max_size) ? ">=" : "  ",
			(unsigned long) i, s->totalgets, s->gets);
1145
#if ISC_MEM_USE_INTERNAL_MALLOC
1146
1147
1148
		if (s->blocks != 0 || s->freefrags != 0)
			fprintf(out, " (%lu bl, %lu ff)",
				s->blocks, s->freefrags);
1149
#endif /* ISC_MEM_USE_INTERNAL_MALLOC */
1150
		fputc('\n', out);
Michael Graff's avatar
Michael Graff committed
1151
1152
	}

Michael Graff's avatar
Michael Graff committed
1153
1154
1155
1156
1157
1158
1159
	/*
	 * Note that since a pool can be locked now, these stats might be
	 * somewhat off if the pool is in active use at the time the stats
	 * are dumped.  The link fields are protected by the isc_mem_t's
	 * lock, however, so walking this list and extracting integers from
	 * stats fields is always safe.
	 */
Michael Graff's avatar
Michael Graff committed
1160
1161
	pool = ISC_LIST_HEAD(ctx->pools);
	if (pool != NULL) {
1162
1163
1164
		fprintf(out, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
					    ISC_MSG_POOLSTATS,
					    "[Pool statistics]\n"));
Michael Graff's avatar
Michael Graff committed
1165
		fprintf(out, "%15s %10s %10s %10s %10s %10s %10s %10s %1s\n",
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
			isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
				       ISC_MSG_POOLNAME, "name"),
			isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
				       ISC_MSG_POOLSIZE, "size"),
			isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
				       ISC_MSG_POOLMAXALLOC, "maxalloc"),
			isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
				       ISC_MSG_POOLALLOCATED, "allocated"),
			isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
				       ISC_MSG_POOLFREECOUNT, "freecount"),
			isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
				       ISC_MSG_POOLFREEMAX, "freemax"),
			isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
				       ISC_MSG_POOLFILLCOUNT, "fillcount"),
			isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
				       ISC_MSG_POOLGETS, "gets"),
			"L");
Michael Graff's avatar
Michael Graff committed
1183
1184
	}
	while (pool != NULL) {
1185
1186
		fprintf(out, "%15s %10lu %10u %10u %10u %10u %10u %10u %s\n",
			pool->name, (unsigned long) pool->size, pool->maxalloc,
Michael Graff's avatar
Michael Graff committed
1187
1188
			pool->allocated, pool->freecount, pool->freemax,
			pool->fillcount, pool->gets,
Michael Graff's avatar
Michael Graff committed
1189
			(pool->lock == NULL ? "N" : "Y"));
Michael Graff's avatar
Michael Graff committed
1190
		pool = ISC_LIST_NEXT(pool, link);
Bob Halley's avatar
base  
Bob Halley committed
1191
1192
	}

1193
#if ISC_MEM_TRACKLINES
1194
	print_active(ctx, out);
Michael Graff's avatar
Michael Graff committed
1195
1196
#endif

Bob Halley's avatar
Bob Halley committed
1197
	UNLOCK(&ctx->lock);
Bob Halley's avatar
base  
Bob Halley committed
1198
1199
1200
}

/*
1201
1202
 * Replacements for malloc() and free() -- they implicitly remember the
 * size of the object allocated (with some additional overhead).
Bob Halley's avatar
base  
Bob Halley committed
1203
1204
 */

Michael Graff's avatar
Michael Graff committed
1205
1206
static void *
isc__mem_allocateunlocked(isc_mem_t *ctx, size_t size) {
Bob Halley's avatar
Bob Halley committed
1207
	size_info *si;
Bob Halley's avatar
base  
Bob Halley committed
1208
1209

	size += ALIGNMENT_SIZE;
1210
#if ISC_MEM_USE_INTERNAL_MALLOC
Michael Graff's avatar
Michael Graff committed
1211
	si = mem_getunlocked(ctx, size);
1212
1213
1214
#else /* ISC_MEM_USE_INTERNAL_MALLOC */
	si = mem_get(ctx, size);
#endif /* ISC_MEM_USE_INTERNAL_MALLOC */
Bob Halley's avatar
base  
Bob Halley committed
1215
1216
	if (si == NULL)
		return (NULL);
1217
	si->u.size = size;
Bob Halley's avatar
base  
Bob Halley committed
1218
1219
1220
	return (&si[1]);
}

1221
void *
Michael Graff's avatar
Michael Graff committed
1222
isc__mem_allocate(isc_mem_t *ctx, size_t size FLARG) {
1223
1224
	size_info *si;

Michael Graff's avatar
Michael Graff committed
1225
	REQUIRE(VALID_CONTEXT(ctx));
1226

1227
#if ISC_MEM_USE_INTERNAL_MALLOC
Michael Graff's avatar
Michael Graff committed
1228
1229
	LOCK(&ctx->lock);
	si = isc__mem_allocateunlocked(ctx, size);
1230
1231
1232
#else /* ISC_MEM_USE_INTERNAL_MALLOC */
	si = isc__mem_allocateunlocked(ctx, size);
	LOCK(&ctx->lock);
1233
1234
	if (si != NULL)
		mem_getstats(ctx, si[-1].u.size);
1235
1236
#endif /* ISC_MEM_USE_INTERNAL_MALLOC */

1237
#if ISC_MEM_TRACKLINES
1238
	ADD_TRACE(ctx, si, si[-1].u.size, file, line);
Michael Graff's avatar
Michael Graff committed
1239
#endif
1240

Michael Graff's avatar
Michael Graff committed
1241
	UNLOCK(&ctx->lock);
1242

Michael Graff's avatar
Michael Graff committed
1243
	return (si);
1244
1245
}

Bob Halley's avatar
base  
Bob Halley committed
1246
void
Michael Graff's avatar
Michael Graff committed
1247
isc__mem_free(isc_mem_t *ctx, void *ptr FLARG) {
Bob Halley's avatar
Bob Halley committed
1248
	size_info *si;
1249
	size_t size;
Bob Halley's avatar
base  
Bob Halley committed
1250

Michael Graff's avatar
Michael Graff committed
1251
1252
1253
	REQUIRE(VALID_CONTEXT(ctx));
	REQUIRE(ptr != NULL);

Bob Halley's avatar
Bob Halley committed
1254
	si = &(((size_info *)ptr)[-1]);
1255
1256
1257
1258
1259
1260
1261
	size = si->u.size;

#if ISC_MEM_USE_INTERNAL_MALLOC
	LOCK(&ctx->lock);
	mem_putunlocked(ctx, si, size);
#else /* ISC_MEM_USE_INTERNAL_MALLOC */
	mem_put(ctx, si, size);
Michael Graff's avatar
Michael Graff committed
1262
	LOCK(&ctx->lock);