405 lines
8.9 KiB
C++
405 lines
8.9 KiB
C++
|
|
/* File: FreeStore.cpp
|
|
|
|
Description: Declaration for class FreeStore. This class provides
|
|
a replacement for global new and delete. It adds value by
|
|
recording allocations in DEBUG builds to help find memory leaks.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- ----------- ----------
|
|
06/12/96 Initial creation. BrianAu
|
|
*/
|
|
|
|
#include "precomp.hxx" // PCH
|
|
#pragma hdrstop
|
|
|
|
FreeStore g_FreeStore; // Global heap FreeStore object.
|
|
|
|
|
|
|
|
/* Function: new
|
|
|
|
Description: Replacement for global new.
|
|
|
|
Arguments:
|
|
cb - Number of bytes to allocate.
|
|
|
|
Returns:
|
|
On success, returns pointer to allocated block.
|
|
Throws OutOfMemory if block can't be allocated.
|
|
|
|
Exceptions: OutOfMemory.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- ----------- ----------
|
|
06/12/96 Initial creation. BrianAu
|
|
*/
|
|
|
|
void * __cdecl
|
|
operator new(
|
|
unsigned int cb
|
|
) throw(OutOfMemory)
|
|
{
|
|
void *pv = g_FreeStore.Alloc(cb);
|
|
|
|
DebugMsg(DM_ALLOC, TEXT("new: %6d bytes allocated at 0x%08X"), cb, pv);
|
|
return pv;
|
|
}
|
|
|
|
|
|
|
|
/* Function: delete
|
|
|
|
Description: Replacement for global delete.
|
|
|
|
Arguments:
|
|
pv - Address of block (previously returned by "new") to deallocate.
|
|
|
|
Returns: Nothing.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- ----------- ----------
|
|
06/12/96 Initial creation. BrianAu
|
|
*/
|
|
|
|
void __cdecl
|
|
operator delete(
|
|
void *pv
|
|
)
|
|
{
|
|
DebugMsg(DM_ALLOC, TEXT("delete: block at 0x%08X"), pv);
|
|
g_FreeStore.Free(pv);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG_ALLOC
|
|
|
|
/* Function: FreeStore::Stats::~Stats
|
|
|
|
Description: Constructor for FreeStore statistics object.
|
|
|
|
Arguments: None.
|
|
|
|
Returns: Nothing.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- ----------- ----------
|
|
07/01/96 Initial creation. BrianAu
|
|
*/
|
|
|
|
FreeStore::Stats::Stats(
|
|
VOID
|
|
) : m_pBlockList(NULL),
|
|
m_cCurrentBlocks(0),
|
|
m_cCummulativeBlocks(0),
|
|
m_cCurrentBytes(0),
|
|
m_cCummulativeBytes(0),
|
|
m_hMutex(NULL)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Function: FreeStore::Stats::~Stats
|
|
|
|
Description: Destructor for FreeStore statistics.
|
|
|
|
Arguments: None.
|
|
|
|
Returns: Nothing.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- ----------- ----------
|
|
07/01/96 Initial creation. BrianAu
|
|
*/
|
|
|
|
FreeStore::Stats::~Stats(
|
|
VOID
|
|
)
|
|
{
|
|
Lock();
|
|
Block *pThis = m_pBlockList;
|
|
while(NULL != pThis)
|
|
{
|
|
m_pBlockList = pThis->m_pNext;
|
|
LocalFree(pThis);
|
|
pThis = m_pBlockList;
|
|
}
|
|
ReleaseLock();
|
|
if (NULL != m_hMutex)
|
|
CloseHandle(m_hMutex);
|
|
}
|
|
|
|
|
|
/* Function: FreeStore::Stats::Initialize
|
|
|
|
Description: Initializes the FreeStore statistics object.
|
|
|
|
Arguments: None.
|
|
|
|
Returns:
|
|
NO_ERROR - Success
|
|
E_FAIL - Couldn't create mutex.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- ----------- ----------
|
|
07/01/96 Initial creation. BrianAu
|
|
*/
|
|
|
|
HRESULT
|
|
FreeStore::Stats::Initialize(
|
|
VOID
|
|
)
|
|
{
|
|
m_hMutex = CreateMutex(NULL, FALSE, NULL);
|
|
return NULL != m_hMutex ? NO_ERROR : E_FAIL;
|
|
}
|
|
|
|
|
|
/* Function: FreeStore::Stats::Add
|
|
|
|
Description: Adds a new entry to the FreeStore's statistics pool.
|
|
|
|
Arguments:
|
|
pBlock - Address of block allocated.
|
|
|
|
cbBlock - Number of bytes in block.
|
|
|
|
Returns:
|
|
NO_ERROR - Success
|
|
E_OUTOFMEMORY - Insufficient memory to allocate stats node.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- ----------- ----------
|
|
07/01/96 Initial creation. BrianAu
|
|
*/
|
|
|
|
HRESULT
|
|
FreeStore::Stats::Add(
|
|
LPVOID pBlock,
|
|
DWORD cbBlock
|
|
)
|
|
{
|
|
HRESULT hResult = NO_ERROR;
|
|
Lock();
|
|
|
|
// Create a new node and insert at head of list.
|
|
|
|
Block *pInfo = (Block *)LocalAlloc(LPTR, sizeof(Block));
|
|
if (NULL != pInfo)
|
|
{
|
|
pInfo->m_pBlock = pBlock;
|
|
pInfo->m_cbBlock = cbBlock;
|
|
|
|
pInfo->m_pNext = m_pBlockList;
|
|
m_pBlockList = pInfo;
|
|
|
|
m_cCurrentBlocks++;
|
|
m_cCurrentBytes += cbBlock;
|
|
m_cCummulativeBlocks++;
|
|
m_cCummulativeBytes += cbBlock;
|
|
if (m_cCurrentBlocks > m_cMaxBlocks)
|
|
m_cMaxBlocks = m_cCurrentBlocks;
|
|
if (m_cCurrentBytes > m_cMaxBytes)
|
|
m_cMaxBytes = m_cCurrentBytes;
|
|
}
|
|
else
|
|
hResult = E_OUTOFMEMORY;
|
|
|
|
ReleaseLock();
|
|
return hResult;
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Function: FreeStore::Stats::Delete
|
|
|
|
Description: Remove an entry from the FreeStore's statistics pool.
|
|
|
|
Arguments:
|
|
pBlock - Address of allocated block to remove.
|
|
|
|
Returns:
|
|
NO_ERROR - Success.
|
|
E_FAIL - pBlock not found.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- ----------- ----------
|
|
07/01/96 Initial creation. BrianAu
|
|
*/
|
|
|
|
HRESULT
|
|
FreeStore::Stats::Delete(
|
|
LPVOID pBlock
|
|
)
|
|
{
|
|
Lock();
|
|
HRESULT hResult = NO_ERROR;
|
|
Block *pThis = m_pBlockList;
|
|
Block *pPrev = NULL;
|
|
|
|
while(NULL != pThis && pThis->m_pBlock != pBlock)
|
|
{
|
|
pPrev = pThis;
|
|
pThis = pThis->m_pNext;
|
|
}
|
|
|
|
if (NULL != pThis)
|
|
{
|
|
m_cCurrentBlocks--;
|
|
m_cCurrentBytes -= pThis->m_cbBlock;
|
|
|
|
if (pThis == m_pBlockList)
|
|
m_pBlockList = pThis->m_pNext;
|
|
else
|
|
pPrev->m_pNext = pThis->m_pNext;
|
|
|
|
LocalFree(pThis);
|
|
}
|
|
else
|
|
hResult = E_FAIL;
|
|
|
|
ReleaseLock();
|
|
return hResult;
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Function: FreeStore::Stats::Realloc
|
|
|
|
Description: Change the accounting information for a block to reflect
|
|
a re-allocation of the block.
|
|
|
|
Arguments:
|
|
pOldBlock - Address of allocated block to be reallocated.
|
|
|
|
pNewBlock - New address of reallocated block. May be the same as
|
|
pOldBlock.
|
|
|
|
cbNewBlock - Number of bytes in new block.
|
|
|
|
Returns:
|
|
NO_ERROR - Success.
|
|
E_FAIL - pBlock not found.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- ----------- ----------
|
|
07/01/96 Initial creation. BrianAu
|
|
*/
|
|
|
|
HRESULT
|
|
FreeStore::Stats::Realloc(
|
|
LPVOID pOldBlock,
|
|
LPVOID pNewBlock,
|
|
DWORD cbNewBlock
|
|
)
|
|
{
|
|
Lock();
|
|
HRESULT hResult = NO_ERROR;
|
|
Block *pThis = m_pBlockList;
|
|
Block *pPrev = NULL;
|
|
|
|
while(NULL != pThis && pThis->m_pBlock != pOldBlock)
|
|
{
|
|
pPrev = pThis;
|
|
pThis = pThis->m_pNext;
|
|
}
|
|
|
|
if (NULL != pThis)
|
|
{
|
|
m_cCurrentBlocks--;
|
|
m_cCurrentBytes += (cbNewBlock - pThis->m_cbBlock);
|
|
if (m_cCurrentBytes > m_cMaxBytes)
|
|
m_cMaxBytes = m_cCurrentBytes;
|
|
|
|
pThis->m_pBlock = pNewBlock;
|
|
pThis->m_cbBlock = cbNewBlock;
|
|
}
|
|
else
|
|
hResult = E_FAIL;
|
|
|
|
ReleaseLock();
|
|
return hResult;
|
|
}
|
|
|
|
|
|
|
|
/* Function: FreeStore::Stats::Dump
|
|
|
|
Description: Dumps contents of FreeStore's statistics object to the debug
|
|
terminal.
|
|
|
|
Arguments:
|
|
bDumpAll - If TRUE, data for each node is dumped. If FALSE, only
|
|
summary information is output.
|
|
|
|
Returns:
|
|
NO_ERROR - Always returns NO_ERROR.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- ----------- ----------
|
|
07/01/96 Initial creation. BrianAu
|
|
*/
|
|
|
|
HRESULT
|
|
FreeStore::Stats::Dump(
|
|
BOOL bDumpAll
|
|
)
|
|
{
|
|
DWORD dwDebugMask = DM_ALLOC | DM_ALLOCSUM;
|
|
|
|
Lock();
|
|
Block *pThis = m_pBlockList;
|
|
|
|
DebugMsg(dwDebugMask,
|
|
TEXT("[blks/bytes] - Cur [%d/%d] Cumm [%d/%d] Max [%d/%d]"),
|
|
m_cCurrentBlocks,
|
|
m_cCurrentBytes,
|
|
m_cCummulativeBlocks,
|
|
m_cCummulativeBytes,
|
|
m_cMaxBlocks,
|
|
m_cMaxBytes);
|
|
|
|
if (bDumpAll && m_cCurrentBlocks > 0)
|
|
{
|
|
DebugMsg(dwDebugMask, TEXT("List of blocks currently allocated:"));
|
|
|
|
while(NULL != pThis)
|
|
{
|
|
DebugMsg(dwDebugMask, TEXT("\tBlock 0x%08X, %4d bytes"),
|
|
pThis->m_pBlock, pThis->m_cbBlock);
|
|
pThis = pThis->m_pNext;
|
|
}
|
|
}
|
|
ReleaseLock();
|
|
return NO_ERROR;
|
|
}
|
|
|
|
#endif // DEBUG_ALLOC
|