mem.c 69 KB
Newer Older
Bob Halley's avatar
base  
Bob Halley committed
1
/*
Tinderbox User's avatar
Tinderbox User committed
2
 * Copyright (C) 2004-2010, 2012, 2013  Internet Systems Consortium, Inc. ("ISC")
Mark Andrews's avatar
Mark Andrews committed
3
 * Copyright (C) 1997-2003  Internet Software Consortium.
4
 *
Automatic Updater's avatar
Automatic Updater committed
5
 * Permission to use, copy, modify, and/or distribute this software for any
Bob Halley's avatar
base  
Bob Halley committed
6 7
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
8
 *
Mark Andrews's avatar
Mark Andrews committed
9 10 11 12 13 14 15
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS.  IN NO EVENT SHALL ISC 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
 */

Mark Andrews's avatar
Mark Andrews committed
18
/* $Id$ */
19 20

/*! \file */
David Lawrence's avatar
David Lawrence committed
21

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

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

Michael Graff's avatar
Michael Graff committed
28 29
#include <limits.h>

30
#include <isc/bind9.h>
31
#include <isc/json.h>
32
#include <isc/magic.h>
Bob Halley's avatar
Bob Halley committed
33
#include <isc/mem.h>
34
#include <isc/msgs.h>
35
#include <isc/once.h>
36
#include <isc/ondestroy.h>
37
#include <isc/string.h>
Bob Halley's avatar
update  
Bob Halley committed
38
#include <isc/mutex.h>
39
#include <isc/print.h>
Michael Graff's avatar
Michael Graff committed
40
#include <isc/util.h>
41
#include <isc/xml.h>
Bob Halley's avatar
update  
Bob Halley committed
42

43 44 45
#define MCTXLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) LOCK(l)
#define MCTXUNLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) UNLOCK(l)

46 47 48
#ifndef ISC_MEM_DEBUGGING
#define ISC_MEM_DEBUGGING 0
#endif
49
LIBISC_EXTERNAL_DATA unsigned int isc_mem_debugging = ISC_MEM_DEBUGGING;
50 51 52 53 54 55 56

/*
 * Constants.
 */

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

Bob Halley's avatar
base  
Bob Halley committed
62 63 64
/*
 * Types.
 */
65 66 67
typedef struct isc__mem isc__mem_t;
typedef struct isc__mempool isc__mempool_t;

68
#if ISC_MEM_TRACKLINES
Michael Graff's avatar
Michael Graff committed
69 70 71 72
typedef struct debuglink debuglink_t;
struct debuglink {
	ISC_LINK(debuglink_t)	link;
	const void	       *ptr[DEBUGLIST_COUNT];
73
	unsigned int		size[DEBUGLIST_COUNT];
Michael Graff's avatar
Michael Graff committed
74 75 76 77
	const char	       *file[DEBUGLIST_COUNT];
	unsigned int		line[DEBUGLIST_COUNT];
	unsigned int		count;
};
Bob Halley's avatar
base  
Bob Halley committed
78

Michael Graff's avatar
Michael Graff committed
79
#define FLARG_PASS	, file, line
80
#define FLARG		, const char *file, unsigned int line
Michael Graff's avatar
Michael Graff committed
81 82 83 84
#else
#define FLARG_PASS
#define FLARG
#endif
85

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

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

struct stats {
Bob Halley's avatar
Bob Halley committed
103 104 105 106
	unsigned long		gets;
	unsigned long		totalgets;
	unsigned long		blocks;
	unsigned long		freefrags;
Bob Halley's avatar
base  
Bob Halley committed
107 108
};

109 110
#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
111

112
#if ISC_MEM_TRACKLINES
113
typedef ISC_LIST(debuglink_t)	debuglist_t;
114
#endif
115

116 117
/* List of all active memory contexts. */

118
static ISC_LIST(isc__mem_t)	contexts;
119

120
static isc_once_t		once = ISC_ONCE_INIT;
121
static isc_mutex_t		lock;
122
static isc_mutex_t 		createlock;
123

124 125 126 127 128 129
/*%
 * Total size of lost memory due to a bug of external library.
 * Locked by the global lock.
 */
