338 lines
9.2 KiB
C++
338 lines
9.2 KiB
C++
|
// --------------------------------------------------------------------------------
|
||
|
// MemCache.h
|
||
|
// Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
|
||
|
// --------------------------------------------------------------------------------
|
||
|
#include "pch.hxx"
|
||
|
#include "memcache.h"
|
||
|
#include <BadStrFunctions.h>
|
||
|
|
||
|
// --------------------------------------------------------------------------------
|
||
|
// CELLSIZE
|
||
|
// --------------------------------------------------------------------------------
|
||
|
#define CELLSIZE(_ulIndex) ((DWORD)(_ulIndex + m_cbMin))
|
||
|
|
||
|
// --------------------------------------------------------------------------------
|
||
|
// CELLINDEX
|
||
|
// --------------------------------------------------------------------------------
|
||
|
#define CELLINDEX(_cb) ((ULONG)(_cb - m_cbMin))
|
||
|
|
||
|
// --------------------------------------------------------------------------------
|
||
|
// ISVALIDITEM
|
||
|
// --------------------------------------------------------------------------------
|
||
|
#define ISVALIDITEM(_pv, _iCell) \
|
||
|
(FALSE == IsBadReadPtr(_pv, CELLSIZE(_iCell)) && \
|
||
|
FALSE == IsBadWritePtr(_pv, CELLSIZE(_iCell)) && \
|
||
|
m_pMalloc->GetSize(_pv) >= CELLSIZE(_iCell))
|
||
|
|
||
|
// --------------------------------------------------------------------------------
|
||
|
// CMemoryCache::CMemoryCache
|
||
|
// --------------------------------------------------------------------------------
|
||
|
CMemoryCache::CMemoryCache(IMalloc *pMalloc, ULONG cbMin /* =0 */, ULONG cbCacheMax /* =131072 */)
|
||
|
: m_pMalloc(pMalloc), m_cbMin(cbMin + sizeof(MEMCACHEITEM)), m_cbCacheMax(cbCacheMax)
|
||
|
{
|
||
|
m_cRef = 1;
|
||
|
m_cbCacheCur = 0;
|
||
|
ZeroMemory(m_rgCell, sizeof(m_rgCell));
|
||
|
#ifdef DEBUG
|
||
|
ZeroMemory(&m_rMetric, sizeof(MEMCACHEMETRIC));
|
||
|
#endif
|
||
|
InitializeCriticalSection(&m_cs);
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------------
|
||
|
// CMemoryCache::CMemoryCache
|
||
|
// --------------------------------------------------------------------------------
|
||
|
CMemoryCache::~CMemoryCache(void)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
DebugTrace("InetComm - CMemoryCache: cAlloc = %d\n", m_rMetric.cAlloc);
|
||
|
DebugTrace("InetComm - CMemoryCache: cAllocCache = %d\n", m_rMetric.cAllocCache);
|
||
|
DebugTrace("InetComm - CMemoryCache: cbAlloc = %d bytes\n", m_rMetric.cbAlloc);
|
||
|
DebugTrace("InetComm - CMemoryCache: cFree = %d\n", m_rMetric.cFree);
|
||
|
DebugTrace("InetComm - CMemoryCache: cbFree = %d bytes\n", m_rMetric.cbFree);
|
||
|
DebugTrace("InetComm - CMemoryCache: cbCacheMax = %d bytes\n", m_rMetric.cbCacheMax);
|
||
|
DebugTrace("InetComm - CMemoryCache: cFreeFull = %d\n", m_rMetric.cFreeFull);
|
||
|
DebugTrace("InetComm - CMemoryCache: cLookAhead = %d\n", m_rMetric.cLookAhead);
|
||
|
DebugTrace("InetComm - CMemoryCache: Average Look Aheads = %d\n", (m_rMetric.cLookAhead / m_rMetric.cAlloc));
|
||
|
DebugTrace("InetComm - CMemoryCache: cMostFree = %d\n", m_rMetric.cMostFree);
|
||
|
DebugTrace("InetComm - CMemoryCache: cbMostFree = %d bytes\n", m_rMetric.cbMostFree);
|
||
|
DebugTrace("InetComm - CMemoryCache: cMostAlloc = %d\n", m_rMetric.cMostAlloc);
|
||
|
DebugTrace("InetComm - CMemoryCache: cbMostAlloc = %d bytes\n", m_rMetric.cbMostAlloc);
|
||
|
#endif
|
||
|
HeapMinimize();
|
||
|
DeleteCriticalSection(&m_cs);
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------------
|
||
|
// CMemoryCache::AddRef
|
||
|
// --------------------------------------------------------------------------------
|
||
|
STDMETHODIMP_(ULONG) CMemoryCache::AddRef(void)
|
||
|
{
|
||
|
return ++m_cRef;
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------------
|
||
|
// CMemoryCache::CMemoryCache
|
||
|
// --------------------------------------------------------------------------------
|
||
|
STDMETHODIMP_(ULONG) CMemoryCache::Release(void)
|
||
|
{
|
||
|
if (0 != --m_cRef)
|
||
|
return m_cRef;
|
||
|
delete this;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------------
|
||
|
// CMemoryCache::Alloc
|
||
|
// --------------------------------------------------------------------------------
|
||
|
STDMETHODIMP_(LPVOID) CMemoryCache::Alloc(DWORD cbAlloc)
|
||
|
{
|
||
|
// Locals
|
||
|
ULONG iCell;
|
||
|
ULONG iCellMax;
|
||
|
LPVOID pvAlloc;
|
||
|
|
||
|
// No Work
|
||
|
if (0 == cbAlloc)
|
||
|
return NULL;
|
||
|
|
||
|
// Count Number of allocations
|
||
|
INCMETRIC(cAlloc, 1);
|
||
|
INCMETRIC(cbAlloc, cbAlloc);
|
||
|
|
||
|
// Get Index
|
||
|
iCell = CELLINDEX(cbAlloc);
|
||
|
|
||
|
// Out of range
|
||
|
if (iCell >= CACHECELLS)
|
||
|
{
|
||
|
// Normal Alloc
|
||
|
return m_pMalloc->Alloc(cbAlloc);
|
||
|
}
|
||
|
|
||
|
// Thread Safety
|
||
|
EnterCriticalSection(&m_cs);
|
||
|
|
||
|
// Compute iMax
|
||
|
iCellMax = min(iCell + 10, CACHECELLS);
|
||
|
|
||
|
// Try to allocate within 0 - 10 bytes of iCell
|
||
|
while(iCell < iCellMax)
|
||
|
{
|
||
|
// Set pvAlloc
|
||
|
pvAlloc = m_rgCell[iCell].pvItemHead;
|
||
|
|
||
|
// Done
|
||
|
if (pvAlloc)
|
||
|
break;
|
||
|
|
||
|
// Next
|
||
|
iCell++;
|
||
|
|
||
|
// Metric
|
||
|
INCMETRIC(cLookAhead, 1);
|
||
|
}
|
||
|
|
||
|
// Is there memory here
|
||
|
if (NULL == pvAlloc)
|
||
|
{
|
||
|
// Thread Safety
|
||
|
LeaveCriticalSection(&m_cs);
|
||
|
|
||
|
// Normal Alloc
|
||
|
return m_pMalloc->Alloc(cbAlloc);
|
||
|
}
|
||
|
|
||
|
// Count Number of allocations
|
||
|
INCMETRIC(cAllocCache, 1);
|
||
|
INCMETRIC(cbAllocCache, CELLSIZE(iCell));
|
||
|
|
||
|
// Adjust the Chain
|
||
|
m_rgCell[iCell].pvItemHead = ((LPMEMCACHEITEM)pvAlloc)->pvItemNext;
|
||
|
|
||
|
// Reduce the Size
|
||
|
m_cbCacheCur -= CELLSIZE(iCell);
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
memset(pvAlloc, 0xFF, cbAlloc);
|
||
|
m_rgCell[iCell].cAlloc++;
|
||
|
if (m_rgCell[iCell].cAlloc > m_rMetric.cMostAlloc)
|
||
|
{
|
||
|
m_rMetric.cMostAlloc = m_rgCell[iCell].cAlloc;
|
||
|
m_rMetric.cbMostAlloc = CELLSIZE(iCell);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// Thread Safety
|
||
|
LeaveCriticalSection(&m_cs);
|
||
|
|
||
|
// Done
|
||
|
return pvAlloc;
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------------
|
||
|
// CMemoryCache::Realloc
|
||
|
// --------------------------------------------------------------------------------
|
||
|
STDMETHODIMP_(LPVOID) CMemoryCache::Realloc(LPVOID pv, DWORD cbAlloc)
|
||
|
{
|
||
|
// Locals
|
||
|
ULONG cbCurrent;
|
||
|
LPVOID pvAlloc;
|
||
|
|
||
|
// Free
|
||
|
if (0 == cbAlloc)
|
||
|
{
|
||
|
// Free pv
|
||
|
Free(pv);
|
||
|
|
||
|
// Done
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
// No pv
|
||
|
if (NULL == pv)
|
||
|
{
|
||
|
// Just Alloc
|
||
|
return Alloc(cbAlloc);
|
||
|
}
|
||
|
|
||
|
// If we have Get Size of pv
|
||
|
cbCurrent = m_pMalloc->GetSize(pv);
|
||
|
|
||
|
// Allocate
|
||
|
pvAlloc = Alloc(cbAlloc);
|
||
|
|
||
|
// Failure
|
||
|
if (NULL == pvAlloc)
|
||
|
return NULL;
|
||
|
|
||
|
// Copy
|
||
|
CopyMemory(pvAlloc, pv, min(cbCurrent, cbAlloc));
|
||
|
|
||
|
// Done
|
||
|
return pvAlloc;
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------------
|
||
|
// CMemoryCache::Free
|
||
|
// --------------------------------------------------------------------------------
|
||
|
STDMETHODIMP_(VOID) CMemoryCache::Free(LPVOID pvFree)
|
||
|
{
|
||
|
// Locals
|
||
|
ULONG iCell;
|
||
|
ULONG cbFree;
|
||
|
MEMCACHEITEM rItem;
|
||
|
|
||
|
// No Work
|
||
|
if (NULL == pvFree)
|
||
|
return;
|
||
|
|
||
|
// Get the size
|
||
|
cbFree = m_pMalloc->GetSize(pvFree);
|
||
|
|
||
|
// Metrics
|
||
|
INCMETRIC(cFree, 1);
|
||
|
INCMETRIC(cbFree, cbFree);
|
||
|
|
||
|
// Lets put it into the cell
|
||
|
iCell = CELLINDEX(cbFree);
|
||
|
|
||
|
// Verify the buffer
|
||
|
Assert(ISVALIDITEM(pvFree, iCell));
|
||
|
|
||
|
// Thread Safety
|
||
|
EnterCriticalSection(&m_cs);
|
||
|
|
||
|
// Size of buffer is out of range or the cache has reached its max
|
||
|
if (cbFree < m_cbMin || cbFree - m_cbMin > CACHECELLS || m_cbCacheCur + cbFree > m_cbCacheMax)
|
||
|
{
|
||
|
// Stats
|
||
|
INCMETRIC(cFreeFull, 1);
|
||
|
|
||
|
// Thread Safety
|
||
|
LeaveCriticalSection(&m_cs);
|
||
|
|
||
|
// Free It
|
||
|
m_pMalloc->Free(pvFree);
|
||
|
|
||
|
// Done
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Set Next
|
||
|
rItem.pvItemNext = m_rgCell[iCell].pvItemHead;
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
memset(pvFree, 0xDD, cbFree);
|
||
|
#endif
|
||
|
|
||
|
// Write this into the buffer
|
||
|
CopyMemory(pvFree, &rItem, sizeof(MEMCACHEITEM));
|
||
|
|
||
|
// Reset pvItemHead
|
||
|
m_rgCell[iCell].pvItemHead = pvFree;
|
||
|
|
||
|
// Increment m_cbCacheCur
|
||
|
m_cbCacheCur += cbFree;
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
if (m_cbCacheCur > m_rMetric.cbCacheMax)
|
||
|
m_rMetric.cbCacheMax = m_cbCacheCur;
|
||
|
m_rgCell[iCell].cFree++;
|
||
|
if (m_rgCell[iCell].cFree > m_rMetric.cMostFree)
|
||
|
{
|
||
|
m_rMetric.cMostFree = m_rgCell[iCell].cFree;
|
||
|
m_rMetric.cbMostFree = CELLSIZE(iCell);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// Thread Safety
|
||
|
LeaveCriticalSection(&m_cs);
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------------
|
||
|
// CMemoryCache::HeapMinimize
|
||
|
// --------------------------------------------------------------------------------
|
||
|
STDMETHODIMP_(VOID) CMemoryCache::HeapMinimize(void)
|
||
|
{
|
||
|
// Locals
|
||
|
LPVOID pvCurr;
|
||
|
LPVOID pvNext;
|
||
|
ULONG i;
|
||
|
|
||
|
// Thread Safety
|
||
|
EnterCriticalSection(&m_cs);
|
||
|
|
||
|
// Walk throught the cells
|
||
|
for (i=0; i<ARRAYSIZE(m_rgCell); i++)
|
||
|
{
|
||
|
// Set Current
|
||
|
pvCurr = m_rgCell[i].pvItemHead;
|
||
|
|
||
|
// Call the Chain of Buffers
|
||
|
while(pvCurr)
|
||
|
{
|
||
|
// Valid Buffer
|
||
|
Assert(ISVALIDITEM(pvCurr, i));
|
||
|
|
||
|
// Get Next
|
||
|
pvNext = ((LPMEMCACHEITEM)pvCurr)->pvItemNext;
|
||
|
|
||
|
// Free this buffer
|
||
|
m_pMalloc->Free(pvCurr);
|
||
|
|
||
|
// Goto Next
|
||
|
pvCurr = pvNext;
|
||
|
}
|
||
|
|
||
|
// Clear the cell
|
||
|
m_rgCell[i].pvItemHead = NULL;
|
||
|
}
|
||
|
|
||
|
// Minimize internal cache
|
||
|
m_pMalloc->HeapMinimize();
|
||
|
|
||
|
// Thread Safety
|
||
|
LeaveCriticalSection(&m_cs);
|
||
|
}
|