1061 lines
24 KiB
C++
1061 lines
24 KiB
C++
/*==========================================================================
|
|
*
|
|
* Copyright (C) 1995 - 2000 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: LockedPool.h
|
|
* Content: Pool manager for classes
|
|
*
|
|
* History:
|
|
* Date By Reason
|
|
* ====== == ======
|
|
* 12-18-97 aarono Original
|
|
* 11-06-98 ejs Add custom handler for Release function
|
|
* 04-12-99 johnkan Trimmed unused functions and parameters, added size assert
|
|
* 01-31-2000 johnkan Added code to check for items already being in the pool on Release().
|
|
* 02-08-2000 johnkan Derived from ClassFPM.h
|
|
* 03-26-2000 johnkan Renamed to avoid collisions with other classes
|
|
* 04-06-2000 johnkan Modified to have a base class to derive pool items from
|
|
* 03-20-2001 vanceo Added thread-local versions
|
|
***************************************************************************/
|
|
|
|
#ifndef __LOCKED_POOL__
|
|
#define __LOCKED_POOL__
|
|
|
|
#undef DPF_SUBCOMP
|
|
#define DPF_SUBCOMP DN_SUBCOMP_COMMON
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define TRACK_POOL_STATS
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//**********************************************************************
|
|
// Constant definitions
|
|
//**********************************************************************
|
|
|
|
#define CHECK_FOR_DUPLICATE_LOCKED_POOL_RELEASE
|
|
|
|
//**********************************************************************
|
|
// Macro definitions
|
|
//**********************************************************************
|
|
|
|
#ifndef OFFSETOF
|
|
// Macro to compute the offset of an element inside of a larger structure (copied from MSDEV's STDLIB.H)
|
|
#define OFFSETOF(s,m) ( (INT_PTR) &(((s *)0)->m) )
|
|
#define __LOCAL_OFFSETOF_DEFINED__
|
|
#endif // OFFSETOF
|
|
|
|
//**********************************************************************
|
|
// Structure definitions
|
|
//**********************************************************************
|
|
|
|
//
|
|
// forward reference
|
|
//
|
|
class CLockedPoolItem;
|
|
template< class T > class CLockedPool;
|
|
|
|
//**********************************************************************
|
|
// Variable definitions
|
|
//**********************************************************************
|
|
|
|
//**********************************************************************
|
|
// Function prototypes
|
|
//**********************************************************************
|
|
|
|
//**********************************************************************
|
|
// Class definitions
|
|
//**********************************************************************
|
|
|
|
//
|
|
// class to act as a link in the pool
|
|
//
|
|
class CLockedPoolItem
|
|
{
|
|
public:
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CLockedPoolItem::CLockedPoolItem"
|
|
CLockedPoolItem()
|
|
{
|
|
m_iRefCount = 0;
|
|
m_pNext = NULL;
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CLockedPoolItem::~CLockedPoolItem"
|
|
virtual ~CLockedPoolItem() { DNASSERT( m_iRefCount == 0 ); }
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CLockedPoolItem::AddRef"
|
|
void AddRef( void )
|
|
{
|
|
DNASSERT( m_iRefCount != -1 );
|
|
InterlockedIncrement( const_cast<LONG*>( &m_iRefCount ) );
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CLockedPoolItem::DecRef"
|
|
void DecRef( void )
|
|
{
|
|
DNASSERT( m_iRefCount != 0 );
|
|
if ( InterlockedDecrement( const_cast<LONG*>( &m_iRefCount ) ) == 0 )
|
|
{
|
|
ReturnSelfToPool();
|
|
}
|
|
}
|
|
|
|
CLockedPoolItem *GetNext( void ) const { return m_pNext; }
|
|
void InvalidateNext( void ) { m_pNext = NULL; }
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CLockedPoolItem::LinkToPool"
|
|
void LinkToPool( CLockedPoolItem *volatile *const ppPoolItems )
|
|
{
|
|
DNASSERT( ppPoolItems != NULL );
|
|
m_pNext = *ppPoolItems;
|
|
*ppPoolItems = this;
|
|
}
|
|
|
|
//
|
|
// Default initialization and deinitialization functions. These can
|
|
// be overridden by the derived classes.
|
|
//
|
|
virtual BOOL PoolAllocFunction( void ){ return TRUE; }
|
|
virtual BOOL PoolInitFunction( void ){ return TRUE; }
|
|
virtual void PoolReleaseFunction( void ){};
|
|
virtual void PoolDeallocFunction( void ){};
|
|
|
|
protected:
|
|
|
|
private:
|
|
//
|
|
// reference count used to return this item to the pool
|
|
//
|
|
volatile LONG m_iRefCount;
|
|
|
|
//
|
|
// pointer used to link this item to the rest of the pool
|
|
//
|
|
CLockedPoolItem *m_pNext;
|
|
|
|
virtual void ReturnSelfToPool( void ) = 0;
|
|
|
|
//
|
|
// prevent unwarranted copies
|
|
//
|
|
CLockedPoolItem( const CLockedPoolItem & );
|
|
CLockedPoolItem& operator=( const CLockedPoolItem & );
|
|
};
|
|
|
|
|
|
//
|
|
// class to manage the pool
|
|
//
|
|
template< class T >
|
|
class CLockedPool
|
|
{
|
|
public:
|
|
CLockedPool();
|
|
~CLockedPool();
|
|
|
|
void Lock( void ) { DNEnterCriticalSection( &m_Lock ); }
|
|
void Unlock( void ) { DNLeaveCriticalSection( &m_Lock ); }
|
|
|
|
BOOL Initialize( void );
|
|
void Deinitialize( void );
|
|
|
|
T *Get( void );
|
|
void Release( T *const pItem );
|
|
|
|
protected:
|
|
|
|
private:
|
|
DNCRITICAL_SECTION m_Lock;
|
|
|
|
CLockedPoolItem *volatile m_pPool; // pointer to list of available elements
|
|
|
|
DEBUG_ONLY( BOOL m_fInitialized );
|
|
DEBUG_ONLY( volatile LONG m_lOutstandingItemCount );
|
|
|
|
T *RemoveNode( void )
|
|
{
|
|
T *pReturn;
|
|
|
|
|
|
if ( m_pPool != NULL )
|
|
{
|
|
pReturn = static_cast<T*>( m_pPool );
|
|
m_pPool = m_pPool->GetNext();
|
|
DEBUG_ONLY( pReturn->InvalidateNext() );
|
|
}
|
|
else
|
|
{
|
|
pReturn = NULL;
|
|
}
|
|
|
|
return pReturn;
|
|
}
|
|
|
|
//
|
|
// prevent unwarranted copies
|
|
//
|
|
CLockedPool< T >( const CLockedPool< T > & );
|
|
CLockedPool< T >& operator=( const CLockedPool< T > & );
|
|
};
|
|
|
|
|
|
//**********************************************************************
|
|
// Class function definitions
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CLockedPool::CLockedPool - constructor
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CLockedPool::CLockedPool"
|
|
|
|
template< class T >
|
|
CLockedPool< T >::CLockedPool():
|
|
m_pPool( NULL )
|
|
{
|
|
DEBUG_ONLY( m_fInitialized = FALSE );
|
|
DEBUG_ONLY( m_lOutstandingItemCount = 0 );
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CLockedPool::~CLockedPool - destructor
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CLockedPool::~CLockedPool"
|
|
|
|
template< class T >
|
|
CLockedPool< T >::~CLockedPool()
|
|
{
|
|
DEBUG_ONLY( DNASSERT( m_lOutstandingItemCount == 0 ) );
|
|
DEBUG_ONLY( DNASSERT( m_fInitialized == FALSE ) );
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CLockedPool::Initialize - initialize pool
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Boolean indicating success
|
|
// TRUE = initialization succeeded
|
|
// FALSE = initialization failed
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CLockedPool::Initialize"
|
|
|
|
template< class T >
|
|
BOOL CLockedPool< T >::Initialize( void )
|
|
{
|
|
BOOL fReturn;
|
|
|
|
|
|
DEBUG_ONLY( DNASSERT( m_fInitialized == FALSE ) );
|
|
|
|
fReturn = TRUE;
|
|
|
|
if ( DNInitializeCriticalSection( &m_Lock ) == FALSE )
|
|
{
|
|
fReturn = FALSE;
|
|
goto Exit;
|
|
}
|
|
DebugSetCriticalSectionRecursionCount( &m_Lock, 0 );
|
|
|
|
DEBUG_ONLY( m_fInitialized = TRUE );
|
|
|
|
Exit:
|
|
return fReturn;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CLockedPool::Deinitialize - deinitialize pool
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CLockedPool::Deinitialize"
|
|
|
|
template< class T >
|
|
void CLockedPool< T >::Deinitialize( void )
|
|
{
|
|
DEBUG_ONLY( DNASSERT( m_fInitialized != FALSE ) );
|
|
|
|
Lock();
|
|
|
|
DEBUG_ONLY( DNASSERT( m_lOutstandingItemCount == 0 ) );
|
|
while ( m_pPool != NULL )
|
|
{
|
|
CLockedPoolItem *pNode;
|
|
|
|
|
|
pNode = RemoveNode();
|
|
pNode->PoolDeallocFunction();
|
|
delete pNode;
|
|
}
|
|
|
|
Unlock();
|
|
|
|
DNDeleteCriticalSection( &m_Lock );
|
|
|
|
DEBUG_ONLY( m_fInitialized = FALSE );
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CLockedPool::Get - get an item from the pool
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Pointer to item
|
|
// NULL = out of memory
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CLockedPool::Get"
|
|
|
|
template< class T >
|
|
T *CLockedPool< T >::Get( void )
|
|
{
|
|
T *pReturn;
|
|
|
|
|
|
DEBUG_ONLY( DNASSERT( m_fInitialized != FALSE ) );
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
pReturn = NULL;
|
|
|
|
Lock();
|
|
|
|
//
|
|
// if the pool is empty, try to allocate a new entry, otherwise grab
|
|
// the first item from the pool
|
|
//
|
|
if ( m_pPool == NULL )
|
|
{
|
|
Unlock();
|
|
|
|
pReturn = new T;
|
|
if ( pReturn != NULL )
|
|
{
|
|
if ( pReturn->PoolAllocFunction() == FALSE )
|
|
{
|
|
delete pReturn;
|
|
pReturn = NULL;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pReturn = RemoveNode();
|
|
Unlock();
|
|
}
|
|
|
|
|
|
//
|
|
// if we have an entry (it was freshly created, or removed from the pool),
|
|
// attempt to initialize it before passing it to the user
|
|
//
|
|
if ( pReturn != NULL )
|
|
{
|
|
if ( pReturn->PoolInitFunction() == FALSE )
|
|
{
|
|
Lock();
|
|
|
|
pReturn->LinkToPool( &m_pPool );
|
|
|
|
Unlock();
|
|
|
|
pReturn = NULL;
|
|
}
|
|
else
|
|
{
|
|
pReturn->SetOwningPool( this );
|
|
pReturn->AddRef();
|
|
DEBUG_ONLY( InterlockedIncrement( const_cast<LONG*>( &m_lOutstandingItemCount ) ) );
|
|
}
|
|
}
|
|
|
|
return pReturn;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CLockedPool::Release - return item to pool
|
|
//
|
|
// Entry: Pointer to item
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CLockedPool::Release"
|
|
|
|
template< class T >
|
|
void CLockedPool< T >::Release( T *const pItem )
|
|
{
|
|
DEBUG_ONLY( DNASSERT( m_fInitialized != FALSE ) );
|
|
DNASSERT( pItem != NULL );
|
|
|
|
|
|
DEBUG_ONLY( DNASSERT( pItem->GetNext() == NULL ) );
|
|
pItem->PoolReleaseFunction();
|
|
|
|
Lock();
|
|
|
|
#if defined(CHECK_FOR_DUPLICATE_LOCKED_POOL_RELEASE) && defined(DEBUG)
|
|
{
|
|
CLockedPoolItem *pTemp;
|
|
|
|
|
|
pTemp = m_pPool;
|
|
while ( pTemp != NULL )
|
|
{
|
|
DNASSERT( pTemp != pItem );
|
|
pTemp = pTemp->GetNext();
|
|
}
|
|
}
|
|
#endif // CHECK_FOR_DUPLICATE_LOCKED_POOL_RELEASE
|
|
|
|
DEBUG_ONLY( pItem->SetOwningPool( NULL ) );
|
|
|
|
#ifdef NO_POOLS
|
|
pItem->PoolDeallocFunction();
|
|
delete pItem;
|
|
#else
|
|
pItem->LinkToPool( &m_pPool );
|
|
#endif
|
|
|
|
Unlock();
|
|
|
|
DEBUG_ONLY( InterlockedDecrement( const_cast<LONG*>( &m_lOutstandingItemCount ) ) );
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
|
|
//
|
|
// class to act as a link in the pool
|
|
//
|
|
class CLockedTLPoolItem
|
|
{
|
|
public:
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CLockedTLPoolItem::CLockedTLPoolItem"
|
|
CLockedTLPoolItem()
|
|
{
|
|
m_iRefCount = 0;
|
|
m_blList.Initialize();
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CLockedTLPoolItem::~CLockedTLPoolItem"
|
|
virtual ~CLockedTLPoolItem()
|
|
{
|
|
DNASSERT( m_iRefCount == 0 );
|
|
DNASSERT( m_blList.IsEmpty() );
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CLockedTLPoolItem::AddRef"
|
|
void AddRef( void )
|
|
{
|
|
DNASSERT( m_iRefCount != -1 );
|
|
InterlockedIncrement( const_cast<LONG*>( &m_iRefCount ) );
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CLockedTLPoolItem::DecRef"
|
|
void DecRef( void )
|
|
{
|
|
DNASSERT( m_iRefCount != 0 );
|
|
if ( InterlockedDecrement( const_cast<LONG*>( &m_iRefCount ) ) == 0 )
|
|
{
|
|
ReturnSelfToPool();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Default initialization and deinitialization functions. These can
|
|
// be overridden by the derived classes.
|
|
//
|
|
virtual BOOL PoolAllocFunction( void ){ return TRUE; }
|
|
virtual BOOL PoolInitFunction( void ){ return TRUE; }
|
|
virtual void PoolReleaseFunction( void ){};
|
|
virtual void PoolDeallocFunction( void ){};
|
|
|
|
|
|
//
|
|
// linkage to the rest of the pool
|
|
//
|
|
CBilink m_blList;
|
|
#ifdef TRACK_POOL_STATS
|
|
DWORD m_dwSourceThreadID;
|
|
#endif // TRACK_POOL_STATS
|
|
|
|
|
|
protected:
|
|
|
|
private:
|
|
//
|
|
// reference count used to return this item to the pool
|
|
//
|
|
volatile LONG m_iRefCount;
|
|
|
|
virtual void ReturnSelfToPool( void ) = 0;
|
|
|
|
//
|
|
// prevent unwarranted copies
|
|
//
|
|
CLockedTLPoolItem( const CLockedTLPoolItem & );
|
|
CLockedTLPoolItem& operator=( const CLockedTLPoolItem & );
|
|
};
|
|
|
|
|
|
//
|
|
// class to manage the pool
|
|
//
|
|
template< class T >
|
|
class CLockedTLPool
|
|
{
|
|
public:
|
|
CLockedTLPool();
|
|
~CLockedTLPool();
|
|
|
|
BOOL Initialize( CLockedTLPool< T > * pGlobalPool );
|
|
void Deinitialize( void );
|
|
|
|
T *Get( void );
|
|
void Release( T *const pItem );
|
|
static void ReleaseWithoutPool( T *const pItem );
|
|
|
|
protected:
|
|
|
|
private:
|
|
CBilink m_blItems; // bilink list of available elements
|
|
CLockedTLPool< T > * m_pGlobalPool; // pointer to global pool, or NULL if this is the global pool
|
|
DNCRITICAL_SECTION * m_pcsLock; // pointer to pool critical section, or NULL if this is not the global pool
|
|
DWORD m_dwNumItems; // number of items currently in this pool
|
|
|
|
DEBUG_ONLY( BOOL m_fInitialized );
|
|
#ifdef TRACK_POOL_STATS
|
|
DWORD m_dwAllocations; // how many objects were allocated by this pool
|
|
DWORD m_dwSlurpsFromGlobal; // how many times some items were taken from the global pool
|
|
DWORD m_dwLargestSlurpFromGlobal; // most number of items taken from the global pool at one time
|
|
DWORD m_dwRetrievals; // how many times objects were pulled out of this pool
|
|
DWORD m_dwReturnsOnSameThread; // how many times objects that were pulled out of this pool were returned to this pool
|
|
DWORD m_dwReturnsOnDifferentThread; // how many times objects that were pulled out of another thread's pool were returned to this pool
|
|
DWORD m_dwDumpsToGlobal; // how many times some items were dumped into the global pool
|
|
DWORD m_dwDeallocations; // how many objects were freed by this pool
|
|
#endif // TRACK_POOL_STATS
|
|
|
|
|
|
//
|
|
// prevent unwarranted copies
|
|
//
|
|
CLockedTLPool< T >( const CLockedTLPool< T > & );
|
|
CLockedTLPool< T >& operator=( const CLockedTLPool< T > & );
|
|
};
|
|
|
|
|
|
//**********************************************************************
|
|
// Class function definitions
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CLockedTLPool::CLockedTLPool - constructor
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CLockedTLPool::CLockedTLPool"
|
|
|
|
template< class T >
|
|
CLockedTLPool< T >::CLockedTLPool():
|
|
m_pGlobalPool( NULL ),
|
|
m_pcsLock( NULL ),
|
|
m_dwNumItems( 0 )
|
|
{
|
|
m_blItems.Initialize();
|
|
|
|
DEBUG_ONLY( m_fInitialized = FALSE );
|
|
#ifdef TRACK_POOL_STATS
|
|
m_dwAllocations = 0;
|
|
m_dwSlurpsFromGlobal = 0;
|
|
m_dwLargestSlurpFromGlobal = 0;
|
|
m_dwRetrievals = 0;
|
|
m_dwReturnsOnSameThread = 0;
|
|
m_dwReturnsOnDifferentThread = 0;
|
|
m_dwDumpsToGlobal = 0;
|
|
m_dwDeallocations = 0;
|
|
#endif // TRACK_POOL_STATS
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CLockedTLPool::~CLockedTLPool - destructor
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CLockedTLPool::~CLockedTLPool"
|
|
|
|
template< class T >
|
|
CLockedTLPool< T >::~CLockedTLPool()
|
|
{
|
|
DNASSERT( m_fInitialized == FALSE );
|
|
DNASSERT( m_dwNumItems == 0 );
|
|
DNASSERT( m_blItems.IsEmpty() );
|
|
DNASSERT( m_pcsLock == NULL );
|
|
|
|
#ifdef TRACK_POOL_STATS
|
|
DPFX(DPFPREP, 9, "Pool 0x%p information:", this);
|
|
DPFX(DPFPREP, 9, "\tAllocations = %u", m_dwAllocations);
|
|
DPFX(DPFPREP, 9, "\tSlurpsFromGlobal = %u", m_dwSlurpsFromGlobal);
|
|
DPFX(DPFPREP, 9, "\tLargestSlurpFromGlobal = %u", m_dwLargestSlurpFromGlobal);
|
|
DPFX(DPFPREP, 9, "\tRetrievals = %u", m_dwRetrievals);
|
|
DPFX(DPFPREP, 9, "\tReturnsOnSameThread = %u", m_dwReturnsOnSameThread);
|
|
DPFX(DPFPREP, 9, "\tReturnsOnDifferentThread = %u", m_dwReturnsOnDifferentThread);
|
|
DPFX(DPFPREP, 9, "\tDumpsToGlobal = %u", m_dwDumpsToGlobal);
|
|
DPFX(DPFPREP, 9, "\tDeallocations = %u", m_dwDeallocations);
|
|
#endif // TRACK_POOL_STATS
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CLockedTLPool::Initialize - initialize pool
|
|
//
|
|
// Entry: Pointer to global pool, or NULL if this is the global pool
|
|
//
|
|
// Exit: Boolean indicating success
|
|
// TRUE = initialization succeeded
|
|
// FALSE = initialization failed
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CLockedTLPool::Initialize"
|
|
|
|
template< class T >
|
|
BOOL CLockedTLPool< T >::Initialize( CLockedTLPool< T > * pGlobalPool )
|
|
{
|
|
BOOL fReturn;
|
|
|
|
|
|
fReturn = TRUE;
|
|
|
|
m_pGlobalPool = pGlobalPool;
|
|
if (pGlobalPool == NULL)
|
|
{
|
|
//DPFX(DPFPREP, 9, "Initializing global pool 0x%p.", this);
|
|
m_pcsLock = (DNCRITICAL_SECTION*) DNMalloc( sizeof(DNCRITICAL_SECTION) );
|
|
if (m_pcsLock == NULL)
|
|
{
|
|
fReturn = FALSE;
|
|
goto Exit;
|
|
}
|
|
|
|
if (! DNInitializeCriticalSection( m_pcsLock ))
|
|
{
|
|
DNFree( m_pcsLock );
|
|
DEBUG_ONLY( m_pcsLock = NULL );
|
|
fReturn = FALSE;
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
DEBUG_ONLY( DNASSERT( m_fInitialized == FALSE ) );
|
|
DEBUG_ONLY( m_fInitialized = TRUE );
|
|
|
|
|
|
Exit:
|
|
|
|
return fReturn;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CLockedTLPool::Deinitialize - deinitialize pool
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CLockedTLPool::Deinitialize"
|
|
|
|
template< class T >
|
|
void CLockedTLPool< T >::Deinitialize( void )
|
|
{
|
|
CBilink * pBilink;
|
|
T * pItem;
|
|
|
|
|
|
pBilink = m_blItems.GetNext();
|
|
while ( pBilink != &m_blItems )
|
|
{
|
|
pItem = CONTAINING_OBJECT(pBilink, T, m_blList);
|
|
pBilink = pBilink->GetNext();
|
|
pItem->m_blList.RemoveFromList();
|
|
|
|
pItem->PoolDeallocFunction();
|
|
delete pItem;
|
|
#ifdef TRACK_POOL_STATS
|
|
m_dwDeallocations++;
|
|
#endif // TRACK_POOL_STATS
|
|
DEBUG_ONLY( m_dwNumItems-- );
|
|
}
|
|
|
|
DEBUG_ONLY( DNASSERT( m_fInitialized != FALSE ) );
|
|
DEBUG_ONLY( m_fInitialized = FALSE );
|
|
|
|
if (m_pcsLock != NULL)
|
|
{
|
|
//DPFX(DPFPREP, 9, "Deinitializing global pool 0x%p.", this);
|
|
|
|
DNDeleteCriticalSection( m_pcsLock );
|
|
|
|
DNFree( m_pcsLock );
|
|
DEBUG_ONLY( m_pcsLock = NULL );
|
|
}
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CLockedTLPool::Get - get an item from the pool
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Pointer to item
|
|
// NULL = out of memory
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CLockedTLPool::Get"
|
|
|
|
template< class T >
|
|
T *CLockedTLPool< T >::Get( void )
|
|
{
|
|
CBilink * pBilink;
|
|
T * pReturn;
|
|
|
|
|
|
DNASSERT( m_fInitialized != FALSE );
|
|
DNASSERT( m_pGlobalPool != NULL );
|
|
|
|
|
|
//
|
|
// If the pool is empty, steal the ones in the global pool.
|
|
//
|
|
pBilink = m_blItems.GetNext();
|
|
if ( pBilink == &m_blItems )
|
|
{
|
|
DNEnterCriticalSection( m_pGlobalPool->m_pcsLock );
|
|
|
|
pBilink = m_pGlobalPool->m_blItems.GetNext();
|
|
if ( pBilink == &m_pGlobalPool->m_blItems )
|
|
{
|
|
//
|
|
// No items. Drop global pool lock and allocate a new one.
|
|
//
|
|
DNLeaveCriticalSection( m_pGlobalPool->m_pcsLock );
|
|
|
|
|
|
pReturn = new T;
|
|
if ( pReturn != NULL )
|
|
{
|
|
if ( pReturn->PoolAllocFunction() == FALSE )
|
|
{
|
|
delete pReturn;
|
|
|
|
pReturn = NULL;
|
|
goto Exit;
|
|
}
|
|
#ifdef TRACK_POOL_STATS
|
|
else
|
|
{
|
|
//
|
|
// Update counter.
|
|
//
|
|
m_dwAllocations++;
|
|
}
|
|
#endif // TRACK_POOL_STATS
|
|
}
|
|
else
|
|
{
|
|
pReturn = NULL;
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Separate all the items from the global list.
|
|
// We still have a pointer to the orphaned items (pBilink).
|
|
//
|
|
|
|
m_pGlobalPool->m_blItems.RemoveFromList();
|
|
|
|
DNASSERT(m_pGlobalPool->m_dwNumItems > 0);
|
|
|
|
#ifdef TRACK_POOL_STATS
|
|
m_dwSlurpsFromGlobal++;
|
|
if ( m_pGlobalPool->m_dwNumItems > m_dwLargestSlurpFromGlobal )
|
|
{
|
|
m_dwLargestSlurpFromGlobal = m_pGlobalPool->m_dwNumItems;
|
|
}
|
|
#endif // TRACK_POOL_STATS
|
|
|
|
m_dwNumItems = m_pGlobalPool->m_dwNumItems - 1; // -1 because we need one right now
|
|
m_pGlobalPool->m_dwNumItems = 0;
|
|
|
|
|
|
//
|
|
// Drop the lock since we don't need the global pool anymore.
|
|
//
|
|
DNLeaveCriticalSection( m_pGlobalPool->m_pcsLock );
|
|
|
|
|
|
//
|
|
// Get the first item from the orphaned list.
|
|
//
|
|
pReturn = CONTAINING_OBJECT(pBilink, T, m_blList);
|
|
|
|
//
|
|
// If there was more than one item in the global pool, transfer
|
|
// the remaining orphaned items (after the first) to this pool.
|
|
//
|
|
if (pBilink != pBilink->GetNext())
|
|
{
|
|
pBilink = pBilink->GetNext();
|
|
pReturn->m_blList.RemoveFromList();
|
|
m_blItems.InsertBefore(pBilink);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pReturn = CONTAINING_OBJECT(pBilink, T, m_blList);
|
|
pBilink->RemoveFromList();
|
|
|
|
DNASSERT( m_dwNumItems > 0 );
|
|
m_dwNumItems--;
|
|
}
|
|
|
|
//
|
|
// If we're here, we have an entry (it was freshly created, or removed from
|
|
// some pool). Attempt to initialize it before passing it to the user.
|
|
//
|
|
if ( pReturn->PoolInitFunction() == FALSE )
|
|
{
|
|
pReturn->m_blList.InsertAfter( &m_blItems );
|
|
pReturn = NULL;
|
|
}
|
|
else
|
|
{
|
|
pReturn->AddRef();
|
|
|
|
#ifdef TRACK_POOL_STATS
|
|
//
|
|
// Update status counts.
|
|
//
|
|
m_dwRetrievals++;
|
|
pReturn->m_dwSourceThreadID = GetCurrentThreadId();
|
|
#endif // TRACK_POOL_STATS
|
|
}
|
|
|
|
|
|
Exit:
|
|
|
|
return pReturn;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CLockedTLPool::Release - return item to pool
|
|
//
|
|
// Entry: Pointer to item
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CLockedTLPool::Release"
|
|
|
|
template< class T >
|
|
void CLockedTLPool< T >::Release( T *const pItem )
|
|
{
|
|
DNASSERT( m_fInitialized != FALSE );
|
|
DNASSERT( m_pGlobalPool != NULL );
|
|
DNASSERT( pItem != NULL );
|
|
DBG_CASSERT( sizeof( BYTE* ) == sizeof( pItem ) );
|
|
|
|
#if defined(CHECK_FOR_DUPLICATE_CONTEXTCFPM_RELEASE) && defined(DEBUG)
|
|
DNASSERT( ! pItem->m_blList.IsListMember( &m_blItems ));
|
|
#endif // CHECK_FOR_DUPLICATE_CONTEXTCFPM_RELEASE
|
|
|
|
pItem->PoolReleaseFunction();
|
|
|
|
#ifdef TRACK_POOL_STATS
|
|
//
|
|
// Update status counts.
|
|
//
|
|
if (pItem->m_dwSourceThreadID == GetCurrentThreadId())
|
|
{
|
|
m_dwReturnsOnSameThread++;
|
|
}
|
|
else
|
|
{
|
|
m_dwReturnsOnDifferentThread++;
|
|
}
|
|
#endif // TRACK_POOL_STATS
|
|
|
|
|
|
#ifdef NO_POOLS
|
|
pItem->PoolDeallocFunction();
|
|
delete pItem;
|
|
#ifdef TRACK_POOL_STATS
|
|
m_dwDeallocations++;
|
|
#endif // TRACK_POOL_STATS
|
|
#else
|
|
pItem->m_blList.InsertAfter( &m_blItems );
|
|
m_dwNumItems++;
|
|
|
|
|
|
//
|
|
// If this pool has built up some extra items, return them to the
|
|
// global pool.
|
|
//
|
|
if ( m_dwNumItems >= 25 )
|
|
{
|
|
CBilink * pFirstItem;
|
|
|
|
|
|
//
|
|
// Save a pointer to the first item.
|
|
//
|
|
pFirstItem = m_blItems.GetNext();
|
|
DNASSERT( pFirstItem != &m_blItems );
|
|
|
|
//
|
|
// Orphan the items.
|
|
//
|
|
m_blItems.RemoveFromList();
|
|
|
|
|
|
//
|
|
// Take the lock and transfer the list to the global pool.
|
|
//
|
|
|
|
DNEnterCriticalSection( m_pGlobalPool->m_pcsLock );
|
|
|
|
m_pGlobalPool->m_blItems.AttachListBefore(pFirstItem);
|
|
m_pGlobalPool->m_dwNumItems += m_dwNumItems;
|
|
|
|
DNLeaveCriticalSection( m_pGlobalPool->m_pcsLock );
|
|
|
|
m_dwNumItems = 0;
|
|
#ifdef TRACK_POOL_STATS
|
|
m_dwDumpsToGlobal++;
|
|
#endif // TRACK_POOL_STATS
|
|
}
|
|
#endif // ! NO_POOLS
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CLockedTLPool::ReleaseWithoutPool - destroy an item without returning it
|
|
// to a pool
|
|
// NOTE: this is a static function
|
|
// and cannot use the 'this' pointer!
|
|
//
|
|
// Entry: Pointer to item
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CContextFixedTLPool::ReleaseWithoutPool"
|
|
|
|
template< class T >
|
|
void CLockedTLPool< T >::ReleaseWithoutPool( T *const pItem )
|
|
{
|
|
DNASSERT( pItem != NULL );
|
|
DBG_CASSERT( sizeof( BYTE* ) == sizeof( pItem ) );
|
|
|
|
DNASSERT( pItem->m_blList.IsEmpty() );
|
|
pItem->PoolReleaseFunction();
|
|
pItem->PoolDeallocFunction();
|
|
delete pItem;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
|
|
#ifdef __LOCAL_OFFSETOF_DEFINED__
|
|
#undef __LOCAL_OFFSETOF_DEFINED__
|
|
#undef OFFSETOF
|
|
#endif // __LOCAL_OFFSETOF_DEFINED__
|
|
|
|
|
|
#undef DPF_SUBCOMP
|
|
#undef DPF_MODNAME
|
|
|
|
#endif // __LOCKED_POOL__
|