windows-nt/Source/XPSP1/NT/inetsrv/iis/staxinc/export/lockq.inl

271 lines
5.9 KiB
Plaintext
Raw Normal View History

2020-09-26 03:20:57 -05:00
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