/* * @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 /* NULL */ #include #ifdef WIN32 #include #include #include #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 && imalloc_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); } }