static isc_uint64_t		totallost;

130 131
struct isc__mem {
	isc_mem_t		common;
132
	isc_ondestroy_t		ondestroy;
133
	unsigned int		flags;
134
	isc_mutex_t		lock;
135 136 137
	isc_memalloc_t		memalloc;
	isc_memfree_t		memfree;
	void *			arg;
Bob Halley's avatar
base  
Bob Halley committed
138
	size_t			max_size;
139
	isc_boolean_t		checkfree;
Bob Halley's avatar
base  
Bob Halley committed
140
	struct stats *		stats;
141
	unsigned int		references;
142 143
	char			name[16];
	void *			tag;
144
	size_t			quota;
Bob Halley's avatar
Bob Halley committed
145
	size_t			total;
146
	size_t			inuse;
147
	size_t			maxinuse;
148 149 150
	size_t			hi_water;
	size_t			lo_water;
	isc_boolean_t		hi_called;
151
	isc_boolean_t		is_overmem;
152 153
	isc_mem_water_t		water;
	void *			water_arg;
154
	ISC_LIST(isc__mempool_t) pools;
155
	unsigned int		poolcnt;
156

157
	/*  ISC_MEMFLAG_INTERNAL */
158 159 160 161 162 163 164 165 166
	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;

167
#if ISC_MEM_TRACKLINES
168
	debuglist_t *	 	debuglist;
169
	unsigned int		debuglistcnt;
Michael Graff's avatar
Michael Graff committed
170
#endif
171 172

	unsigned int		memalloc_failures;
173
	ISC_LINK(isc__mem_t)	link;
Michael Graff's avatar
Michael Graff committed
174 175
};

176 177
#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
178

179
struct isc__mempool {
Michael Graff's avatar
Michael Graff committed
180
	/* always unlocked */
181
	isc_mempool_t	common;		/*%< common header of mempool's */
182
	isc_mutex_t    *lock;		/*%< optional lock */
183
	isc__mem_t      *mctx;		/*%< our memory context */
184
	/*%< locked via the memory context's lock */
185
	ISC_LINK(isc__mempool_t)	link;	/*%< next pool in this mem context */
186 187 188 189 190 191 192 193 194 195 196
	/*%< optionally locked from here down */
	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 */
	/*%< Debugging only. */
197
#if ISC_MEMPOOL_NAMES
198
	char		name[16];	/*%< printed name in stats reports */
Michael Graff's avatar
Michael Graff committed
199
#endif
Bob Halley's avatar
base  
Bob Halley committed
200 201
};

202 203 204
/*
 * Private Inline-able.
 */
Bob Halley's avatar
base  
Bob Halley committed
205

206
#if ! ISC_MEM_TRACKLINES
Michael Graff's avatar
Michael Graff committed
207 208
#define ADD_TRACE(a, b, c, d, e)
#define DELETE_TRACE(a, b, c, d, e)
209
#define ISC_MEMFUNC_SCOPE
Michael Graff's avatar
Michael Graff committed
210
#else
211
#define ADD_TRACE(a, b, c, d, e) \
212 213 214 215
	do { \
		if ((isc_mem_debugging & (ISC_MEM_DEBUGTRACE | \
					  ISC_MEM_DEBUGRECORD)) != 0 && \
		     b != NULL) \
Automatic Updater's avatar
Automatic Updater committed
216
			 add_trace_entry(a, b, c, d, e); \
217
	} while (0)
Michael Graff's avatar
Michael Graff committed
218 219
#define DELETE_TRACE(a, b, c, d, e)	delete_trace_entry(a, b, c, d, e)

220
static void
221 222 223
print_active(isc__mem_t *ctx, FILE *out);

/*%
224 225 226
 * The following are intended for internal use (indicated by "isc__"
 * prefix) but are not declared as static, allowing direct access
 * from unit tests, etc.
227 228
 */

229
isc_result_t
230 231
isc__mem_create2(size_t init_max_size, size_t target_size,
		 isc_mem_t **ctxp, unsigned int flags);
