mem.c revision b622f2b07bb545749d8dc131777aa9038d587560
/*
* Copyright (C) 1997, 1998, 1999 Internet Software Consortium.
*
* 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.
*
* 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.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <limits.h>
#include <isc/assertions.h>
#ifndef ISC_SINGLETHREADED
#include "util.h"
#else
#define LOCK(l)
#define UNLOCK(l)
#endif
#ifndef ISC_MEM_FILL
/*
* XXXMPA
* We want this on during development to catch:
* 1. some reference after free bugs.
* 2. some failure to initalise bugs.
*/
#define ISC_MEM_FILL 1
#endif
#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
/*
* Constants.
*/
#define DEF_MAX_SIZE 1100
#define DEF_MEM_TARGET 4096
#define ALIGNMENT_SIZE 8
#define TABLE_INCREMENT 1024
/*
* Types.
*/
typedef struct {
void * next;
} element;
typedef struct {
/*
* This structure must be ALIGNMENT_SIZE bytes.
*/
union {
char bytes[ALIGNMENT_SIZE];
} u;
} size_info;
struct stats {
unsigned long gets;
unsigned long totalgets;
unsigned long blocks;
unsigned long freefrags;
};
struct isc_mem {
unsigned int magic;
void * arg;
unsigned char ** basic_table;
unsigned int basic_table_count;
unsigned int basic_table_size;
unsigned char * lowest;
unsigned char * highest;
};
struct isc_mempool {
/* always unlocked */
unsigned int magic; /* magic number */
/* locked via the memory context's lock */
/* optionally locked from here down */
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. */
#endif
};
/*
* Forward.
*/
/*
* Private Inline-able.
*/
static inline size_t
int temp;
/*
* Round up the result in order to get a size big
* enough to satisfy the request and be aligned on ALIGNMENT_SIZE
* byte boundaries.
*/
}
/*
* Private.
*/
static void *
(void)arg;
}
static void
(void)arg;
}
/*
* Public.
*/
{
return (ISC_R_NOMEMORY);
if (init_max_size == 0)
else
if (target_size == 0)
else
return (ISC_R_NOMEMORY);
}
return (ISC_R_NOMEMORY);
}
ctx->basic_table_count = 0;
ctx->basic_table_size = 0;
"isc_mutex_init() failed");
return (ISC_R_UNEXPECTED);
}
return (ISC_R_SUCCESS);
}
{
ctxp));
}
void
unsigned int i;
}
#if 0 /* XXX brister debugging */
for (i = 0; i < ctx->basic_table_count; i++)
#endif
for (i = 0; i < ctx->basic_table_count; i++)
}
if (result != ISC_R_SUCCESS)
return (result);
}
static void
void *new;
unsigned char **table;
unsigned int table_size;
int i;
/* Require: we hold the context lock. */
/*
* Did we hit the quota for this context?
*/
return;
table_size * sizeof (unsigned char *));
return;
if (ctx->basic_table_size != 0) {
sizeof (unsigned char *));
}
}
return;
ctx->basic_table_count++;
for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) {
}
/*
* curr is now pointing at the last block in the
* array.
*/
}
void *
{
void *ret;
return (ret);
}
static inline void *
{
void *ret;
/* memget() was called on something beyond our upper limit. */
goto done;
}
/*
* If we don't set new_size to size, then the
* ISC_MEM_FILL code might write over bytes we
* don't own.
*/
}
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.
*/
int i, frags;
void *new;
goto done;
}
}
/* Set up a linked-list of blocks of size "new_size". */
for (i = 0; i < (frags - 1); i++) {
}
/* curr is now pointing at the last block in the array. */
}
/* The free list uses the "rounded-up" size "new_size": */
/*
* 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.
*/
done:
#if ISC_MEM_FILL
#endif
return (ret);
}
void
{
}
static inline void
{
/* memput() called on something beyond our upper limit */
#if ISC_MEM_FILL
#endif
return;
}
#if ISC_MEM_FILL
#endif
/* The free list uses the "rounded-up" size "new_size": */
/*
* 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.
*/
}
void *
void *ptr;
return (ptr);
}
void
int line)
{
}
/*
* Print the stats[] on the stream "out" with suitable formatting.
*/
void
{
size_t i;
const struct stats *s;
const isc_mempool_t *pool;
continue;
if (s->blocks != 0)
}
}
/*
* 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.
*/
"name", "size", "maxalloc", "allocated", "freecount",
"freemax", "fillcount", "gets", "L");
}
}
}
return (result);
}
/*
* Replacements for malloc() and free().
*/
void *
size += ALIGNMENT_SIZE;
return (NULL);
return (&si[1]);
}
void
}
/*
* Other useful things.
*/
char *
char *ns;
return (NULL);
return (ns);
}
return (oldval);
}
/*
* Quotas
*/
void
}
return (quota);
}
#ifdef ISC_MEMCLUSTER_LEGACY
/*
* Public Legacy.
*/
int
/* need default_context lock here */
if (default_context != NULL)
return (-1);
}
mem_default_context(void) {
/* need default_context lock here */
return (NULL);
return (default_context);
}
void *
/* need default_context lock here */
return (NULL);
}
void
/* need default_context lock here */
}
void *
void *ptr;
return (ptr);
}
void
}
int
/* need default_context lock here */
}
void
/* need default_context lock here */
}
#endif /* ISC_MEMCLUSTER_LEGACY */
/*
* 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
{
unsigned int count;
return;
}
/*
* All remaining items are to be freed. Lock the context once,
* free them all, and unlock the context.
*/
do {
}
#endif
/*
* Release all items on the free list. No locking is done, the memory
* context must be locked, and the pool if needed.
*/
static void
{
return;
do {
}
{
/*
* Allocate space for this pool, initialize values, and if all works
* well, attach to the memory context.
*/
return (ISC_R_NOMEMORY);
}
#endif
return (ISC_R_SUCCESS);
}
void
{
#else
(void)mpctx;
(void)name;
#endif
}
void
{
/*
* Return any items on the free list
*/
/*
* Remove our linked list entry from the memory context.
*/
}
void
{
}
void *
{
unsigned int i;
/*
* Don't let the caller go over quota
*/
goto out;
}
/*
* if we have a free list item, return the first here
*/
goto out;
}
/*
* We need to dip into the well. Lock the memory context here and
* fill up our free list.
*/
break;
}
/*
* If we didn't get any items, return NULL.
*/
goto out;
out:
return (item);
}
void
{
/*
* If our free list is full, return this to the mctx directly.
*/
return;
}
/*
* Otherwise, attach it to our free list and bump the counter.
*/
}
void *
{
void *ptr;
return (ptr);
}
void
{
}
/*
* Quotas
*/
void
{
}
unsigned int
{
unsigned int freemax;
return (freemax);
}
unsigned int
{
unsigned int freecount;
return (freecount);
}
void
{
}
unsigned int
{
unsigned int maxalloc;
return (maxalloc);
}
unsigned int
{
unsigned int allocated;
return (allocated);
}
void
{
}
unsigned int
{
unsigned int fillcount;
return (fillcount);
}