Update UNRAR.H
[xy_vsfilter.git] / src / filters / BaseClasses / schedule.cpp
blob02726b402601ace3797bb0a99e39edf59617da6d
1 //------------------------------------------------------------------------------
2 // File: Schedule.cpp
3 //
4 // Desc: DirectShow base classes.
5 //
6 // Copyright (c) 1996-2002 Microsoft Corporation. All rights reserved.
7 //------------------------------------------------------------------------------
10 #include <streams.h>
12 // DbgLog values (all on LOG_TIMING):
14 // 2 for schedulting, firing and shunting of events
15 // 3 for wait delays and wake-up times of event thread
16 // 4 for details of whats on the list when the thread awakes
18 /* Construct & destructors */
20 CAMSchedule::CAMSchedule( HANDLE ev )
21 : CBaseObject(TEXT("CAMSchedule"))
22 , head(&z, 0), z(0, MAX_TIME)
23 , m_dwNextCookie(0), m_dwAdviseCount(0)
24 , m_pAdviseCache(0), m_dwCacheCount(0)
25 , m_ev( ev )
27 head.m_dwAdviseCookie = z.m_dwAdviseCookie = 0;
30 CAMSchedule::~CAMSchedule()
32 m_Serialize.Lock();
34 // Delete cache
35 CAdvisePacket * p = m_pAdviseCache;
36 while (p)
38 CAdvisePacket *const p_next = p->m_next;
39 delete p;
40 p = p_next;
43 ASSERT( m_dwAdviseCount == 0 );
44 // Better to be safe than sorry
45 if ( m_dwAdviseCount > 0 )
47 DumpLinkedList();
48 while ( !head.m_next->IsZ() )
50 head.DeleteNext();
51 --m_dwAdviseCount;
55 // If, in the debug version, we assert twice, it means, not only
56 // did we have left over advises, but we have also let m_dwAdviseCount
57 // get out of sync. with the number of advises actually on the list.
58 ASSERT( m_dwAdviseCount == 0 );
60 m_Serialize.Unlock();
63 /* Public methods */
65 DWORD CAMSchedule::GetAdviseCount()
67 // No need to lock, m_dwAdviseCount is 32bits & declared volatile
68 return m_dwAdviseCount;
71 REFERENCE_TIME CAMSchedule::GetNextAdviseTime()
73 CAutoLock lck(&m_Serialize); // Need to stop the linked list from changing
74 return head.m_next->m_rtEventTime;
77 DWORD_PTR CAMSchedule::AddAdvisePacket
78 ( const REFERENCE_TIME & time1
79 , const REFERENCE_TIME & time2
80 , HANDLE h, BOOL periodic
83 // Since we use MAX_TIME as a sentry, we can't afford to
84 // schedule a notification at MAX_TIME
85 ASSERT( time1 < MAX_TIME );
86 DWORD_PTR Result;
87 CAdvisePacket * p;
89 m_Serialize.Lock();
91 if (m_pAdviseCache)
93 p = m_pAdviseCache;
94 m_pAdviseCache = p->m_next;
95 --m_dwCacheCount;
97 else
99 p = new CAdvisePacket();
101 if (p)
103 p->m_rtEventTime = time1; p->m_rtPeriod = time2;
104 p->m_hNotify = h; p->m_bPeriodic = periodic;
105 Result = AddAdvisePacket( p );
107 else Result = 0;
109 m_Serialize.Unlock();
111 return Result;
114 HRESULT CAMSchedule::Unadvise(DWORD_PTR dwAdviseCookie)
116 HRESULT hr = S_FALSE;
117 CAdvisePacket * p_prev = &head;
118 CAdvisePacket * p_n;
119 m_Serialize.Lock();
120 while ( p_n = p_prev->Next() ) // The Next() method returns NULL when it hits z
122 if ( p_n->m_dwAdviseCookie == dwAdviseCookie )
124 Delete( p_prev->RemoveNext() );
125 --m_dwAdviseCount;
126 hr = S_OK;
127 // Having found one cookie that matches, there should be no more
128 #ifdef DEBUG
129 while (p_n = p_prev->Next())
131 ASSERT(p_n->m_dwAdviseCookie != dwAdviseCookie);
132 p_prev = p_n;
134 #endif
135 break;
137 p_prev = p_n;
139 m_Serialize.Unlock();
140 return hr;
143 REFERENCE_TIME CAMSchedule::Advise( const REFERENCE_TIME & rtTime )
145 REFERENCE_TIME rtNextTime;
146 CAdvisePacket * pAdvise;
148 DbgLog((LOG_TIMING, 2,
149 TEXT("CAMSchedule::Advise( %lu ms )"), ULONG(rtTime / (UNITS / MILLISECONDS))));
151 CAutoLock lck(&m_Serialize);
153 #ifdef DEBUG
154 if (DbgCheckModuleLevel(LOG_TIMING, 4)) DumpLinkedList();
155 #endif
157 // Note - DON'T cache the difference, it might overflow
158 while ( rtTime >= (rtNextTime = (pAdvise=head.m_next)->m_rtEventTime) &&
159 !pAdvise->IsZ() )
161 ASSERT(pAdvise->m_dwAdviseCookie); // If this is zero, its the head or the tail!!
163 ASSERT(pAdvise->m_hNotify != INVALID_HANDLE_VALUE);
165 if (pAdvise->m_bPeriodic == TRUE)
167 ReleaseSemaphore(pAdvise->m_hNotify,1,NULL);
168 pAdvise->m_rtEventTime += pAdvise->m_rtPeriod;
169 ShuntHead();
171 else
173 ASSERT( pAdvise->m_bPeriodic == FALSE );
174 EXECUTE_ASSERT(SetEvent(pAdvise->m_hNotify));
175 --m_dwAdviseCount;
176 Delete( head.RemoveNext() );
181 DbgLog((LOG_TIMING, 3,
182 TEXT("CAMSchedule::Advise() Next time stamp: %lu ms, for advise %lu."),
183 DWORD(rtNextTime / (UNITS / MILLISECONDS)), pAdvise->m_dwAdviseCookie ));
185 return rtNextTime;
188 /* Private methods */
190 DWORD_PTR CAMSchedule::AddAdvisePacket( CAdvisePacket * pPacket )
192 ASSERT(pPacket->m_rtEventTime >= 0 && pPacket->m_rtEventTime < MAX_TIME);
193 ASSERT(CritCheckIn(&m_Serialize));
195 CAdvisePacket * p_prev = &head;
196 CAdvisePacket * p_n;
198 const DWORD_PTR Result = pPacket->m_dwAdviseCookie = ++m_dwNextCookie;
199 // This relies on the fact that z is a sentry with a maximal m_rtEventTime
200 for(;;p_prev = p_n)
202 p_n = p_prev->m_next;
203 if ( p_n->m_rtEventTime >= pPacket->m_rtEventTime ) break;
205 p_prev->InsertAfter( pPacket );
206 ++m_dwAdviseCount;
208 DbgLog((LOG_TIMING, 2, TEXT("Added advise %lu, for thread 0x%02X, scheduled at %lu"),
209 pPacket->m_dwAdviseCookie, GetCurrentThreadId(), (pPacket->m_rtEventTime / (UNITS / MILLISECONDS)) ));
211 // If packet added at the head, then clock needs to re-evaluate wait time.
212 if ( p_prev == &head ) SetEvent( m_ev );
214 return Result;
217 void CAMSchedule::Delete( CAdvisePacket * pPacket )
219 if ( m_dwCacheCount >= dwCacheMax ) delete pPacket;
220 else
222 m_Serialize.Lock();
223 pPacket->m_next = m_pAdviseCache;
224 m_pAdviseCache = pPacket;
225 ++m_dwCacheCount;
226 m_Serialize.Unlock();
231 // Takes the head of the list & repositions it
232 void CAMSchedule::ShuntHead()
234 CAdvisePacket * p_prev = &head;
235 CAdvisePacket * p_n;
237 m_Serialize.Lock();
238 CAdvisePacket *const pPacket = head.m_next;
240 // This will catch both an empty list,
241 // and if somehow a MAX_TIME time gets into the list
242 // (which would also break this method).
243 ASSERT( pPacket->m_rtEventTime < MAX_TIME );
245 // This relies on the fact that z is a sentry with a maximal m_rtEventTime
246 for(;;p_prev = p_n)
248 p_n = p_prev->m_next;
249 if ( p_n->m_rtEventTime > pPacket->m_rtEventTime ) break;
251 // If p_prev == pPacket then we're already in the right place
252 if (p_prev != pPacket)
254 head.m_next = pPacket->m_next;
255 (p_prev->m_next = pPacket)->m_next = p_n;
257 #ifdef DEBUG
258 DbgLog((LOG_TIMING, 2, TEXT("Periodic advise %lu, shunted to %lu"),
259 pPacket->m_dwAdviseCookie, (pPacket->m_rtEventTime / (UNITS / MILLISECONDS)) ));
260 #endif
261 m_Serialize.Unlock();
265 #ifdef DEBUG
266 void CAMSchedule::DumpLinkedList()
268 m_Serialize.Lock();
269 int i=0;
270 DbgLog((LOG_TIMING, 1, TEXT("CAMSchedule::DumpLinkedList() this = 0x%p"), this));
271 for ( CAdvisePacket * p = &head
273 ; p = p->m_next , i++
276 DbgLog((LOG_TIMING, 1, TEXT("Advise List # %lu, Cookie %d, RefTime %lu"),
278 p->m_dwAdviseCookie,
279 p->m_rtEventTime / (UNITS / MILLISECONDS)
282 m_Serialize.Unlock();
284 #endif