blob: 8b372a678ecf09005ef7443da69bb8498b54add4 [file] [log] [blame]
/* -----------------------------------------------------------------------------
* This file is part of SWIG, which is licensed as a whole under version 3
* (or any later version) of the GNU General Public License. Some additional
* terms also apply to certain portions of SWIG. The full details of the SWIG
* license and copyrights can be found in the LICENSE and COPYRIGHT files
* included with the SWIG source code as distributed by the SWIG developers
* and at https://www.swig.org/legal.html.
*
* memory.c
*
* This file implements all of DOH's memory management including allocation
* of objects and checking of objects.
* ----------------------------------------------------------------------------- */
#include "dohint.h"
#include <stdio.h>
#include <stdlib.h>
#ifndef DOH_POOL_SIZE
#define DOH_POOL_SIZE 4194304
#endif
/* Checks stale DOH object use - will use a lot more memory as pool memory is not re-used. */
/*
#define DOH_DEBUG_MEMORY_POOLS
*/
static int PoolSize = DOH_POOL_SIZE;
DOH *DohNone = 0; /* The DOH None object */
typedef struct pool {
DohBase *ptr; /* Start of pool */
int len; /* Length of pool */
int blen; /* Byte length of pool */
int current; /* Current position for next allocation */
char *pbeg; /* Beg of pool */
char *pend; /* End of pool */
struct pool *next; /* Next pool */
} Pool;
static DohBase *FreeList = 0; /* List of free objects */
static Pool *Pools = 0;
static int pools_initialized = 0;
/* ----------------------------------------------------------------------
* CreatePool() - Create a new memory pool
* ---------------------------------------------------------------------- */
static void CreatePool(void) {
Pool *p = 0;
p = (Pool *) DohMalloc(sizeof(Pool));
p->ptr = (DohBase *) DohCalloc(PoolSize, sizeof(DohBase));
p->len = PoolSize;
p->blen = PoolSize * sizeof(DohBase);
p->current = 0;
p->pbeg = ((char *) p->ptr);
p->pend = p->pbeg + p->blen;
p->next = Pools;
Pools = p;
}
/* ----------------------------------------------------------------------
* InitPools() - Initialize the memory allocator
* ---------------------------------------------------------------------- */
static void InitPools(void) {
if (pools_initialized)
return;
CreatePool(); /* Create initial pool */
pools_initialized = 1;
DohNone = NewVoid(0, 0); /* Create the None object */
DohIntern(DohNone);
}
/* ----------------------------------------------------------------------
* DohCheck()
*
* Returns 1 if an arbitrary pointer is a DOH object.
* ---------------------------------------------------------------------- */
int DohCheck(const DOH *ptr) {
Pool *p = Pools;
char *cptr = (char *) ptr;
while (p) {
if ((cptr >= p->pbeg) && (cptr < p->pend)) {
#ifdef DOH_DEBUG_MEMORY_POOLS
DohBase *b = (DohBase *) ptr;
int DOH_object_already_deleted = b->type == 0;
assert(!DOH_object_already_deleted);
#endif
return 1;
}
/*
pptr = (char *) p->ptr;
if ((cptr >= pptr) && (cptr < (pptr+(p->current*sizeof(DohBase))))) return 1; */
p = p->next;
}
return 0;
}
/* -----------------------------------------------------------------------------
* DohIntern()
* ----------------------------------------------------------------------------- */
void DohIntern(DOH *obj) {
DohBase *b = (DohBase *) obj;
b->flag_intern = 1;
}
/* ----------------------------------------------------------------------
* DohObjMalloc()
*
* Allocate memory for a new object.
* ---------------------------------------------------------------------- */
DOH *DohObjMalloc(DohObjInfo *type, void *data) {
DohBase *obj;
if (!pools_initialized)
InitPools();
#ifndef DOH_DEBUG_MEMORY_POOLS
if (FreeList) {
obj = FreeList;
FreeList = (DohBase *) obj->data;
} else {
#endif
while (Pools->current == Pools->len) {
CreatePool();
}
obj = Pools->ptr + Pools->current;
++Pools->current;
#ifndef DOH_DEBUG_MEMORY_POOLS
}
#endif
obj->type = type;
obj->data = data;
obj->meta = 0;
obj->refcount = 1;
obj->flag_intern = 0;
obj->flag_marked = 0;
obj->flag_user = 0;
obj->flag_usermark = 0;
return (DOH *) obj;
}
/* ----------------------------------------------------------------------
* DohObjFree() - Free a DOH object
* ---------------------------------------------------------------------- */
void DohObjFree(DOH *ptr) {
DohBase *b, *meta;
b = (DohBase *) ptr;
if (b->flag_intern)
return;
meta = (DohBase *) b->meta;
b->data = (void *) FreeList;
b->meta = 0;
b->type = 0;
b->refcount = 0;
FreeList = b;
if (meta) {
Delete(meta);
}
}
/* ----------------------------------------------------------------------
* DohMemoryDebug()
*
* Display memory usage statistics
* ---------------------------------------------------------------------- */
void DohMemoryDebug(void) {
extern DohObjInfo DohStringType;
extern DohObjInfo DohListType;
extern DohObjInfo DohHashType;
Pool *p;
int totsize = 0;
int totused = 0;
int totfree = 0;
int numstring = 0;
int numlist = 0;
int numhash = 0;
printf("Memory statistics:\n\n");
printf("Pools:\n");
p = Pools;
while (p) {
/* Calculate number of used, free items */
int i;
int nused = 0, nfree = 0;
for (i = 0; i < p->len; i++) {
if (p->ptr[i].refcount <= 0)
nfree++;
else {
nused++;
if (p->ptr[i].type == &DohStringType)
numstring++;
else if (p->ptr[i].type == &DohListType)
numlist++;
else if (p->ptr[i].type == &DohHashType)
numhash++;
}
}
printf(" Pool %8p: size = %10d. used = %10d. free = %10d\n", (void *) p, p->len, nused, nfree);
totsize += p->len;
totused += nused;
totfree += nfree;
p = p->next;
}
printf("\n Total: size = %10d, used = %10d, free = %10d\n", totsize, totused, totfree);
printf("\nObject types\n");
printf(" Strings : %d\n", numstring);
printf(" Lists : %d\n", numlist);
printf(" Hashes : %d\n", numhash);
#if 0
p = Pools;
while (p) {
int i;
for (i = 0; i < p->len; i++) {
if (p->ptr[i].refcount > 0) {
if (p->ptr[i].type == &DohStringType) {
Printf(stdout, "%s\n", p->ptr + i);
}
}
}
p = p->next;
}
#endif
}
/* Function to call instead of exit(). */
static void (*doh_exit_handler)(int) = NULL;
void DohSetExitHandler(void (*new_handler)(int)) {
doh_exit_handler = new_handler;
}
void DohExit(int status) {
if (doh_exit_handler) {
void (*handler)(int) = doh_exit_handler;
/* Unset the handler to avoid infinite loops if it tries to do something
* which calls DohExit() (e.g. calling Malloc() and that failing).
*/
doh_exit_handler = NULL;
handler(status);
}
doh_internal_exit(status);
}
static void allocation_failed(size_t n, size_t size) {
/* Report and exit as directly as possible to try to avoid further issues due
* to lack of memory. */
if (n == 1) {
#if defined __STDC_VERSION__ && __STDC_VERSION__-0 >= 199901L
fprintf(stderr, "Failed to allocate %zu bytes\n", size);
#else
fprintf(stderr, "Failed to allocate %lu bytes\n", (unsigned long)size);
#endif
} else {
#if defined __STDC_VERSION__ && __STDC_VERSION__-0 >= 199901L
fprintf(stderr, "Failed to allocate %zu*%zu bytes\n", n, size);
#else
fprintf(stderr, "Failed to allocate %lu*%lu bytes\n", (unsigned long)n, (unsigned long)size);
#endif
}
DohExit(EXIT_FAILURE);
}
void *DohMalloc(size_t size) {
void *p = doh_internal_malloc(size);
if (!p) allocation_failed(1, size);
return p;
}
void *DohRealloc(void *ptr, size_t size) {
void *p = doh_internal_realloc(ptr, size);
if (!p) allocation_failed(1, size);
return p;
}
void *DohCalloc(size_t n, size_t size) {
void *p = doh_internal_calloc(n, size);
if (!p) allocation_failed(n, size);
return p;
}