PVALLOC.C

/* 
- P V A L L O C . C
-
* Copyright (C) 1995 Microsoft Corporation
* Purpose:
* Implementation of a chained memory manager.
*
*/

#include <string.h>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <pvalloc.h>

#undef _PVALLOC_LOG

#ifdef _PVALLOC_LOG
static CB cbTotalAlloc = 0;
static CB ulTotalBlockNum = 0;
#endif




/*
- PvAlloc
-
* Purpose:
* Allocates a chunk of memory on the global heap.
*
* Parameters:
* cbSize - Count of bytes requested.
*
* Returns:
* lpv - Pointer to the allocated memory
*
*/

PV PvAlloc(CB cbSize)
{
PV lpv = pvNull;
HANDLE hMem;
PPVINFO ppvinfo;
#ifdef _PVALLOC_LOG
char szFileName[80];
LPSTR lpszTemp = NULL;
FILE *pFile = NULL;
char szBuff[128];
#endif

/* Make sure allocations are in multiples of 4 */

if(cbSize < 4)
cbSize = 4;
else if(cbSize & 3)
cbSize += 4 - (cbSize & 3);

/* Allocate the block */

hMem = GlobalAlloc(GMEM_MOVEABLE, cbSize + sizeof(PVINFO));
if(hMem)
{
ppvinfo = (PPVINFO)GlobalLock(hMem);
ppvinfo->hMem = hMem;
ppvinfo->lpvNext = pvNull;
ppvinfo->lpvBuf = ((PB)ppvinfo) + sizeof(PVINFO);
#ifdef _PVALLOC_LOG
ppvinfo->cbSize = cbSize;
ulTotalBlockNum++;
ppvinfo->ulBlockNum = ulTotalBlockNum;
cbTotalAlloc += cbSize;

// log to file
lpszTemp = getenv("TEMP");

if(lpszTemp)
strcpy(szFileName, lpszTemp);
else
strcpy(szFileName, "c:\\temp");

strcat(szFileName, "\\pvalloc.log");


pFile = fopen(szFileName,"a");
if (pFile == NULL)
goto NoFile;
// return NULL;

fprintf(pFile, "Block: \t%lu\tPvAlloc: %ld Bytes\t\tTotal: %ld Bytes\n",
ulTotalBlockNum, cbSize, cbTotalAlloc);

if (pFile)
fclose(pFile);

// log to comm port
wsprintf(szBuff,"Block: \t%lu\tPvAlloc: %ld Bytes\t\tTotal: %ld Bytes\n",
ulTotalBlockNum, cbSize, cbTotalAlloc);
OutputDebugString(szBuff);

NoFile:

#ifdef _WIN32
memset(ppvinfo->lpvBuf, 0xaa, (size_t)cbSize);
#else
_fmemset(ppvinfo->lpvBuf, 0xaa, (size_t)cbSize);
#endif /* _WIN32 */

#endif /* _PVALLOC_LOG */
lpv = ppvinfo->lpvBuf;
}

return lpv;
}

/*
- PvAllocMore
-
* Purpose:
* Allocates a chunk of memory and chains it to a parent block.
*
* Parameters:
* cbSize - Count of additional bytes to allocate
* lpvParent - Pointer to parent in memory chain
*
* Returns:
* lpv - Pointer to the allocated memory
*
*/

PV PvAllocMore(CB cbSize, PV lpvParent)
{
PV lpvStep = lpvParent;
PV lpv = pvNull;
PPVINFO ppvinfoMore;
HANDLE hMem;
PPVINFO ppvinfo;

/* Step to the last link */
do
{
ppvinfoMore = (PPVINFO)(((PB)lpvStep) - sizeof(PVINFO));
lpvStep = ppvinfoMore->lpvNext;
}
while(ppvinfoMore->lpvNext != pvNull);

// beginning of section that was taken from PvAlloc

if(cbSize < 4)
cbSize = 4;
else if(cbSize & 3)
cbSize += 4 - (cbSize & 3);


hMem = GlobalAlloc(GMEM_MOVEABLE, cbSize + sizeof(PVINFO));
if(hMem)
{
ppvinfo = (PPVINFO)GlobalLock(hMem);
ppvinfo->hMem = hMem;
ppvinfo->lpvNext = pvNull;
ppvinfo->lpvBuf = ((PB)ppvinfo) + sizeof(PVINFO);
#ifdef _PVALLOC_LOG
ppvinfo->cbSize = cbSize;
ppvinfo->ulBlockNum = ppvinfoMore->ulBlockNum;
cbTotalAlloc += cbSize;

#ifdef _WIN32
memset(ppvinfo->lpvBuf, 0xaa, (size_t)cbSize);
#else
_fmemset(ppvinfo->lpvBuf, 0xaa, (size_t)cbSize);
#endif

#endif
lpv = ppvinfo->lpvBuf;
}
else
return lpv;

// end of section taken from pvalloc

#ifdef _WIN32
memset(lpv, 0xbb, (size_t)cbSize);
#else
_fmemset(lpv, 0xbb, (size_t)cbSize);
#endif /* _WIN32 */

ppvinfoMore->lpvNext = lpv;

return lpv;
}



