Windows2003-3790/inetcore/outlookexpress/msoert/memcache.cpp
2020-09-30 16:53:55 +02:00

338 lines
9.6 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);
}