mem.c revision 36bcb04af27e050ddc04b2ff37dbeafc84538fd4
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer * Copyright (C) 1997, 1998, 1999, 2000 Internet Software Consortium.
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer * Permission to use, copy, modify, and distribute this software for any
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer * purpose with or without fee is hereby granted, provided that the above
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer * copyright notice and this permission notice appear in all copies.
15a44745412679c30a6d022733925af70a38b715David Lawrence * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
15a44745412679c30a6d022733925af70a38b715David Lawrence * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
15a44745412679c30a6d022733925af70a38b715David Lawrence * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
15a44745412679c30a6d022733925af70a38b715David Lawrence * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
15a44745412679c30a6d022733925af70a38b715David Lawrence * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15a44745412679c30a6d022733925af70a38b715David Lawrence * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
15a44745412679c30a6d022733925af70a38b715David Lawrence * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer * We want this on during development to catch:
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer * 1. some reference after free bugs.
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer * 2. some failure to initalise bugs.
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer * During development it is nice to be able to see names associated with
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer * memory pools.
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyertypedef struct {
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer * This structure must be ALIGNMENT_SIZE bytes.
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer unsigned long gets;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer unsigned long totalgets;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer unsigned long blocks;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer unsigned long freefrags;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer#define VALID_CONTEXT(c) ((c) != NULL && (c)->magic == MEM_MAGIC)
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer unsigned int magic;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer unsigned char ** basic_table;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer unsigned char * lowest;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer unsigned char * highest;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer#define VALID_MEMPOOL(c) ((c) != NULL && (c)->magic == MEMPOOL_MAGIC)
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer /* always unlocked */
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer /* locked via the memory context's lock */
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer ISC_LINK(isc_mempool_t) link; /* next pool in this mem context */
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer /* optionally locked from here down */
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer size_t size; /* size of each item on this pool */
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer unsigned int maxalloc; /* max number of items allowed */
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer unsigned int allocated; /* # of items currently given out */
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer unsigned int freecount; /* # of items on reserved list */
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer unsigned int freemax; /* # of items allowed on free list */
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer unsigned int fillcount; /* # of items to fetch on each fill */
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer /* Stats only. */
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer unsigned int gets; /* # of requests to this pool */
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer /* Debugging only. */
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer char name[16]; /* printed name in stats reports */
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer * Private Inline-able.
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer * Round up the result in order to get a size big
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer * enough to satisfy the request and be aligned on ALIGNMENT_SIZE
38cf6e52ce4b33795713388824b69d78e430b115Michael Sawyer * byte boundaries.
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyerstatic inline void
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyersplit(isc_mem_t *ctx, size_t size, size_t new_size) {
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer unsigned char *ptr;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer * Unlink a frag of size 'size'.
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer ctx->freelists[size] = ctx->freelists[size]->next;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer * Create a frag of size 'new_size' and link it in.
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer ((element *)ptr)->next = ctx->freelists[new_size];
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer * Create a frag of size 'size - new_size' and link it in.
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer ((element *)ptr)->next = ctx->freelists[remaining_size];
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer ctx->freelists[remaining_size] = (element *)ptr;
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence * Try splitting a frag that's at least twice as big as the size
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer * No luck. Try splitting any frag bigger than the size we need.
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer unsigned char **table;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer /* Require: we hold the context lock. */
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer * Did we hit the quota for this context?
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer increment = NUM_BASIC_BLOCKS * ctx->mem_target;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer if (ctx->quota != 0 && ctx->total + increment > ctx->quota)
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer INSIST(ctx->basic_table_count <= ctx->basic_table_size);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer if (ctx->basic_table_count == ctx->basic_table_size) {
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer table_size = ctx->basic_table_size + TABLE_INCREMENT;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer table_size * sizeof (unsigned char *));
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer sizeof (unsigned char *));
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer new = (ctx->memalloc)(ctx->arg, NUM_BASIC_BLOCKS * ctx->mem_target);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer ctx->basic_table[ctx->basic_table_count] = new;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) {
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer * curr is now pointing at the last block in the
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer last = first + NUM_BASIC_BLOCKS * ctx->mem_target - 1;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer if (first < ctx->lowest || ctx->lowest == NULL)
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer * Try to get more fragments by chopping up a basic block.
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer * We can't get more memory from the OS, or we've
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer * hit the quota for this context.
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer * XXXRTH "At quota" notification here.
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer * Maybe we can split one of our existing
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer * list frags.
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer * Set up a linked-list of blocks of size
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer * "new_size".
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer * curr is now pointing at the last block in the
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyerstatic inline void *
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyermem_getunlocked(isc_mem_t *ctx, size_t size) {
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer if (size >= ctx->max_size || new_size >= ctx->max_size) {
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer * memget() was called on something beyond our upper limit.
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer if (ctx->quota != 0 && ctx->total + size > ctx->quota) {
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence * If we don't set new_size to size, then the
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer * ISC_MEM_FILL code might write over bytes we
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer * If there are no blocks in the free list for this size, get a chunk
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer * of memory and then break it up into "new_size"-sized blocks, adding
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer * them to the free list.
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer if (ctx->freelists[new_size] == NULL && !more_frags(ctx, new_size))
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer * The free list uses the "rounded-up" size "new_size".
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer ctx->freelists[new_size] = ctx->freelists[new_size]->next;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer * The stats[] uses the _actual_ "size" requested by the
a5ed46c9fd270775c39770bfd0250a52d374ebf2Michael Sawyer * caller, with the caveat (in the code above) that "size" >= the
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer * max. size (max_size) ends up getting recorded as a call to
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer memset(ret, 0xbe, new_size); /* Mnemonic for "beef". */
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyerstatic inline void
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyermem_putunlocked(isc_mem_t *ctx, void *mem, size_t size) {
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer if (size == ctx->max_size || new_size >= ctx->max_size) {
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer * memput() called on something beyond our upper limit.
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer memset(mem, 0xde, size); /* Mnemonic for "dead". */
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer memset(mem, 0xde, new_size); /* Mnemonic for "dead". */
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer * The free list uses the "rounded-up" size "new_size".
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer ((element *)mem)->next = ctx->freelists[new_size];
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer * The stats[] uses the _actual_ "size" requested by the
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer * caller, with the caveat (in the code above) that "size" >= the
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer * max. size (max_size) ends up getting recorded as a call to
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyerisc_mem_createx(size_t init_max_size, size_t target_size,
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer ctx->freelists = (memalloc)(arg, ctx->max_size * sizeof (element *));
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer memset(ctx->stats, 0, (ctx->max_size + 1) * sizeof (struct stats));
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer if (isc_mutex_init(&ctx->lock) != ISC_R_SUCCESS) {
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer "isc_mutex_init() failed");
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyerisc_mem_create(size_t init_max_size, size_t target_size,
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer return (isc_mem_createx(init_max_size, target_size,
d821f1cd7e97552401296e880e7518c98c9ebea1Michael Sawyer unsigned int i;
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer#if 0 /* XXX brister debugging */
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer (ctx->memfree)(ctx->arg, ctx->basic_table[i]);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyerisc_mem_attach(isc_mem_t *source, isc_mem_t **targetp) {
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer REQUIRE(targetp != NULL && *targetp == NULL);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer * This routine provides legacy support for callers who use mctxs
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyerisc_mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event) {
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer res = isc_ondestroy_register(&ctx->ondestroy, task, event);
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer#if ISC_MEM_FILL != 0 && ISC_MEM_CHECKOVERRUN != 0
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyerstatic inline void
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyercheck_overrun(void *mem, size_t size, size_t new_size) {
38cf6e52ce4b33795713388824b69d78e430b115Michael Sawyer unsigned char *cp;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyerisc__mem_put(isc_mem_t *ctx, void *mem, size_t size) {
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyerisc__mem_getdebug(isc_mem_t *ctx, size_t size, const char *file, int line) {
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer fprintf(stderr, "%s:%d: mem_get(%p, %lu) -> %p\n", file, line,
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyerisc__mem_putdebug(isc_mem_t *ctx, void *ptr, size_t size, const char *file,
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer fprintf(stderr, "%s:%d: mem_put(%p, %p, %lu)\n", file, line,
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer for (i = 0; i < ctx->max_size; i += ALIGNMENT_SIZE) {
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer * Print the stats[] on the stream "out" with suitable formatting.
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer const struct stats *s;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer * Note that since a pool can be locked now, these stats might be
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer * somewhat off if the pool is in active use at the time the stats
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer * are dumped. The link fields are protected by the isc_mem_t's
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer * lock, however, so walking this list and extracting integers from
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer * stats fields is always safe.
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer fprintf(out, "%15s %10s %10s %10s %10s %10s %10s %10s %1s\n",
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer "name", "size", "maxalloc", "allocated", "freecount",
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer fprintf(out, "%15s %10u %10u %10u %10u %10u %10u %10u %s\n",
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer pool->allocated, pool->freecount, pool->freemax,
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer if (ctx->lowest != NULL && cp >= ctx->lowest && cp <= ctx->highest)
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer * Replacements for malloc() and free() -- they implicitly remember the
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence * size of the object allocated (with some additional overhead).
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyerisc__mem_allocate(isc_mem_t *ctx, size_t size) {
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyerisc__mem_allocatedebug(isc_mem_t *ctx, size_t size, const char *file,
ad7bb5bff3e796f5648835bf87a203d23d8319e4David Lawrence fprintf(stderr, "%s:%d: mem_get(%p, %lu) -> %p\n", file, line,
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyerisc__mem_freedebug(isc_mem_t *ctx, void *ptr, const char *file, int line) {
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer fprintf(stderr, "%s:%d: mem_put(%p, %p, %lu)\n", file, line,
9fe3676b8490319aa65182f2072cbf5086097979Michael Sawyer * Other useful things.
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyerisc__mem_strdup(isc_mem_t *mctx, const char *s) {
db8b100cae62de849ecf4ba9ad3be811fb375b53Michael Sawyerisc__mem_strdupdebug(isc_mem_t *mctx, const char *s, const char *file,
return (ptr);
return (quota);
return (inuse);
#ifdef ISC_MEMCLUSTER_LEGACY
mem_default_context(void) {
return (NULL);
return (default_context);
return (NULL);
void *ptr;
if (isc_mem_debugging)
return (ptr);
if (isc_mem_debugging)
unsigned int count;
return (ISC_R_NOMEMORY);
return (ISC_R_SUCCESS);
goto out;
goto out;
goto out;
out:
return (item);
void *ptr;
if (isc_mem_debugging)
return (ptr);
int line)
if (isc_mem_debugging)
unsigned int freemax;
return (freemax);
unsigned int freecount;
return (freecount);
unsigned int maxalloc;
return (maxalloc);
unsigned int allocated;
return (allocated);
unsigned int fillcount;
return (fillcount);