Leaked source code of windows server 2003
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.

268 lines
6.2 KiB

  1. inline
  2. CQueueLock::CQueueLock( ) : m_pHead( &m_special ), m_pTail( &m_special ) {
  3. //
  4. // This function initializes the queue to an empty state.
  5. // In the empty state the queue contains one element which
  6. // has a Next pointer of 'LOCKVAL'.
  7. // The next pointer is initialized to LOCKVAL so that the first
  8. // append to the Queue owns the removal lock.
  9. //
  10. m_special.m_pNext = (CQElement*)((DWORD)LOCKVAL) ;
  11. }
  12. inline
  13. CQueueLock::CQueueLock( BOOL fSet ) :
  14. m_pHead( &m_special ),
  15. m_pTail( &m_special ) {
  16. if( fSet ) {
  17. m_special.m_pNext = (CQElement*)((DWORD)LOCKVAL) ;
  18. } else {
  19. m_special.m_pNext = 0 ;
  20. }
  21. }
  22. #ifdef LOCKQ_DEBUG
  23. CQueueLock::~CQueueLock( ) {
  24. // _ASSERT( m_pHead == m_pTail ) ;
  25. // _ASSERT( m_pHead == &m_special ) ;
  26. // _ASSERT( m_dwOwningThread == 0 || m_dwOwningThread == GetCurrentThreadId() ) ;
  27. }
  28. #endif
  29. inline void
  30. CQueueLock::Reset( ) {
  31. m_pTail->m_pNext = (CQElement*)((DWORD)LOCKVAL) ;
  32. }
  33. inline BOOL
  34. CQueueLock::Append( CQElement* pAppend ) {
  35. //
  36. // We must set the Next pointer to NULL so that the next
  37. // we come to append the tail pointer is properly set up.
  38. //
  39. // _ASSERT( pAppend->m_pNext == 0 ) ;
  40. pAppend->m_pNext = 0 ;
  41. // Get the old tail pointer. This guy won't be touched by the
  42. // remove thread if his next pointer is still NULL.
  43. CQElement* pTemp = (CQElement*)InterlockedExchangePointer( (LPLONG)&m_pTail, (LONG)pAppend ) ;
  44. // After we set the old tail pointer's next pointer to NON NULL
  45. // he becomes fair game for whoever is removing from the queue.
  46. // We may become the thread removing from the queue if whoever was
  47. // previously removing got to the last element and changed its next pointer
  48. // to LOCKVAL.
  49. //
  50. // NOTE : This thread and any thread doing removals should be the only
  51. // threads touching the pNext field of the pTemp element.
  52. //
  53. LONG l = InterlockedExchange( (LPLONG)&(pTemp->m_pNext), (LONG)pAppend ) ;
  54. return l == LOCKVAL ;
  55. }
  56. inline CQElement*
  57. CQueueLock::RemoveAndRelease( void ) {
  58. CQElement* p = (CQElement*)InterlockedCompareExchangePointer( (LPVOID*)&m_pHead->m_pNext,
  59. (LPVOID)LOCKVAL,
  60. 0 ) ;
  61. _ASSERT( (DWORD)p != 0xFFFFFFFF ) ;
  62. if( p != 0 ) {
  63. //
  64. // There is an element following the head element -
  65. // so we can safely examine the head element has nobody
  66. // will touch its next pointer but us !
  67. //
  68. CQElement* pReturn = m_pHead ;
  69. m_pHead = p ;
  70. pReturn->m_pNext = 0 ;
  71. if( pReturn == &m_special ) {
  72. //
  73. // We can ignore the return value of Append -
  74. // it must always succeed as we are the only thread
  75. // that is allowed to relinquish the lock, and we ain't going to
  76. // do so !
  77. //
  78. Append( pReturn ) ;
  79. //
  80. // Now, we must offer ownership again !
  81. //
  82. p = (CQElement*)InterlockedCompareExchangePointer( (LPVOID*)&m_pHead->m_pNext,
  83. (LPVOID)LOCKVAL,
  84. 0 ) ;
  85. _ASSERT( (DWORD)p != 0xFFFFFFFF ) ;
  86. if( p != 0 ) {
  87. //
  88. // The head element must not be the special element -
  89. // we took pains already to see that that didn't happen -
  90. // so we can safely remove the element from the head of the queue.
  91. //
  92. pReturn = m_pHead ;
  93. m_pHead = p ;
  94. pReturn->m_pNext = 0 ;
  95. return pReturn ;
  96. }
  97. } else {
  98. return pReturn ;
  99. }
  100. }
  101. //
  102. // _ASSERT( p==0 ) ;
  103. //
  104. return p ;
  105. }
  106. inline CQElement*
  107. CQueueLock::Remove( void ) {
  108. CQElement* p = m_pHead->m_pNext ;
  109. if( p != 0 ) {
  110. //
  111. // There is an element following the head element -
  112. // so we can safely examine the head element has nobody
  113. // will touch its next pointer but us !
  114. //
  115. if( p == &m_special ) {
  116. //
  117. // The head element is the special element, so we want
  118. // to send it to the back and try examining the front again !
  119. //
  120. m_pHead = p->m_pNext ;
  121. p->m_pNext = 0 ;
  122. //
  123. // We can ignore the return value of Append -
  124. // it must always succeed as we are the only thread
  125. // that is allowed to relinquish the lock, and we ain't going to
  126. // do so !
  127. //
  128. Append( p ) ;
  129. //
  130. // Ok, lets see if we can remove the head element now !
  131. //
  132. p = m_pHead->m_pNext ;
  133. }
  134. //
  135. // If this ain't 0, then the next pointer is set
  136. // and no other threads will be touching the next pointer,
  137. // so we can safely advance the head pointer and return
  138. // the first element.
  139. //
  140. if( p != 0 ) {
  141. //
  142. // The head element must not be the special element -
  143. // we took pains already to see that that didn't happen -
  144. // so we can safely remove the element from the head of the queue.
  145. //
  146. m_pHead = p->m_pNext ;
  147. p->m_pNext = 0 ;
  148. return p ;
  149. }
  150. }
  151. return 0 ;
  152. }
  153. template< class Element >
  154. inline TLockQueue< Element >::TLockQueue( ) { }
  155. template< class Element >
  156. inline TLockQueue< Element >::TLockQueue( BOOL fSet ) :
  157. m_queue( fSet ) { }
  158. template< class Element >
  159. inline void TLockQueue< Element >::Reset() {
  160. m_queue.Reset() ;
  161. }
  162. template< class Element >
  163. inline BOOL TLockQueue< Element >::Append( Element *p ) {
  164. return m_queue.Append( (CQElement*)p ) ;
  165. }
  166. template< class Element >
  167. inline Element* TLockQueue< Element >::Remove( ) {
  168. return (Element*) m_queue.Remove( ) ;
  169. }
  170. template< class Element >
  171. inline Element* TLockQueue< Element >::RemoveAndRelease( ) {
  172. return (Element*) m_queue.RemoveAndRelease( ) ;
  173. }
  174. #ifndef _NO_TEMPLATES_
  175. template< class Element >
  176. inline TLockQueueV1< Element >::TLockQueueV1( ) { }
  177. template< class Element >
  178. inline TLockQueueV1< Element >::~TLockQueueV1( ) { }
  179. template< class Element >
  180. inline BOOL TLockQueueV1< Element >::Append( Element *p ) {
  181. return m_queue.Append( (CQElement*)p ) ;
  182. }
  183. template< class Element >
  184. inline void TLockQueueV1< Element >::Remove( ) {
  185. m_queue.Remove( ) ;
  186. }
  187. template< class Element >
  188. inline BOOL TLockQueueV1< Element >::GetHead( Element* &p ) {
  189. CQElement *pTemp = 0 ;
  190. BOOL fTemp = m_queue.GetHead( pTemp ) ;
  191. p = (Element*)pTemp ;
  192. return fTemp ;
  193. }
  194. template< class Element >
  195. inline BOOL TLockQueueV1< Element >::RemoveAndRelease( ) {
  196. return m_queue.RemoveAndRelease( ) ;
  197. }
  198. #endif