448 lines
13 KiB
C
448 lines
13 KiB
C
/*
|
|
* @DEC_COPYRIGHT@
|
|
*/
|
|
/*
|
|
* HISTORY
|
|
* $Log: sc_mem.c,v $
|
|
* Revision 1.1.4.2 1996/01/02 18:30:56 Bjorn_Engberg
|
|
* Got rid of compiler warnings: Added include files for NT.
|
|
* [1996/01/02 15:25:04 Bjorn_Engberg]
|
|
*
|
|
* Revision 1.1.2.4 1995/09/20 14:59:33 Bjorn_Engberg
|
|
* Port to NT
|
|
* [1995/09/20 14:41:14 Bjorn_Engberg]
|
|
*
|
|
* Revision 1.1.2.3 1995/09/14 17:28:09 Bjorn_Engberg
|
|
* Ported to NT
|
|
* [1995/09/14 17:21:10 Bjorn_Engberg]
|
|
*
|
|
* Revision 1.1.2.2 1995/05/31 18:07:53 Hans_Graves
|
|
* Inclusion in new SLIB location.
|
|
* [1995/05/31 16:15:46 Hans_Graves]
|
|
*
|
|
* Revision 1.1.2.2 1995/05/03 19:12:55 Hans_Graves
|
|
* First time under SLIB
|
|
* [1995/05/03 19:12:17 Hans_Graves]
|
|
*
|
|
* Revision 1.1.2.3 1995/04/17 17:46:54 Hans_Graves
|
|
* Added ScAlloc2()
|
|
* [1995/04/17 17:45:28 Hans_Graves]
|
|
*
|
|
* Revision 1.1.2.2 1995/04/07 18:40:03 Hans_Graves
|
|
* Inclusion in SLIB's Su library
|
|
* [1995/04/07 18:39:43 Hans_Graves]
|
|
*
|
|
* $EndLog$
|
|
*/
|
|
/*****************************************************************************
|
|
** Copyright (c) Digital Equipment Corporation, 1993 **
|
|
** **
|
|
** All Rights Reserved. Unpublished rights reserved under the copyright **
|
|
** laws of the United States. **
|
|
** **
|
|
** The software contained on this media is proprietary to and embodies **
|
|
** the confidential technology of Digital Equipment Corporation. **
|
|
** Possession, use, duplication or dissemination of the software and **
|
|
** media is authorized only pursuant to a valid written license from **
|
|
** Digital Equipment Corporation. **
|
|
** **
|
|
** RESTRICTED RIGHTS LEGEND Use, duplication, or disclosure by the U.S. **
|
|
** Government is subject to restrictions as set forth in Subparagraph **
|
|
** (c)(1)(ii) of DFARS 252.227-7013, or in FAR 52.227-19, as applicable. **
|
|
******************************************************************************/
|
|
|
|
/*-------------------------------------------------------------------------
|
|
** Modification History: sc_mem.c
|
|
** 05-29-93 Victor Bahl Paged aligned malloc and free
|
|
** 12-07-93 PSG Added error reporting code
|
|
** 03-15-95 HWG Moved to Su library, Added SuAlloc & SuFree
|
|
** 04-04-97 HWG With WIN32 use LocalAlloc and LocalFree in
|
|
** place of malloc and free
|
|
** Added ScCalloc function.
|
|
** 04-15-97 HWG Added memory linked list to help track leaks
|
|
** Fixed potential initalization bug in linked
|
|
** list used to track ScPaMalloc's
|
|
--------------------------------------------------------------------------*/
|
|
/*
|
|
#define _SLIBDEBUG_
|
|
*/
|
|
|
|
#include <stdio.h> /* NULL */
|
|
#include <sys/types.h>
|
|
#ifdef WIN32
|
|
#include <windows.h>
|
|
#include <stdlib.h>
|
|
#include <malloc.h>
|
|
#endif /* WIN32 */
|
|
#include "SC.h"
|
|
#include "SC_err.h"
|
|
|
|
#ifdef _SLIBDEBUG_
|
|
#include "sc_debug.h"
|
|
|
|
#define _DEBUG_ 0 /* detailed debuging statements */
|
|
#define _VERBOSE_ 0 /* show progress */
|
|
#define _VERIFY_ 1 /* verify correct operation */
|
|
#define _WARN_ 1 /* warnings about strange behavior */
|
|
|
|
/* keep a linked list to ttrack memory leaks */
|
|
typedef struct memblock_s {
|
|
void *ptr;
|
|
dword size;
|
|
dword counter;
|
|
char desc[15];
|
|
struct memblock_s *next;
|
|
} memblock_t;
|
|
|
|
static memblock_t *_blocklist=NULL;
|
|
static _blockcounter=0;
|
|
static _memused=0;
|
|
|
|
void scMemAddWatch(void *ptr, dword size, char *desc)
|
|
{
|
|
memblock_t *pblock;
|
|
#if defined(WIN32)
|
|
pblock = (void *)LocalAlloc(LPTR, sizeof(memblock_t));
|
|
#else
|
|
pblock = (void *)malloc(sizeof(memblock_t));
|
|
#endif
|
|
_memused+=size;
|
|
if (pblock)
|
|
{
|
|
pblock->ptr=ptr;
|
|
pblock->next=_blocklist;
|
|
pblock->size=size;
|
|
pblock->counter=_blockcounter;
|
|
if (desc==NULL)
|
|
pblock->desc[0]=0;
|
|
else
|
|
{
|
|
int i;
|
|
for (i=0; desc[i] && i<14; i++)
|
|
pblock->desc[i]=desc[i];
|
|
pblock->desc[i]=0;
|
|
}
|
|
_blocklist=pblock;
|
|
_blockcounter++;
|
|
}
|
|
}
|
|
|
|
ScBoolean_t scMemRemoveWatch(void *ptr)
|
|
{
|
|
memblock_t *plastblock=NULL, *pblock=_blocklist;
|
|
while (pblock)
|
|
{
|
|
if (pblock->ptr==ptr) /* remove from list */
|
|
{
|
|
if (plastblock==NULL) /* beginning of linked list */
|
|
_blocklist=pblock->next;
|
|
else
|
|
plastblock->next=pblock->next;
|
|
_memused-=pblock->size;
|
|
#ifdef WIN32
|
|
LocalFree(pblock);
|
|
#else
|
|
free(pblock);
|
|
#endif
|
|
if (_blocklist==NULL) /* all memory freed, reset counter */
|
|
_blockcounter=0;
|
|
return(TRUE);
|
|
}
|
|
plastblock=pblock;
|
|
pblock=pblock->next;
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
dword scMemDump()
|
|
{
|
|
memblock_t *plastblock=NULL, *pblock=_blocklist;
|
|
ScDebugPrintf(NULL, "scMemDump: memused=%ld\n", _memused);
|
|
while (pblock)
|
|
{
|
|
ScDebugPrintf(NULL, " ptr=%p counter=%ld size=%ld desc=%s\n",
|
|
pblock->ptr, pblock->counter, pblock->size, pblock->desc);
|
|
pblock=pblock->next;
|
|
}
|
|
return(_memused);
|
|
}
|
|
#endif
|
|
|
|
#ifdef WIN32
|
|
int getpagesize()
|
|
{
|
|
SYSTEM_INFO sysInfo;
|
|
static int pagesize = 0 ;
|
|
|
|
if( pagesize == 0 ) {
|
|
GetSystemInfo(&sysInfo);
|
|
|
|
pagesize = (int)sysInfo.dwPageSize;
|
|
}
|
|
|
|
return pagesize ;
|
|
}
|
|
|
|
#define bzero(_addr_,_len_) memset(_addr_,0,_len_)
|
|
#endif
|
|
|
|
/*------------------------------------------------------------------------
|
|
Simple Memory Allocation
|
|
-------------------------------------------------------------------------*/
|
|
/*
|
|
** Name: ScAlloc
|
|
** Purpose: Allocate number of bytes of memory.
|
|
**
|
|
*/
|
|
void *ScAlloc(unsigned long bytes)
|
|
{
|
|
void *ptr;
|
|
|
|
#ifdef MACINTOSH
|
|
ptr = NewPtr(bytes);
|
|
#elif MSC60
|
|
ptr = (void FAR *) _fmalloc((unsigned int)bytes); /* far memory */
|
|
#elif defined(WIN32)
|
|
ptr = (void *)LocalAlloc(LPTR, bytes);
|
|
#else
|
|
ptr = (void *)malloc(bytes);
|
|
#endif
|
|
_SlibDebug(ptr, scMemAddWatch(ptr, bytes, NULL) );
|
|
_SlibDebug(_DEBUG_, ScDebugPrintf(NULL, "ScAlloc(%ld) returns %p\n",bytes,ptr) );
|
|
return(ptr);
|
|
}
|
|
|
|
/*
|
|
** Name: ScCalloc
|
|
** Purpose: Allocate number of bytes of memory and zero it out.
|
|
**
|
|
*/
|
|
void *ScCalloc(unsigned long bytes)
|
|
{
|
|
void *ptr = ScAlloc(bytes);
|
|
if (ptr != NULL)
|
|
{
|
|
#ifdef MSC60
|
|
_fmemset(ptr, 0, (unsigned int)bytes);
|
|
#else
|
|
memset(ptr, 0, bytes);
|
|
#endif
|
|
}
|
|
_SlibDebug(_DEBUG_, ScDebugPrintf(NULL, "ScCalloc(%ld) returns %p\n",bytes,ptr) );
|
|
return(ptr);
|
|
}
|
|
|
|
/*
|
|
** Name: ScAlloc2
|
|
** Purpose: Allocate number of bytes of memory equal to "bytes".
|
|
** Takes an extra argument "name" which identifies the block
|
|
** (used for debugging).
|
|
*/
|
|
void *ScAlloc2(unsigned long bytes, char *desc)
|
|
{
|
|
void *ptr;
|
|
|
|
ptr = ScAlloc(bytes);
|
|
#ifdef _SLIBDEBUG_
|
|
if (_blocklist) /* copy description to leak tracking info */
|
|
{
|
|
int i;
|
|
for (i=0; desc[i] && i<14; i++)
|
|
_blocklist->desc[i]=desc[i];
|
|
_blocklist->desc[i]=0;
|
|
}
|
|
#endif
|
|
_SlibDebug(_DEBUG_,
|
|
ScDebugPrintf(NULL, "ScAlloc(%ld, %s) returns %p\n",bytes,desc,ptr) );
|
|
return(ptr);
|
|
}
|
|
|
|
/*
|
|
** Name: ScFree
|
|
** Purpose: Free memory pointed to by "*ptr_addr"
|
|
**
|
|
*/
|
|
void ScFree(void *ptr)
|
|
{
|
|
_SlibDebug(_DEBUG_, ScDebugPrintf(NULL, "ScFree(%p)\n", ptr) );
|
|
_SlibDebug(ptr, scMemRemoveWatch(ptr) );
|
|
if (ptr != NULL)
|
|
{
|
|
#ifdef MACINTOSH
|
|
DisposPtr(ptr);
|
|
#elif defined(WIN32)
|
|
#ifdef _SLIBDEBUG_
|
|
_SlibDebug(LocalFree(ptr)!=NULL, ScDebugPrintf(NULL, "ScFree(%p) failed\n", ptr) );
|
|
#else
|
|
LocalFree(ptr);
|
|
#endif
|
|
#else
|
|
free(ptr);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Name: ScMemCheck
|
|
** Purpose: Check block of memory all equal to a single byte,
|
|
** else return FALSE
|
|
*/
|
|
int ScMemCheck(char *array, int test, int num)
|
|
{
|
|
int i=0;
|
|
/* 'test' is only tested as a char (bottom 8 bits) */
|
|
while (array[i] == test && i<num)
|
|
i++;
|
|
if (i==num)
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------
|
|
Paged aligned malloc() and free()
|
|
-------------------------------------------------------------------------*/
|
|
|
|
/*
|
|
** This structure is used by the page align malloc/free support code.
|
|
** These "working sets" will contain the malloc-ed address and the
|
|
** page aligned address for the free*() call.
|
|
*/
|
|
typedef struct mpa_ws_s
|
|
{
|
|
char *palign_addr; /* the page aligned address that's used */
|
|
char *malloc_addr; /* the malloc-ed address to free */
|
|
struct mpa_ws_s *next; /* for the next on the list */
|
|
} mpa_ws_t;
|
|
|
|
|
|
/*
|
|
** Initialized and uninitialized data.
|
|
*/
|
|
static mpa_ws_t *mpa_qhead=NULL; /* local Q head for the malloc stuctures */
|
|
|
|
|
|
/*
|
|
** Name: ScPaMalloc
|
|
** Purpose: Allocate Paged Alligned Memory
|
|
** This routine allocates and returns to the caller a system
|
|
** page aligned buffer. Enough space will be added, one more
|
|
** page, to allow the pointers to be adjusted to the next page
|
|
** boundry. A local linked list will keep copies of the original
|
|
** and adjusted addresses. This list will be used by sv_PaFree()
|
|
** to free the correct buffer.
|
|
**
|
|
*/
|
|
char *ScPaMalloc(int size)
|
|
{
|
|
mpa_ws_t *ws; /* pointer for the working set */
|
|
ULONG_PTR tptr; /* to store pointer temp for bit masking */
|
|
int PageSize = getpagesize(); /* system's page size */
|
|
|
|
/*
|
|
** The space for the working set structure that will go on the queue
|
|
** is allocated first.
|
|
*/
|
|
if ((ws = (mpa_ws_t *)ScAlloc(sizeof(mpa_ws_t))) == (mpa_ws_t *)NULL)
|
|
return( (char *)NULL );
|
|
|
|
|
|
/*
|
|
** Using the requested size, from the argument list, and the page size
|
|
** from the system, allocate enough space to page align the requested
|
|
** buffer. The original request will have the space of one system page
|
|
** added to it. The pointer will be adjusted.
|
|
*/
|
|
ws->malloc_addr = (char *)ScAlloc(size + PageSize);
|
|
if (ws->malloc_addr == (char *)NULL)
|
|
{
|
|
ScFree(ws); /* not going to be used */
|
|
return((char *)NULL); /* signal the failure */
|
|
} else
|
|
(void) bzero (ws->malloc_addr, (size + PageSize));
|
|
|
|
/*
|
|
** Now using the allocated space + 1 page, adjust the pointer to
|
|
** point to the next page boundry.
|
|
*/
|
|
ws->palign_addr = ws->malloc_addr + PageSize; /* to the next page */
|
|
|
|
/*
|
|
** Using the page size and subtracting 1 to get a bit mask, mask off
|
|
** the low order "page offset" bits to get the aligned address. Now the
|
|
** aligned pointer will contain the address of the next page with enough
|
|
** space to hold the users requested size.
|
|
*/
|
|
tptr = (ULONG_PTR)ws->palign_addr; /* copy to local int */
|
|
tptr &= (ULONG_PTR)(~(PageSize - 1)); /* Mask addr bit to the */
|
|
ws->palign_addr = (char *)tptr; /* put back the address */
|
|
/*
|
|
** Put the working set onto the linked list so that the original
|
|
** malloc-ed buffer can be freeed when the user program is done with it.
|
|
*/
|
|
ws->next=mpa_qhead;
|
|
mpa_qhead=ws; /* just put it at the head */
|
|
|
|
/*
|
|
** Now return the aligned address to the caller.
|
|
*/
|
|
return((char *)ws->palign_addr);
|
|
}
|
|
|
|
/*
|
|
** Name: ScPaFree
|
|
** Purpose: This is a local free routine to return to the system a previously
|
|
** alloc-ed buffer. A local linked list keeps copies of the original
|
|
** and adjusted addresses. This list is used by this routine to free
|
|
** the correct buffer.
|
|
*/
|
|
void ScPaFree (void *pa_addr)
|
|
{
|
|
mpa_ws_t *p, *q; /* walkers for the malloc list */
|
|
|
|
/*
|
|
** Walk along the malloc-ed memory linked list, watch for a match
|
|
** on the page aligned address. If a match is found break out of the
|
|
** loop.
|
|
*/
|
|
p = mpa_qhead; /* set the pointers */
|
|
q = NULL;
|
|
|
|
while (p != NULL)
|
|
{
|
|
if (p->palign_addr == pa_addr) /* found the buffer */
|
|
break;
|
|
|
|
q = p; /* save current */
|
|
p = p->next; /* get next */
|
|
}
|
|
_SlibDebug(_WARN_ && p==NULL,
|
|
ScDebugPrintf(NULL, "ScPaFree(%p) Illegal pointer\n", pa_addr) );
|
|
|
|
/*
|
|
** After falling out of the loop the pointers are at the place where
|
|
** some work has to be done, (this could also be at the beginning).
|
|
** If a match is found call the free() routine to return the buffer, if
|
|
** the loop fell off the end just return.
|
|
*/
|
|
if (p != NULL)
|
|
{
|
|
/*
|
|
** Where on the list is it, check for making it empty.
|
|
*/
|
|
if (q == NULL) /* at the front */
|
|
mpa_qhead = p->next; /* pop off front */
|
|
else /* inside the list */
|
|
q->next = p->next; /* pop it */
|
|
|
|
ScFree(p->malloc_addr); /* free the malloc-ed addr */
|
|
|
|
/*
|
|
** Now free up the working set, it is not needed any more.
|
|
*/
|
|
ScFree(p);
|
|
}
|
|
}
|
|
|
|
|