mem.c 26.6 KB
Newer Older
Bob Halley's avatar
base  
Bob Halley committed
1
/*
Bob Halley's avatar
Bob Halley committed
2
 * Copyright (C) 1997, 1998, 1999, 2000  Internet Software Consortium.
Bob Halley's avatar
Bob Halley committed
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.
Bob Halley's avatar
Bob Halley committed
7
 * 
Bob Halley's avatar
base  
Bob Halley committed
8 9 10 11 12 13 14 15 16 17
 * 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
Bob Halley committed
18
#include <config.h>
Bob Halley's avatar
base  
Bob Halley committed
19 20 21

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

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

Bob Halley's avatar
base  
Bob Halley committed
27
#include <isc/assertions.h>
28
#include <isc/error.h>
Bob Halley's avatar
Bob Halley committed
29
#include <isc/mem.h>
30
#include <isc/ondestroy.h>
Bob Halley's avatar
Bob Halley committed
31

32
#ifndef ISC_SINGLETHREADED
Bob Halley's avatar
update  
Bob Halley committed
33
#include <isc/mutex.h>
Michael Graff's avatar
Michael Graff committed
34
#include <isc/util.h>
Bob Halley's avatar
Bob Halley committed
35
#else
Bob Halley's avatar
Bob Halley committed
36 37
#define LOCK(l)
#define UNLOCK(l)
Bob Halley's avatar
update  
Bob Halley committed
38 39
#endif

Bob Halley's avatar
Bob Halley committed
40
#ifndef ISC_MEM_FILL
41 42
	/*
	 * XXXMPA
Bob Halley's avatar
Bob Halley committed
43
	 * We want this on during development to catch:
44 45 46 47 48 49
	 * 1. some reference after free bugs.
	 * 2. some failure to initalise bugs.
	 */
#define ISC_MEM_FILL 1
#endif

Michael Graff's avatar
Michael Graff committed
50 51 52 53 54 55 56 57
#ifndef ISC_MEMPOOL_NAMES
/*
 * During development it is nice to be able to see names associated with
 * memory pools.
 */
#define ISC_MEMPOOL_NAMES 1
#endif

58 59 60 61 62 63 64 65 66 67 68

/*
 * Constants.
 */

#define DEF_MAX_SIZE		1100
#define DEF_MEM_TARGET		4096
#define ALIGNMENT_SIZE		8
#define NUM_BASIC_BLOCKS	64			/* must be > 1 */
#define TABLE_INCREMENT		1024

Bob Halley's avatar
base  
Bob Halley committed
69 70 71 72
/*
 * Types.
 */

73 74 75 76 77
typedef struct element element;

struct element {
	element *		next;
};
Bob Halley's avatar
base  
Bob Halley committed
78 79 80 81 82

typedef struct {
	/*
	 * This structure must be ALIGNMENT_SIZE bytes.
	 */
83 84 85 86
	union {
		size_t		size;
		char		bytes[ALIGNMENT_SIZE];
	} u;
Bob Halley's avatar
Bob Halley committed
87
} size_info;
Bob Halley's avatar
base  
Bob Halley committed
88 89

struct stats {
Bob Halley's avatar
Bob Halley committed
90 91 92 93
	unsigned long		gets;
	unsigned long		totalgets;
	unsigned long		blocks;
	unsigned long		freefrags;
Bob Halley's avatar
base  
Bob Halley committed
94 95
};

96 97
#define MEM_MAGIC		0x4D656d43U	/* MemC. */
#define VALID_CONTEXT(c)	((c) != NULL && (c)->magic == MEM_MAGIC)
Bob Halley's avatar
Bob Halley committed
98

99
struct isc_mem {
Bob Halley's avatar
Bob Halley committed
100
	unsigned int		magic;
101
	isc_ondestroy_t		ondestroy;
Bob Halley's avatar
Bob Halley committed
102
	isc_mutex_t		lock;
103 104 105
	isc_memalloc_t		memalloc;
	isc_memfree_t		memfree;
	void *			arg;
Bob Halley's avatar
base  
Bob Halley committed
106 107
	size_t			max_size;
	size_t			mem_target;
Bob Halley's avatar
Bob Halley committed
108 109
	element **		freelists;
	element *		basic_blocks;
110 111 112
	unsigned char **	basic_table;
	unsigned int		basic_table_count;
	unsigned int		basic_table_size;
Bob Halley's avatar
Bob Halley committed
113 114
	unsigned char *		lowest;
	unsigned char *		highest;
115
	isc_boolean_t		checkfree;
Bob Halley's avatar
base  
Bob Halley committed
116
	struct stats *		stats;
117
	size_t			quota;
Bob Halley's avatar
Bob Halley committed
118
	size_t			total;
Michael Graff's avatar
Michael Graff committed
119 120 121 122 123 124 125
	ISC_LIST(isc_mempool_t)	pools;
};

#define MEMPOOL_MAGIC		0x4D454d70U	/* MEMp. */
#define VALID_MEMPOOL(c)	((c) != NULL && (c)->magic == MEMPOOL_MAGIC)

struct isc_mempool {
Michael Graff's avatar
Michael Graff committed
126
	/* always unlocked */
Michael Graff's avatar
Michael Graff committed
127
	unsigned int	magic;		/* magic number */
Michael Graff's avatar
Michael Graff committed
128
	isc_mutex_t    *lock;		/* optional lock */
Michael Graff's avatar
Michael Graff committed
129
	isc_mem_t      *mctx;		/* our memory context */
Michael Graff's avatar
Michael Graff committed
130 131 132
	/* 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
133 134 135 136 137 138 139 140 141
	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
142 143 144 145
	/* Debugging only. */
#if ISC_MEMPOOL_NAMES
	char		name[16];	/* printed name in stats reports */
#endif
Bob Halley's avatar
base  
Bob Halley committed
146 147
};

