|
|
// --------------------------------------------------------------------------------
// 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); }
|