home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / DirectShow / BaseClasses / schedule.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-08  |  7.7 KB  |  266 lines

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