148 149 150
/*
 * Forward.
 */
Bob Halley's avatar
base  
Bob Halley committed
151

Michael Graff's avatar
Michael Graff committed
152
static inline size_t		quantize(size_t);
Mark Andrews's avatar
Mark Andrews committed
153 154
static inline void		mem_putunlocked(isc_mem_t *, void *, size_t);
static inline void *		mem_getunlocked(isc_mem_t *, size_t);
Bob Halley's avatar
base  
Bob Halley committed
155

156 157 158
/*
 * Private Inline-able.
 */
Bob Halley's avatar
base  
Bob Halley committed
159

160
static inline size_t
Bob Halley's avatar
base  
Bob Halley committed
161
quantize(size_t size) {
162
	int temp;
Bob Halley's avatar
base  
Bob Halley committed
163 164

	/*
165
	 * Round up the result in order to get a size big
Bob Halley's avatar
base  
Bob Halley committed
166 167 168
	 * enough to satisfy the request and be aligned on ALIGNMENT_SIZE
	 * byte boundaries.
	 */
169

170 171
	if (size == 0)
		return (ALIGNMENT_SIZE);
Mark Andrews's avatar
Mark Andrews committed
172
	temp = size + (ALIGNMENT_SIZE - 1);
173
	return (temp - temp % ALIGNMENT_SIZE); 
Bob Halley's avatar
base  
Bob Halley committed
174 175
}

176 177 178
/*
 * Private.
 */
179 180 181 182 183 184 185 186 187 188

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

static void
default_memfree(void *arg, void *ptr) {
	(void)arg;
James Brister's avatar
James Brister committed
189
	free(ptr);
190 191
}

192 193 194
/*
 * Public.
 */
Bob Halley's avatar
base  
Bob Halley committed
195

Bob Halley's avatar
Bob Halley committed
196
isc_result_t
197 198 199
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)
Bob Halley's avatar
Bob Halley committed
200
{
201
	isc_mem_t *ctx;
Bob Halley's avatar
Bob Halley committed
202 203

	REQUIRE(ctxp != NULL && *ctxp == NULL);
204 205
	REQUIRE(memalloc != NULL);
	REQUIRE(memfree != NULL);
Bob Halley's avatar
base  
Bob Halley committed
206

207
	ctx = (memalloc)(arg, sizeof *ctx);
Michael Graff's avatar
Michael Graff committed
208 209 210
	if (ctx == NULL)
		return (ISC_R_NOMEMORY);

Bob Halley's avatar
base  
Bob Halley committed
211 212 213 214 215 216 217 218
	if (init_max_size == 0)
		ctx->max_size = DEF_MAX_SIZE;
	else
		ctx->max_size = init_max_size;
	if (target_size == 0)
		ctx->mem_target = DEF_MEM_TARGET;
	else
		ctx->mem_target = target_size;
219 220 221 222
	ctx->memalloc = memalloc;
	ctx->memfree = memfree;
	ctx->arg = arg;
	ctx->freelists = (memalloc)(arg, ctx->max_size * sizeof (element *));
Mark Andrews's avatar
Mark Andrews committed
223
	if (ctx->freelists == NULL) {
224
		(memfree)(arg, ctx);
Bob Halley's avatar
Bob Halley committed
225
		return (ISC_R_NOMEMORY);
Bob Halley's avatar
base  
Bob Halley committed
226
	}
227
	ctx->checkfree = ISC_TRUE;
Bob Halley's avatar
Bob Halley committed
228 229
	memset(ctx->freelists, 0,
	       ctx->max_size * sizeof (element *));
230 231
	ctx->stats = (memalloc)(arg,
				(ctx->max_size+1) * sizeof (struct stats));
Bob Halley's avatar
base  
Bob Halley committed
232
	if (ctx->stats == NULL) {
233 234
		(memfree)(arg, ctx->freelists);
		(memfree)(arg, ctx);
Bob Halley's avatar
Bob Halley committed
235
		return (ISC_R_NOMEMORY);
Bob Halley's avatar
base  
Bob Halley committed
236 237 238
	}
	memset(ctx->stats, 0, (ctx->max_size + 1) * sizeof (struct stats));
	ctx->basic_blocks = NULL;
239 240 241
	ctx->basic_table = NULL;
	ctx->basic_table_count = 0;
	ctx->basic_table_size = 0;
Bob Halley's avatar
base  
Bob Halley committed
242 243
	ctx->lowest = NULL;
	ctx->highest = NULL;
Bob Halley's avatar
Bob Halley committed
244
	if (isc_mutex_init(&ctx->lock) != ISC_R_SUCCESS) {
245 246 247
		(memfree)(arg, ctx->stats);
		(memfree)(arg, ctx->freelists);
		(memfree)(arg, ctx);
Bob Halley's avatar
Bob Halley committed
248
		UNEXPECTED_ERROR(__FILE__, __LINE__,
Bob Halley's avatar
Bob Halley committed
249
				 "isc_mutex_init() failed");
Bob Halley's avatar
Bob Halley committed
250
		return (ISC_R_UNEXPECTED);
Bob Halley's avatar
update  
Bob Halley committed
251
	}
252
	ctx->quota = 0;
Bob Halley's avatar
Bob Halley committed
253
	ctx->total = 0;
Bob Halley's avatar
Bob Halley committed
254
	ctx->magic = MEM_MAGIC;
255
	isc_ondestroy_init(&ctx->ondestroy);
Michael Graff's avatar
Michael Graff committed
256 257
	ISC_LIST_INIT(ctx->pools);

Bob Halley's avatar
base  
Bob Halley committed
258
	*ctxp = ctx;
Bob Halley's avatar
Bob Halley committed
259
	return (ISC_R_SUCCESS);
Bob Halley's avatar
base  
Bob Halley committed
260 261
}

