216 lines
4.4 KiB
C
Executable File
216 lines
4.4 KiB
C
Executable File
/* mempool.c
|
|
**
|
|
** A simple fast memory allocation package.
|
|
**
|
|
** By Steve Hill in Graphics Gems III, David Kirk (ed.),
|
|
** Academic Press, Boston, MA, 1992
|
|
**
|
|
** Modified by Lew Rossman, 8/13/94.
|
|
**
|
|
** AllocInit() - create an alloc pool, returns the old pool handle
|
|
** Alloc() - allocate memory
|
|
** AllocReset() - reset the current pool
|
|
** AllocSetPool() - set the current pool
|
|
** AllocFree() - free the memory used by the current pool.
|
|
**
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#ifndef __APPLE__
|
|
#include <malloc.h>
|
|
#endif
|
|
#include "mempool.h"
|
|
|
|
#ifdef _MSC_VER
|
|
#define THREAD_LOCAL __declspec(thread)
|
|
#else
|
|
#define THREAD_LOCAL __thread
|
|
#endif
|
|
|
|
/*
|
|
** ALLOC_BLOCK_SIZE - adjust this size to suit your installation - it
|
|
** should be reasonably large otherwise you will be mallocing a lot.
|
|
*/
|
|
|
|
#define ALLOC_BLOCK_SIZE 64000 /*(62*1024)*/
|
|
|
|
/*
|
|
** alloc_hdr_t - Header for each block of memory.
|
|
*/
|
|
|
|
typedef struct alloc_hdr_s
|
|
{
|
|
struct alloc_hdr_s *next; /* Next Block */
|
|
char *block, /* Start of block */
|
|
*free, /* Next free in block */
|
|
*end; /* block + block size */
|
|
} alloc_hdr_t;
|
|
|
|
/*
|
|
** alloc_root_t - Header for the whole pool.
|
|
*/
|
|
|
|
typedef struct alloc_root_s
|
|
{
|
|
alloc_hdr_t *first, /* First header in pool */
|
|
*current; /* Current header */
|
|
} alloc_root_t;
|
|
|
|
/*
|
|
** root - Pointer to the current pool.
|
|
*/
|
|
|
|
THREAD_LOCAL alloc_root_t *root;
|
|
|
|
|
|
/*
|
|
** AllocHdr()
|
|
**
|
|
** Private routine to allocate a header and memory block.
|
|
*/
|
|
|
|
static alloc_hdr_t *AllocHdr(void);
|
|
|
|
static alloc_hdr_t * AllocHdr()
|
|
{
|
|
alloc_hdr_t *hdr;
|
|
char *block;
|
|
|
|
block = (char *) malloc(ALLOC_BLOCK_SIZE);
|
|
hdr = (alloc_hdr_t *) malloc(sizeof(alloc_hdr_t));
|
|
|
|
if (hdr == NULL || block == NULL) return(NULL);
|
|
hdr->block = block;
|
|
hdr->free = block;
|
|
hdr->next = NULL;
|
|
hdr->end = block + ALLOC_BLOCK_SIZE;
|
|
|
|
return(hdr);
|
|
}
|
|
|
|
|
|
/*
|
|
** AllocInit()
|
|
**
|
|
** Create a new memory pool with one block.
|
|
** Returns pointer to the new pool.
|
|
*/
|
|
|
|
DLLEXPORT alloc_handle_t * AllocInit()
|
|
{
|
|
alloc_handle_t *newpool;
|
|
root = (alloc_root_t *) malloc(sizeof(alloc_root_t));
|
|
if (root == NULL) {
|
|
return(NULL);
|
|
}
|
|
if ( (root->first = AllocHdr()) == NULL) {
|
|
return(NULL);
|
|
}
|
|
root->current = root->first;
|
|
newpool = (alloc_handle_t *) root;
|
|
return(newpool);
|
|
}
|
|
|
|
|
|
/*
|
|
** Alloc()
|
|
**
|
|
** Use as a direct replacement for malloc(). Allocates
|
|
** memory from the current pool.
|
|
*/
|
|
|
|
DLLEXPORT char *Alloc(long size)
|
|
{
|
|
alloc_hdr_t *hdr = root->current;
|
|
char *ptr;
|
|
|
|
/*
|
|
** Align to 4 byte boundary - should be ok for most machines.
|
|
** Change this if your machine has weird alignment requirements.
|
|
*/
|
|
size = (size + 3) & 0xfffffffc;
|
|
|
|
ptr = hdr->free;
|
|
hdr->free += size;
|
|
|
|
/* Check if the current block is exhausted. */
|
|
|
|
if (hdr->free >= hdr->end)
|
|
{
|
|
/* Is the next block already allocated? */
|
|
|
|
if (hdr->next != NULL)
|
|
{
|
|
/* re-use block */
|
|
hdr->next->free = hdr->next->block;
|
|
root->current = hdr->next;
|
|
}
|
|
else
|
|
{
|
|
/* extend the pool with a new block */
|
|
if ( (hdr->next = AllocHdr()) == NULL) return(NULL);
|
|
root->current = hdr->next;
|
|
}
|
|
|
|
/* set ptr to the first location in the next block */
|
|
ptr = root->current->free;
|
|
root->current->free += size;
|
|
}
|
|
|
|
/* Return pointer to allocated memory. */
|
|
|
|
return(ptr);
|
|
}
|
|
|
|
|
|
/*
|
|
** AllocSetPool()
|
|
**
|
|
** Change the current pool. Return the old pool.
|
|
*/
|
|
|
|
DLLEXPORT alloc_handle_t * AllocSetPool(alloc_handle_t *newpool)
|
|
{
|
|
alloc_handle_t *old = (alloc_handle_t *) root;
|
|
root = (alloc_root_t *) newpool;
|
|
return(old);
|
|
}
|
|
|
|
|
|
/*
|
|
** AllocReset()
|
|
**
|
|
** Reset the current pool for re-use. No memory is freed,
|
|
** so this is very fast.
|
|
*/
|
|
|
|
DLLEXPORT void AllocReset()
|
|
{
|
|
root->current = root->first;
|
|
root->current->free = root->current->block;
|
|
}
|
|
|
|
|
|
/*
|
|
** AllocFreePool()
|
|
**
|
|
** Free the memory used by the current pool.
|
|
** Don't use where AllocReset() could be used.
|
|
*/
|
|
|
|
DLLEXPORT void AllocFreePool()
|
|
{
|
|
alloc_hdr_t *tmp,
|
|
*hdr = root->first;
|
|
|
|
while (hdr != NULL)
|
|
{
|
|
tmp = hdr->next;
|
|
free((char *) hdr->block);
|
|
free((char *) hdr);
|
|
hdr = tmp;
|
|
}
|
|
free((char *) root);
|
|
root = NULL;
|
|
}
|