|
|
/**********************************************************************/ /** Microsoft Windows NT **/ /** Copyright(c) Microsoft Corp., 1997 **/ /**********************************************************************/
/*
madel.cxx
This module contains the code for a memory allocation class that doesn't delete memory until the class goes away.
FILE HISTORY: 1/12/98 michth created */
#include "precomp.hxx"
#define DLL_IMPLEMENTATION
#define IMPLEMENTATION_EXPORT
#include <manodel.hxx>
#include <madel.hxx>
MEMORY_ALLOC_DELETE::MEMORY_ALLOC_DELETE( DWORD dwAllocSize, DWORD dwAlignment, DWORD dwReserveNum, DWORD dwMinBlockMultiple, DWORD dwMaxBlockMultiple, HANDLE hHeap): m_dwAllocSize(dwAllocSize), m_dwAlignment(dwAlignment), m_dwReserveNum(dwReserveNum), m_dwBlockMultiple(dwMinBlockMultiple), m_dwMaxBlockMultiple(dwMaxBlockMultiple), m_hHeap(hHeap), m_dwNumAlloced(0), m_dwNumFree(0), m_dwNumBlocks(0), m_dwBlockHeaderSpace(sizeof(MADEL_BLOCK_HEADER)), m_dwAllocHeaderSpace(sizeof(MADEL_ALLOC_HEADER)) { //DebugBreak();
//DBG_ASSERT ((dwAlignment == 4) || (dwAlignment == 8));
//
// 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);
//
// The alloc header uses 7 bits to store the block number, so max block multiple
// is 128
//
m_dwMaxBlockMultiple = LESSER_OF(m_dwMaxBlockMultiple, MADEL_MAX_ALLOWED_BLOCK_MULTIPLE); m_dwBlockMultiple = LESSER_OF(m_dwBlockMultiple, MADEL_MAX_ALLOWED_BLOCK_MULTIPLE);
if (m_dwBlockMultiple > m_dwMaxBlockMultiple) { m_dwBlockMultiple = m_dwMaxBlockMultiple; }
m_bMaxBlockMultipleEqualsMin = (m_dwMaxBlockMultiple == m_dwBlockMultiple) ? TRUE : FALSE;
//
// Align the size
//
AlignAdjust(m_dwAllocSize, m_dwAlignment); DBG_ASSERT(m_dwAllocSize != 0); DBG_ASSERT(m_dwAllocSize <= MADEL_MAX_ALLOWED_SIZE);
//
// Determine space to alloc for block header & Alloc header
// The block header just needs to be aligned by 4. It will be
// placed appropriately in the block so that the first alloc
// header will be appropriately aligned.
//
AlignAdjust(m_dwBlockHeaderSpace, LESSER_OF(8, m_dwAlignment));
AlignAdjust(m_dwAllocHeaderSpace, 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 == MADEL_USE_PROCESS_HEAP) { m_hHeap = GetProcessHeap(); } DBG_ASSERT(m_hHeap != NULL);
INITIALIZE_CRITICAL_SECTION(&m_csLock); SET_CRITICAL_SECTION_SPIN_COUNT( &m_csLock, 4000);
InitializeListHead( &m_leBlockList ); InitializeListHead( &m_leFreeList ); InitializeListHead( &m_leDeleteList ); }
MEMORY_ALLOC_DELETE::~MEMORY_ALLOC_DELETE() { LockThis();
PLIST_ENTRY pleIndex, pleNext;
for ( pleIndex = m_leDeleteList.Flink ; pleIndex != &m_leDeleteList ; pleIndex = pleNext ) { pleNext = pleIndex->Flink; RemoveEntryList(pleIndex); HeapFree(m_hHeap, /* Flags */ 0, (PVOID)((PBYTE)pleIndex - ((PMADEL_BLOCK_HEADER)pleIndex)->byteAlignBytes));
}
DBG_ASSERT(IsListEmpty(&m_leBlockList)); DBG_ASSERT(IsListEmpty(&m_leFreeList));
UnlockThis();
DeleteCriticalSection(&m_csLock); }
PVOID MEMORY_ALLOC_DELETE::Alloc() { PVOID pvAlloc = NULL;
LockThis();
pvAlloc = GetAllocFromList(&m_leFreeList);
if (pvAlloc == NULL) { pvAlloc = GetAllocFromList(&m_leDeleteList); }
if (pvAlloc == NULL) { if (AllocBlock()) { pvAlloc = GetAllocFromList(&m_leFreeList); DBG_ASSERT (pvAlloc != NULL); } }
UnlockThis(); return (PVOID)((PBYTE)pvAlloc + m_dwAllocHeaderSpace); }
BOOL MEMORY_ALLOC_DELETE::Free (PVOID pvMem) { if (pvMem != NULL) {
PMADEL_BLOCK_HEADER pmbhCurrentBlock; PMADEL_ALLOC_HEADER pmahCurrentAlloc; PLIST_ENTRY pleIndex, pleNext;
LockThis();
//
// pvMem points to usable mem, header precedes it.
//
pmahCurrentAlloc = (PMADEL_ALLOC_HEADER)((PBYTE)pvMem - m_dwAllocHeaderSpace);
//
// First find the block this is on
//
pmbhCurrentBlock = GetBlockFromAlloc(pmahCurrentAlloc);
//
// Add it to the free list
//
*((PVOID *)pvMem) = pmbhCurrentBlock->pvFreeList; pmbhCurrentBlock->pvFreeList = (PVOID)pmahCurrentAlloc; pmbhCurrentBlock->byteNumFree++; m_dwNumFree++;
DBG_ASSERT(&(pmbhCurrentBlock->m_leBlockList) == (PLIST_ENTRY)pmbhCurrentBlock);
if (pmbhCurrentBlock->byteNumFree == pmbhCurrentBlock->byteBlockMultiple) {
//
// Move to Delete List
//
if (IsListEmpty(&m_leDeleteList)) { m_byteLeastAllocsOnFreeList = pmbhCurrentBlock->byteBlockMultiple; } else { m_byteLeastAllocsOnFreeList = LESSER_OF(m_byteLeastAllocsOnFreeList, pmbhCurrentBlock->byteBlockMultiple); }
RemoveEntryList((PLIST_ENTRY)pmbhCurrentBlock); InsertHeadList(&m_leDeleteList,(PLIST_ENTRY)pmbhCurrentBlock);
} else if ( pmbhCurrentBlock->byteNumFree == 1 ) {
//
// It's on the block list, Move to free list
//
RemoveEntryList((PLIST_ENTRY)pmbhCurrentBlock); InsertHeadList(&m_leFreeList, (PLIST_ENTRY)pmbhCurrentBlock); }
//
// Now see if a block can be deleted. This could be because one was added above,
// or because m_dwNumFree is now high enough.
//
if (!IsListEmpty(&m_leDeleteList) && (m_dwNumFree >= (m_dwReserveNum + m_byteLeastAllocsOnFreeList))) {
//
// Remove Block and reset min
//
if (m_bMaxBlockMultipleEqualsMin) {
//
// Don't need to find a block that fits or recalculate the minblock multiple.
// Just delete a block;
//
pleIndex = m_leDeleteList.Flink; RemoveEntryList(pleIndex); m_dwNumFree -= ((PMADEL_BLOCK_HEADER)pleIndex)->byteNumFree; m_dwNumAlloced -= ((PMADEL_BLOCK_HEADER)pleIndex)->byteNumFree; m_dwNumBlocks--; HeapFree(m_hHeap, /* Flags */ 0, (PVOID)((PBYTE)pleIndex - ((PMADEL_BLOCK_HEADER)pleIndex)->byteAlignBytes)); } else {
m_byteLeastAllocsOnFreeList = (BYTE)m_dwMaxBlockMultiple;
for ( pleIndex = m_leDeleteList.Flink ; pleIndex != &m_leDeleteList ; pleIndex = pleNext ) { pleNext = pleIndex->Flink; if (m_dwNumFree >= (m_dwReserveNum + ((PMADEL_BLOCK_HEADER)pleIndex)->byteBlockMultiple) ) { RemoveEntryList(pleIndex); m_dwNumFree -= ((PMADEL_BLOCK_HEADER)pleIndex)->byteNumFree; m_dwNumAlloced -= ((PMADEL_BLOCK_HEADER)pleIndex)->byteNumFree; m_dwNumBlocks--; HeapFree(m_hHeap, /* Flags */ 0, (PVOID)((PBYTE)pleIndex - ((PMADEL_BLOCK_HEADER)pleIndex)->byteAlignBytes));
} else { m_byteLeastAllocsOnFreeList = LESSER_OF(m_byteLeastAllocsOnFreeList, ((PMADEL_BLOCK_HEADER)pleIndex)->byteBlockMultiple); } } }
}
UnlockThis(); } return TRUE; }
VOID MEMORY_ALLOC_DELETE::GetNewBlockMultiple() { DWORD dwCalculatedMultiple = LESSER_OF((m_dwNumAlloced / 5), m_dwMaxBlockMultiple); m_dwBlockMultiple = GREATER_OF(m_dwBlockMultiple, dwCalculatedMultiple); }
PVOID MEMORY_ALLOC_DELETE::GetAllocFromList(PLIST_ENTRY pleListHead) { PVOID pvAlloc = NULL; PLIST_ENTRY pleFreeBlock; PMADEL_BLOCK_HEADER pmbhFreeBlock;
//
// Remove from list
//
if (!IsListEmpty(pleListHead)) { pleFreeBlock = RemoveHeadList(pleListHead); DBG_ASSERT(pleFreeBlock != NULL); pmbhFreeBlock = (PMADEL_BLOCK_HEADER)pleFreeBlock; DBG_ASSERT(pmbhFreeBlock == (CONTAINING_RECORD(pleFreeBlock, MADEL_BLOCK_HEADER, m_leBlockList))); pvAlloc = pmbhFreeBlock->pvFreeList; DBG_ASSERT(pvAlloc != NULL); pmbhFreeBlock->pvFreeList = *((PVOID *)((PBYTE)(pmbhFreeBlock->pvFreeList) + m_dwAllocHeaderSpace)); pmbhFreeBlock->byteNumFree--; m_dwNumFree--;
//
// Put the block back on a list.
// Just removed one element, so know it doesn't go on the Delete list.
//
if (pmbhFreeBlock->byteNumFree == 0) { InsertHeadList(&m_leBlockList, pleFreeBlock); } else { InsertHeadList(&m_leFreeList, pleFreeBlock); } } return pvAlloc; }
BOOL MEMORY_ALLOC_DELETE::AllocBlock() { PVOID pvNewBlock = NULL; DWORD dwBlockSize; BOOL bReturn = FALSE;
GetNewBlockMultiple();
dwBlockSize = ((m_dwAllocSize + m_dwAllocHeaderSpace) * m_dwBlockMultiple) + m_dwBlockHeaderSpace + m_dwAlignBytes;
pvNewBlock = HeapAlloc(m_hHeap, /* Flags */ 0, dwBlockSize); if (pvNewBlock == NULL) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); } else {
//
// Put the block on the free list. Since all allocs are available,
// it really belongs on the delete list, but one will immediately be
// taken off, so just put it on the free list.
//
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; }
PMADEL_BLOCK_HEADER pmbhBlockHeader = (PMADEL_BLOCK_HEADER)((PBYTE)pbFirstAlloc - m_dwBlockHeaderSpace);
InsertHeadList(&m_leFreeList, (PLIST_ENTRY)pmbhBlockHeader); pmbhBlockHeader->byteBlockMultiple = (BYTE)m_dwBlockMultiple; pmbhBlockHeader->byteNumFree = (BYTE)m_dwBlockMultiple; pmbhBlockHeader->byteAlignBytes = DIFF((PBYTE)pmbhBlockHeader - (PBYTE)pvNewBlock); CreateBlockFreeList(pmbhBlockHeader); m_dwNumAlloced += m_dwBlockMultiple; m_dwNumFree += m_dwBlockMultiple; m_dwNumBlocks++; bReturn = TRUE; } /* INTRINSA suppress = leaks */ return bReturn; }
VOID MEMORY_ALLOC_DELETE::CreateBlockFreeList(PMADEL_BLOCK_HEADER pmbhNewBlock) { PVOID pvEnd = (PVOID)((PBYTE)pmbhNewBlock + m_dwBlockHeaderSpace + (m_dwBlockMultiple * (m_dwAllocSize + m_dwAllocHeaderSpace)));
DBG_ASSERT(pmbhNewBlock != NULL);
pmbhNewBlock->pvFreeList = NULL;
BYTE i; PVOID pvAllocIndex;
for ((pvAllocIndex = (PVOID)((PBYTE)pmbhNewBlock + m_dwBlockHeaderSpace)), i = 0; pvAllocIndex < pvEnd; pvAllocIndex = (PVOID)((PBYTE)pvAllocIndex + m_dwAllocSize + m_dwAllocHeaderSpace), i++) { InitAllocHead((PMADEL_ALLOC_HEADER)pvAllocIndex, i); *((PVOID *)((PBYTE)pvAllocIndex + m_dwAllocHeaderSpace)) = pmbhNewBlock->pvFreeList; pmbhNewBlock->pvFreeList = pvAllocIndex; } }
VOID MEMORY_ALLOC_DELETE::AlignAdjust(DWORD &rdwSize, DWORD dwAlignment) { if ((rdwSize % dwAlignment != 0)) { rdwSize &= (0xFFFFFFFF - dwAlignment + 1); rdwSize += dwAlignment; } }
#ifdef _WIN64
VOID MEMORY_ALLOC_DELETE::AlignAdjust(ULONG_PTR &rSize, ULONG_PTR Alignment) { rSize = ( rSize + Alignment - 1 ) & ~( Alignment - 1 ); } #endif
VOID MEMORY_ALLOC_DELETE::InitAllocHead(PMADEL_ALLOC_HEADER pvAlloc, DWORD dwAllocIndex) { pvAlloc->dwSize = m_dwAllocSize; pvAlloc->bNumAlloc = dwAllocIndex; pvAlloc->bMadelAlloc = 1; }
PMADEL_BLOCK_HEADER MEMORY_ALLOC_DELETE::GetBlockFromAlloc(PMADEL_ALLOC_HEADER pmahMem) { return (PMADEL_BLOCK_HEADER)((PBYTE)pmahMem - ((pmahMem->bNumAlloc * (m_dwAllocSize + m_dwAllocHeaderSpace)) + m_dwBlockHeaderSpace)); }
|