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