232
void
233
isc__mem_attach(isc_mem_t *source, isc_mem_t **targetp);
234
void
235
isc__mem_detach(isc_mem_t **ctxp);
236
void
237
isc___mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG);
238
void
239
isc__mem_destroy(isc_mem_t **ctxp);
240
isc_result_t
241
isc__mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event);
242
void *
243
isc___mem_get(isc_mem_t *ctx, size_t size FLARG);
244
void
245
isc___mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG);
246
void
247
isc__mem_stats(isc_mem_t *ctx, FILE *out);
248
void *
249
isc___mem_allocate(isc_mem_t *ctx, size_t size FLARG);
250
void *
251
isc___mem_reallocate(isc_mem_t *ctx, void *ptr, size_t size FLARG);
252
void
253
isc___mem_free(isc_mem_t *ctx, void *ptr FLARG);
254
char *
255
isc___mem_strdup(isc_mem_t *mctx, const char *s FLARG);
256
void
257
isc__mem_setdestroycheck(isc_mem_t *ctx, isc_boolean_t flag);
258
void
259
isc__mem_setquota(isc_mem_t *ctx, size_t quota);
260
size_t
261
isc__mem_getquota(isc_mem_t *ctx);
262
size_t
263
isc__mem_inuse(isc_mem_t *ctx);
264
size_t
265
isc__mem_maxinuse(isc_mem_t *ctx);
266
size_t
267
isc__mem_total(isc_mem_t *ctx);
268
isc_boolean_t
269
isc__mem_isovermem(isc_mem_t *ctx);
270
void
271 272
isc__mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg,
		  size_t hiwater, size_t lowater);
273
void
274
isc__mem_waterack(isc_mem_t *ctx0, int flag);
275
void
276
isc__mem_setname(isc_mem_t *ctx, const char *name, void *tag);
277
const char *
278
isc__mem_getname(isc_mem_t *ctx);
279
void *
280
isc__mem_gettag(isc_mem_t *ctx);
281
isc_result_t
282
isc__mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp);
283
void
284
isc__mempool_setname(isc_mempool_t *mpctx, const char *name);
285
void
286
isc__mempool_destroy(isc_mempool_t **mpctxp);
287
void
288
isc__mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock);
289
void *
290
isc___mempool_get(isc_mempool_t *mpctx FLARG);
291
void
292
isc___mempool_put(isc_mempool_t *mpctx, void *mem FLARG);
293
void
294
isc__mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit);
295
unsigned int
296
isc__mempool_getfreemax(isc_mempool_t *mpctx);
297
unsigned int
298
isc__mempool_getfreecount(isc_mempool_t *mpctx);
299
void
300
isc__mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit);
301
unsigned int
302
isc__mempool_getmaxalloc(isc_mempool_t *mpctx);
303
unsigned int
304
isc__mempool_getallocated(isc_mempool_t *mpctx);
305
void
306
isc__mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit);
307
unsigned int
308
isc__mempool_getfillcount(isc_mempool_t *mpctx);
309
void
310
isc__mem_printactive(isc_mem_t *ctx0, FILE *file);
311
void
312
isc__mem_printallactive(FILE *file);
313
unsigned int
314
isc__mem_references(isc_mem_t *ctx0);
315
#endif /* ISC_MEM_TRACKLINES */
316 317 318 319 320 321 322 323

static struct isc__memmethods {
	isc_memmethods_t methods;

	/*%
	 * The following are defined just for avoiding unused static functions.
	 */
	void *createx, *create, *create2, *ondestroy, *stats,
324
	     *setquota, *getquota, *setname, *getname, *gettag;
325 326 327 328 329 330 331 332 333
} memmethods = {
	{
		isc__mem_attach,
		isc__mem_detach,
		isc__mem_destroy,
		isc___mem_get,
		isc___mem_put,
		isc___mem_putanddetach,
		isc___mem_allocate,
334
		isc___mem_reallocate,
335 336 337 338 339 340
		isc___mem_strdup,
		isc___mem_free,
		isc__mem_setdestroycheck,
		isc__mem_setwater,
		isc__mem_waterack,
		isc__mem_inuse,
341 342
		isc__mem_maxinuse,
		isc__mem_total,
343
		isc__mem_isovermem,
344
		isc__mempool_create
345 346 347 348 349 350 351 352 353 354 355
	},
	(void *)isc_mem_createx,
	(void *)isc_mem_create,
	(void *)isc_mem_create2,
	(void *)isc_mem_ondestroy,
	(void *)isc_mem_stats,
	(void *)isc_mem_setquota,
	(void *)isc_mem_getquota,
	(void *)isc_mem_setname,
	(void *)isc_mem_getname,
	(void *)isc_mem_gettag
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
};

