450 lines
11 KiB
C
450 lines
11 KiB
C
|
/*==========================================================================
|
||
|
*
|
||
|
* Copyright (C) 1995 - 2000 Microsoft Corporation. All Rights Reserved.
|
||
|
*
|
||
|
* File: LockedContextFixedPool.h
|
||
|
* Content: fixed pool manager for classes that takes into account contexts
|
||
|
*
|
||
|
* 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
|
||
|
***************************************************************************/
|
||
|
|
||
|
#ifndef __LOCKED_CONTEXT_FIXED_POOL__
|
||
|
#define __LOCKED_CONTEXT_FIXED_POOL__
|
||
|
|
||
|
#undef DPF_SUBCOMP
|
||
|
#define DPF_SUBCOMP DN_SUBCOMP_COMMON
|
||
|
|
||
|
|
||
|
//**********************************************************************
|
||
|
// Constant definitions
|
||
|
//**********************************************************************
|
||
|
|
||
|
#define CHECK_FOR_DUPLICATE_LOCKED_CONTEXT_FPM_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
|
||
|
//
|
||
|
template< class S > class CLockedContextFixedPoolItem;
|
||
|
template< class T, class S > class CLockedContextFixedPool;
|
||
|
|
||
|
//**********************************************************************
|
||
|
// Variable definitions
|
||
|
//**********************************************************************
|
||
|
|
||
|
//**********************************************************************
|
||
|
// Function prototypes
|
||
|
//**********************************************************************
|
||
|
|
||
|
//**********************************************************************
|
||
|
// Class definitions
|
||
|
//**********************************************************************
|
||
|
|
||
|
//
|
||
|
// class to act as a link in the pool
|
||
|
//
|
||
|
template< class S >
|
||
|
class CLockedContextFixedPoolItem
|
||
|
{
|
||
|
public:
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CLockedContextFixedPoolItem::CLockedContextFixedPoolItem"
|
||
|
CLockedContextFixedPoolItem()
|
||
|
{
|
||
|
m_iRefCount = 0;
|
||
|
m_pNext = NULL;
|
||
|
}
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CLockedContextFixedPoolItem::~CLockedContextFixedPoolItem"
|
||
|
virtual ~CLockedContextFixedPoolItem() { DNASSERT( m_iRefCount == 0 ); }
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CLockedContextFixedPoolItem::AddRef"
|
||
|
void AddRef( void )
|
||
|
{
|
||
|
DNASSERT( m_iRefCount != -1 );
|
||
|
InterlockedIncrement( const_cast<LONG*>( &m_iRefCount ) );
|
||
|
}
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CLockedContextFixedPoolItem::DecRef"
|
||
|
void DecRef( void )
|
||
|
{
|
||
|
DNASSERT( m_iRefCount != 0 );
|
||
|
if ( InterlockedDecrement( const_cast<LONG*>( &m_iRefCount ) ) == 0 )
|
||
|
{
|
||
|
ReturnSelfToPool();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CLockedContextFixedPoolItem *GetNext( void ) const { return m_pNext; }
|
||
|
void InvalidateNext( void ) { m_pNext = NULL; }
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CLockedContextFixedPoolItem::LinkToPool"
|
||
|
void LinkToPool( CLockedContextFixedPoolItem *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( S Context ){ return TRUE; }
|
||
|
virtual BOOL PoolInitFunction( S Context ){ 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
|
||
|
//
|
||
|
CLockedContextFixedPoolItem *m_pNext;
|
||
|
|
||
|
virtual void ReturnSelfToPool( void ) = 0;
|
||
|
|
||
|
//
|
||
|
// prevent unwarranted copies
|
||
|
//
|
||
|
CLockedContextFixedPoolItem< S >( const CLockedContextFixedPoolItem< S > & );
|
||
|
CLockedContextFixedPoolItem< S >& operator=( const CLockedContextFixedPoolItem< S > & );
|
||
|
};
|
||
|
|
||
|
|
||
|
//
|
||
|
// class to manage the pool
|
||
|
//
|
||
|
template< class T, class S >
|
||
|
class CLockedContextFixedPool
|
||
|
{
|
||
|
public:
|
||
|
CLockedContextFixedPool();
|
||
|
~CLockedContextFixedPool();
|
||
|
|
||
|
void Lock( void ) { DNEnterCriticalSection( &m_Lock ); }
|
||
|
void Unlock( void ) { DNLeaveCriticalSection( &m_Lock ); }
|
||
|
|
||
|
BOOL Initialize( void );
|
||
|
void Deinitialize( void );
|
||
|
|
||
|
T *Get( S Context );
|
||
|
void Release( T *const pItem );
|
||
|
|
||
|
protected:
|
||
|
|
||
|
private:
|
||
|
DNCRITICAL_SECTION m_Lock;
|
||
|
|
||
|
CLockedContextFixedPoolItem< S > *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
|
||
|
//
|
||
|
CLockedContextFixedPool< T, S >( const CLockedContextFixedPool< T, S > & );
|
||
|
CLockedContextFixedPool< T, S >& operator=( const CLockedContextFixedPool< T, S > & );
|
||
|
};
|
||
|
|
||
|
|
||
|
//**********************************************************************
|
||
|
// Class function definitions
|
||
|
//**********************************************************************
|
||
|
|
||
|
|
||
|
//**********************************************************************
|
||
|
// ------------------------------
|
||
|
// CLockedContextFixedPool::CLockedContextFixedPool - constructor
|
||
|
//
|
||
|
// Entry: Nothing
|
||
|
//
|
||
|
// Exit: Nothing
|
||
|
// ------------------------------
|
||
|
template< class T, class S >
|
||
|
CLockedContextFixedPool< T, S >::CLockedContextFixedPool():
|
||
|
m_pPool( NULL )
|
||
|
{
|
||
|
DEBUG_ONLY( m_fInitialized = FALSE );
|
||
|
DEBUG_ONLY( m_lOutstandingItemCount = 0 );
|
||
|
}
|
||
|
//**********************************************************************
|
||
|
|
||
|
|
||
|
//**********************************************************************
|
||
|
// ------------------------------
|
||
|
// CLockedContextFixedPool::~CLockedContextFixedPool - destructor
|
||
|
//
|
||
|
// Entry: Nothing
|
||
|
//
|
||
|
// Exit: Nothing
|
||
|
// ------------------------------
|
||
|
template< class T, class S >
|
||
|
CLockedContextFixedPool< T, S >::~CLockedContextFixedPool()
|
||
|
{
|
||
|
DEBUG_ONLY( DNASSERT( m_lOutstandingItemCount == 0 ) );
|
||
|
DEBUG_ONLY( DNASSERT( m_fInitialized == FALSE ) );
|
||
|
}
|
||
|
//**********************************************************************
|
||
|
|
||
|
|
||
|
//**********************************************************************
|
||
|
// ------------------------------
|
||
|
// CLockedContextFixedPool::Initialize - initialize pool
|
||
|
//
|
||
|
// Entry: Nothing
|
||
|
// Pointer to function to call when a new entry is removed from the pool
|
||
|
// Pointer to function to call when an entry is returned to the pool
|
||
|
// Pointer to function to call when an entry is deallocated
|
||
|
//
|
||
|
// Exit: Boolean indicating success
|
||
|
// TRUE = initialization succeeded
|
||
|
// FALSE = initialization failed
|
||
|
// ------------------------------
|
||
|
template< class T, class S >
|
||
|
BOOL CLockedContextFixedPool< T, S >::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;
|
||
|
}
|
||
|
//**********************************************************************
|
||
|
|
||
|
|
||
|
//**********************************************************************
|
||
|
// ------------------------------
|
||
|
// CLockedContextFixedPool::Deinitialize - deinitialize pool
|
||
|
//
|
||
|
// Entry: Nothing
|
||
|
//
|
||
|
// Exit: Nothing
|
||
|
// ------------------------------
|
||
|
template< class T, class S >
|
||
|
void CLockedContextFixedPool< T, S >::Deinitialize( void )
|
||
|
{
|
||
|
DEBUG_ONLY( DNASSERT( m_fInitialized != FALSE ) );
|
||
|
|
||
|
Lock();
|
||
|
|
||
|
DEBUG_ONLY( DNASSERT( m_lOutstandingItemCount == 0 ) );
|
||
|
while ( m_pPool != NULL )
|
||
|
{
|
||
|
CLockedContextFixedPoolItem< S > *pNode;
|
||
|
|
||
|
|
||
|
pNode = RemoveNode();
|
||
|
pNode->PoolDeallocFunction();
|
||
|
delete pNode;
|
||
|
}
|
||
|
|
||
|
Unlock();
|
||
|
|
||
|
DNDeleteCriticalSection( &m_Lock );
|
||
|
|
||
|
DEBUG_ONLY( m_fInitialized = FALSE );
|
||
|
}
|
||
|
//**********************************************************************
|
||
|
|
||
|
|
||
|
//**********************************************************************
|
||
|
// ------------------------------
|
||
|
// CLockedContextFixedPool::Get - get an item from the pool
|
||
|
//
|
||
|
// Entry: Pointer to user context
|
||
|
//
|
||
|
// Exit: Pointer to item
|
||
|
// NULL = out of memory
|
||
|
// ------------------------------
|
||
|
template< class T, class S >
|
||
|
T *CLockedContextFixedPool< T, S >::Get( S Context )
|
||
|
{
|
||
|
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( Context ) == 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( Context ) == 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;
|
||
|
}
|
||
|
//**********************************************************************
|
||
|
|
||
|
|
||
|
//**********************************************************************
|
||
|
// ------------------------------
|
||
|
// CLockedContextFixedPool::Release - return item to pool
|
||
|
//
|
||
|
// Entry: Pointer to item
|
||
|
//
|
||
|
// Exit: Nothing
|
||
|
// ------------------------------
|
||
|
template< class T, class S >
|
||
|
void CLockedContextFixedPool< T, S >::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_CONTEXT_FPM_RELEASE) && defined(DEBUG)
|
||
|
{
|
||
|
CLockedContextFixedPoolItem< S > *pTemp;
|
||
|
|
||
|
|
||
|
pTemp = m_pPool;
|
||
|
while ( pTemp != NULL )
|
||
|
{
|
||
|
DNASSERT( pTemp != pItem );
|
||
|
pTemp = pTemp->GetNext();
|
||
|
}
|
||
|
}
|
||
|
#endif // CHECK_FOR_DUPLICATE_LOCKED_CONTEXT_FPM_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 ) ) );
|
||
|
}
|
||
|
//**********************************************************************
|
||
|
|
||
|
#ifdef __LOCAL_OFFSETOF_DEFINED__
|
||
|
#undef __LOCAL_OFFSETOF_DEFINED__
|
||
|
#undef OFFSETOF
|
||
|
#endif // __LOCAL_OFFSETOF_DEFINED__
|
||
|
|
||
|
#undef DPF_SUBCOMP
|
||
|
#undef DPF_MODNAME
|
||
|
|
||
|
#endif // __LOCKED_CONTEXT_FIXED_POOL__
|