// -------------------------------------------------------------------------------- // MemCache.h // Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved // -------------------------------------------------------------------------------- #include "pch.hxx" #include "memcache.h" #include // -------------------------------------------------------------------------------- // 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; ipvItemNext; // 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); }