static struct isc__mempoolmethods {
	isc_mempoolmethods_t methods;

	/*%
	 * The following are defined just for avoiding unused static functions.
	 */
	void *getfreemax, *getfreecount, *getmaxalloc, *getfillcount;
} mempoolmethods = {
	{
		isc__mempool_destroy,
		isc___mempool_get,
		isc___mempool_put,
		isc__mempool_getallocated,
		isc__mempool_setmaxalloc,
		isc__mempool_setfreemax,
		isc__mempool_setname,
		isc__mempool_associatelock,
		isc__mempool_setfillcount
376 377 378 379 380
	},
	(void *)isc_mempool_getfreemax,
	(void *)isc_mempool_getfreecount,
	(void *)isc_mempool_getmaxalloc,
	(void *)isc_mempool_getfillcount
381
};
382

383
#if ISC_MEM_TRACKLINES
384
/*!
Michael Graff's avatar
Michael Graff committed
385 386 387
 * mctx must be locked.
 */
static inline void
388
add_trace_entry(isc__mem_t *mctx, const void *ptr, unsigned int size FLARG) {
Michael Graff's avatar
Michael Graff committed
389 390
	debuglink_t *dl;
	unsigned int i;
391
	unsigned int mysize = size;
Michael Graff's avatar
Michael Graff committed
392

393
	if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
394 395 396 397
		fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
					       ISC_MSG_ADDTRACE,
					       "add %p size %u "
					       "file %s line %u mctx %p\n"),
398
			ptr, size, file, line, mctx);
Michael Graff's avatar
Michael Graff committed
399

400
	if (mctx->debuglist == NULL)
Michael Graff's avatar
Michael Graff committed
401 402
		return;

403 404
	if (mysize > mctx->max_size)
		mysize = mctx->max_size;
405

406
	dl = ISC_LIST_HEAD(mctx->debuglist[mysize]);
Michael Graff's avatar
Michael Graff committed
407 408 409
	while (dl != NULL) {
		if (dl->count == DEBUGLIST_COUNT)
			goto next;
410
		for (i = 0; i < DEBUGLIST_COUNT; i++) {
Michael Graff's avatar
Michael Graff committed
411 412
			if (dl->ptr[i] == NULL) {
				dl->ptr[i] = ptr;
413
				dl->size[i] = size;
Michael Graff's avatar
Michael Graff committed
414 415 416 417 418 419 420 421 422 423 424 425 426 427
				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);
428
	for (i = 1; i < DEBUGLIST_COUNT; i++) {
Michael Graff's avatar
Michael Graff committed
429
		dl->ptr[i] = NULL;
430
		dl->size[i] = 0;
Michael Graff's avatar
Michael Graff committed
431 432 433 434 435
		dl->file[i] = NULL;
		dl->line[i] = 0;
	}

	dl->ptr[0] = ptr;
436
	dl->size[0] = size;
Michael Graff's avatar
Michael Graff committed
437 438 439 440
	dl->file[0] = file;
	dl->line[0] = line;
	dl->count = 1;

441
	ISC_LIST_PREPEND(mctx->debuglist[mysize], dl, link);
442
	mctx->debuglistcnt++;
Michael Graff's avatar
Michael Graff committed
443 444 445
}

static inline void
446
delete_trace_entry(isc__mem_t *mctx, const void *ptr, unsigned int size,
Michael Graff's avatar
Michael Graff committed
447 448 449 450 451
		   const char *file, unsigned int line)
{
	debuglink_t *dl;
	unsigned int i;

452
	if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
453 454 455 456
		fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
					       ISC_MSG_DELTRACE,
					       "del %p size %u "
					       "file %s line %u mctx %p\n"),
457
			ptr, size, file, line, mctx);
