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.

270 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_PTR)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_PTR)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_PTR)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( (LPVOID *)&m_pTail, 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. PVOID l = InterlockedExchangePointer( (LPVOID *)&(pTemp->m_pNext), pAppend ) ;
  54. return l == (PVOID)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_PTR)p != LOCKVAL ) ;
  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_PTR)p != LOCKVAL ) ;
  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. p = m_pHead ;
  116. if( p == &m_special ) {
  117. //
  118. // The head element is the special element, so we want
  119. // to send it to the back and try examining the front again !
  120. //
  121. m_pHead = p->m_pNext ;
  122. p->m_pNext = 0 ;
  123. //
  124. // We can ignore the return value of Append -
  125. // it must always succeed as we are the only thread
  126. // that is allowed to relinquish the lock, and we ain't going to
  127. // do so !
  128. //
  129. Append( p ) ;
  130. //
  131. // Ok, lets see if we can remove the head element now !
  132. //
  133. p = m_pHead->m_pNext ;
  134. }
  135. //
  136. // If this ain't 0, then the next pointer is set
  137. // and no other threads will be touching the next pointer,
  138. // so we can safely advance the head pointer and return
  139. // the first element.
  140. //
  141. if( p != 0 ) {
  142. p = m_pHead ;
  143. //
  144. // The head element must not be the special element -
  145. // we took pains already to see that that didn't happen -
  146. // so we can safely remove the element from the head of the queue.
  147. //
  148. m_pHead = p->m_pNext ;
  149. p->m_pNext = 0 ;
  150. return p ;
  151. }
  152. }
  153. return 0 ;
  154. }
  155. template< class Element >
  156. inline TLockQueue< Element >::TLockQueue( ) { }
  157. template< class Element >
  158. inline TLockQueue< Element >::TLockQueue( BOOL fSet ) :
  159. m_queue( fSet ) { }
  160. template< class Element >
  161. inline void TLockQueue< Element >::Reset() {
  162. m_queue.Reset() ;
  163. }
  164. template< class Element >
  165. inline BOOL TLockQueue< Element >::Append( Element *p ) {
  166. return m_queue.Append( (CQElement*)p ) ;
  167. }
  168. template< class Element >
  169. inline Element* TLockQueue< Element >::Remove( ) {
  170. return (Element*) m_queue.Remove( ) ;
  171. }
  172. template< class Element >
  173. inline Element* TLockQueue< Element >::RemoveAndRelease( ) {
  174. return (Element*) m_queue.RemoveAndRelease( ) ;
  175. }
  176. #ifndef _NO_TEMPLATES_
  177. template< class Element >
  178. inline TLockQueueV1< Element >::TLockQueueV1( ) { }
  179. template< class Element >
  180. inline TLockQueueV1< Element >::~TLockQueueV1( ) { }
  181. template< class Element >
  182. inline BOOL TLockQueueV1< Element >::Append( Element *p ) {
  183. return m_queue.Append( (CQElement*)p ) ;
  184. }
  185. template< class Element >
  186. inline void TLockQueueV1< Element >::Remove( ) {
  187. m_queue.Remove( ) ;
  188. }
  189. template< class Element >
  190. inline BOOL TLockQueueV1< Element >::GetHead( Element* &p ) {
  191. CQElement *pTemp = 0 ;
  192. BOOL fTemp = m_queue.GetHead( pTemp ) ;
  193. p = (Element*)pTemp ;
  194. return fTemp ;
  195. }
  196. template< class Element >
  197. inline BOOL TLockQueueV1< Element >::RemoveAndRelease( ) {
  198. return m_queue.RemoveAndRelease( ) ;
  199. }
  200. #endif