/**********************************************************************/ /** Microsoft Windows NT **/ /** Copyright(c) Microsoft Corp., 1997 **/ /**********************************************************************/ /* manodel.cxx This module contains the code for a memory allocation class that doesn't delete memory until the class goes away. FILE HISTORY: 1/9/98 michth created */ #include "precomp.hxx" #define DLL_IMPLEMENTATION #define IMPLEMENTATION_EXPORT #include MEMORY_ALLOC_NO_DELETE::MEMORY_ALLOC_NO_DELETE( DWORD dwAllocSize, DWORD dwAlignment, BOOL bSortFree, DWORD dwMinBlockMultiple, HANDLE hHeap): m_dwAllocSize(dwAllocSize), m_dwAlignment(dwAlignment), m_dwBlockMultiple(dwMinBlockMultiple), m_hHeap(hHeap), m_dwNumAlloced(0), m_dwNumFree(0), m_dwNumBlocks(0), m_bSortFree(bSortFree), m_pvBlockList(NULL), m_pvFreeList(NULL) { // // Make sure there really is an alignment // if (m_dwAlignment == 0) { m_dwAlignment = 4; } // // Now Make sure the alignment is a multiple of 4 // AlignAdjust(m_dwAlignment, 4); // // Align the size // AlignAdjust(m_dwAllocSize, m_dwAlignment); // // Calculate the Max Block Multiple // if (m_dwAllocSize <= 100) { m_dwMaxBlockMultiple = 2000 / m_dwAllocSize; } else if (m_dwAllocSize <= 1000) { m_dwMaxBlockMultiple = 10; } else { m_dwMaxBlockMultiple = 5; } // // Determine space to alloc for block header // m_dwBlockHeaderSpace = BLOCK_HEADER_SIZE; AlignAdjust(m_dwBlockHeaderSpace, LESSER_OF(8, m_dwAlignment)); if (m_dwAlignment > 8) { m_dwAlignBytes = m_dwAlignment - 8; } else { m_dwAlignBytes = 0; } // // Get Heap Handle if not passed in // if (m_hHeap == USE_PROCESS_HEAP) { m_hHeap = GetProcessHeap(); } DBG_ASSERT(m_hHeap != NULL); INITIALIZE_CRITICAL_SECTION(&m_csLock); SET_CRITICAL_SECTION_SPIN_COUNT( &m_csLock, 4000); } MEMORY_ALLOC_NO_DELETE::~MEMORY_ALLOC_NO_DELETE() { LockThis(); PVOID pvIndex, pvNext; for (pvIndex = m_pvBlockList; pvIndex != NULL; pvIndex = pvNext) { pvNext = *((PVOID *)pvIndex); HeapFree(m_hHeap, /* Flags */ 0, pvIndex); } UnlockThis(); DeleteCriticalSection(&m_csLock); } PVOID MEMORY_ALLOC_NO_DELETE::Alloc() { PVOID pvAlloc = NULL; LockThis(); pvAlloc = GetAllocFromFreeList(); if (pvAlloc == NULL) { if (AllocBlock()) { pvAlloc = GetAllocFromFreeList(); DBG_ASSERT (pvAlloc != NULL); } } UnlockThis(); return pvAlloc; } BOOL MEMORY_ALLOC_NO_DELETE::Free (PVOID pvMem) { if (pvMem != NULL) { LockThis(); if (!m_bSortFree) { *((PVOID *)pvMem) = m_pvFreeList; m_pvFreeList = pvMem; } else { // // Sort the free list. // Sort in reverse order, since AddBlockToFreeList // puts them on in reverse order. // PVOID *ppvIndex; for (ppvIndex = &m_pvFreeList; (*ppvIndex != NULL) && (*ppvIndex > pvMem); ppvIndex = *(PVOID **)(ppvIndex)) { } *(PVOID *)pvMem = *ppvIndex; *ppvIndex = pvMem; } m_dwNumFree++; UnlockThis(); } return TRUE; } VOID MEMORY_ALLOC_NO_DELETE::GetNewBlockMultiple() { DWORD dwCalculatedMultiple = LESSER_OF((m_dwNumAlloced / 5), m_dwMaxBlockMultiple); m_dwBlockMultiple = GREATER_OF(m_dwBlockMultiple, dwCalculatedMultiple); } PVOID MEMORY_ALLOC_NO_DELETE::GetAllocFromFreeList() { PVOID pvAlloc = m_pvFreeList; // // Remove from free list if necessary // if (m_pvFreeList != NULL) { m_pvFreeList = *((PVOID *)m_pvFreeList); m_dwNumFree--; } return pvAlloc; } BOOL MEMORY_ALLOC_NO_DELETE::AllocBlock() { PVOID pvNewBlock = NULL; DWORD dwBlockSize; BOOL bReturn = FALSE; GetNewBlockMultiple(); dwBlockSize = (m_dwAllocSize * m_dwBlockMultiple) + m_dwBlockHeaderSpace + m_dwAlignBytes; pvNewBlock = HeapAlloc(m_hHeap, /* Flags */ 0, dwBlockSize); if (pvNewBlock == NULL) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); } else { *((PVOID *)pvNewBlock) = m_pvBlockList; m_pvBlockList = pvNewBlock; AddBlockToFreeList(pvNewBlock); m_dwNumAlloced += m_dwBlockMultiple; m_dwNumBlocks++; bReturn = TRUE; } return bReturn; } VOID MEMORY_ALLOC_NO_DELETE::AddBlockToFreeList(PVOID pvNewBlock) { DBG_ASSERT(pvNewBlock != NULL); PBYTE pbFirstAlloc = (PBYTE)pvNewBlock + m_dwBlockHeaderSpace; if (m_dwAlignment > 8) { // // May need to put some bytes in front to align allocs // Find the first place that is aligned. // ULONG_PTR firstAlloc = (ULONG_PTR)pbFirstAlloc; AlignAdjust(firstAlloc, (ULONG_PTR)m_dwAlignment); pbFirstAlloc = (PBYTE)firstAlloc; } PVOID pvEnd = (PVOID)((PBYTE)pbFirstAlloc + (m_dwBlockMultiple * m_dwAllocSize)); for (PVOID pvAllocIndex = (PVOID)pbFirstAlloc; pvAllocIndex < pvEnd; pvAllocIndex = (PVOID)((PBYTE)pvAllocIndex + m_dwAllocSize)) { *((PVOID *)pvAllocIndex) = m_pvFreeList; m_pvFreeList = pvAllocIndex; } m_dwNumFree += m_dwBlockMultiple; } VOID MEMORY_ALLOC_NO_DELETE::AlignAdjust(DWORD &rdwSize, DWORD dwAlignment) { if ((rdwSize % dwAlignment != 0)) { rdwSize &= (0xFFFFFFFF - dwAlignment + 1); rdwSize += dwAlignment; } } #ifdef _WIN64 VOID MEMORY_ALLOC_NO_DELETE::AlignAdjust(ULONG_PTR &rSize, ULONG_PTR Alignment) { rSize = ( rSize + Alignment - 1 ) & ~( Alignment - 1 ); } #endif