00001
00002
00003
00004
00005
00006 #include <streams.h>
00007
00008 CAMSchedule::CAMSchedule( HANDLE ev )
00009 : CBaseObject(TEXT("CAMSchedule"))
00010 , head(&z, 0), z(0, MAX_TIME)
00011 , m_dwNextCookie(0), m_dwAdviseCount(0)
00012 , m_pAdviseCache(0), m_dwCacheCount(0)
00013 , m_ev( ev )
00014 {
00015 head.m_dwAdviseCookie = z.m_dwAdviseCookie = 0;
00016 }
00017
00018 CAMSchedule::~CAMSchedule()
00019 {
00020 m_Serialize.Lock();
00021
00022
00023 CAdvisePacket * p = m_pAdviseCache;
00024 while (p)
00025 {
00026 CAdvisePacket *const p_next = p->m_next;
00027 delete p;
00028 p = p_next;
00029 }
00030
00031 ASSERT( m_dwAdviseCount == 0 );
00032
00033 if ( m_dwAdviseCount > 0 )
00034 {
00035 DumpLinkedList();
00036 while ( !head.m_next->IsZ() )
00037 {
00038 head.DeleteNext();
00039 --m_dwAdviseCount;
00040 }
00041 }
00042
00043
00044
00045
00046 ASSERT( m_dwAdviseCount == 0 );
00047
00048 m_Serialize.Unlock();
00049 }
00050
00051 DWORD CAMSchedule::GetAdviseCount()
00052 {
00053
00054 return m_dwAdviseCount;
00055 }
00056
00057 REFERENCE_TIME CAMSchedule::GetNextAdviseTime()
00058 {
00059 CAutoLock lck(&m_Serialize);
00060 return head.m_next->m_rtEventTime;
00061 }
00062
00063 DWORD_PTR CAMSchedule::AddAdvisePacket
00064 ( const REFERENCE_TIME & time1
00065 , const REFERENCE_TIME & time2
00066 , HANDLE h, BOOL periodic
00067 )
00068 {
00069
00070
00071 ASSERT( time1 < MAX_TIME );
00072 DWORD_PTR Result;
00073 CAdvisePacket * p;
00074
00075 m_Serialize.Lock();
00076
00077 if (m_pAdviseCache)
00078 {
00079 p = m_pAdviseCache;
00080 m_pAdviseCache = p->m_next;
00081 --m_dwCacheCount;
00082 }
00083 else
00084 {
00085 p = new CAdvisePacket();
00086 }
00087 if (p)
00088 {
00089 p->m_rtEventTime = time1; p->m_rtPeriod = time2;
00090 p->m_hNotify = h; p->m_bPeriodic = periodic;
00091 Result = AddAdvisePacket( p );
00092 }
00093 else Result = 0;
00094
00095 m_Serialize.Unlock();
00096
00097 return Result;
00098 }
00099
00100 HRESULT CAMSchedule::Unadvise(DWORD_PTR dwAdviseCookie)
00101 {
00102 HRESULT hr = S_FALSE;
00103 CAdvisePacket * p_prev = &head;
00104 CAdvisePacket * p_n;
00105 m_Serialize.Lock();
00106 while ( p_n = p_prev->Next() )
00107 {
00108 if ( p_n->m_dwAdviseCookie == dwAdviseCookie )
00109 {
00110 Delete( p_prev->RemoveNext() );
00111 --m_dwAdviseCount;
00112 hr = S_OK;
00113
00114 #ifdef DEBUG
00115 while (p_n = p_prev->Next())
00116 {
00117 ASSERT(p_n->m_dwAdviseCookie != dwAdviseCookie);
00118 p_prev = p_n;
00119 }
00120 #endif
00121 break;
00122 }
00123 p_prev = p_n;
00124 };
00125 m_Serialize.Unlock();
00126 return hr;
00127 }
00128
00129 REFERENCE_TIME CAMSchedule::Advise( const REFERENCE_TIME & rtTime )
00130 {
00131 REFERENCE_TIME rtNextTime;
00132 CAdvisePacket * pAdvise;
00133
00134 DbgLog((LOG_TIMING, 2,
00135 TEXT("CAMSchedule::Advise( %lu ms )"), ULONG(rtTime / (UNITS / MILLISECONDS))));
00136
00137 CAutoLock lck(&m_Serialize);
00138
00139 #ifdef DEBUG
00140 if (DbgCheckModuleLevel(LOG_TIMING, 4)) DumpLinkedList();
00141 #endif
00142
00143
00144 while ( rtTime >= (rtNextTime = (pAdvise=head.m_next)->m_rtEventTime) &&
00145 !pAdvise->IsZ() )
00146 {
00147 ASSERT(pAdvise->m_dwAdviseCookie);
00148
00149 ASSERT(pAdvise->m_hNotify != INVALID_HANDLE_VALUE);
00150
00151 if (pAdvise->m_bPeriodic == TRUE)
00152 {
00153 EXECUTE_ASSERT(ReleaseSemaphore(pAdvise->m_hNotify,1,NULL));
00154 pAdvise->m_rtEventTime += pAdvise->m_rtPeriod;
00155 ShuntHead();
00156 }
00157 else
00158 {
00159 ASSERT( pAdvise->m_bPeriodic == FALSE );
00160 EXECUTE_ASSERT(SetEvent(pAdvise->m_hNotify));
00161 --m_dwAdviseCount;
00162 Delete( head.RemoveNext() );
00163 }
00164
00165 }
00166
00167 DbgLog((LOG_TIMING, 3,
00168 TEXT("CAMSchedule::Advise() Next time stamp: %lu ms, for advise %lu."),
00169 DWORD(rtNextTime / (UNITS / MILLISECONDS)), pAdvise->m_dwAdviseCookie ));
00170
00171 return rtNextTime;
00172 }
00173
00174 DWORD_PTR CAMSchedule::AddAdvisePacket( CAdvisePacket * pPacket )
00175 {
00176 ASSERT(pPacket->m_rtEventTime >= 0 && pPacket->m_rtEventTime < MAX_TIME);
00177 ASSERT(CritCheckIn(&m_Serialize));
00178
00179 CAdvisePacket * p_prev = &head;
00180 CAdvisePacket * p_n;
00181
00182 const DWORD_PTR Result = pPacket->m_dwAdviseCookie = ++m_dwNextCookie;
00183
00184 for(;;p_prev = p_n)
00185 {
00186 p_n = p_prev->m_next;
00187 if ( p_n->m_rtEventTime >= pPacket->m_rtEventTime ) break;
00188 }
00189 p_prev->InsertAfter( pPacket );
00190 ++m_dwAdviseCount;
00191
00192 DbgLog((LOG_TIMING, 2, TEXT("Added advise %lu, for thread 0x%02X, scheduled at %lu"),
00193 pPacket->m_dwAdviseCookie, GetCurrentThreadId(), (pPacket->m_rtEventTime / (UNITS / MILLISECONDS)) ));
00194
00195
00196 if ( p_prev == &head ) SetEvent( m_ev );
00197
00198 return Result;
00199 }
00200
00201 void CAMSchedule::Delete( CAdvisePacket * pPacket )
00202 {
00203 if ( m_dwCacheCount >= dwCacheMax ) delete pPacket;
00204 else
00205 {
00206 m_Serialize.Lock();
00207 pPacket->m_next = m_pAdviseCache;
00208 m_pAdviseCache = pPacket;
00209 ++m_dwCacheCount;
00210 m_Serialize.Unlock();
00211 }
00212 }
00213
00214 void CAMSchedule::ShuntHead()
00215 {
00216 CAdvisePacket * p_prev = &head;
00217 CAdvisePacket * p_n;
00218
00219 m_Serialize.Lock();
00220 CAdvisePacket *const pPacket = head.m_next;
00221
00222
00223
00224
00225 ASSERT( pPacket->m_rtEventTime < MAX_TIME );
00226
00227
00228 for(;;p_prev = p_n)
00229 {
00230 p_n = p_prev->m_next;
00231 if ( p_n->m_rtEventTime > pPacket->m_rtEventTime ) break;
00232 }
00233
00234 if (p_prev != pPacket)
00235 {
00236 head.m_next = pPacket->m_next;
00237 (p_prev->m_next = pPacket)->m_next = p_n;
00238 }
00239 #ifdef DEBUG
00240 DbgLog((LOG_TIMING, 2, TEXT("Periodic advise %lu, shunted to %lu"),
00241 pPacket->m_dwAdviseCookie, (pPacket->m_rtEventTime / (UNITS / MILLISECONDS)) ));
00242 #endif
00243 m_Serialize.Unlock();
00244 }
00245
00246 #ifdef DEBUG
00247 void CAMSchedule::DumpLinkedList()
00248 {
00249 m_Serialize.Lock();
00250 int i=0;
00251 DbgLog((LOG_TIMING, 1, TEXT("CAMSchedule::DumpLinkedList() this = 0x%p"), this));
00252 for ( CAdvisePacket * p = &head
00253 ; p
00254 ; p = p->m_next , i++
00255 )
00256 {
00257 DbgLog((LOG_TIMING, 1, TEXT("Advise List # %lu, Cookie %d, RefTime %lu"),
00258 i,
00259 p->m_dwAdviseCookie,
00260 p->m_rtEventTime / (UNITS / MILLISECONDS)
00261 ));
00262 }
00263 m_Serialize.Unlock();
00264 }
00265 #endif