/*========================================================================== * * 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( &m_iRefCount ) ); } #undef DPF_MODNAME #define DPF_MODNAME "CLockedContextFixedPoolItem::DecRef" void DecRef( void ) { DNASSERT( m_iRefCount != 0 ); if ( InterlockedDecrement( const_cast( &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( 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( &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( &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__