262 263 264 265 266 267 268 269 270
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));
}

Bob Halley's avatar
base  
Bob Halley committed
271
void
272
isc_mem_destroy(isc_mem_t **ctxp) {
273
	unsigned int i;
274
	isc_mem_t *ctx;
275
	isc_ondestroy_t ondest;
276

Bob Halley's avatar
base  
Bob Halley committed
277
	REQUIRE(ctxp != NULL);
278
	ctx = *ctxp;
Bob Halley's avatar
Bob Halley committed
279 280 281
	REQUIRE(VALID_CONTEXT(ctx));

	ctx->magic = 0;
282

Michael Graff's avatar
Michael Graff committed
283 284
	INSIST(ISC_LIST_EMPTY(ctx->pools));

285 286 287 288 289 290 291 292 293 294 295
	if (ctx->checkfree) {
		for (i = 0; i <= ctx->max_size; i++)
			INSIST(ctx->stats[i].gets == 0);
	}

#if 0					/* XXX brister debugging */
	for (i = 0; i < ctx->basic_table_count; i++)
		memset(ctx->basic_table[i], 0x0,
		       NUM_BASIC_BLOCKS * ctx->mem_target);
#endif
	
296 297

	for (i = 0; i < ctx->basic_table_count; i++)
298 299 300 301
		(ctx->memfree)(ctx->arg, ctx->basic_table[i]);
	(ctx->memfree)(ctx->arg, ctx->freelists);
	(ctx->memfree)(ctx->arg, ctx->stats);
	(ctx->memfree)(ctx->arg, ctx->basic_table);
302

303 304
	ondest = ctx->ondestroy;

Bob Halley's avatar
Bob Halley committed
305
	(void)isc_mutex_destroy(&ctx->lock);
306
	(ctx->memfree)(ctx->arg, ctx);
Bob Halley's avatar
base  
Bob Halley committed
307

308 309
	isc_ondestroy_notify(&ondest, ctx);

Bob Halley's avatar
base  
Bob Halley committed
310 311 312
	*ctxp = NULL;
}

313 314 315 316 317 318 319 320 321 322 323 324
isc_result_t
isc_mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event) {
	isc_result_t res;
	
	LOCK(&ctx->lock);
	res = isc_ondestroy_register(&ctx->ondestroy, task, event);
	UNLOCK(&ctx->lock);

	return (res);
}


325 326 327 328 329 330 331 332 333 334 335
isc_result_t
isc_mem_restore(isc_mem_t *ctx) {
	isc_result_t result;

	result = isc_mutex_init(&ctx->lock); 
	if (result != ISC_R_SUCCESS)
		ctx->magic = 0;

	return (result);
}

336
static void
337
more_basic_blocks(isc_mem_t *ctx) {
338 339 340 341 342
	void *new;
	unsigned char *curr, *next;
	unsigned char *first, *last;
	unsigned char **table;
	unsigned int table_size;
Bob Halley's avatar
Bob Halley committed
343
	size_t increment;
344 345 346 347
	int i;

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

348 349 350
	/*
	 * Did we hit the quota for this context?
	 */
Bob Halley's avatar
Bob Halley committed
351 352 353
	increment = NUM_BASIC_BLOCKS * ctx->mem_target;
	if (ctx->quota != 0 && ctx->total + increment > ctx->quota)
		return;
354 355 356

	INSIST(ctx->basic_table_count <= ctx->basic_table_size);
	if (ctx->basic_table_count == ctx->basic_table_size) {
357
		table_size = ctx->basic_table_size + TABLE_INCREMENT;
358 359
		table = (ctx->memalloc)(ctx->arg,
					table_size * sizeof (unsigned char *));
360 361
		if (table == NULL)
			return;
362 363 364 365
		if (ctx->basic_table_size != 0) {
			memcpy(table, ctx->basic_table,
			       ctx->basic_table_size *
			       sizeof (unsigned char *));
366
			(ctx->memfree)(ctx->arg, ctx->basic_table);
367
		}
368 369
		ctx->basic_table = table;
		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
		return;
Bob Halley's avatar
Bob Halley committed
375
	ctx->total += increment;
376 377
	ctx->basic_table[ctx->basic_table_count] = new;
	ctx->basic_table_count++;
378

379 380 381
	curr = new;
	next = curr + ctx->mem_target;
	for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) {
382
		((element *)curr)->next = (element *)next;
383 384 385 386 387 388 389
		curr = next;
		next += ctx->mem_target;
	}
	/*
	 * curr is now pointing at the last block in the
	 * array.
	 */
Bob Halley's avatar
Bob Halley committed
390
	((element *)curr)->next = NULL;
391 392 393 394 395 396 397 398 399
	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;
}

Bob Halley's avatar
base  
Bob Halley committed
400
void *
Mark Andrews's avatar
Mark Andrews committed
401
__isc_mem_get(isc_mem_t *ctx, size_t size)
Michael Graff's avatar
Michael Graff committed
402
{
Bob Halley's avatar
base  
Bob Halley committed
403 404
	void *ret;

Bob Halley's avatar
Bob Halley committed
405
	REQUIRE(VALID_CONTEXT(ctx));
Michael Graff's avatar
Michael Graff committed
406

Bob Halley's avatar
Bob Halley committed
407
	LOCK(&ctx->lock);
Mark Andrews's avatar
Mark Andrews committed
408
	ret = mem_getunlocked(ctx, size);
Michael Graff's avatar
Michael Graff committed
409 410 411 412 413
	UNLOCK(&ctx->lock);

	return (ret);
}

