home *** CD-ROM | disk | FTP | other *** search
/ The Net: Ultimate Internet Guide / WWLCD1.ISO / mac / SiteBldr / AMOVIE / SDK / _SETUP / COMMON.Z / schedule.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-18  |  8.7 KB  |  308 lines

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