schedule.cpp
上传用户:liguizhu
上传日期:2015-11-01
资源大小:2422k
文件大小:8k
源码类别:

P2P编程

开发平台:

Visual C++

  1. //------------------------------------------------------------------------------
  2. // File: Schedule.cpp
  3. //
  4. // Desc: DirectShow base classes.
  5. //
  6. // Copyright (c) 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( 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( 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