schedule.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. //------------------------------------------------------------------------------
  2. // File: Schedule.cpp
  3. //
  4. // Desc: DirectShow base classes.
  5. //
  6. // Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved.
  7. //------------------------------------------------------------------------------
  8. #include <streams.h>
  9. // DbgLog values (all on LOG_TIMING):
  10. //
  11. // 2 for schedulting, firing and shunting of events
  12. // 3 for wait delays and wake-up times of event thread
  13. // 4 for details of whats on the list when the thread awakes
  14. /* Construct & destructors */
  15. CAMSchedule::CAMSchedule( HANDLE ev )
  16. : CBaseObject(TEXT("CAMSchedule"))
  17. , head(&z, 0), z(0, MAX_TIME)
  18. , m_dwNextCookie(0), m_dwAdviseCount(0)
  19. , m_pAdviseCache(0), m_dwCacheCount(0)
  20. , m_ev( ev )
  21. {
  22. head.m_dwAdviseCookie = z.m_dwAdviseCookie = 0;
  23. }
  24. CAMSchedule::~CAMSchedule()
  25. {
  26. m_Serialize.Lock();
  27. // Delete cache
  28. CAdvisePacket * p = m_pAdviseCache;
  29. while (p)
  30. {
  31. CAdvisePacket *const p_next = p->m_next;
  32. delete p;
  33. p = p_next;
  34. }
  35. ASSERT( m_dwAdviseCount == 0 );
  36. // Better to be safe than sorry
  37. if ( m_dwAdviseCount > 0 )
  38. {
  39. DumpLinkedList();
  40. while ( !head.m_next->IsZ() )
  41. {
  42. head.DeleteNext();
  43. --m_dwAdviseCount;
  44. }
  45. }
  46. // If, in the debug version, we assert twice, it means, not only
  47. // did we have left over advises, but we have also let m_dwAdviseCount
  48. // get out of sync. with the number of advises actually on the list.
  49. ASSERT( m_dwAdviseCount == 0 );
  50. m_Serialize.Unlock();
  51. }
  52. /* Public methods */
  53. DWORD CAMSchedule::GetAdviseCount()
  54. {
  55. // No need to lock, m_dwAdviseCount is 32bits & declared volatile
  56. return m_dwAdviseCount;
  57. }
  58. REFERENCE_TIME CAMSchedule::GetNextAdviseTime()
  59. {
  60. CAutoLock lck(&m_Serialize); // Need to stop the linked list from changing
  61. return head.m_next->m_rtEventTime;
  62. }
  63. DWORD_PTR CAMSchedule::AddAdvisePacket
  64. ( const REFERENCE_TIME & time1
  65. , const REFERENCE_TIME & time2
  66. , HANDLE h, BOOL periodic
  67. )
  68. {
  69. // Since we use MAX_TIME as a sentry, we can't afford to
  70. // schedule a notification at MAX_TIME
  71. ASSERT( time1 < MAX_TIME );
  72. DWORD_PTR Result;
  73. CAdvisePacket * p;
  74. m_Serialize.Lock();
  75. if (m_pAdviseCache)
  76. {
  77. p = m_pAdviseCache;
  78. m_pAdviseCache = p->m_next;
  79. --m_dwCacheCount;
  80. }
  81. else
  82. {
  83. p = new CAdvisePacket();
  84. }
  85. if (p)
  86. {
  87. p->m_rtEventTime = time1; p->m_rtPeriod = time2;
  88. p->m_hNotify = h; p->m_bPeriodic = periodic;
  89. Result = AddAdvisePacket( p );
  90. }
  91. else Result = 0;
  92. m_Serialize.Unlock();
  93. return Result;
  94. }
  95. HRESULT CAMSchedule::Unadvise(DWORD_PTR dwAdviseCookie)
  96. {
  97. HRESULT hr = S_FALSE;
  98. CAdvisePacket * p_prev = &head;
  99. CAdvisePacket * p_n;
  100. m_Serialize.Lock();
  101. while ( p_n = p_prev->Next() ) // The Next() method returns NULL when it hits z
  102. {
  103. if ( p_n->m_dwAdviseCookie == dwAdviseCookie )
  104. {
  105. Delete( p_prev->RemoveNext() );
  106. --m_dwAdviseCount;
  107. hr = S_OK;
  108. // Having found one cookie that matches, there should be no more
  109. #ifdef DEBUG
  110. while (p_n = p_prev->Next())
  111. {
  112. ASSERT(p_n->m_dwAdviseCookie != dwAdviseCookie);
  113. p_prev = p_n;
  114. }
  115. #endif
  116. break;
  117. }
  118. p_prev = p_n;
  119. };
  120. m_Serialize.Unlock();
  121. return hr;
  122. }
  123. REFERENCE_TIME CAMSchedule::Advise( const REFERENCE_TIME & rtTime )
  124. {
  125. REFERENCE_TIME rtNextTime;
  126. CAdvisePacket * pAdvise;
  127. DbgLog((LOG_TIMING, 2,
  128. TEXT("CAMSchedule::Advise( %lu ms )"), ULONG(rtTime / (UNITS / MILLISECONDS))));
  129. CAutoLock lck(&m_Serialize);
  130. #ifdef DEBUG
  131. if (DbgCheckModuleLevel(LOG_TIMING, 4)) DumpLinkedList();
  132. #endif
  133. // Note - DON'T cache the difference, it might overflow
  134. while ( rtTime >= (rtNextTime = (pAdvise=head.m_next)->m_rtEventTime) &&
  135. !pAdvise->IsZ() )
  136. {
  137. ASSERT(pAdvise->m_dwAdviseCookie); // If this is zero, its the _head or the _tail!!
  138. ASSERT(pAdvise->m_hNotify != INVALID_HANDLE_VALUE);
  139. if (pAdvise->m_bPeriodic == TRUE)
  140. {
  141. ReleaseSemaphore(pAdvise->m_hNotify,1,NULL);
  142. pAdvise->m_rtEventTime += pAdvise->m_rtPeriod;
  143. ShuntHead();
  144. }
  145. else
  146. {
  147. ASSERT( pAdvise->m_bPeriodic == FALSE );
  148. EXECUTE_ASSERT(SetEvent(pAdvise->m_hNotify));
  149. --m_dwAdviseCount;
  150. Delete( head.RemoveNext() );
  151. }
  152. }
  153. DbgLog((LOG_TIMING, 3,
  154. TEXT("CAMSchedule::Advise() Next time stamp: %lu ms, for advise %lu."),
  155. DWORD(rtNextTime / (UNITS / MILLISECONDS)), pAdvise->m_dwAdviseCookie ));
  156. return rtNextTime;
  157. }
  158. /* Private methods */
  159. DWORD_PTR CAMSchedule::AddAdvisePacket( __inout CAdvisePacket * pPacket )
  160. {
  161. ASSERT(pPacket->m_rtEventTime >= 0 && pPacket->m_rtEventTime < MAX_TIME);
  162. ASSERT(CritCheckIn(&m_Serialize));
  163. CAdvisePacket * p_prev = &head;
  164. CAdvisePacket * p_n;
  165. const DWORD_PTR Result = pPacket->m_dwAdviseCookie = ++m_dwNextCookie;
  166. // This relies on the fact that z is a sentry with a maximal m_rtEventTime
  167. for(;;p_prev = p_n)
  168. {
  169. p_n = p_prev->m_next;
  170. if ( p_n->m_rtEventTime >= pPacket->m_rtEventTime ) break;
  171. }
  172. p_prev->InsertAfter( pPacket );
  173. ++m_dwAdviseCount;
  174. DbgLog((LOG_TIMING, 2, TEXT("Added advise %lu, for thread 0x%02X, scheduled at %lu"),
  175. pPacket->m_dwAdviseCookie, GetCurrentThreadId(), (pPacket->m_rtEventTime / (UNITS / MILLISECONDS)) ));
  176. // If packet added at the _head, then clock needs to re-evaluate wait time.
  177. if ( p_prev == &head ) SetEvent( m_ev );
  178. return Result;
  179. }
  180. void CAMSchedule::Delete( __inout CAdvisePacket * pPacket )
  181. {
  182. if ( m_dwCacheCount >= dwCacheMax ) delete pPacket;
  183. else
  184. {
  185. m_Serialize.Lock();
  186. pPacket->m_next = m_pAdviseCache;
  187. m_pAdviseCache = pPacket;
  188. ++m_dwCacheCount;
  189. m_Serialize.Unlock();
  190. }
  191. }
  192. // Takes the _head of the list & repositions it
  193. void CAMSchedule::ShuntHead()
  194. {
  195. CAdvisePacket * p_prev = &head;
  196. CAdvisePacket * p_n;
  197. m_Serialize.Lock();
  198. CAdvisePacket *const pPacket = head.m_next;
  199. // This will catch both an empty list,
  200. // and if somehow a MAX_TIME time gets into the list
  201. // (which would also break this method).
  202. ASSERT( pPacket->m_rtEventTime < MAX_TIME );
  203. // This relies on the fact that z is a sentry with a maximal m_rtEventTime
  204. for(;;p_prev = p_n)
  205. {
  206. p_n = p_prev->m_next;
  207. if ( p_n->m_rtEventTime > pPacket->m_rtEventTime ) break;
  208. }
  209. // If p_prev == pPacket then we're already in the right place
  210. if (p_prev != pPacket)
  211. {
  212. head.m_next = pPacket->m_next;
  213. (p_prev->m_next = pPacket)->m_next = p_n;
  214. }
  215. #ifdef DEBUG
  216. DbgLog((LOG_TIMING, 2, TEXT("Periodic advise %lu, shunted to %lu"),
  217. pPacket->m_dwAdviseCookie, (pPacket->m_rtEventTime / (UNITS / MILLISECONDS)) ));
  218. #endif
  219. m_Serialize.Unlock();
  220. }
  221. #ifdef DEBUG
  222. void CAMSchedule::DumpLinkedList()
  223. {
  224. m_Serialize.Lock();
  225. int i=0;
  226. DbgLog((LOG_TIMING, 1, TEXT("CAMSchedule::DumpLinkedList() this = 0x%p"), this));
  227. for ( CAdvisePacket * p = &head
  228. ; p
  229. ; p = p->m_next , i++
  230. )
  231. {
  232. DbgLog((LOG_TIMING, 1, TEXT("Advise List # %lu, Cookie %d, RefTime %lu"),
  233. i,
  234. p->m_dwAdviseCookie,
  235. p->m_rtEventTime / (UNITS / MILLISECONDS)
  236. ));
  237. }
  238. m_Serialize.Unlock();
  239. }
  240. #endif