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.

227 lines
5.1 KiB

  1. /*
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. */
  4. #ifndef __TIMER_QUEUE__
  5. #define __TIMER_QUEUE__
  6. #include "meterf.h"
  7. // we don't allow timeouts greater than 1 day
  8. // this ensures that we don't get multiple wraparounds in the timerqueue,
  9. // which has a wraparound time of 49 days
  10. const DWORD MAX_TIMEOUT = 1000 * 60 * 60 * 24;
  11. const DWORD MAX_DWORD = DWORD(-1);
  12. class CTimerQueue;
  13. class CMediaPump;
  14. class CFilterInfo
  15. {
  16. friend CTimerQueue;
  17. friend CMediaPump;
  18. public:
  19. // null entries
  20. inline CFilterInfo(
  21. IN CMediaTerminalFilter *pFilter = NULL,
  22. IN HANDLE hWaitEvent = NULL
  23. );
  24. inline BOOL InQueue();
  25. inline void ScheduleNextTimeout(
  26. IN CTimerQueue &TimerQueue,
  27. IN DWORD TimeOut
  28. );
  29. LONG AddRef()
  30. {
  31. return InterlockedIncrement(&m_lRefCount);
  32. }
  33. LONG Release()
  34. {
  35. LONG l = InterlockedDecrement(&m_lRefCount);
  36. if (0 == l)
  37. {
  38. delete this;
  39. }
  40. return l;
  41. }
  42. private:
  43. LONG m_lRefCount;
  44. protected:
  45. //
  46. // the only way to destroy filterinfo is through Release()
  47. //
  48. inline ~CFilterInfo();
  49. // m_pFilter holds a refcnt.
  50. // the wait event is signaled when a new sample
  51. // is available
  52. CMediaTerminalFilter *m_pFilter;
  53. HANDLE m_hWaitEvent;
  54. // contains the absolute time to trigger the timeout event
  55. // this is based upon the value returned by timeGetTime()
  56. DWORD m_WaitTime;
  57. // prev and next ptrs in an intrusive doubly linked list
  58. CFilterInfo *m_pPrev;
  59. CFilterInfo *m_pNext;
  60. };
  61. // null entries
  62. inline
  63. CFilterInfo::CFilterInfo(
  64. IN CMediaTerminalFilter *pFilter, /* = NULL */
  65. IN HANDLE hWaitEvent /* = NULL */
  66. )
  67. : m_pFilter(pFilter),
  68. m_hWaitEvent(hWaitEvent),
  69. m_pPrev(NULL),
  70. m_pNext(NULL),
  71. m_lRefCount(0)
  72. {
  73. // either both pFilter and hWaitEvent are null, or both are non-null
  74. // enough to assert on this
  75. TM_ASSERT((NULL == pFilter) == (NULL == hWaitEvent));
  76. if (NULL != m_pFilter) m_pFilter->GetControllingUnknown()->AddRef();
  77. }
  78. CFilterInfo::~CFilterInfo(
  79. )
  80. {
  81. // release refcnt on the filter
  82. if (NULL != m_pFilter) m_pFilter->GetControllingUnknown()->Release();
  83. }
  84. inline BOOL
  85. CFilterInfo::InQueue(
  86. )
  87. {
  88. // either both prev/next are null or both are not null
  89. TM_ASSERT((NULL == m_pPrev) == (NULL == m_pNext));
  90. return (NULL != m_pPrev) ? TRUE : FALSE;
  91. }
  92. // ScheduleNextTimeout(2 params) - declared at the end of the file
  93. // as it uses CTimerQueue::Insert and has to be inline
  94. // CTimerQueue is a doubly linked intrusive list of CFilterInfo
  95. // the wait time values in the entries represents the absolute time at which
  96. // they must be fired.
  97. // we assume that the timeout values are small (<=MAX_TIMEOUT) and,
  98. // therefore, we can have atmost one wrap around in the list at a time.
  99. // to deal with a wrap around, when computing the time difference between two
  100. // time values, we use the least time to get to one time from the other
  101. // ex. MAX_DWORD-1, 5 - the difference is (MAX_DWORD - (MAX_DWORD-1) + 5)
  102. // this is quite reasonable as the value range is 49.1 days (MAX_DWORD)
  103. class CTimerQueue
  104. {
  105. public:
  106. inline CTimerQueue()
  107. {
  108. m_Head.m_pNext = m_Head.m_pPrev = &m_Head;
  109. }
  110. inline BOOL IsEmpty();
  111. DWORD GetTimeToTimeout();
  112. inline CFilterInfo *RemoveFirst();
  113. void Insert(
  114. IN CFilterInfo *pNewFilterInfo
  115. );
  116. BOOL Remove(
  117. IN CFilterInfo *pFilterInfo
  118. );
  119. protected:
  120. // no need to call Init
  121. CFilterInfo m_Head;
  122. inline BOOL IsHead(
  123. IN const CFilterInfo *pFilterInfo
  124. )
  125. {
  126. return (&m_Head == pFilterInfo) ? TRUE : FALSE;
  127. }
  128. // to deal with a wrap around, when computing the time difference
  129. // between two time values, we use the least time to get to one time
  130. // from the other - ex. MAX_DWORD-1, 5 - the difference is
  131. // (MAX_DWORD - (MAX_DWORD-1) + 5). this is quite reasonable as the
  132. // value range is 49.1 days (MAX_DWORD)
  133. DWORD GetMinDiff(
  134. IN DWORD Time1,
  135. IN DWORD Time2,
  136. OUT BOOL &bIsWrap
  137. );
  138. };
  139. inline BOOL
  140. CTimerQueue::IsEmpty(
  141. )
  142. {
  143. return IsHead(m_Head.m_pNext);
  144. }
  145. CFilterInfo *
  146. CTimerQueue::RemoveFirst(
  147. )
  148. {
  149. TM_ASSERT(!IsEmpty());
  150. CFilterInfo *ToReturn = m_Head.m_pNext;
  151. Remove(ToReturn);
  152. return ToReturn;
  153. }
  154. // this method has to be declared after the CTimerQueue declaration as it
  155. // uses its Insert method
  156. // this is called after returning from GetFilledBuffer. the filter suggests
  157. // a timeout offset for the next call into GetFilledBuffer, but the timer
  158. // puts a limit on the time out value to a max of MAX_TIMEOUT
  159. inline void
  160. CFilterInfo::ScheduleNextTimeout(
  161. IN CTimerQueue &TimerQueue,
  162. IN DWORD TimeOut
  163. )
  164. {
  165. TM_ASSERT(!InQueue());
  166. if (MAX_TIMEOUT < TimeOut) TimeOut = MAX_TIMEOUT;
  167. m_WaitTime = TimeOut + timeGetTime();
  168. TimerQueue.Insert(this);
  169. }
  170. #endif // __TIMER_QUEUE__