Michael Graff's avatar
Michael Graff committed
458

459
	if (mctx->debuglist == NULL)
Michael Graff's avatar
Michael Graff committed
460 461
		return;

462 463 464 465
	if (size > mctx->max_size)
		size = mctx->max_size;

	dl = ISC_LIST_HEAD(mctx->debuglist[size]);
Michael Graff's avatar
Michael Graff committed
466
	while (dl != NULL) {
467
		for (i = 0; i < DEBUGLIST_COUNT; i++) {
Michael Graff's avatar
Michael Graff committed
468 469
			if (dl->ptr[i] == ptr) {
				dl->ptr[i] = NULL;
470
				dl->size[i] = 0;
Michael Graff's avatar
Michael Graff committed
471 472 473 474 475 476
				dl->file[i] = NULL;
				dl->line[i] = 0;

				INSIST(dl->count > 0);
				dl->count--;
				if (dl->count == 0) {
477
					ISC_LIST_UNLINK(mctx->debuglist[size],
Michael Graff's avatar
Michael Graff committed
478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494
							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 */

495 496 497
static inline size_t
rmsize(size_t size) {
	/*
Automatic Updater's avatar
Automatic Updater committed
498
	 * round down to ALIGNMENT_SIZE
499
	 */
500
	return (size & (~(ALIGNMENT_SIZE - 1)));
501 502
}

503
static inline size_t
Bob Halley's avatar
base  
Bob Halley committed
504
quantize(size_t size) {
505
	/*!
506
	 * Round up the result in order to get a size big
Bob Halley's avatar
base  
Bob Halley committed
507 508 509
	 * enough to satisfy the request and be aligned on ALIGNMENT_SIZE
	 * byte boundaries.
	 */
510

Mark Andrews's avatar
Mark Andrews committed
511
	if (size == 0U)
512
		return (ALIGNMENT_SIZE);
513
	return ((size + ALIGNMENT_SIZE - 1) & (~(ALIGNMENT_SIZE - 1)));
Bob Halley's avatar
base  
Bob Halley committed
514 515
}

516
static inline isc_boolean_t
517
more_basic_blocks(isc__mem_t *ctx) {
518 519 520 521 522
	void *new;
	unsigned char *curr, *next;
	unsigned char *first, *last;
	unsigned char **table;
	unsigned int table_size;
Bob Halley's avatar
Bob Halley committed
523
	size_t increment;
524 525 526 527
	int i;

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

528 529 530
	/*
	 * Did we hit the quota for this context?
	 */
Bob Halley's avatar
Bob Halley committed
531
	increment = NUM_BASIC_BLOCKS * ctx->mem_target;
Mark Andrews's avatar
Mark Andrews committed
532
	if (ctx->quota != 0U && ctx->total + increment > ctx->quota)
533
		return (ISC_FALSE);
534 535 536

	INSIST(ctx->basic_table_count <= ctx->basic_table_size);
	if (ctx->basic_table_count == ctx->basic_table_size) {
537
		table_size = ctx->basic_table_size + TABLE_INCREMENT;
538
		table = (ctx->memalloc)(ctx->arg,
Andreas Gustafsson's avatar
Andreas Gustafsson committed
539
					table_size * sizeof(unsigned char *));
540 541
		if (table == NULL) {
			ctx->memalloc_failures++;
542
			return (ISC_FALSE);
543
		}
544 545 546
		if (ctx->basic_table_size != 0) {
			memcpy(table, ctx->basic_table,
			       ctx->basic_table_size *
Andreas Gustafsson's avatar
Andreas Gustafsson committed
547
			       sizeof(unsigned char *));
548
			(ctx->memfree)(ctx->arg, ctx->basic_table);
549
		}
550 551
		ctx->basic_table = table;
		ctx->basic_table_size = table_size;
552
	}
553

554
	new = (ctx->memalloc)(ctx->arg, NUM_BASIC_BLOCKS * ctx->mem_target);
555 556
	if (new == NULL) {
		ctx->memalloc_failures++;
557
		return (ISC_FALSE);
558
	}
Bob Halley's avatar
Bob Halley committed
559
	ctx->total += increment;
560 561
	ctx->basic_table[ctx->basic_table_count] = new;
	ctx->basic_table_count++;
562

563 564 565
	curr = new;
	next = curr + ctx->mem_target;
	for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) {
566
		((element *)curr)->next = (element *)next;
567 568 569 570 571 572 573
		curr = next;
		next += ctx->mem_target;
	}
	/*
	 * curr is now pointing at the last block in the
	 * array.
	 */
Bob Halley's avatar
Bob Halley committed
574
	((element *)curr)->next = NULL;
575 576 577 578 579 580 581
	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;
582 583

	return (ISC_TRUE);
584 585
}

586
static inline isc_boolean_t
587
more_frags(isc__mem_t *ctx, size_t new_size) {
588 589 590 591 592
	int i, frags;
	size_t total_size;
	void *new;
	unsigned char *curr, *next;

593
	/*!
594 595 596 597 598 599 600 601 602 603
	 * 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.
			 */
			/*
604
			 * XXXRTH  "At quota" notification here.
605
			 */
606
			return (ISC_FALSE);
607 608 609 610 611 612 613 614 615 616 617 618 619 620 621
		}
	}

	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;
622
	total_size -= new_size;
623 624 625 626
	for (i = 0; i < (frags - 1); i++) {
		((element *)curr)->next = (element *)next;
		curr = next;
		next += new_size;
627 628 629 630 631 632
		total_size -= new_size;
	}
	/*
	 * Add the remaining fragment of the basic block to a free list.
	 */
	total_size = rmsize(total_size);
Mark Andrews's avatar
Mark Andrews committed
633
	if (total_size > 0U) {
634 635 636
		((element *)next)->next = ctx->freelists[total_size];
		ctx->freelists[total_size] = (element *)next;
		ctx->stats[total_size].freefrags++;
637 638 639 640 641 642 643 644 645 646 647
	}
	/*
	 * 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
648
static inline void *
649
mem_getunlocked(isc__mem_t *ctx, size_t size) {
Michael Graff's avatar
Michael Graff committed
650 651
	size_t new_size = quantize(size);
	void *ret;
Bob Halley's avatar
base  
Bob Halley committed
652 653

	if (size >= ctx->max_size || new_size >= ctx->max_size) {
654 655 656
		/*
		 * memget() was called on something beyond our upper limit.
		 */
Mark Andrews's avatar
Mark Andrews committed
657
		if (ctx->quota != 0U && ctx->total + size > ctx->quota) {
Bob Halley's avatar
Bob Halley committed
658 659 660
			ret = NULL;
			goto done;
		}
Mark Andrews's avatar
Mark Andrews committed
661
		ret = (ctx->memalloc)(ctx->arg, size);
662 663 664
		if (ret == NULL) {
			ctx->memalloc_failures++;
			goto done;
Bob Halley's avatar
base  
Bob Halley committed
665
		}
666 667 668 669 670 671 672 673 674 675
		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;
676
		goto done;
Bob Halley's avatar
base  
Bob Halley committed
677 678
	}

679
	/*
Bob Halley's avatar
base  
Bob Halley committed
680 681 682 683
	 * 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.
	 */
684 685
	if (ctx->freelists[new_size] == NULL && !more_frags(ctx, new_size))
		return (NULL);
Bob Halley's avatar
base  
Bob Halley committed
686

687 688 689
	/*
	 * The free list uses the "rounded-up" size "new_size".
	 */
Bob Halley's avatar
base  
Bob Halley committed
690 691 692
	ret = ctx->freelists[new_size];
	ctx->freelists[new_size] = ctx->freelists[new_size]->next;

693
	/*
Bob Halley's avatar
base  
Bob Halley committed
694 695 696 697 698 699 700 701
	 * 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--;
702
	ctx->inuse += new_size;
Bob Halley's avatar
base  
Bob Halley committed
703 704 705

 done:

706
#if ISC_MEM_FILL
707 708
	if (ret != NULL)
		memset(ret, 0xbe, new_size); /* Mnemonic for "beef". */
David Lawrence's avatar
David Lawrence committed
709 710 711
#endif

	return (ret);
Michael Graff's avatar
Michael Graff committed
712 713
}

714 715 716 717 718 719 720 721 722 723 724 725 726 727 728
#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

729
/* coverity[+free : arg-1] */
Michael Graff's avatar
Michael Graff committed
730
static inline void
731
mem_putunlocked(isc__mem_t *ctx, void *mem, size_t size) {
Michael Graff's avatar
Michael Graff committed
732
	size_t new_size = quantize(size);
Bob Halley's avatar
base  
Bob Halley committed
733

734
	if (size == ctx->max_size || new_size >= ctx->max_size) {
735 736 737
		/*
		 * memput() called on something beyond our upper limit.
		 */
738
#if ISC_MEM_FILL
Mark Andrews's avatar
Mark Andrews committed
739 740
		memset(mem, 0xde, size); /* Mnemonic for "dead". */
#endif
741
		(ctx->memfree)(ctx->arg, mem);
Mark Andrews's avatar
Mark Andrews committed
742
		INSIST(ctx->stats[ctx->max_size].gets != 0U);
Bob Halley's avatar
base  
Bob Halley committed
743
		ctx->stats[ctx->max_size].gets--;
Bob Halley's avatar
Bob Halley committed
744
		INSIST(size <= ctx->total);
745
		ctx->inuse -= size;
Bob Halley's avatar
Bob Halley committed
746
		ctx->total -= size;
Michael Graff's avatar
Michael Graff committed
747
		return;
Bob Halley's avatar
base  
Bob Halley committed
748 749
	}

750 751
#if ISC_MEM_FILL
#if ISC_MEM_CHECKOVERRUN
752 753
	check_overrun(mem, size, new_size);
#endif
Mark Andrews's avatar
Mark Andrews committed
754 755
	memset(mem, 0xde, new_size); /* Mnemonic for "dead". */
#endif
756

757 758 759
	/*
	 * The free list uses the "rounded-up" size "new_size".
	 */
Mark Andrews's avatar
Mark Andrews committed
760 761
	((element *)mem)->next = ctx->freelists[new_size];
	ctx->freelists[new_size] = (element *)mem;
Bob Halley's avatar
base  
Bob Halley committed
762

763
	/*
Bob Halley's avatar
base  
Bob Halley committed
764 765 766 767 768
	 * 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.
	 */
Mark Andrews's avatar
Mark Andrews committed
769
	INSIST(ctx->stats[size].gets != 0U);
Bob Halley's avatar
base  
Bob Halley committed
770 771
	ctx->stats[size].gets--;
	ctx->stats[new_size].freefrags++;
772
	ctx->inuse -= new_size;
Bob Halley's avatar
base  
Bob Halley committed
773 774
}

775
/*!
776 777 778
 * Perform a malloc, doing memory filling and overrun detection as necessary.
 */
static inline void *
779
mem_get(isc__mem_t *ctx, size_t size) {
780 781 782 783 784 785 786
	char *ret;

#if ISC_MEM_CHECKOVERRUN
	size += 1;
#endif

	ret = (ctx->memalloc)(ctx->arg, size);
787
	if (ret == NULL)
Automatic Updater's avatar
Automatic Updater committed
788
		ctx->memalloc_failures++;
789 790 791 792 793 794 795 796 797 798 799 800 801 802

#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);
}

803
/*!
804 805
 * Perform a free, doing memory filling and overrun detection as necessary.
 */
806
/* coverity[+free : arg-1] */
807
static inline void
808
mem_put(isc__mem_t *ctx, void *mem, size_t size) {
809
#if ISC_MEM_CHECKOVERRUN
810
	INSIST(((unsigned char *)mem)[size] == 0xbe);
811 812 813
#endif
#if ISC_MEM_FILL
	memset(mem, 0xde, size); /* Mnemonic for "dead". */
Andreas Gustafsson's avatar
Andreas Gustafsson committed
814 815
#else
	UNUSED(size);
816 817 818 819
#endif
	(ctx->memfree)(ctx->arg, mem);
}

820
/*!
821 822 823
 * Update internal counters after a memory get.
 */
static inline void
824
mem_getstats(isc__mem_t *ctx, size_t size) {