windows-nt/Source/XPSP1/NT/inetsrv/iis/svcs/iisrtl/manodel.cxx
2020-09-26 16:20:57 +08:00

277 lines
6.2 KiB
C++

/**********************************************************************/
/** 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