Source code of Windows XP (NT5)
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.

354 lines
7.2 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. queue.c
  5. Abstract:
  6. Generic efficient queue package.
  7. Author:
  8. John Vert (jvert) 12-Jan-1996
  9. Revision History:
  10. --*/
  11. #include "clusrtlp.h"
  12. DWORD
  13. ClRtlInitializeQueue(
  14. PCL_QUEUE Queue
  15. )
  16. /*++
  17. Routine Description:
  18. Initializes a queue for use.
  19. Arguments:
  20. Queue - Supplies a pointer to a queue structure to initialize
  21. Return Value:
  22. ERROR_SUCCESS if successful
  23. Win32 error code otherwise.
  24. --*/
  25. {
  26. DWORD Status;
  27. InitializeListHead(&Queue->ListHead);
  28. InitializeCriticalSection(&Queue->Lock);
  29. Queue->Count = 0;
  30. Queue->Event = CreateEvent(NULL,
  31. TRUE,
  32. FALSE,
  33. NULL);
  34. if (Queue->Event == NULL) {
  35. Status = GetLastError();
  36. DeleteCriticalSection(&Queue->Lock);
  37. } else {
  38. Queue->Abort = CreateEvent(NULL,
  39. TRUE,
  40. FALSE,
  41. NULL);
  42. if (Queue->Abort == NULL) {
  43. Status = GetLastError();
  44. CloseHandle(Queue->Event);
  45. DeleteCriticalSection(&Queue->Lock);
  46. } else {
  47. Status = ERROR_SUCCESS;
  48. }
  49. }
  50. return(Status);
  51. }
  52. VOID
  53. ClRtlDeleteQueue(
  54. IN PCL_QUEUE Queue
  55. )
  56. /*++
  57. Routine Description:
  58. Releases all resources used by a queue.
  59. Arguments:
  60. Queue - supplies the queue to be deleted
  61. Return Value:
  62. None.
  63. --*/
  64. {
  65. DeleteCriticalSection(&Queue->Lock);
  66. CloseHandle(Queue->Event);
  67. CloseHandle(Queue->Abort);
  68. //
  69. // Zero the memory in order to cause grief to people who try
  70. // and use a deleted queue.
  71. //
  72. ZeroMemory(Queue, sizeof(CL_QUEUE));
  73. }
  74. VOID
  75. ClRtlRundownQueue(
  76. IN PCL_QUEUE Queue,
  77. OUT PLIST_ENTRY ListHead
  78. )
  79. /*++
  80. Routine Description:
  81. Runs down a queue that is about to be destroyed. Any threads currently
  82. waiting on the queue are unwaited (ClRtlRemoveHeadQueue will return NULL)
  83. and the contents of the queue (if any) are returned to the caller for
  84. cleanup.
  85. Arguments:
  86. Queue - supplies the queue to be rundown
  87. ListHead - returns the list of items currently in the queue.
  88. Return Value:
  89. None.
  90. --*/
  91. {
  92. EnterCriticalSection(&Queue->Lock);
  93. //
  94. // Set the aborted event to awaken any threads currently
  95. // blocked on the queue.
  96. //
  97. SetEvent(Queue->Abort);
  98. //
  99. // Move the contents of the list into the passed in listhead
  100. //
  101. if (IsListEmpty(&Queue->ListHead)) {
  102. InitializeListHead(ListHead);
  103. } else {
  104. *ListHead = Queue->ListHead;
  105. ListHead->Flink->Blink = ListHead;
  106. ListHead->Blink->Flink = ListHead;
  107. }
  108. Queue->ListHead.Flink = Queue->ListHead.Blink = NULL;
  109. Queue->Count = 0;
  110. LeaveCriticalSection(&Queue->Lock);
  111. }
  112. PLIST_ENTRY
  113. ClRtlRemoveHeadQueue(
  114. IN PCL_QUEUE Queue
  115. )
  116. /*++
  117. Routine Description:
  118. Removes the item at the head of the queue. If the queue is empty,
  119. blocks until an item is inserted into the queue.
  120. Arguments:
  121. Queue - Supplies the queue to remove an item from.
  122. Return Value:
  123. Pointer to list entry removed from the head of the queue.
  124. --*/
  125. {
  126. return(ClRtlRemoveHeadQueueTimeout(Queue, INFINITE,NULL,NULL));
  127. }
  128. PLIST_ENTRY
  129. ClRtlRemoveHeadQueueTimeout(
  130. IN PCL_QUEUE Queue,
  131. IN DWORD dwMilliseconds,
  132. IN CLRTL_CHECK_HEAD_QUEUE_CALLBACK pfnCallback,
  133. IN OUT PVOID pvContext
  134. )
  135. /*++
  136. Routine Description:
  137. Removes the item at the head of the queue. If the queue is empty,
  138. blocks until an item is inserted into the queue.
  139. Arguments:
  140. Queue - Supplies the queue to remove an item from.
  141. Timeout - Supplies a timeout value that specifies the relative
  142. time, in milliseconds, over which the wait is to be completed.
  143. Callback - Checks to see whether we should return the event if
  144. we find one. This simulates a peek.
  145. Context - Caller-defined data to be passed in with callback.
  146. Return Value:
  147. Pointer to list entry removed from the head of the queue.
  148. NULL if the wait times out, the queue is run down, or the name exceeds
  149. the buffer length. If this routine returns NULL, GetLastError
  150. will return ERROR_INVALID_HANDLE (if the queue has been rundown),
  151. WAIT_TIMEOUT (to indicate a timeout has occurred)
  152. --*/
  153. {
  154. DWORD Status;
  155. PLIST_ENTRY Entry;
  156. BOOL Empty;
  157. HANDLE WaitArray[2];
  158. Retry:
  159. if (Queue->Count == 0) {
  160. //
  161. // Block until something is inserted on the queue
  162. //
  163. WaitArray[0] = Queue->Abort;
  164. WaitArray[1] = Queue->Event;
  165. Status = WaitForMultipleObjects(2, WaitArray, FALSE, dwMilliseconds);
  166. if ((Status == WAIT_OBJECT_0) ||
  167. (Status == WAIT_FAILED)) {
  168. //
  169. // The queue has been rundown, return NULL immediately.
  170. //
  171. SetLastError(ERROR_INVALID_HANDLE);
  172. return(NULL);
  173. } else if (Status == WAIT_TIMEOUT) {
  174. SetLastError(WAIT_TIMEOUT);
  175. return(NULL);
  176. }
  177. CL_ASSERT(Status == 1);
  178. }
  179. //
  180. // Lock the queue and try to remove something
  181. //
  182. EnterCriticalSection(&Queue->Lock);
  183. if (Queue->Count == 0) {
  184. //
  185. // Somebody got here before we did, drop the lock and retry
  186. //
  187. LeaveCriticalSection(&Queue->Lock);
  188. goto Retry;
  189. }
  190. CL_ASSERT(!IsListEmpty(&Queue->ListHead));
  191. if ( NULL != pfnCallback ) {
  192. //
  193. // We've got a callback function - if it returns ERROR_SUCCESS then dequeue.
  194. // Otherwise return NULL and SetLastError to whatever error code the callback returns.
  195. //
  196. Entry = (&Queue->ListHead)->Flink;
  197. Status = (*pfnCallback)( Entry, pvContext );
  198. if ( ERROR_SUCCESS == Status ) {
  199. //
  200. // The entry is appropriate to pass back.
  201. //
  202. Entry = RemoveHeadList(&Queue->ListHead);
  203. } else {
  204. Entry = NULL;
  205. }
  206. } else {
  207. Entry = RemoveHeadList(&Queue->ListHead);
  208. Status = ERROR_SUCCESS;
  209. }
  210. //
  211. // Only decrement the count if we removed the event
  212. //
  213. if ( NULL != Entry ) {
  214. //
  215. // Decrement count and check for empty list.
  216. //
  217. if (--Queue->Count == 0) {
  218. //
  219. // The queue has transitioned from full to empty,
  220. // reset the event.
  221. //
  222. CL_ASSERT(IsListEmpty(&Queue->ListHead));
  223. ResetEvent(Queue->Event);
  224. }
  225. }
  226. LeaveCriticalSection(&Queue->Lock);
  227. SetLastError( Status );
  228. return(Entry);
  229. }
  230. VOID
  231. ClRtlInsertTailQueue(
  232. IN PCL_QUEUE Queue,
  233. IN PLIST_ENTRY Item
  234. )
  235. /*++
  236. Routine Description:
  237. Inserts a new entry on the tail of the queue.
  238. Arguments:
  239. Queue - Supplies the queue to add the entry to.
  240. Item - Supplies the entry to be added to the queue.
  241. Return Value:
  242. None.
  243. --*/
  244. {
  245. EnterCriticalSection(&Queue->Lock);
  246. InsertTailList(&Queue->ListHead, Item);
  247. if (++Queue->Count == 1) {
  248. //
  249. // The queue has transitioned from empty to full, set
  250. // the event to awaken any waiters.
  251. //
  252. SetEvent(Queue->Event);
  253. }
  254. LeaveCriticalSection(&Queue->Lock);
  255. }