/* File: memsubs.c
* Author: Richard Durbin (rd@sanger.ac.uk)
* Copyright (C) J Thierry-Mieg and R Durbin, 1998
*-------------------------------------------------------------------
* This file is part of the ACEDB genome database package, written by
* Richard Durbin (MRC LMB, UK) rd@sanger.ac.uk, and
* Jean Thierry-Mieg (CRBM du CNRS, France) mieg@kaa.cnrs-mop.fr
*
* Description:
* Exported functions:
* HISTORY:
* Last edited: Dec 4 11:24 1998 (fw)
* Created: Thu Aug 20 16:54:55 1998 (rd)
*-------------------------------------------------------------------
*/
/* define MALLOC_CHECK here to check mallocs - also in regular.h */
#include "regular.h"
#if defined(NEXT) || defined(HP) || defined(MACINTOSH)
extern void* malloc(mysize_t size) ;
#elif !defined(WIN32) && !defined(DARWIN)
#include <malloc.h> /* normal machines */
#endif
/********** primary type definition **************/
typedef struct _STORE_HANDLE_STRUCT {
STORE_HANDLE next ; /* for chaining together on Handles */
STORE_HANDLE back ; /* to unchain */
void (*final)(void*) ; /* finalisation routine */
int size ; /* of user memory to follow */
#ifdef MALLOC_CHECK
int check1 ; /* set to known value */
#endif
} STORE_HANDLE_STRUCT ;
/*********************************************************************/
/********** memory allocation - messalloc() and handles *************/
static int numMessAlloc = 0 ;
static int totMessAlloc = 0 ;
/* Calculate to size of an STORE_HANDLE_STRUCT rounded to the nearest upward
multiple of sizeof(double). This avoids alignment problems when
we put an STORE_HANDLE_STRUCT at the start of a memory block */
#define STORE_OFFSET ((((sizeof(STORE_HANDLE_STRUCT)-1)/MALLOC_ALIGNMENT)+1)\
* MALLOC_ALIGNMENT)
/* macros to convert between a void* and the corresponding STORE_HANDLE */
#define toAllocUnit(x) (STORE_HANDLE) ((char*)(x) - STORE_OFFSET)
#define toMemPtr(unit)((void*)((char*)(unit) + STORE_OFFSET))
#ifdef MALLOC_CHECK
BOOL handlesInitialised = FALSE;
static Array handles = 0 ;
/* macro to give the terminal check int for an STORE_HANDLE_STRUCT */
/* unit->size must be a multiple of sizeof(int) */
#define check2(unit) *(int*)(((char*)toMemPtr(unit)) + (unit)->size)
static void checkUnit (STORE_HANDLE unit) ;
static int handleOrder (void *a, void *b)
{ return (*((STORE_HANDLE *)a) == *((STORE_HANDLE *)b)) ? 0 :
(*((STORE_HANDLE *)a) > *((STORE_HANDLE *)b)) ? 1 : -1 ;
}
#endif
#if defined(MALLOC_CHECK) || defined(MEM_DEBUG)
STORE_HANDLE_STRUCT handle0 ;
#endif
/************** halloc(): key function - messalloc() calls this ****************/
#ifdef MEM_DEBUG
void *halloc_dbg(int size, STORE_HANDLE handle,const char *hfname, int hlineno)
#else
void *halloc(int size, STORE_HANDLE handle)
#endif
{
STORE_HANDLE unit ;
#ifdef MALLOC_CHECK
if (!handlesInitialised) /* initialise */
{ handlesInitialised = TRUE;
/* BEWARE, arrayCreate calls handleAlloc, line above must precede
following line to avoid infinite recursion */
handles = arrayCreate (16, STORE_HANDLE) ;
array (handles, 0, STORE_HANDLE) = &handle0 ;
handle0.next = 0 ;
}
while (size % INT_ALIGNMENT) size++ ; /* so check2 alignment is OK */
unit = (STORE_HANDLE) malloc(STORE_OFFSET + size + sizeof(int)) ;
if (unit) memset (unit, 0, STORE_OFFSET + size + sizeof(int)) ;
#else
unit = (STORE_HANDLE) malloc(STORE_OFFSET + size) ;
if (unit) memset (unit, 0, STORE_OFFSET + size) ;
#endif
if (!unit) /* out of memory -> messcrash */
{
messcrash (
"Memory allocation failure when requesting %d bytes, %d already allocated",
size, totMessAlloc) ;
}
#if defined(MALLOC_CHECK) || defined(MEM_DEBUG)
if (!handle)
handle = &handle0 ;
#endif
if (handle)
{ unit->next = handle->next ;
unit->back = handle ;
if (handle->next) (handle->next)->back = unit ;
handle->next = unit ;
}
unit->size = size ;
#ifdef MALLOC_CHECK
unit->check1 = 0x12345678 ;
check2(unit) = 0x12345678 ;
#endif
++numMessAlloc ;
totMessAlloc += size ;
return toMemPtr(unit) ;
}
void blockSetFinalise(void *block, void (*final)(void *))
{ STORE_HANDLE unit = toAllocUnit(block);
unit->final = final ;
}
/***** handleAlloc() - does halloc() + blockSetFinalise() - archaic *****/
#ifdef MEM_DEBUG
void *handleAlloc_dbg (void (*final)(void*), STORE_HANDLE handle, int size,
const char *hfname, int hlineno)
{
void *result = halloc_dbg(size, handle, hfname, hlineno) ;
#else
void *handleAlloc (void (*final)(void*), STORE_HANDLE handle, int size)
{
void *result = halloc(size, handle);
#endif
if (final)
blockSetFinalise(result, final);
return result;
}
/****************** useful utility ************/
#ifdef MEM_DEBUG
char *strnew_dbg(char *old, STORE_HANDLE handle, const char *hfname, int hlineno)
{ char *result = 0 ;
if (old)
{ result = (char *)halloc_dbg(1+strlen(old), handle, hfname, hlineno) ;
#else
char *strnew(char *old, STORE_HANDLE handle)
{ char *result = 0 ;
if (old)
{ result = (char *)halloc(1+strlen(old), handle);
#endif
strcpy(result, old);
}
return result;
}
/****************** messfree ***************/
void umessfree (void *cp)
{
STORE_HANDLE unit = toAllocUnit(cp) ;
#ifdef MALLOC_CHECK
checkUnit (unit) ;
unit->check1 = 0x87654321; /* test for double free */
#endif
if (unit->final)
(*unit->final)(cp) ;
if (unit->back)
{ (unit->back)->next = unit->next;
if (unit->next) (unit->next)->back = unit->back;
}
--numMessAlloc ;
totMessAlloc -= unit->size ;
free (unit) ;
}
/************** create and destroy handles **************/
/* NOTE: handleDestroy is #defined in regular.h to be messfree */
/* The actual work is done by handleFinalise, which is the finalisation */
/* routine attached to all STORE_HANDLEs. This allows multiple levels */
/* of free-ing by allocating new STORE_HANDLES on old ones, using */
/* handleHandleCreate. handleCreate is simply defined as handleHandleCreate(0) */
static void handleFinalise (void *p)
{
STORE_HANDLE handle = (STORE_HANDLE)p;
STORE_HANDLE next, unit = handle->next ;
/* do handle finalisation first */
if (handle->final)
(*handle->final)((void *)handle->back);
while (unit)
{
#ifdef MALLOC_CHECK
checkUnit (unit) ;
unit->check1 = 0x87654321; /* test for double free */
#endif
if (unit->final)
(*unit->final)(toMemPtr(unit)) ;
next = unit->next ;
--numMessAlloc ;
totMessAlloc -= unit->size ;
free (unit) ;
unit = next ;
}
#ifdef MALLOC_CHECK
arrayRemove (handles, &p, handleOrder) ;
#endif
/* This is a finalisation routine, the actual store is freed in messfree,
or another invokation of itself. */
}
void handleSetFinalise(STORE_HANDLE handle, void (*final)(void *), void *arg)
{ handle->final = final;
handle->back = (STORE_HANDLE)arg;
}
STORE_HANDLE handleHandleCreate(STORE_HANDLE handle)
{
STORE_HANDLE res = (STORE_HANDLE) handleAlloc(handleFinalise,
handle,
sizeof(STORE_HANDLE_STRUCT));
#ifdef MALLOC_CHECK
/* NB call to handleAlloc above ensures that handles is initialised here */
arrayInsert (handles, &res, handleOrder) ;
#endif
res->next = res->back = 0 ; /* No blocks on this handle yet. */
res->final = 0 ; /* No handle finalisation */
return res ;
}
BOOL finalCleanup = FALSE ;
#ifdef MEM_DEBUG
void handleCleanUp (void)
{ finalCleanup = TRUE ;
handleFinalise ((void *)&handle0) ;
}
#endif
/************** checking functions, require MALLOC_CHECK *****/
#ifdef MALLOC_CHECK
static void checkUnit (STORE_HANDLE unit)
{
if (unit->check1 == 0x87654321)
messerror ("Block at %x freed twice - bad things will happen.",
toMemPtr(unit));
else
if (unit->check1 != 0x12345678)
messerror ("Malloc error at %x length %d: "
"start overwritten with %x",
toMemPtr(unit), unit->size, unit->check1) ;
if (check2(unit) != 0x12345678)
messerror ("Malloc error at %x length %d: "
"end overwritten with %x",
toMemPtr(unit), unit->size, check2(unit)) ;
}
void messalloccheck (void)
{
int i ;
STORE_HANDLE unit ;
if (!handles) return ;
for (i = 0 ; i < arrayMax(handles) ; ++i)
for (unit = arr(handles,i,STORE_HANDLE)->next ; unit ; unit=unit->next)
checkUnit (unit) ;
}
#else
void messalloccheck (void) {}
#endif
/******************* status monitoring functions ******************/
void handleInfo (STORE_HANDLE handle, int *number, int *size)
{
STORE_HANDLE unit = handle->next;
*number = 0;
*size = 0;
while (unit)
{ ++*number ;
*size += unit->size ;
unit = unit->next ;
}
}
int messAllocStatus (int *mem)
{
*mem = totMessAlloc ;
return numMessAlloc ;
}
/*************************** end of file ************************/
/****************************************************************/