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.

370 lines
8.6 KiB

  1. /* Copyright (c) 1998 Microsoft Corporation */
  2. /*
  3. * @DOC DMusic16
  4. *
  5. * @MODULE EQueue.c - Event queue routines |
  6. *
  7. * These routines maintain queues of events. It is expected that other routines will operate
  8. * directly on the queue. The following invariants must be maintained:
  9. *
  10. * If the queue is empty, then the head and tail pointers must be NULL and the element count must be zero.
  11. *
  12. * The queue must not contain circular links.
  13. *
  14. * An event may only be on one queue.
  15. *
  16. * The element count must be equal to the number of events in the queue.
  17. */
  18. #include <windows.h>
  19. #include <mmsystem.h>
  20. #include <memory.h>
  21. #include "dmusic16.h"
  22. #include "debug.h"
  23. /* @func Initialize an event queue to be empty
  24. *
  25. * @comm
  26. *
  27. * Any previous contents of the queue will be lost (NOT freed).
  28. */
  29. VOID PASCAL
  30. QueueInit(
  31. NPEVENTQUEUE pQueue) /* @parm Pointer to the queue to initialize */
  32. {
  33. DPF(4, "QueueInit(%04X)", (WORD)pQueue);
  34. pQueue->pHead = NULL;
  35. pQueue->pTail = NULL;
  36. pQueue->cEle = 0;
  37. AssertQueueValid(pQueue);
  38. }
  39. /* @func Append an event to the end of the queue
  40. *
  41. */
  42. VOID PASCAL
  43. QueueAppend(
  44. NPEVENTQUEUE pQueue, /* @parm Pointer to the queue */
  45. LPEVENT pEvent) /* @parm Pointer to the event to tack on the end of the queue */
  46. {
  47. DPF(4, "QueueAppend(%04X,%08lX)", (WORD)pQueue, (DWORD)pEvent);
  48. if (pQueue->cEle)
  49. {
  50. assert(pQueue->pHead);
  51. assert(pQueue->pTail);
  52. pQueue->pTail->lpNext = pEvent;
  53. }
  54. else
  55. {
  56. assert(NULL == pQueue->pHead);
  57. assert(NULL == pQueue->pTail);
  58. pQueue->pHead = pEvent;
  59. }
  60. pEvent->lpNext = NULL;
  61. pQueue->pTail = pEvent;
  62. ++pQueue->cEle;
  63. AssertQueueValid(pQueue);
  64. }
  65. /* @func Concatenate two queues
  66. *
  67. * @comm
  68. *
  69. * This function tacks the contents of <p pSrc> onto the end of <p pDest> in very short constant time.
  70. * <p pSrc> is left empty after the operation.
  71. */
  72. VOID PASCAL
  73. QueueCat(
  74. NPEVENTQUEUE pDest, /* @parm The queue to receive new events */
  75. NPEVENTQUEUE pSrc) /* @parm The queue which will lost all its events */
  76. {
  77. DPF(4, "QueueCat(%04X,%04X)", (WORD)pDest, (WORD)pSrc);
  78. if (0 == pSrc->cEle)
  79. {
  80. assert(NULL == pSrc->pHead);
  81. assert(NULL == pSrc->pTail);
  82. return;
  83. }
  84. assert(pSrc->pHead);
  85. assert(pSrc->pTail);
  86. if (0 != pDest->cEle)
  87. {
  88. assert(pDest->pHead);
  89. assert(pDest->pTail);
  90. pDest->cEle += pSrc->cEle;
  91. pDest->pTail->lpNext = pSrc->pHead;
  92. pDest->pTail = pSrc->pTail;
  93. }
  94. else
  95. {
  96. assert(NULL == pDest->pHead);
  97. assert(NULL == pDest->pTail);
  98. *pDest = *pSrc;
  99. }
  100. pSrc->pHead = NULL;
  101. pSrc->pTail = NULL;
  102. pSrc->cEle = 0;
  103. AssertQueueValid(pDest);
  104. AssertQueueValid(pSrc);
  105. }
  106. /* @func Dequeue an element from the front of the queue
  107. *
  108. * @rdesc Returns an event pointer or NULL if the queue is empty
  109. *
  110. */
  111. LPEVENT PASCAL
  112. QueueRemoveFromFront(
  113. NPEVENTQUEUE pQueue) /* @parm The queue to dequeue from */
  114. {
  115. LPEVENT pEvent;
  116. DPF(4, "QueueRemoveFromFront(%04X)", (WORD)pQueue);
  117. if (0 == pQueue->cEle)
  118. {
  119. assert(NULL == pQueue->pHead);
  120. assert(NULL == pQueue->pTail);
  121. return NULL;
  122. }
  123. assert(pQueue->pHead);
  124. assert(pQueue->pTail);
  125. pEvent = pQueue->pHead;
  126. if (0 != --pQueue->cEle)
  127. {
  128. assert(pQueue->pHead != pQueue->pTail);
  129. pQueue->pHead = pQueue->pHead->lpNext;
  130. }
  131. else
  132. {
  133. assert(pQueue->pHead == pQueue->pTail);
  134. pQueue->pHead = NULL;
  135. pQueue->pTail = NULL;
  136. }
  137. AssertQueueValid(pQueue);
  138. return pEvent;
  139. }
  140. /* @func Enumerate the events in a queue, possibly deleting some or all of them
  141. *
  142. * @comm
  143. *
  144. * This function calls the function pointed to by <p pfnFilter> once for each event in
  145. * the queue, starting at the front and working towards the back.
  146. *
  147. * The function <p pfnFilter> may return one of two values:
  148. * @flag QUEUE_FILTER_KEEP | If the event is to be kept
  149. * @flag QUEUE_FILTER_REMOVE | If the event is to be removed from the queue
  150. */
  151. VOID PASCAL
  152. QueueFilter(
  153. NPEVENTQUEUE pQueue, /* @parm The queue to enumerate */
  154. DWORD dwInstance, /* @parm Instance data which will be passed to
  155. <p pfnFilter> on each call. */
  156. PFNQUEUEFILTER pfnFilter) /* @parm The function to call with each event */
  157. {
  158. LPEVENT pPrev;
  159. LPEVENT pCurr;
  160. LPEVENT pNext;
  161. DPF(4, "QueueFilter(%04X, %08lX, %08lX)", (WORD)pQueue, (DWORD)dwInstance, (DWORD)pfnFilter);
  162. pPrev = NULL;
  163. pCurr = pQueue->pHead;
  164. while (pCurr)
  165. {
  166. /* Callback is allowed to relink into another queue, so save the next
  167. * pointer now.
  168. */
  169. pNext = pCurr->lpNext;
  170. switch((*pfnFilter)(pCurr, dwInstance))
  171. {
  172. case QUEUE_FILTER_REMOVE:
  173. if (pPrev)
  174. {
  175. pPrev->lpNext = pNext;
  176. }
  177. else
  178. {
  179. pQueue->pHead = pNext;
  180. }
  181. if (pNext == NULL)
  182. {
  183. pQueue->pTail = pPrev;
  184. }
  185. --pQueue->cEle;
  186. AssertQueueValid(pQueue);
  187. pCurr = pNext;
  188. break;
  189. case QUEUE_FILTER_KEEP:
  190. pPrev = pCurr;
  191. pCurr = pNext;
  192. break;
  193. default:
  194. assert(0);
  195. }
  196. }
  197. AssertQueueValid(pQueue);
  198. }
  199. /* @func Peek at the head of the event queue to see what's next
  200. *
  201. * @comm
  202. *
  203. * Non-destructively return the first event in the queue
  204. *
  205. * @rdesc
  206. * Returns the event pointer or NULL if the queue is empty
  207. */
  208. LPEVENT PASCAL
  209. QueuePeek(
  210. NPEVENTQUEUE pQueue)
  211. {
  212. DPF(4, "QueuePeek(%04X)", (WORD)pQueue);
  213. return pQueue->pHead;
  214. }
  215. /* @func Look at the queue and make sure it's internally consistent.
  216. *
  217. * @comm
  218. *
  219. * Walk the queue and make sure it isn't circularly linked. Also make sure the count
  220. * is correct.
  221. *
  222. * Asserts into debugger if queue is corrupt.
  223. *
  224. * Called by the AssertQueueValid macro in debug builds.
  225. *
  226. * Disables interrupts to avoid false reports of corruption based on the queue changing under
  227. * the routine.
  228. *
  229. */
  230. #ifdef DEBUG
  231. void PASCAL
  232. _AssertQueueValid(
  233. NPEVENTQUEUE pQueue,
  234. LPSTR szFile,
  235. UINT uLine)
  236. {
  237. LPEVENT pEventSlow;
  238. LPEVENT pEventFast;
  239. UINT cEle;
  240. WORD wIntStat;
  241. BOOL fTrace = FALSE;
  242. wIntStat = DisableInterrupts();
  243. if (!pQueue)
  244. {
  245. DPF(0, "_AssertQueueValid %s@%u: Passed NULL!", szFile, uLine);
  246. assert(FALSE);
  247. goto cleanup;
  248. }
  249. pEventFast = pEventSlow = pQueue->pHead;
  250. cEle = 0;
  251. while (pEventSlow)
  252. {
  253. ++cEle;
  254. pEventSlow = pEventSlow->lpNext;
  255. if (pEventFast)
  256. {
  257. pEventFast = pEventFast->lpNext;
  258. }
  259. if (pEventFast)
  260. {
  261. pEventFast = pEventFast->lpNext;
  262. }
  263. if (pEventSlow && pEventFast && pEventSlow == pEventFast)
  264. {
  265. DPF(0, "_AssertQueueValid %s@%u: Queue %04X is circularly linked!",
  266. szFile,
  267. uLine,
  268. (WORD)pQueue);
  269. assert(FALSE);
  270. fTrace = TRUE;
  271. break;
  272. }
  273. }
  274. if (cEle != pQueue->cEle)
  275. {
  276. DPF(0, "_AssertQueueValid %s@%u: Queue %04X has incorrect element count!",
  277. szFile,
  278. uLine,
  279. (WORD)pQueue);
  280. assert(FALSE);
  281. fTrace = TRUE;
  282. }
  283. if ((pQueue->pHead && !pQueue->pTail) ||
  284. (pQueue->pTail && !pQueue->pHead))
  285. {
  286. DPF(0, "_AssertQueueValid %s@%u: Queue %04X head XOR tail is NULL!",
  287. szFile,
  288. uLine,
  289. (WORD)pQueue);
  290. assert(FALSE);
  291. fTrace = TRUE;
  292. }
  293. if (fTrace)
  294. {
  295. DPF(0, "Queue %04X: head %08lX tail %08lX count %u",
  296. (WORD)pQueue,
  297. (DWORD)pQueue->pHead,
  298. (DWORD)pQueue->pTail,
  299. (WORD)pQueue->cEle);
  300. for (pEventSlow = pQueue->pHead; pEventSlow; pEventSlow = pEventSlow->lpNext)
  301. {
  302. DPF(2, " Event %08lX: lpNext %08lX msTime %lu wFlags %04X cbEvent %04X",
  303. (DWORD)pEventSlow,
  304. (DWORD)pEventSlow->lpNext,
  305. (DWORD)pEventSlow->msTime,
  306. (WORD)pEventSlow->wFlags,
  307. (WORD)pEventSlow->cbEvent);
  308. }
  309. }
  310. cleanup:
  311. RestoreInterrupts(wIntStat);
  312. }
  313. #endif //DEBUG