/*
- PvFree
-
* Purpose:
* This function frees memory allocated by PvAlloc or PvAllocMore.
* After the call, the pointer memory will be invalid and should
* not be referenced again.
* When memory is allocated by PvAlloc and PvAllocMore, which can
* contain several levels of pointers, all the application needs to
* do to free the entire structure is call this routine with the
* base pointer returned by the PvAlloc call.
*
* Parameters:
* lpv - Pointer to memory to be freed.
*
* Returns:
* Void
*
*/

BOOL PvFree(PV lpv)
{
PPVINFO ppvinfo;
#ifdef _PVALLOC_LOG
CB cbSize;
CB ulBlockNum;
FILE *pFile = NULL;
CB cbFree = 0;
CB cbTotalBeforeFree = cbTotalAlloc;
char szFileName[80];
LPSTR lpszTemp = NULL;
char szBuff[128];
#endif

if(!lpv)
return 0;

ppvinfo = (PPVINFO)(((PB)lpv) - sizeof(PVINFO));

while(ppvinfo)
{
lpv = ppvinfo->lpvNext;

#ifdef _PVALLOC_LOG
cbSize = ppvinfo->cbSize;
cbFree += ppvinfo->cbSize;
ulBlockNum = ppvinfo->ulBlockNum;

#ifdef _WIN32
memset(ppvinfo->lpvBuf, 0xcc, (size_t)ppvinfo->cbSize);
#else
_fmemset(ppvinfo->lpvBuf, 0xcc, (size_t)ppvinfo->cbSize);
#endif /* _WIN32 */

#endif /* _PVALLOC_LOG */

if(GlobalUnlock(ppvinfo->hMem))
goto err; // Our lock count is non-zero

if(GlobalFree(ppvinfo->hMem))
goto err; // Failure

#ifdef _PVALLOC_LOG
cbTotalAlloc -= cbSize;
#endif

if(lpv)
ppvinfo = (PPVINFO)(((PB)lpv) - sizeof(PVINFO));
else
break;
}


#ifdef _PVALLOC_LOG

if((cbTotalBeforeFree - cbTotalAlloc) != cbFree)
goto err;

// log to file
lpszTemp = getenv("TEMP");

if(lpszTemp)
strcpy(szFileName, lpszTemp);
else
strcpy(szFileName, "c:\\temp");

strcat(szFileName, "\\pvalloc.log");

pFile = fopen(szFileName,"a");

if (pFile == NULL)
goto err;

fprintf(pFile, "Block: \t%lu\t\t***PvFree***, Freeing %lu Bytes(Alloc and AllocMore)\tUnFreed: %ld Bytes\n",
ulBlockNum, cbFree, cbTotalAlloc);
if (pFile)
fclose(pFile);

// log to comm port
wsprintf(szBuff,"Block: \t%lu\t\t***PvFree***, Freeing %lu Bytes(Alloc and AllocMore)\tUnFreed: %ld Bytes\n",
ulBlockNum, cbFree, cbTotalAlloc);
OutputDebugString(szBuff);

#endif /* _PVALLOC_LOG */

return 0; // Success!

err:
#ifdef _PVALLOC_LOG

// find file to open
lpszTemp = getenv("TEMP");

if(lpszTemp)
strcpy(szFileName, lpszTemp);
else
strcpy(szFileName, "c:\\temp");

strcat(szFileName, "\\pvalloc.log");


pFile = fopen(szFileName,"a");

if (pFile == NULL)
return 1;

fprintf(pFile, "Block: %lu Failure freeing: %ld Bytes\tUnFreed: %ld Bytes\n",
ulBlockNum, cbSize, cbTotalAlloc);
if (pFile)
fclose(pFile);

#endif /* _PVALLOC_LOG */

return 1; // Failure!
}