414 415 416 417 418 419 420 421 422 423 424 425 426
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++;
	}
}

Michael Graff's avatar
Michael Graff committed
427
static inline void *
Mark Andrews's avatar
Mark Andrews committed
428
mem_getunlocked(isc_mem_t *ctx, size_t size)
Michael Graff's avatar
Michael Graff committed
429 430 431
{
	size_t new_size = quantize(size);
	void *ret;
Bob Halley's avatar
base  
Bob Halley committed
432 433 434

	if (size >= ctx->max_size || new_size >= ctx->max_size) {
		/* memget() was called on something beyond our upper limit. */
Bob Halley's avatar
Bob Halley committed
435 436 437 438
		if (ctx->quota != 0 && ctx->total + size > ctx->quota) {
			ret = NULL;
			goto done;
		}
Mark Andrews's avatar
Mark Andrews committed
439
		ret = (ctx->memalloc)(ctx->arg, size);
Bob Halley's avatar
base  
Bob Halley committed
440
		if (ret != NULL) {
Bob Halley's avatar
Bob Halley committed
441
			ctx->total += size;
Bob Halley's avatar
base  
Bob Halley committed
442 443
			ctx->stats[ctx->max_size].gets++;
			ctx->stats[ctx->max_size].totalgets++;
Mark Andrews's avatar
Mark Andrews committed
444 445 446 447 448 449
			/*
			 * 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;
Bob Halley's avatar
base  
Bob Halley committed
450 451 452 453 454 455 456 457 458 459 460 461 462
		}
		goto done;
	}

	/* 
	 * 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.
	 */
	if (ctx->freelists[new_size] == NULL) {
		int i, frags;
		size_t total_size;
		void *new;
Bob Halley's avatar
Bob Halley committed
463
		unsigned char *curr, *next;
Bob Halley's avatar
base  
Bob Halley committed
464 465

		if (ctx->basic_blocks == NULL) {
466 467
			more_basic_blocks(ctx);
			if (ctx->basic_blocks == NULL) {
Bob Halley's avatar
base  
Bob Halley committed
468 469 470 471 472 473 474 475 476 477 478 479 480 481
				ret = NULL;
				goto done;
			}
		}
		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;
		for (i = 0; i < (frags - 1); i++) {
482
			((element *)curr)->next = (element *)next;
Bob Halley's avatar
base  
Bob Halley committed
483 484 485 486
			curr = next;
			next += new_size;
		}
		/* curr is now pointing at the last block in the array. */
Bob Halley's avatar
Bob Halley committed
487
		((element *)curr)->next = NULL;
Bob Halley's avatar
base  
Bob Halley committed
488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506
		ctx->freelists[new_size] = new;
	}

	/* The free list uses the "rounded-up" size "new_size": */
	ret = ctx->freelists[new_size];
	ctx->freelists[new_size] = ctx->freelists[new_size]->next;

	/* 
	 * 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--;

 done:

507 508 509 510 511
#if ISC_MEM_FILL
	if (ret != NULL)
		memset(ret, 0xbe, new_size); /* Mnemonic for "beef". */
#endif

Bob Halley's avatar
base  
Bob Halley committed
512 513 514 515
	return (ret);
}

void
Mark Andrews's avatar
Mark Andrews committed
516
__isc_mem_put(isc_mem_t *ctx, void *mem, size_t size)
Michael Graff's avatar
Michael Graff committed
517
{
Bob Halley's avatar
Bob Halley committed
518
	REQUIRE(VALID_CONTEXT(ctx));
Michael Graff's avatar
Michael Graff committed
519

Bob Halley's avatar
Bob Halley committed
520
	LOCK(&ctx->lock);
Mark Andrews's avatar
Mark Andrews committed
521
	mem_putunlocked(ctx, mem, size);
Michael Graff's avatar
Michael Graff committed
522 523 524 525
	UNLOCK(&ctx->lock);
}

static inline void
Mark Andrews's avatar
Mark Andrews committed
526
mem_putunlocked(isc_mem_t *ctx, void *mem, size_t size)
Michael Graff's avatar
Michael Graff committed
527 528
{
	size_t new_size = quantize(size);
Bob Halley's avatar
base  
Bob Halley committed
529

530 531
	if (size == ctx->max_size || new_size >= ctx->max_size) {
		/* memput() called on something beyond our upper limit */
Mark Andrews's avatar
Mark Andrews committed
532 533 534
#if ISC_MEM_FILL
		memset(mem, 0xde, size); /* Mnemonic for "dead". */
#endif
535
		(ctx->memfree)(ctx->arg, mem);
Bob Halley's avatar
base  
Bob Halley committed
536 537
		INSIST(ctx->stats[ctx->max_size].gets != 0);
		ctx->stats[ctx->max_size].gets--;
Bob Halley's avatar
Bob Halley committed
538 539
		INSIST(size <= ctx->total);
		ctx->total -= size;
Michael Graff's avatar
Michael Graff committed
540
		return;
Bob Halley's avatar
base  
Bob Halley committed
541 542
	}

Mark Andrews's avatar
Mark Andrews committed
543
#if ISC_MEM_FILL
544 545 546
#if ISC_MEM_CHECKOVERRUN
	check_overrun(mem, size, new_size);
#endif
Mark Andrews's avatar
Mark Andrews committed
547 548
	memset(mem, 0xde, new_size); /* Mnemonic for "dead". */
#endif
549

Bob Halley's avatar
base  
Bob Halley committed
550
	/* The free list uses the "rounded-up" size "new_size": */
Mark Andrews's avatar
Mark Andrews committed
551 552
	((element *)mem)->next = ctx->freelists[new_size];
	ctx->freelists[new_size] = (element *)mem;
Bob Halley's avatar
base  
Bob Halley committed
553 554 555 556 557 558 559 560 561 562 563 564 565

	/* 
	 * 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++;
}

void *
566
__isc_mem_getdebug(isc_mem_t *ctx, size_t size, const char *file, int line) {
Bob Halley's avatar
base  
Bob Halley committed
567
	void *ptr;
Bob Halley's avatar
Bob Halley committed
568

Mark Andrews's avatar
Mark Andrews committed
569
	ptr = __isc_mem_get(ctx, size);
Bob Halley's avatar
base  
Bob Halley committed
570
	fprintf(stderr, "%s:%d: mem_get(%p, %lu) -> %p\n", file, line,
Bob Halley's avatar
Bob Halley committed
571
		ctx, (unsigned long)size, ptr);
Bob Halley's avatar
base  
Bob Halley committed
572 573 574 575
	return (ptr);
}

void
576
__isc_mem_putdebug(isc_mem_t *ctx, void *ptr, size_t size, const char *file,
Bob Halley's avatar
Bob Halley committed
577
		 int line)
Bob Halley's avatar
base  
Bob Halley committed
578 579
{
	fprintf(stderr, "%s:%d: mem_put(%p, %p, %lu)\n", file, line, 
Bob Halley's avatar
Bob Halley committed
580
		ctx, ptr, (unsigned long)size);
Mark Andrews's avatar
Mark Andrews committed
581
	__isc_mem_put(ctx, ptr, size);
Bob Halley's avatar
base  
Bob Halley committed
582 583 584 585 586 587
}

/*
 * Print the stats[] on the stream "out" with suitable formatting.
 */
void
588
isc_mem_stats(isc_mem_t *ctx, FILE *out) {
Bob Halley's avatar
base  
Bob Halley committed
589
	size_t i;
Michael Graff's avatar
Michael Graff committed
590 591
	const struct stats *s;
	const isc_mempool_t *pool;
Bob Halley's avatar
base  
Bob Halley committed
592

Bob Halley's avatar
Bob Halley committed
593 594
	REQUIRE(VALID_CONTEXT(ctx));
	LOCK(&ctx->lock);
Bob Halley's avatar
base  
Bob Halley committed
595

Michael Graff's avatar
Michael Graff committed
596
	if (ctx->freelists != NULL) {
597
		for (i = 0; i <= ctx->max_size; i++) {
Michael Graff's avatar
Michael Graff committed
598 599 600 601 602 603 604 605 606 607 608 609 610 611
			s = &ctx->stats[i];

			if (s->totalgets == 0 && s->gets == 0)
				continue;
			fprintf(out, "%s%5d: %11lu gets, %11lu rem",
				(i == ctx->max_size) ? ">=" : "  ",
				i, s->totalgets, s->gets);
			if (s->blocks != 0)
				fprintf(out, " (%lu bl, %lu ff)",
					s->blocks, s->freefrags);
			fputc('\n', out);
		}
	}

Michael Graff's avatar
Michael Graff committed
612 613 614 615 616 617 618
	/*
	 * 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
619 620 621
	pool = ISC_LIST_HEAD(ctx->pools);
	if (pool != NULL) {
		fprintf(out, "[Pool statistics]\n");
Michael Graff's avatar
Michael Graff committed
622 623
		fprintf(out, "%15s %10s %10s %10s %10s %10s %10s %10s %1s\n",
			"name", "size", "maxalloc", "allocated", "freecount",
Michael Graff's avatar
Michael Graff committed
624
			"freemax", "fillcount", "gets", "L");
Michael Graff's avatar
Michael Graff committed
625 626
	}
	while (pool != NULL) {
Michael Graff's avatar
Michael Graff committed
627 628 629 630
		fprintf(out, "%15s %10u %10u %10u %10u %10u %10u %10u %s\n",
			pool->name, pool->size, pool->maxalloc,
			pool->allocated, pool->freecount, pool->freemax,
			pool->fillcount, pool->gets,
Michael Graff's avatar
Michael Graff committed
631
			(pool->lock == NULL ? "N" : "Y"));
Michael Graff's avatar
Michael Graff committed
632
		pool = ISC_LIST_NEXT(pool, link);
Bob Halley's avatar
base  
Bob Halley committed
633 634
	}

Bob Halley's avatar
Bob Halley committed
635
	UNLOCK(&ctx->lock);
Bob Halley's avatar
base  
Bob Halley committed
636 637
}

Bob Halley's avatar
Bob Halley committed
638
isc_boolean_t
639
isc_mem_valid(isc_mem_t *ctx, void *ptr) {
Bob Halley's avatar
Bob Halley committed
640
	unsigned char *cp = ptr;
Bob Halley's avatar
Bob Halley committed
641
	isc_boolean_t result = ISC_FALSE;
Bob Halley's avatar
base  
Bob Halley committed
642

Bob Halley's avatar
Bob Halley committed
643 644
	REQUIRE(VALID_CONTEXT(ctx));
	LOCK(&ctx->lock);
Bob Halley's avatar
base  
Bob Halley committed
645 646

	if (ctx->lowest != NULL && cp >= ctx->lowest && cp <= ctx->highest)
Bob Halley's avatar
Bob Halley committed
647
		result = ISC_TRUE;
Bob Halley's avatar
base  
Bob Halley committed
648

Bob Halley's avatar
Bob Halley committed
649
	UNLOCK(&ctx->lock);
Bob Halley's avatar
base  
Bob Halley committed
650

Bob Halley's avatar
Bob Halley committed
651
	return (result);
Bob Halley's avatar
base  
Bob Halley committed
652 653 654
}

/*
655 656
 * 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
657 658 659
 */

void *
660
__isc_mem_allocate(isc_mem_t *ctx, size_t size) {
Bob Halley's avatar
Bob Halley committed
661
	size_info *si;
Bob Halley's avatar
base  
Bob Halley committed
662 663

	size += ALIGNMENT_SIZE;
664
	si = __isc_mem_get(ctx, size);
Bob Halley's avatar
base  
Bob Halley committed
665 666
	if (si == NULL)
		return (NULL);
667
	si->u.size = size;
Bob Halley's avatar
base  
Bob Halley committed
668 669 670
	return (&si[1]);
}

671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691
void *
__isc_mem_allocatedebug(isc_mem_t *ctx, size_t size, const char *file,
			int line) {
	size_info *si;

	si = __isc_mem_allocate(ctx, size);
	if (si == NULL)
		return (NULL);
	fprintf(stderr, "%s:%d: mem_get(%p, %lu) -> %p\n", file, line,
		ctx, (unsigned long)si[-1].u.size, si);
	return (si);
}

void
__isc_mem_free(isc_mem_t *ctx, void *ptr) {
	size_info *si;

	si = &(((size_info *)ptr)[-1]);
	__isc_mem_put(ctx, si, si->u.size);
}

Bob Halley's avatar
base  
Bob Halley committed
692
void
693
__isc_mem_freedebug(isc_mem_t *ctx, void *ptr, const char *file, int line) {
Bob Halley's avatar
Bob Halley committed
694
	size_info *si;
Bob Halley's avatar
base  
Bob Halley committed
695

Bob Halley's avatar
Bob Halley committed
696
	si = &(((size_info *)ptr)[-1]);
697 698 699
	fprintf(stderr, "%s:%d: mem_put(%p, %p, %lu)\n", file, line, 
		ctx, ptr, (unsigned long)si->u.size);
	__isc_mem_put(ctx, si, si->u.size);
Bob Halley's avatar
base  
Bob Halley committed
700 701
}

Bob Halley's avatar
Bob Halley committed
702 703 704 705
/*
 * Other useful things.
 */

Bob Halley's avatar
Bob Halley committed
706
char *
707
__isc_mem_strdup(isc_mem_t *mctx, const char *s) {
Bob Halley's avatar
Bob Halley committed
708 709 710 711
	size_t len;
	char *ns;

	len = strlen(s);
712
	ns = __isc_mem_allocate(mctx, len + 1);
Bob Halley's avatar
Bob Halley committed
713 714 715 716 717 718 719
	if (ns == NULL)
		return (NULL);
	strncpy(ns, s, len + 1);
	
	return (ns);
}

720 721 722 723 724 725 726 727 728 729 730 731 732
char *
__isc_mem_strdupdebug(isc_mem_t *mctx, const char *s, const char *file,
		      int line) {
	char *ptr;
	size_info *si;

	ptr = __isc_mem_strdup(mctx, s);
	si = &(((size_info *)ptr)[-1]);
	fprintf(stderr, "%s:%d: mem_get(%p, %lu) -> %p\n", file, line,
		mctx, (unsigned long)si->u.size, ptr);
	return (ptr);
}

733 734 735 736 737 738 739 740 741 742 743 744
isc_boolean_t
isc_mem_destroy_check(isc_mem_t *mctx, isc_boolean_t flag) {
	isc_boolean_t oldval;

	INSIST(mctx != NULL);

	oldval = mctx->checkfree;
	mctx->checkfree = flag;
	return (oldval);
}


745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772
/*
 * Quotas
 */

void
isc_mem_setquota(isc_mem_t *ctx, size_t quota) {
	REQUIRE(VALID_CONTEXT(ctx));
	LOCK(&ctx->lock);

	ctx->quota = quota;

	UNLOCK(&ctx->lock);
}

size_t
isc_mem_getquota(isc_mem_t *ctx) {
	size_t quota;

	REQUIRE(VALID_CONTEXT(ctx));
	LOCK(&ctx->lock);

	quota = ctx->quota;

	UNLOCK(&ctx->lock);

	return (quota);
}

Bob Halley's avatar
Bob Halley committed
773 774
#ifdef ISC_MEMCLUSTER_LEGACY

Bob Halley's avatar
base  
Bob Halley committed
775 776 777 778
/*
 * Public Legacy.
 */

779
static isc_mem_t *default_context = NULL;
Bob Halley's avatar
Bob Halley committed
780

Bob Halley's avatar
base  
Bob Halley committed
781 782 783 784 785
int
meminit(size_t init_max_size, size_t target_size) {
	/* need default_context lock here */
	if (default_context != NULL)
		return (-1);
Bob Halley's avatar
Bob Halley committed
786
	return (isc_mem_create(init_max_size, target_size, &default_context));
Bob Halley's avatar
base  
Bob Halley committed
787 788
}

789
isc_mem_t *
Bob Halley's avatar
base  
Bob Halley committed
790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816
mem_default_context(void) {
	/* need default_context lock here */
	if (default_context == NULL && meminit(0, 0) == -1)
		return (NULL);
	return (default_context);
}

void *
__memget(size_t size) {
	/* need default_context lock here */
	if (default_context == NULL && meminit(0, 0) == -1)
		return (NULL);
	return (__mem_get(default_context, size));
}

void
__memput(void *mem, size_t size) {
	/* need default_context lock here */
	REQUIRE(default_context != NULL);
	__mem_put(default_context, mem, size);
}

void *
__memget_debug(size_t size, const char *file, int line) {
	void *ptr;
	ptr = __memget(size);
	fprintf(stderr, "%s:%d: memget(%lu) -> %p\n", file, line,
Bob Halley's avatar
Bob Halley committed
817
		(unsigned long)size, ptr);
Bob Halley's avatar
base  
Bob Halley committed
818 819 820 821 822 823
	return (ptr);
}

void
__memput_debug(void *ptr, size_t size, const char *file, int line) {
	fprintf(stderr, "%s:%d: memput(%p, %lu)\n", file, line, 
Bob Halley's avatar
Bob Halley committed
824
		ptr, (unsigned long)size);
Bob Halley's avatar
base  
Bob Halley committed
825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840
	__memput(ptr, size);
}

int
memvalid(void *ptr) {
	/* need default_context lock here */
	REQUIRE(default_context != NULL);
	return (mem_valid(default_context, ptr));
}

void
memstats(FILE *out) {
	/* need default_context lock here */
	REQUIRE(default_context != NULL);
	mem_stats(default_context, out);
}
Bob Halley's avatar
Bob Halley committed
841 842

#endif /* ISC_MEMCLUSTER_LEGACY */
Michael Graff's avatar
Michael Graff committed
843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870


/*
 * Memory pool stuff
 */


#if 0
/*
 * Free all but "n" items from the pool's free list.  If n == 0, all items
 * will be returned to the mctx.
 */
static void
mempool_release(isc_mempool_t *mpctx, unsigned int n)
{
	isc_mem_t *mctx;
	element *item;
	element *next;
	unsigned int count;

	mctx = mpctx->mctx;

	if (mpctx->freecount <= n)
		return;

	INSIST(mpctx->items != NULL);
	item = mpctx->items;
	for (count = 0 ; count < n ; count++) {
Michael Graff's avatar
Michael Graff committed
871
		item = item->next;
Michael Graff's avatar
Michael Graff committed
872 873 874 875 876 877 878 879 880
		INSIST(item != NULL);
	}

	/*
	 * All remaining items are to be freed.  Lock the context once,
	 * free them all, and unlock the context.
	 */
	LOCK(&mctx->lock);
	do {
Michael Graff's avatar
Michael Graff committed
881
		next = item->next;
Michael Graff's avatar
Michael Graff committed
882 883 884 885 886 887 888 889 890 891 892
		mem_putunlocked(mctx, item, mpctx->size);
		INSIST(mpctx->freecount > 0);
		mpctx->freecount--;
		item = next;
	} while (item != NULL);
	UNLOCK(&mctx->lock);
}
#endif

/*
 * Release all items on the free list.  No locking is done, the memory
Michael Graff's avatar
Michael Graff committed
893
 * context must be locked, and the pool if needed.
Michael Graff's avatar
Michael Graff committed
894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910
 */
static void
mempool_releaseall(isc_mempool_t *mpctx)
{
	isc_mem_t *mctx;
	element *item;
	element *next;

	mctx = mpctx->mctx;

	if (mpctx->freecount == 0)
		return;

	INSIST(mpctx->items != NULL);
	item = mpctx->items;

	do {
Michael Graff's avatar
Michael Graff committed
911
		next = item->next;
Mark Andrews's avatar
Mark Andrews committed
912
		mem_putunlocked(mctx, item, mpctx->size);
Michael Graff's avatar
Michael Graff committed
913 914 915 916 917 918 919
		INSIST(mpctx->freecount > 0);
		mpctx->freecount--;
		item = next;
	} while (item != NULL);
}

isc_result_t
Michael Graff's avatar
Michael Graff committed
920
isc_mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp)
Michael Graff's avatar
Michael Graff committed
921 922 923 924
{
	isc_mempool_t *mpctx;

	REQUIRE(VALID_CONTEXT(mctx));
Michael Graff's avatar
Michael Graff committed
925
	REQUIRE(size > 0);
Michael Graff's avatar
Michael Graff committed
926 927 928 929 930 931 932 933
	REQUIRE(mpctxp != NULL && *mpctxp == NULL);

	/*
	 * Allocate space for this pool, initialize values, and if all works
	 * well, attach to the memory context.
	 */
	LOCK(&mctx->lock);

Mark Andrews's avatar
Mark Andrews committed
934
	mpctx = mem_getunlocked(mctx, sizeof(isc_mempool_t));
Michael Graff's avatar
Michael Graff committed
935 936 937 938 939 940
	if (mpctx == NULL) {
		UNLOCK(&mctx->lock);
		return (ISC_R_NOMEMORY);
	}

	mpctx->magic = MEMPOOL_MAGIC;
Michael Graff's avatar
Michael Graff committed
941
	mpctx->lock = NULL;
Michael Graff's avatar
Michael Graff committed
942
	mpctx->mctx = mctx;
Michael Graff's avatar
Michael Graff committed
943
	mpctx->size = size;
Michael Graff's avatar
Michael Graff committed
944 945 946 947 948 949
	mpctx->maxalloc = UINT_MAX;
	mpctx->allocated = 0;
	mpctx->freecount = 0;
	mpctx->freemax = 1;
	mpctx->fillcount = 1;
	mpctx->gets = 0;
Michael Graff's avatar
Michael Graff committed
950 951 952
#if ISC_MEMPOOL_NAMES
	mpctx->name[0] = 0;
#endif
Michael Graff's avatar
Michael Graff committed
953 954 955 956 957 958 959 960 961 962 963
	mpctx->items = NULL;

	*mpctxp = mpctx;

	ISC_LIST_APPEND(mctx->pools, mpctx, link);

	UNLOCK(&mctx->lock);

	return (ISC_R_SUCCESS);
}

Michael Graff's avatar
Michael Graff committed
964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983
void
isc_mempool_setname(isc_mempool_t *mpctx, char *name)
{
	REQUIRE(name != NULL);

#if ISC_MEMPOOL_NAMES
	if (mpctx->lock != NULL)
		LOCK(mpctx->lock);

	memset(mpctx->name, 0, sizeof(mpctx->name));
	strncpy(mpctx->name, name, sizeof(mpctx->name) - 1);

	if (mpctx->lock != NULL)
		UNLOCK(mpctx->lock);
#else
	(void)mpctx;
	(void)name;
#endif
}

Michael Graff's avatar
Michael Graff committed
984 985 986 987 988
void
isc_mempool_destroy(isc_mempool_t **mpctxp)
{
	isc_mempool_t *mpctx;
	isc_mem_t *mctx;
Michael Graff's avatar
Michael Graff committed
989
	isc_mutex_t *lock;
Michael Graff's avatar
Michael Graff committed
990 991 992 993 994 995 996 997

	REQUIRE(mpctxp != NULL);
	mpctx = *mpctxp;
	REQUIRE(VALID_MEMPOOL(mpctx));
	REQUIRE(mpctx->allocated == 0);

	mctx = mpctx->mctx;

Michael Graff's avatar
Michael Graff committed
998 999 1000 1001 1002
	lock = mpctx->lock;

	if (lock != NULL)
		LOCK(lock);

Michael Graff's avatar
Michael Graff committed
1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016
	LOCK(&mctx->lock);

	/*
	 * Return any items on the free list
	 */
	mempool_releaseall(mpctx);

	/*
	 * Remove our linked list entry from the memory context.
	 */
	ISC_LIST_UNLINK(mctx->pools, mpctx, link);
	
	mpctx->magic = 0;

Mark Andrews's avatar
Mark Andrews committed
1017
	mem_putunlocked(mpctx->mctx, mpctx, sizeof(isc_mempool_t));
Michael Graff's avatar
Michael Graff committed
1018 1019 1020

	UNLOCK(&mctx->lock);

Michael Graff's avatar
Michael Graff committed
1021 1022 1023
	if (lock != NULL)
		UNLOCK(lock);

Michael Graff's avatar
Michael Graff committed
1024 1025 1026
	*mpctxp = NULL;
}

Michael Graff's avatar
Michael Graff committed
1027 1028 1029 1030 1031 1032 1033 1034 1035 1036
void
isc_mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock)
{
	REQUIRE(VALID_MEMPOOL(mpctx));
	REQUIRE(mpctx->lock == NULL);
	REQUIRE(lock != NULL);

	mpctx->lock = lock;
}

Michael Graff's avatar
Michael Graff committed
1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047
void *
__isc_mempool_get(isc_mempool_t *mpctx)
{
	element *item;
	isc_mem_t *mctx;
	unsigned int i;

	REQUIRE(VALID_MEMPOOL(mpctx));

	mctx = mpctx->mctx;

Michael Graff's avatar
Michael Graff committed
1048 1049 1050
	if (mpctx->lock != NULL)
		LOCK(mpctx->lock);

Michael Graff's avatar
Michael Graff committed
1051 1052 1053
	/*
	 * Don't let the caller go over quota
	 */
Michael Graff's avatar
Michael Graff committed
1054 1055 1056 1057
	if (mpctx->allocated >= mpctx->maxalloc) {
		item = NULL;
		goto out;
	}
Michael Graff's avatar
Michael Graff committed
1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068

	/*
	 * if we have a free list item, return the first here
	 */
	item = mpctx->items;
	if (item != NULL) {
		mpctx->items = item->next;
		INSIST(mpctx->freecount > 0);
		mpctx->freecount--;
		mpctx->gets++;
		mpctx->allocated++;
Michael Graff's avatar
Michael Graff committed
1069
		goto out;
Michael Graff's avatar
Michael Graff committed
1070 1071 1072 1073 1074 1075 1076 1077
	}

	/*
	 * We need to dip into the well.  Lock the memory context here and
	 * fill up our free list.
	 */
	LOCK(&mctx->lock);
	for (i = 0 ; i < mpctx->fillcount ; i++) {
Mark Andrews's avatar
Mark Andrews committed
1078
		item = mem_getunlocked(mctx, mpctx->size);
Michael Graff's avatar
Michael Graff committed
1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091
		if (item == NULL)
			break;
		item->next = mpctx->items;
		mpctx->items = item;
		mpctx->freecount++;
	}
	UNLOCK(&mctx->lock);

	/*
	 * If we didn't get any items, return NULL.
	 */
	item = mpctx->items;
	if (item == NULL)
Michael Graff's avatar
Michael Graff committed
1092
		goto out;
Michael Graff's avatar
Michael Graff committed
1093 1094 1095 1096 1097

	mpctx->items = item->next;
	mpctx->freecount--;
	mpctx->gets++;
	mpctx->allocated++;
Michael Graff's avatar
Michael Graff committed
1098 1099 1100 1101 1102

 out:
	if (mpctx->lock != NULL)
		UNLOCK(mpctx->lock);

Michael Graff's avatar
Michael Graff committed
1103 1104 1105 1106 1107 1108 1109 1110 1111 1112