You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1038 lines
24 KiB
1038 lines
24 KiB
//#---------------------------------------------------------------
|
|
// File: CPool.cpp
|
|
//
|
|
// Synopsis: This file implements the CPool class
|
|
//
|
|
// Copyright (C) 1995 Microsoft Corporation
|
|
// All rights reserved.
|
|
//
|
|
// Authors: HowardCu
|
|
//----------------------------------------------------------------
|
|
#ifdef THIS_FILE
|
|
#undef THIS_FILE
|
|
#endif
|
|
static char __szTraceSourceFile[] = __FILE__;
|
|
#define THIS_FILE __szTraceSourceFile
|
|
|
|
#include <windows.h>
|
|
#include "cpool.h"
|
|
#include "dbgtrace.h"
|
|
|
|
#define PREAMBLE (BYTE)'H'
|
|
#define POSTAMBLE (BYTE)'C'
|
|
#define FILLER (BYTE)0xCC
|
|
|
|
|
|
//
|
|
// Define internal Debug structs designed to help find over/underwrites
|
|
//
|
|
#ifdef DEBUG
|
|
#ifndef DISABLE_CPOOL_DEBUG
|
|
#define CPOOL_DEBUG
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef CPOOL_DEBUG
|
|
|
|
#define HEAD_SIGNATURE (DWORD)'daeH'
|
|
#define TAIL_SIGNATURE (DWORD)'liaT'
|
|
|
|
#define FREE_STATE (DWORD)'eerF'
|
|
#define USED_STATE (DWORD)'desU'
|
|
|
|
//
|
|
// forward declaration
|
|
//
|
|
class CPoolDebugTail;
|
|
|
|
//
|
|
// Prefix for CPool instances when in debug mode
|
|
//
|
|
class CPoolDebugHead {
|
|
|
|
public:
|
|
//
|
|
// declared so normal CPool free list can clobber this member
|
|
//
|
|
void* m_pLink;
|
|
|
|
CPoolDebugHead();
|
|
~CPoolDebugHead( void );
|
|
|
|
void *operator new( size_t cSize, void *pInstance )
|
|
{ return pInstance; };
|
|
|
|
void operator delete (void *pInstance) {};
|
|
|
|
//
|
|
// Function to mark the instance in use
|
|
//
|
|
void MarkInUse( DWORD m_dwSignature, DWORD m_cInstanceSize );
|
|
|
|
//
|
|
// Function to mark the instance free
|
|
//
|
|
void MarkFree( DWORD m_dwSignature, DWORD m_cInstanceSize );
|
|
|
|
//
|
|
// class signature
|
|
//
|
|
DWORD m_dwSignature;
|
|
|
|
//
|
|
// state; either FREE_STATE or USED_STATE
|
|
//
|
|
DWORD m_dwState;
|
|
|
|
//
|
|
// time of allocation
|
|
//
|
|
SYSTEMTIME m_time;
|
|
|
|
//
|
|
// ThreadID which alloc'd/free'd memory
|
|
//
|
|
DWORD m_dwThreadID;
|
|
|
|
//
|
|
// tail pointer used to find the end
|
|
//
|
|
CPoolDebugTail UNALIGNED *m_pTailDebug;
|
|
|
|
//
|
|
// parent CPool signature
|
|
//
|
|
DWORD m_dwPoolSignature;
|
|
|
|
//
|
|
// parent CPool Fragment
|
|
//
|
|
LPVOID m_PoolFragment;
|
|
};
|
|
|
|
|
|
//
|
|
// Suffix for CPool instances when in debug mode
|
|
//
|
|
class CPoolDebugTail {
|
|
|
|
public:
|
|
CPoolDebugTail();
|
|
~CPoolDebugTail( void );
|
|
|
|
void *operator new( size_t cSize, void *pInstance )
|
|
{ return pInstance; };
|
|
|
|
void operator delete (void *pInstance) {};
|
|
|
|
//
|
|
// routine to validate the integrity of the instance
|
|
//
|
|
void IsValid( DWORD dwPoolSignature, DWORD cInstanceSize );
|
|
|
|
//
|
|
// class signature
|
|
//
|
|
DWORD m_dwSignature;
|
|
|
|
//
|
|
// tail pointer used to find the end
|
|
//
|
|
CPoolDebugHead UNALIGNED *m_pHeadDebug;
|
|
};
|
|
|
|
//+---------------------------------------------------------------
|
|
//
|
|
// Function: CPoolDebugHead
|
|
//
|
|
// Synopsis: constructor; extra init done in def'n
|
|
//
|
|
// Arguments: void
|
|
//
|
|
// Returns: void
|
|
//
|
|
//----------------------------------------------------------------
|
|
CPoolDebugHead::CPoolDebugHead( void ) :
|
|
m_dwState( FREE_STATE ),
|
|
m_dwSignature( HEAD_SIGNATURE ),
|
|
m_pTailDebug( NULL )
|
|
{
|
|
//
|
|
// debug helpers
|
|
//
|
|
GetLocalTime( &m_time ) ;
|
|
m_dwThreadID = GetCurrentThreadId();
|
|
}
|
|
|
|
//+---------------------------------------------------------------
|
|
//
|
|
// Function: ~CPoolDebugHead
|
|
//
|
|
// Synopsis: destructor; only used to assert error conditions
|
|
//
|
|
// Arguments: void
|
|
//
|
|
// Returns: void
|
|
//
|
|
//----------------------------------------------------------------
|
|
CPoolDebugHead::~CPoolDebugHead( void )
|
|
{
|
|
_ASSERT( m_dwSignature == HEAD_SIGNATURE );
|
|
}
|
|
|
|
//+---------------------------------------------------------------
|
|
//
|
|
// Function: CPoolDebugHead::MarkInUse
|
|
//
|
|
// Synopsis: Called when instance is allocated
|
|
//
|
|
// Arguments: DWORD dwPoolSignature: signature of parent pool
|
|
// DWORD cInstanceSize: instance size of parent pool
|
|
//
|
|
// Returns: void
|
|
//
|
|
//----------------------------------------------------------------
|
|
void CPoolDebugHead::MarkInUse( DWORD dwPoolSignature, DWORD cInstanceSize )
|
|
{
|
|
_ASSERT( m_dwSignature == HEAD_SIGNATURE );
|
|
_ASSERT( m_dwState == FREE_STATE );
|
|
|
|
m_dwState = USED_STATE;
|
|
|
|
//
|
|
// validate that the application portion is not tampered with
|
|
//
|
|
for ( LPBYTE pb = (LPBYTE)(this+1);
|
|
pb < (LPBYTE)m_pTailDebug;
|
|
pb++ )
|
|
{
|
|
_ASSERT( *pb == FILLER );
|
|
}
|
|
|
|
//
|
|
// check the validity of the entire instance
|
|
//
|
|
m_pTailDebug->IsValid( dwPoolSignature, cInstanceSize );
|
|
|
|
//
|
|
// debug helpers
|
|
//
|
|
GetLocalTime( &m_time ) ;
|
|
m_dwThreadID = GetCurrentThreadId();
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------
|
|
//
|
|
// Function: CPoolDebugHead::MarkFree
|
|
//
|
|
// Synopsis: Called when instance is freed
|
|
//
|
|
// Arguments: DWORD dwPoolSignature: signature of parent pool
|
|
// DWORD cInstanceSize: instance size of parent pool
|
|
//
|
|
// Returns: void
|
|
//
|
|
//----------------------------------------------------------------
|
|
void CPoolDebugHead::MarkFree( DWORD dwPoolSignature, DWORD cInstanceSize )
|
|
{
|
|
_ASSERT( m_dwSignature == HEAD_SIGNATURE );
|
|
|
|
//
|
|
// Check and set the state
|
|
//
|
|
_ASSERT( m_dwState == USED_STATE );
|
|
m_dwState = FREE_STATE;
|
|
|
|
//
|
|
// check enough to call IsValid
|
|
//
|
|
_ASSERT( m_pTailDebug != 0 );
|
|
_ASSERT( (DWORD_PTR)m_pTailDebug > (DWORD_PTR)this );
|
|
|
|
_ASSERT( m_dwThreadID != 0 ) ;
|
|
|
|
//
|
|
// check the validity of the entire instance
|
|
//
|
|
m_pTailDebug->IsValid( dwPoolSignature, cInstanceSize );
|
|
|
|
//
|
|
// set the application data to filler
|
|
//
|
|
FillMemory( (LPBYTE)(this+1),
|
|
(DWORD)((LPBYTE)m_pTailDebug - (LPBYTE)(this+1)),
|
|
FILLER );
|
|
|
|
//
|
|
// debug helpers
|
|
//
|
|
GetLocalTime( &m_time ) ;
|
|
m_dwThreadID = GetCurrentThreadId();
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------
|
|
//
|
|
// Function: CPoolDebugTail
|
|
//
|
|
// Synopsis: constructor; extra init done in def'n
|
|
//
|
|
// Arguments: void
|
|
//
|
|
// Returns: void
|
|
//
|
|
//----------------------------------------------------------------
|
|
CPoolDebugTail::CPoolDebugTail( void ) :
|
|
m_dwSignature( TAIL_SIGNATURE ),
|
|
m_pHeadDebug( NULL )
|
|
{
|
|
}
|
|
|
|
//+---------------------------------------------------------------
|
|
//
|
|
// Function: ~CPoolDebugTail
|
|
//
|
|
// Synopsis: destructor; only used to assert error conditions
|
|
//
|
|
// Arguments: void
|
|
//
|
|
// Returns: void
|
|
//
|
|
//----------------------------------------------------------------
|
|
CPoolDebugTail::~CPoolDebugTail( void )
|
|
{
|
|
_ASSERT( m_dwSignature == TAIL_SIGNATURE );
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------
|
|
//
|
|
// Function: IsValid
|
|
//
|
|
// Synopsis: check validity of instance
|
|
//
|
|
// Arguments: DWORD dwPoolSignature: signature of parent pool
|
|
// DWORD cInstanceSize: instance size of parent pool
|
|
//
|
|
// Returns: void
|
|
//
|
|
//----------------------------------------------------------------
|
|
void CPoolDebugTail::IsValid( DWORD dwPoolSignature, DWORD cInstanceSize )
|
|
{
|
|
_ASSERT( m_dwSignature == TAIL_SIGNATURE );
|
|
|
|
//
|
|
// validate that the head is offset at the correct location
|
|
//
|
|
_ASSERT( m_pHeadDebug != NULL );
|
|
_ASSERT( (UINT_PTR)m_pHeadDebug == (UINT_PTR)(this+1) - cInstanceSize );
|
|
|
|
//
|
|
// validate the head structure
|
|
//
|
|
_ASSERT( m_pHeadDebug->m_dwSignature == HEAD_SIGNATURE );
|
|
_ASSERT( m_pHeadDebug->m_dwPoolSignature == dwPoolSignature );
|
|
_ASSERT( m_pHeadDebug->m_pTailDebug == this );
|
|
_ASSERT( m_pHeadDebug->m_dwState == FREE_STATE ||
|
|
m_pHeadDebug->m_dwState == USED_STATE );
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
//+---------------------------------------------------------------
|
|
//
|
|
// Function: CPool
|
|
//
|
|
// Synopsis: constructor
|
|
//
|
|
// Arguments: void
|
|
//
|
|
// Returns: void
|
|
//
|
|
// History: gordm Created 5 Jul 1995
|
|
//
|
|
//----------------------------------------------------------------
|
|
CPool::CPool( DWORD dwSignature ) : m_dwSignature( dwSignature )
|
|
{
|
|
TraceFunctEnter( "CPool::CPool" );
|
|
|
|
m_pFreeList = NULL;
|
|
m_pExtraFreeLink = NULL;
|
|
|
|
//
|
|
// Debug variables to help catch heap bugs
|
|
//
|
|
m_pLastAlloc = NULL;
|
|
m_pLastExtraAlloc = NULL;
|
|
|
|
m_cTotalFrees = 0;
|
|
m_cTotalAllocs = 0;
|
|
m_cTotalExtraAllocs = 0;
|
|
|
|
m_cInstanceSize = 0;
|
|
|
|
//
|
|
// Avail + InUse should equal Committed if we're not
|
|
// in grow/alloc or free. Diagnostic and admin only
|
|
// This will keep code in critsec as small as possible
|
|
//
|
|
m_cNumberAvail = 0;
|
|
m_cNumberInUse = 0;
|
|
m_cNumberCommitted = 0;
|
|
|
|
InitializeCriticalSection( &m_PoolCriticalSection );
|
|
|
|
//
|
|
// initialize the fragment member variables
|
|
//
|
|
m_cFragmentInstances = 0;
|
|
m_cFragments = 0;
|
|
ZeroMemory( m_pFragments, sizeof(m_pFragments) );
|
|
|
|
TraceFunctLeave();
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------
|
|
//
|
|
// Function: ~CPool
|
|
//
|
|
// Synopsis: destructor
|
|
//
|
|
// Arguments: void
|
|
//
|
|
// Returns: void
|
|
//
|
|
// History: HowardCu Created 8 May 1995
|
|
//
|
|
//----------------------------------------------------------------
|
|
CPool::~CPool( void )
|
|
{
|
|
TraceFunctEnter( "CPool::~CPool" );
|
|
|
|
_ASSERT( m_cNumberInUse == 0 );
|
|
|
|
for ( int i=0; i<MAX_CPOOL_FRAGMENTS; i++ )
|
|
{
|
|
_ASSERT( m_pFragments[i] == NULL );
|
|
}
|
|
|
|
DebugTrace( (LPARAM)this,
|
|
"CPool: %x EntryCount: %d ContentionCount: %d, Allocs: %d, Frees: %d",
|
|
m_dwSignature,
|
|
GetEntryCount(),
|
|
GetContentionCount(),
|
|
GetTotalAllocCount(),
|
|
GetTotalFreeCount() );
|
|
|
|
DeleteCriticalSection( &m_PoolCriticalSection );
|
|
|
|
TraceFunctLeave();
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------
|
|
//
|
|
// Function: Alloc
|
|
//
|
|
// Synopsis: Allocates a new instance from the pool
|
|
//
|
|
// Arguments: void
|
|
//
|
|
// Returns: pointer to the new instance
|
|
//
|
|
// History: gordm Created 5 Jul 1995
|
|
//
|
|
//----------------------------------------------------------------
|
|
void* CPool::Alloc( void )
|
|
{
|
|
#ifdef ALLOC_TRACING
|
|
TraceFunctEnter( "CPool::Alloc" );
|
|
#endif
|
|
|
|
Link* pAlloc;
|
|
|
|
IsValid();
|
|
|
|
//
|
|
// moved outside of the critsec because it should not be necessary
|
|
// to protect this variable. inc before the alloc so this var wraps
|
|
// the actual allocation
|
|
//
|
|
InterlockedIncrement( (LPLONG)&m_cNumberInUse );
|
|
|
|
//
|
|
// check the extra pointer to avoid the critsec path if
|
|
// possible. big wins because we can potentially avoid
|
|
// the extra code and the wait on semaphore
|
|
//
|
|
pAlloc = (Link*)InterlockedExchangePointer( (PVOID*)&m_pExtraFreeLink, NULL );
|
|
if ( pAlloc == NULL )
|
|
{
|
|
|
|
EnterCriticalSection( &m_PoolCriticalSection );
|
|
|
|
//
|
|
// commit more memory if the list is empty
|
|
//
|
|
if ( (m_pFreeList == NULL) && (m_cNumberCommitted < m_cMaxInstances) )
|
|
{
|
|
GrowPool();
|
|
}
|
|
|
|
//
|
|
// try to allocate a Descriptor from the free list
|
|
//
|
|
if ( (pAlloc = m_pFreeList) != NULL )
|
|
{
|
|
m_pFreeList = pAlloc->pNext;
|
|
}
|
|
|
|
m_pLastAlloc = pAlloc;
|
|
LeaveCriticalSection( &m_PoolCriticalSection );
|
|
}
|
|
else
|
|
{
|
|
m_pLastExtraAlloc = pAlloc;
|
|
m_cTotalExtraAllocs++;
|
|
}
|
|
|
|
//
|
|
// alloc failed
|
|
//
|
|
if ( pAlloc == NULL )
|
|
{
|
|
InterlockedDecrement( (LPLONG)&m_cNumberInUse );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// debug/admin use only - ok to do outside of critsec
|
|
//
|
|
m_cTotalAllocs++;
|
|
|
|
#ifdef CPOOL_DEBUG
|
|
CPoolDebugHead* pHead = (CPoolDebugHead*)pAlloc;
|
|
|
|
//
|
|
// validate that the address in the range
|
|
//
|
|
_ASSERT( (char*)pAlloc >= pHead->m_PoolFragment );
|
|
_ASSERT( (char*)pAlloc < (char*)pHead->m_PoolFragment +
|
|
m_cNumberCommitted*m_cInstanceSize );
|
|
|
|
pHead->MarkInUse( m_dwSignature, m_cInstanceSize );
|
|
pAlloc = (Link*)(pHead+1);
|
|
#endif
|
|
|
|
}
|
|
|
|
#ifdef ALLOC_TRACING
|
|
DebugTrace( (LPARAM)this, "Alloc: 0x%08X", pAlloc );
|
|
TraceFunctLeave();
|
|
#endif
|
|
return (void*)pAlloc;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------
|
|
//
|
|
// Function: Free
|
|
//
|
|
// Synopsis: frees the instances
|
|
//
|
|
// Arguments: pInstance - a pointer to the CDescriptor
|
|
//
|
|
// Returns: void
|
|
//
|
|
// History: gordm Created 5 Jul 1995
|
|
//
|
|
//----------------------------------------------------------------
|
|
void CPool::Free( void* pInstance )
|
|
{
|
|
#ifdef ALLOC_TRACING
|
|
TraceFunctEnter( "CPool::Free" );
|
|
#endif
|
|
|
|
#ifdef CPOOL_DEBUG
|
|
CPoolDebugHead* pHead = ((CPoolDebugHead*)pInstance) - 1;
|
|
|
|
//
|
|
// validate that the address in the range
|
|
//
|
|
_ASSERT( (char*)pInstance >=pHead->m_PoolFragment);
|
|
_ASSERT( (char*)pInstance < (char*)pHead->m_PoolFragment +
|
|
m_cNumberCommitted*m_cInstanceSize );
|
|
|
|
pHead->MarkFree( m_dwSignature, m_cInstanceSize );
|
|
pInstance = (void*)pHead;
|
|
#endif
|
|
|
|
IsValid();
|
|
|
|
_ASSERT(m_cNumberInUse > 0);
|
|
|
|
pInstance = InterlockedExchangePointer( (LPVOID *)&m_pExtraFreeLink, pInstance );
|
|
//
|
|
// free the previous extra pointer if one existed
|
|
//
|
|
if ( pInstance != NULL )
|
|
{
|
|
EnterCriticalSection( &m_PoolCriticalSection );
|
|
|
|
((Link*)pInstance)->pNext = m_pFreeList;
|
|
m_pFreeList = (Link*)pInstance;
|
|
|
|
LeaveCriticalSection( &m_PoolCriticalSection );
|
|
}
|
|
|
|
//
|
|
// moved outside of the critsec because it should not be necessary
|
|
// to protect this variable. We'll think this list is empty only
|
|
// when we get to this point. This var is inc'd before entering
|
|
// the critsec and is dec'd if the operation fails.
|
|
//
|
|
InterlockedDecrement( (LPLONG)&m_cNumberInUse );
|
|
|
|
//
|
|
// debug/admin use only - ok to do outside of critsec - deletes don't fail
|
|
//
|
|
m_cTotalFrees++;
|
|
|
|
#ifdef ALLOC_TRACING
|
|
DebugTrace( (LPARAM)this, "Freed: 0x%08X", pInstance );
|
|
TraceFunctLeave();
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// setup a const DWORD for size manipulation
|
|
//
|
|
const DWORD KB = 1024;
|
|
|
|
//+---------------------------------------------------------------
|
|
//
|
|
// Function: ReserveMemory
|
|
//
|
|
// Synopsis: Initializes the pool
|
|
//
|
|
// Arguments: NumDescriptors - the number of total descriptors in the pool
|
|
// DescriptorSize - the size of any one descriptor
|
|
// Signature - object signature
|
|
//
|
|
// Returns: TRUE is success, else FALSE
|
|
//
|
|
// History: HowardCu Created 8 May 1995
|
|
//
|
|
//----------------------------------------------------------------
|
|
BOOL CPool::ReserveMemory( DWORD MaxInstances,
|
|
DWORD InstanceSize,
|
|
DWORD IncrementSize )
|
|
{
|
|
TraceFunctEnter( "CPool::ReserveMemory" );
|
|
|
|
DWORD cFragments;
|
|
DWORD cFragmentInstances;
|
|
DWORD cIncrementInstances;
|
|
|
|
_ASSERT( MaxInstances != 0 );
|
|
_ASSERT( InstanceSize >= sizeof(struct Link) );
|
|
|
|
#ifdef CPOOL_DEBUG
|
|
InstanceSize += sizeof( CPoolDebugHead ) + sizeof( CPoolDebugTail );
|
|
#endif
|
|
|
|
if ( IncrementSize == DEFAULT_ALLOC_INCREMENT )
|
|
{
|
|
//
|
|
// ensure we go to the OS for at least 8 instances at a time
|
|
//
|
|
if ( InstanceSize <= 4*KB / 8 )
|
|
{
|
|
cIncrementInstances = 4*KB / InstanceSize;
|
|
}
|
|
else if ( InstanceSize <= 64*KB / 8 )
|
|
{
|
|
cIncrementInstances = 64*KB / InstanceSize;
|
|
}
|
|
else
|
|
{
|
|
cIncrementInstances = min( MaxInstances, 8 );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cIncrementInstances = IncrementSize;
|
|
}
|
|
|
|
//
|
|
// now calculate the number larger fragments
|
|
//
|
|
if ( cIncrementInstances > MaxInstances )
|
|
{
|
|
//
|
|
// no need for CPool; but we shouldn't alloc more than necessary
|
|
//
|
|
cFragmentInstances = cIncrementInstances = MaxInstances;
|
|
cFragments = 1;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Round up MaxInstances to a integral number of IncrementSize
|
|
//
|
|
MaxInstances += cIncrementInstances - 1;
|
|
MaxInstances /= cIncrementInstances;
|
|
MaxInstances *= cIncrementInstances;
|
|
|
|
//
|
|
// as an initial attempt divide the number of instances by max frags
|
|
//
|
|
cFragmentInstances = (MaxInstances + MAX_CPOOL_FRAGMENTS - 1) /
|
|
MAX_CPOOL_FRAGMENTS;
|
|
|
|
if ( cFragmentInstances == 0 )
|
|
{
|
|
cFragmentInstances = MaxInstances;
|
|
cFragments = 1;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// round up the number of instances in a fragment to an
|
|
// integral number of IncrementSizes
|
|
//
|
|
cFragmentInstances += cIncrementInstances - 1;
|
|
cFragmentInstances /= cIncrementInstances;
|
|
cFragmentInstances *= cIncrementInstances;
|
|
|
|
//
|
|
// recalculate the number of fragments required based on the integral
|
|
// number of IncrementSizes ( last one may no longer be required )
|
|
//
|
|
cFragments = (MaxInstances + cFragmentInstances - 1) /
|
|
cFragmentInstances;
|
|
}
|
|
}
|
|
|
|
_ASSERT( cFragments > 0 );
|
|
_ASSERT( cFragments*cFragmentInstances >= MaxInstances );
|
|
|
|
m_cInstanceSize = InstanceSize;
|
|
m_cMaxInstances = MaxInstances;
|
|
m_cFragments = cFragments;
|
|
|
|
m_cFragmentInstances = cFragmentInstances;
|
|
m_cIncrementInstances = cIncrementInstances;
|
|
|
|
TraceFunctLeave();
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------
|
|
//
|
|
// Function: ReleaseMemory
|
|
//
|
|
// Synopsis: Releases the pool
|
|
//
|
|
// Arguments: none
|
|
//
|
|
// Returns: TRUE is success, else FALSE
|
|
//
|
|
// History: HowardCu Created 8 May 1995
|
|
//
|
|
//----------------------------------------------------------------
|
|
BOOL CPool::ReleaseMemory( void )
|
|
{
|
|
TraceFunctEnter( "CPool::ReleaseMemory" );
|
|
|
|
BOOL bFree = TRUE;
|
|
DWORD i, cStart;
|
|
|
|
EnterCriticalSection( &m_PoolCriticalSection );
|
|
|
|
for ( i=cStart=0; i<m_cFragments; i++, cStart += m_cFragmentInstances )
|
|
{
|
|
LPVOID pHeap = m_pFragments[i];
|
|
if ( pHeap != NULL )
|
|
{
|
|
_ASSERT( cStart < m_cNumberCommitted );
|
|
|
|
DWORD cSize = min( m_cFragmentInstances, m_cNumberCommitted-cStart );
|
|
|
|
_VERIFY( bFree = VirtualFree( pHeap, cSize*m_cInstanceSize, MEM_DECOMMIT ) );
|
|
_VERIFY( bFree &=VirtualFree( pHeap, 0, MEM_RELEASE ) );
|
|
|
|
if ( bFree == FALSE )
|
|
{
|
|
ErrorTrace( (LPARAM)this, "VirtualFree failed: err %d", GetLastError() );
|
|
break;
|
|
}
|
|
|
|
m_pFragments[i] = NULL;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
LeaveCriticalSection( &m_PoolCriticalSection );
|
|
|
|
//
|
|
// zero out important data fields
|
|
//
|
|
m_pFreeList = NULL;
|
|
m_pExtraFreeLink = NULL;
|
|
|
|
m_cNumberCommitted = 0;
|
|
|
|
return bFree;
|
|
}
|
|
|
|
#ifdef CPOOL_DEBUG
|
|
//+---------------------------------------------------------------
|
|
//
|
|
// Function: InitDebugInstance
|
|
//
|
|
// Synopsis: sets up the appropriate debug class variables
|
|
//
|
|
// Arguments: void* pInstance: the new instance
|
|
// DWORD dwPoolSignature: parent Pool signature
|
|
// DWORD cInstanceSize: size of the enlarged instance
|
|
//
|
|
// Returns: void
|
|
//
|
|
// History: gordm Created 11 Jan 1996
|
|
//
|
|
//----------------------------------------------------------------
|
|
void InitDebugInstance(
|
|
char* pInstance,
|
|
DWORD dwPoolSignature,
|
|
DWORD cInstanceSize,
|
|
LPVOID pPoolFragment
|
|
)
|
|
{
|
|
CPoolDebugHead* pHead = new( pInstance ) CPoolDebugHead();
|
|
CPoolDebugTail* pTail = new( pInstance +
|
|
cInstanceSize -
|
|
sizeof(CPoolDebugTail) ) CPoolDebugTail();
|
|
|
|
pHead->m_pTailDebug = pTail;
|
|
pTail->m_pHeadDebug = pHead;
|
|
|
|
//
|
|
// helps with debugging to see the parent CPool signature
|
|
//
|
|
pHead->m_dwPoolSignature = dwPoolSignature;
|
|
|
|
//
|
|
// helps with asserts for valid ranges
|
|
//
|
|
pHead->m_PoolFragment = pPoolFragment;
|
|
|
|
//
|
|
// fake out the state before calling mark Free
|
|
//
|
|
pHead->m_dwState = USED_STATE;
|
|
pHead->MarkFree( dwPoolSignature, cInstanceSize );
|
|
}
|
|
#endif
|
|
|
|
|
|
//+---------------------------------------------------------------
|
|
//
|
|
// Function: GrowPool
|
|
//
|
|
// Synopsis: grows the number of committed instances in the pool
|
|
//
|
|
// Arguments: void
|
|
//
|
|
// Returns: void
|
|
//
|
|
// History: gordm Created 5 Jul 1995
|
|
//
|
|
//----------------------------------------------------------------
|
|
void CPool::GrowPool( void )
|
|
{
|
|
#ifdef ALLOC_TRACING
|
|
TraceFunctEnter( "CPool::GrowPool" );
|
|
#endif
|
|
|
|
DWORD cFragment = m_cNumberCommitted / m_cFragmentInstances;
|
|
DWORD cStart = m_cNumberCommitted % m_cFragmentInstances;
|
|
DWORD cbSize = (cStart+m_cIncrementInstances) * m_cInstanceSize;
|
|
|
|
#ifdef ALLOC_TRACING
|
|
DebugTrace( (LPARAM)this, "Expanding the pool to %d descriptors",
|
|
cNewCommit );
|
|
#endif
|
|
|
|
//
|
|
// if we're starting a new fragment
|
|
//
|
|
if ( cStart == 0 )
|
|
{
|
|
//
|
|
// if we are at a boundary of a fragment Reserve the next fragment
|
|
m_pFragments[cFragment] = VirtualAlloc(
|
|
NULL,
|
|
m_cFragmentInstances*m_cInstanceSize,
|
|
MEM_RESERVE | MEM_TOP_DOWN,
|
|
PAGE_NOACCESS
|
|
);
|
|
|
|
if ( m_pFragments[cFragment] == NULL )
|
|
{
|
|
#ifdef ALLOC_TRACING
|
|
ErrorTrace( (LPARAM)this,
|
|
"Could not reserve more memory: error = %d",
|
|
GetLastError() );
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
LPVOID pHeap = m_pFragments[cFragment];
|
|
|
|
if ( VirtualAlloc( pHeap,
|
|
cbSize,
|
|
MEM_COMMIT,
|
|
PAGE_READWRITE ) != NULL )
|
|
{
|
|
char* pStart = (char*)pHeap + cStart*m_cInstanceSize;
|
|
char* pLast = (char*)pHeap + cbSize - m_cInstanceSize;
|
|
|
|
//
|
|
// run the list joining the next pointers
|
|
// possible because we own the critsec
|
|
//
|
|
for ( char* p=pStart; p<pLast; p+=m_cInstanceSize)
|
|
{
|
|
|
|
#ifdef CPOOL_DEBUG
|
|
InitDebugInstance( p, m_dwSignature, m_cInstanceSize, pHeap );
|
|
#endif
|
|
//
|
|
// statement works for CPOOL_DEBUG as well because
|
|
// we reserve the first 4 bytes of CPoolDebugHead
|
|
//
|
|
((Link*)p)->pNext = (Link*)(p+m_cInstanceSize);
|
|
}
|
|
|
|
//
|
|
// terminate and then set the head to beginning of new list
|
|
//
|
|
#ifdef CPOOL_DEBUG
|
|
InitDebugInstance( pLast, m_dwSignature, m_cInstanceSize, pHeap );
|
|
#endif
|
|
|
|
((Link*)pLast)->pNext = NULL;
|
|
m_pFreeList = (Link*)pStart;
|
|
|
|
m_cNumberCommitted += m_cIncrementInstances;
|
|
}
|
|
|
|
#ifdef ALLOC_TRACING
|
|
else
|
|
{
|
|
ErrorTrace( (LPARAM)this,
|
|
"Could not commit another descriptor: error = %d",
|
|
GetLastError() );
|
|
}
|
|
TraceFunctLeave();
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------
|
|
//
|
|
// Function: GetContentionCount
|
|
//
|
|
// Synopsis: Returns the contention count on the alloc/free
|
|
// critsec
|
|
//
|
|
// Arguments: void
|
|
//
|
|
// Returns: the actual count
|
|
//
|
|
//----------------------------------------------------------------
|
|
DWORD CPool::GetContentionCount( void )
|
|
{
|
|
return m_PoolCriticalSection.DebugInfo != NULL ?
|
|
m_PoolCriticalSection.DebugInfo->ContentionCount :
|
|
0 ;
|
|
}
|
|
|
|
//+---------------------------------------------------------------
|
|
//
|
|
// Function: GetEntryCount
|
|
//
|
|
// Synopsis: Returns the entry count on the alloc/free
|
|
// critsec
|
|
//
|
|
// Arguments: void
|
|
//
|
|
// Returns: the actual count
|
|
//
|
|
//----------------------------------------------------------------
|
|
DWORD CPool::GetEntryCount( void )
|
|
{
|
|
return m_PoolCriticalSection.DebugInfo != NULL ?
|
|
m_PoolCriticalSection.DebugInfo->EntryCount :
|
|
0 ;
|
|
}
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------
|
|
//
|
|
// Function: GetInstanceSize
|
|
//
|
|
// Synopsis: Returns the application's instance size
|
|
//
|
|
// Arguments: void
|
|
//
|
|
// Returns: the instance size of the app
|
|
//
|
|
//----------------------------------------------------------------
|
|
DWORD CPool::GetInstanceSize( void )
|
|
{
|
|
#ifdef CPOOL_DEBUG
|
|
return m_cInstanceSize - sizeof(CPoolDebugHead) - sizeof(CPoolDebugTail);
|
|
#else
|
|
return m_cInstanceSize;
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
//+---------------------------------------------------------------
|
|
//
|
|
// Function: IsValid
|
|
//
|
|
// Synopsis: Validates the pool signature
|
|
//
|
|
// Arguments: void
|
|
//
|
|
// Returns: TRUE is success, else FALSE
|
|
//
|
|
// History: HowardCu Created 8 May 1995
|
|
//
|
|
//----------------------------------------------------------------
|
|
inline void CPool::IsValid( void )
|
|
{
|
|
_ASSERT( m_cMaxInstances != 0 );
|
|
_ASSERT( m_cInstanceSize >= sizeof(struct Link) );
|
|
_ASSERT( m_cIncrementInstances != 0 );
|
|
_ASSERT( m_dwSignature != 0 );
|
|
}
|
|
#endif
|