inline
CQueueLock::CQueueLock( ) : m_pHead( &m_special ), m_pTail( &m_special ) {

	//
	// This function initializes the queue to an empty state.
	// In the empty state the queue contains one element which
	// has a Next pointer of 'LOCKVAL'.
	// The next pointer is initialized to LOCKVAL so that the first
	// append to the Queue owns the removal lock.
	//
 	m_special.m_pNext = (CQElement*)((DWORD_PTR)LOCKVAL) ;
}

inline
CQueueLock::CQueueLock(	BOOL	fSet ) :
	m_pHead( &m_special ),
	m_pTail( &m_special )	{

	if( fSet ) {
		m_special.m_pNext = (CQElement*)((DWORD_PTR)LOCKVAL) ;
	}	else	{
		m_special.m_pNext = 0 ;
	}
}

#ifdef	LOCKQ_DEBUG

CQueueLock::~CQueueLock( ) {
//	_ASSERT( m_pHead == m_pTail ) ;
//	_ASSERT( m_pHead == &m_special ) ;
//	_ASSERT( m_dwOwningThread == 0 || m_dwOwningThread == GetCurrentThreadId() ) ;

}
#endif

inline void
CQueueLock::Reset(	)	{

	m_pTail->m_pNext = (CQElement*)((DWORD_PTR)LOCKVAL) ;

}



inline BOOL
CQueueLock::Append( CQElement*	pAppend ) {
	//
	// We must set the Next pointer to NULL so that the next
	//	we come to append the tail pointer is properly set up.
	//
//	_ASSERT( pAppend->m_pNext == 0 ) ;
	pAppend->m_pNext = 0 ;

	// Get the old tail pointer.  This guy won't be touched by the
	// remove thread if his next pointer is still NULL.
	CQElement*	pTemp = (CQElement*)InterlockedExchangePointer( (LPVOID *)&m_pTail, pAppend ) ;

	// After we set the old tail pointer's next pointer to NON NULL
	// he becomes fair game for whoever is removing from the queue.
	// We may become the thread removing from the queue if whoever was
	// previously removing got to the last element and changed its next pointer
	// to LOCKVAL.
	//
	// NOTE : This thread and any thread doing removals should be the only
	//	threads touching the pNext field of the pTemp element.
	//
	PVOID	l = InterlockedExchangePointer( (LPVOID *)&(pTemp->m_pNext), pAppend ) ;

	return	l == (PVOID)LOCKVAL ;
}

inline CQElement*
CQueueLock::RemoveAndRelease( void )	{


	CQElement*	p = (CQElement*)InterlockedCompareExchangePointer( (LPVOID*)&m_pHead->m_pNext,
												(LPVOID)LOCKVAL,
												0 ) ;

	_ASSERT( (DWORD_PTR)p != LOCKVAL ) ;

	if( p != 0 ) {

		//
		//	There is an element following the head element -
		//	so we can safely examine the head element has nobody
		//	will touch its next pointer but us !
		//

		CQElement*	pReturn = m_pHead ;
		m_pHead = p ;
		pReturn->m_pNext = 0 ;

		if( pReturn == &m_special ) {

			//
			//	We can ignore the return value of Append -
			//	it must always succeed as we are the only thread
			//	that is allowed to relinquish the lock, and we ain't going to
			//	do so !
			//
			Append( pReturn ) ;

			//
			//	Now, we must offer ownership again !
			//

			p = (CQElement*)InterlockedCompareExchangePointer( (LPVOID*)&m_pHead->m_pNext,
														(LPVOID)LOCKVAL,
														0 ) ;

			_ASSERT( (DWORD_PTR)p != LOCKVAL ) ;

			if( p != 0 ) {

				//
				//	The head element must not be the special element -
				//	we took pains already to see that that didn't happen -
				//	so we can safely remove the element from the head of the queue.
				//

				pReturn = m_pHead ;
				m_pHead = p ;
				pReturn->m_pNext = 0 ;
		
				return	pReturn ;
			}

		}	else	{

			return	pReturn ;

		}
	
	}

	//
	//	_ASSERT( p==0 ) ;
	//

	return	p ;
}

inline CQElement*
CQueueLock::Remove( void )	{


	CQElement*	p = m_pHead->m_pNext ;
	if( p != 0 ) {

		//
		//	There is an element following the head element -
		//	so we can safely examine the head element has nobody
		//	will touch its next pointer but us !
		//
		p = m_pHead ;

		if( p == &m_special ) {

			//
			//	The head element is the special element, so we want
			//	to send it to the back and try examining the front again !
			//

			m_pHead = p->m_pNext ;
			p->m_pNext = 0 ;

			//
			//	We can ignore the return value of Append -
			//	it must always succeed as we are the only thread
			//	that is allowed to relinquish the lock, and we ain't going to
			//	do so !
			//
			Append( p ) ;

			//
			//	Ok, lets see if we can remove the head element now !
			//

			p = m_pHead->m_pNext ;
		}
	
		//
		//	If this ain't 0, then the next pointer is set
		//	and no other threads will be touching the next pointer,
		//	so we can safely advance the head pointer and return
		//	the first element.
		//
		if( p != 0 ) {

			p = m_pHead ;
			//
			//	The head element must not be the special element -
			//	we took pains already to see that that didn't happen -
			//	so we can safely remove the element from the head of the queue.
			//
			m_pHead = p->m_pNext ;
			p->m_pNext = 0 ;
	
			return	p ;
		}
	}

	return	0 ;
}


template< class Element >
inline	TLockQueue< Element >::TLockQueue( ) { }

template< class	Element >
inline	TLockQueue< Element >::TLockQueue( BOOL fSet ) :
	m_queue( fSet ) { }

template< class Element >
inline	void	TLockQueue< Element >::Reset()	{
	m_queue.Reset() ;
}

template< class Element >
inline	BOOL	TLockQueue< Element >::Append( Element *p ) {
	return	m_queue.Append( (CQElement*)p ) ;
}

template< class Element >
inline	Element*	TLockQueue< Element >::Remove( ) {
	return	(Element*) m_queue.Remove( ) ;
}

template< class Element >
inline	Element*	TLockQueue< Element >::RemoveAndRelease( ) {
	return	(Element*) m_queue.RemoveAndRelease( ) ;
}



#ifndef _NO_TEMPLATES_

template< class Element >
inline	TLockQueueV1< Element >::TLockQueueV1( ) { }

template< class Element >
inline	TLockQueueV1< Element >::~TLockQueueV1( ) { }

template< class Element >
inline	BOOL	TLockQueueV1< Element >::Append( Element *p ) {
	return	m_queue.Append( (CQElement*)p ) ;
}

template< class Element >
inline	void	TLockQueueV1< Element >::Remove( ) {
	m_queue.Remove( ) ;
}

template< class Element >
inline	BOOL	TLockQueueV1< Element >::GetHead( Element* &p ) {
	CQElement	*pTemp = 0 ;
	BOOL	fTemp = m_queue.GetHead( pTemp ) ;
	p = (Element*)pTemp ;
	return	fTemp ;
}

template< class Element >
inline	BOOL	TLockQueueV1< Element >::RemoveAndRelease( ) {
	return	m_queue.RemoveAndRelease( ) ;
}

#endif