You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
270 lines
6.2 KiB
270 lines
6.2 KiB
|
|
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
|
|
|