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.

503 lines
12 KiB

  1. // Copyright (c) 1998-1999 Microsoft Corporation
  2. // queue.cpp
  3. #include "debug.h"
  4. #define ASSERT assert
  5. #include "dmime.h"
  6. #include "dmperf.h"
  7. CPMsgQueue::CPMsgQueue()
  8. {
  9. m_pTop = NULL;
  10. m_pLastAccessed = NULL;
  11. }
  12. CPMsgQueue::~CPMsgQueue()
  13. {
  14. }
  15. static PRIV_PMSG * sortevents( PRIV_PMSG * pEvents, long lLen )
  16. {
  17. PRIV_PMSG * pLeft;
  18. PRIV_PMSG * pRight ;
  19. long lLeft;
  20. long lRight ;
  21. PRIV_PMSG * pTop ;
  22. if( lLen < 3 )
  23. {
  24. if( !pEvents )
  25. return( 0 ) ;
  26. if( lLen == 1 )
  27. return( pEvents ) ;
  28. pLeft = pEvents ;
  29. pRight = pEvents->pNext ;
  30. if( !pRight )
  31. return( pLeft ) ;
  32. if( pLeft->rtTime > pRight->rtTime )
  33. {
  34. pLeft->pNext = NULL ;
  35. pRight->pNext = pLeft ;
  36. return( pRight ) ;
  37. }
  38. return( pLeft ) ;
  39. }
  40. lLeft = lLen >> 1 ;
  41. lRight = lLen - lLeft;
  42. pLeft = pEvents ;
  43. for (;lLeft > 1;pEvents = pEvents->pNext) lLeft--;
  44. pRight = sortevents( pEvents->pNext, lRight ) ;
  45. pEvents->pNext = NULL ;
  46. pLeft = sortevents( pLeft, lLen - lRight ) ;
  47. pTop = NULL ;
  48. for( ; pLeft && pRight ; )
  49. {
  50. if( pLeft->rtTime < pRight->rtTime )
  51. {
  52. if( !pTop )
  53. pTop = pLeft ;
  54. else
  55. pEvents->pNext = pLeft ;
  56. pEvents = pLeft ;
  57. pLeft = pEvents->pNext ;
  58. }
  59. else
  60. {
  61. if( !pTop )
  62. pTop = pRight ;
  63. else
  64. pEvents->pNext = pRight ;
  65. pEvents = pRight ;
  66. pRight = pEvents->pNext ;
  67. }
  68. }
  69. if( pLeft )
  70. pEvents->pNext = pLeft ;
  71. else
  72. pEvents->pNext = pRight ;
  73. return( pTop ) ;
  74. }
  75. void CPMsgQueue::Sort()
  76. {
  77. m_pTop = sortevents(m_pTop, GetCount()) ;
  78. m_pLastAccessed = NULL;
  79. }
  80. long CPMsgQueue::GetCount()
  81. {
  82. long lCount = 0;
  83. PRIV_PMSG *pScan = GetHead();
  84. for (;pScan;pScan = pScan->pNext)
  85. {
  86. lCount++;
  87. }
  88. return lCount;
  89. }
  90. void CPMsgQueue::Enqueue(PRIV_PMSG *pItem)
  91. {
  92. if (!pItem)
  93. {
  94. TraceI(0, "ENQUEUE: Attempt to enqueue a NULL pItem!\n");
  95. return;
  96. }
  97. // Ensure not already queued...
  98. if (pItem->dwPrivFlags & PRIV_FLAG_QUEUED)
  99. {
  100. TraceI(0,"ENQUEUE: Item thinks it is still in a queue!\n");
  101. return;
  102. }
  103. pItem->dwPrivFlags |= PRIV_FLAG_QUEUED;
  104. PRIV_PMSG *pScan;
  105. #ifdef DBG
  106. // Verify robustness of list. Check that the event is not already in the list
  107. // and that the time stamps are all in order.
  108. REFERENCE_TIME rtTime = 0;
  109. for (pScan = m_pTop;pScan;pScan = pScan->pNext)
  110. {
  111. if (pScan == pItem)
  112. {
  113. TraceI(0,"ENQUEUE: Item is already in the queue!\n");
  114. return;
  115. }
  116. // this must queue events in time sorted order
  117. if (pScan->rtTime < rtTime)
  118. {
  119. TraceI(0,"ENQUEUE: Queue is not in time order!\n");
  120. pScan->rtTime = rtTime;
  121. }
  122. else if (pScan->rtTime > rtTime)
  123. {
  124. rtTime = pScan->rtTime;
  125. }
  126. }
  127. #endif
  128. if ( !(pItem->dwFlags & DMUS_PMSGF_REFTIME) ) // sorting on reftime, so this must be valid
  129. {
  130. TraceI(0, "ENQUEUE: Attempt to enqueue a pItem with a bogus RefTime!\n");
  131. return;
  132. }
  133. if (m_pLastAccessed && (m_pLastAccessed->rtTime <= pItem->rtTime))
  134. {
  135. pScan = m_pLastAccessed;
  136. }
  137. else
  138. {
  139. pScan = m_pTop;
  140. }
  141. if ( pScan && ( pScan->rtTime <= pItem->rtTime ) )
  142. {
  143. for (;pScan->pNext; pScan = pScan->pNext )
  144. {
  145. if( pScan->pNext->rtTime > pItem->rtTime )
  146. {
  147. break;
  148. }
  149. }
  150. pItem->pNext = pScan->pNext;
  151. pScan->pNext = pItem;
  152. }
  153. else
  154. {
  155. pItem->pNext = m_pTop;
  156. m_pTop = pItem;
  157. }
  158. m_pLastAccessed = pItem;
  159. }
  160. /* Remove the oldest event before time rtTime, making sure that there is still
  161. at minimum one event prior to that time stamp.
  162. This ensures that there is a sufficiently old event, but gets rid of old
  163. stale events. This is used by the timesig and tempomap lists.
  164. */
  165. PRIV_PMSG *CPMsgQueue::FlushOldest(REFERENCE_TIME rtTime)
  166. {
  167. PRIV_PMSG *pNext;
  168. if (m_pTop && (pNext = m_pTop->pNext))
  169. {
  170. if (pNext->rtTime < rtTime)
  171. {
  172. PRIV_PMSG *pDelete = m_pTop;
  173. if (m_pLastAccessed == m_pTop)
  174. {
  175. m_pLastAccessed = pNext;
  176. }
  177. m_pTop = pNext;
  178. pDelete->dwPrivFlags &= ~PRIV_FLAG_QUEUED;
  179. pDelete->pNext = NULL;
  180. return pDelete;
  181. }
  182. }
  183. return NULL;
  184. }
  185. PRIV_PMSG *CPMsgQueue::Dequeue()
  186. {
  187. PRIV_PMSG *pItem = m_pTop;
  188. if (pItem != NULL)
  189. {
  190. m_pTop = pItem->pNext;
  191. pItem->dwPrivFlags &= ~PRIV_FLAG_QUEUED;
  192. pItem->pNext = NULL;
  193. if (m_pLastAccessed == pItem)
  194. {
  195. m_pLastAccessed = m_pTop;
  196. }
  197. }
  198. return pItem;
  199. }
  200. PRIV_PMSG *CPMsgQueue::Dequeue(PRIV_PMSG *pItem)
  201. {
  202. ASSERT(pItem);
  203. if (pItem == m_pTop)
  204. {
  205. return Dequeue();
  206. }
  207. PRIV_PMSG *pScan;
  208. PRIV_PMSG *pNext;
  209. if (m_pLastAccessed &&
  210. (m_pLastAccessed->rtTime < pItem->rtTime))
  211. {
  212. pScan = m_pLastAccessed;
  213. }
  214. else
  215. {
  216. pScan = m_pTop;
  217. }
  218. for (;pScan;pScan = pNext)
  219. {
  220. pNext = pScan->pNext;
  221. if (pNext == pItem)
  222. {
  223. pScan->pNext = pItem->pNext;
  224. pItem->pNext = NULL;
  225. pItem->dwPrivFlags &= ~PRIV_FLAG_QUEUED;
  226. if (m_pLastAccessed == pItem)
  227. {
  228. m_pLastAccessed = pScan;
  229. }
  230. return pItem;
  231. }
  232. }
  233. if (m_pLastAccessed)
  234. {
  235. // This happens every now and then as a result of a curve setting rtTime to 0
  236. // in the middle of FlushEventQueue.
  237. // This should be fixed, but this patch will work for now.
  238. m_pLastAccessed = NULL;
  239. return Dequeue(pItem);
  240. }
  241. return NULL;
  242. }
  243. // queue Segment nodes in time order. pItem must be in the same
  244. // time base as all items in ppList (RefTime or Music Time.)
  245. void CSegStateList::Insert(CSegState* pItem)
  246. {
  247. CSegState *pScan = GetHead();
  248. CSegState *pNext;
  249. pItem->SetNext(NULL);
  250. if (pScan)
  251. {
  252. if( pItem->m_dwPlaySegFlags & DMUS_SEGF_REFTIME )
  253. {
  254. ASSERT( pScan->m_dwPlaySegFlags & DMUS_SEGF_REFTIME );
  255. // Avoid putting circularities in the list
  256. if (pItem == pScan)
  257. {
  258. TraceI(0, "ENQUEUE (SEGMENT RT): NODE IS ALREADY IN AT THE HEAD OF LIST\n");
  259. }
  260. else if( pItem->m_rtGivenStart < pScan->m_rtGivenStart )
  261. {
  262. AddHead(pItem);
  263. }
  264. else
  265. {
  266. while( pNext = pScan->GetNext() )
  267. {
  268. ASSERT( pScan->m_dwPlaySegFlags & DMUS_SEGF_REFTIME );
  269. // Am I trying to insert something that's already in the list?
  270. if (pItem == pScan)
  271. {
  272. break;
  273. }
  274. // Check for the queue getting corrupted (happens on multiproc machines at 400mhz)
  275. if ( ( pNext->m_dwPlaySegFlags & DMUS_SEGF_REFTIME ) &&
  276. pScan->m_rtGivenStart > pNext->m_rtGivenStart )
  277. {
  278. TraceI(0, "ENQUEUE (SEGMENT RT): LOOP CONDITION VIOLATED\n");
  279. // get rid of the potential circularity in the list. Note that this
  280. // (or actually the creation of the circularity) could cause memory leaks.
  281. pScan->SetNext(NULL);
  282. break;
  283. }
  284. if( pItem->m_rtGivenStart < pNext->m_rtGivenStart )
  285. {
  286. break;
  287. }
  288. pScan = pNext;
  289. }
  290. if (pItem != pScan)
  291. {
  292. pItem->SetNext(pScan->GetNext());
  293. pScan->SetNext(pItem);
  294. }
  295. else
  296. {
  297. TraceI(0, "ENQUEUE (SEGMENT RT): NODE IS ALREADY IN LIST\n");
  298. }
  299. }
  300. }
  301. else
  302. {
  303. ASSERT( !( pScan->m_dwPlaySegFlags & DMUS_SEGF_REFTIME ) );
  304. // Avoid putting circularities in the list
  305. if (pItem == pScan)
  306. {
  307. TraceI(0, "ENQUEUE (SEGMENT MT): NODE IS ALREADY IN AT THE HEAD OF LIST\n");
  308. }
  309. else if( pItem->m_mtResolvedStart < pScan->m_mtResolvedStart )
  310. {
  311. AddHead(pItem);
  312. }
  313. else
  314. {
  315. while( pNext = pScan->GetNext() )
  316. {
  317. ASSERT( !( pScan->m_dwPlaySegFlags & DMUS_SEGF_REFTIME ) );
  318. // Am I trying to insert something that's already in the list?
  319. if (pItem == pScan)
  320. {
  321. break;
  322. }
  323. // Check for the queue getting corrupted (happens on multiproc machines at 400mhz)
  324. if ( !( pNext->m_dwPlaySegFlags & DMUS_SEGF_REFTIME ) &&
  325. pScan->m_mtResolvedStart > pNext->m_mtResolvedStart )
  326. {
  327. TraceI(0, "ENQUEUE (SEGMENT MT): LOOP CONDITION VIOLATED\n");
  328. // get rid of the potential circularity in the list. Note that this
  329. // (or actually the creation of the circularity) could cause memory leaks.
  330. pScan->SetNext(NULL);
  331. break;
  332. }
  333. if( pItem->m_mtResolvedStart < pNext->m_mtResolvedStart )
  334. {
  335. break;
  336. }
  337. pScan = pNext;
  338. }
  339. if (pItem != pScan)
  340. {
  341. pItem->SetNext(pScan->GetNext());
  342. pScan->SetNext(pItem);
  343. }
  344. else
  345. {
  346. TraceI(0, "ENQUEUE (SEGMENT MT): NODE IS ALREADY IN LIST\n");
  347. }
  348. }
  349. }
  350. }
  351. else
  352. {
  353. m_pHead = pItem;
  354. }
  355. }
  356. /*
  357. void enqueue(CSegState **ppList, CSegState *pItem)
  358. {
  359. CSegState *li = *ppList;
  360. if (li)
  361. {
  362. if( pItem->m_dwPlaySegFlags & DMUS_SEGF_REFTIME )
  363. {
  364. ASSERT( li->m_dwPlaySegFlags & DMUS_SEGF_REFTIME );
  365. // Avoid putting circularities in the list
  366. if (pItem == *ppList)
  367. {
  368. TraceI(0, "ENQUEUE (SEGMENT RT): NODE IS ALREADY IN AT THE HEAD OF LIST\n");
  369. }
  370. else if( pItem->m_rtGivenStart < li->m_rtGivenStart )
  371. {
  372. pItem->pNext = li;
  373. *ppList = pItem;
  374. }
  375. else
  376. {
  377. while( li->pNext )
  378. {
  379. ASSERT( li->m_dwPlaySegFlags & DMUS_SEGF_REFTIME );
  380. // Am I trying to insert something that's already in the list?
  381. if (pItem == li)
  382. {
  383. break;
  384. }
  385. // Check for the queue getting corrupted (happens on multiproc machines at 400mhz)
  386. if ( ( li->pNext->m_dwPlaySegFlags & DMUS_SEGF_REFTIME ) &&
  387. li->m_rtGivenStart > li->pNext->m_rtGivenStart )
  388. {
  389. TraceI(0, "ENQUEUE (SEGMENT RT): LOOP CONDITION VIOLATED\n");
  390. // get rid of the potential circularity in the list. Note that this
  391. // (or actually the creation of the circularity) could cause memory leaks.
  392. li->pNext = NULL;
  393. break;
  394. }
  395. if( pItem->m_rtGivenStart < li->pNext->m_rtGivenStart )
  396. {
  397. break;
  398. }
  399. li = li->pNext;
  400. }
  401. if (pItem != li)
  402. {
  403. pItem->pNext = li->pNext;
  404. li->pNext = pItem;
  405. }
  406. else
  407. {
  408. TraceI(0, "ENQUEUE (SEGMENT RT): NODE IS ALREADY IN LIST\n");
  409. }
  410. }
  411. }
  412. else
  413. {
  414. ASSERT( !( li->m_dwPlaySegFlags & DMUS_SEGF_REFTIME ) );
  415. // Avoid putting circularities in the list
  416. if (pItem == *ppList)
  417. {
  418. TraceI(0, "ENQUEUE (SEGMENT MT): NODE IS ALREADY IN AT THE HEAD OF LIST\n");
  419. }
  420. else if( pItem->m_mtResolvedStart < li->m_mtResolvedStart )
  421. {
  422. pItem->pNext = li;
  423. *ppList = pItem;
  424. }
  425. else
  426. {
  427. while( li->pNext )
  428. {
  429. ASSERT( !( li->m_dwPlaySegFlags & DMUS_SEGF_REFTIME ) );
  430. // Am I trying to insert something that's already in the list?
  431. if (pItem == li)
  432. {
  433. break;
  434. }
  435. // Check for the queue getting corrupted (happens on multiproc machines at 400mhz)
  436. if ( !( li->pNext->m_dwPlaySegFlags & DMUS_SEGF_REFTIME ) &&
  437. li->m_mtResolvedStart > li->pNext->m_mtResolvedStart )
  438. {
  439. TraceI(0, "ENQUEUE (SEGMENT MT): LOOP CONDITION VIOLATED\n");
  440. // get rid of the potential circularity in the list. Note that this
  441. // (or actually the creation of the circularity) could cause memory leaks.
  442. li->pNext = NULL;
  443. break;
  444. }
  445. if( pItem->m_mtResolvedStart < li->pNext->m_mtResolvedStart )
  446. {
  447. break;
  448. }
  449. li = li->pNext;
  450. }
  451. if (pItem != li)
  452. {
  453. pItem->pNext = li->pNext;
  454. li->pNext = pItem;
  455. }
  456. else
  457. {
  458. TraceI(0, "ENQUEUE (SEGMENT MT): NODE IS ALREADY IN LIST\n");
  459. }
  460. }
  461. }
  462. }
  463. else
  464. {
  465. *ppList = pItem;
  466. }
  467. }*/