|
|
/**********************************************************************/ /** 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 <manodel.hxx>
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
|