AJA NTV2 SDK  18.0.0.2717
NTV2 SDK 18.0.0.2717
schedule.cpp
Go to the documentation of this file.
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 // DbgLog values (all on LOG_TIMING):
13 //
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
17 
18 /* Construct & destructors */
19 
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 )
26 {
27  head.m_dwAdviseCookie = z.m_dwAdviseCookie = 0;
28 }
29 
31 {
32  m_Serialize.Lock();
33 
34  // Delete cache
35  CAdvisePacket * p = m_pAdviseCache;
36  while (p)
37  {
38  CAdvisePacket *const p_next = p->m_next;
39  delete p;
40  p = p_next;
41  }
42 
43  ASSERT( m_dwAdviseCount == 0 );
44  // Better to be safe than sorry
45  if ( m_dwAdviseCount > 0 )
46  {
48  while ( !head.m_next->IsZ() )
49  {
50  head.DeleteNext();
51  --m_dwAdviseCount;
52  }
53  }
54 
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 );
59 
60  m_Serialize.Unlock();
61 }
62 
63 /* Public methods */
64 
66 {
67  // No need to lock, m_dwAdviseCount is 32bits & declared volatile
68  return m_dwAdviseCount;
69 }
70 
72 {
73  CAutoLock lck(&m_Serialize); // Need to stop the linked list from changing
74  return head.m_next->m_rtEventTime;
75 }
76 
78 ( const REFERENCE_TIME & time1
79 , const REFERENCE_TIME & time2
80 , HANDLE h, BOOL periodic
81 )
82 {
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;
88 
89  m_Serialize.Lock();
90 
91  if (m_pAdviseCache)
92  {
93  p = m_pAdviseCache;
94  m_pAdviseCache = p->m_next;
95  --m_dwCacheCount;
96  }
97  else
98  {
99  p = new CAdvisePacket();
100  }
101  if (p)
102  {
103  p->m_rtEventTime = time1; p->m_rtPeriod = time2;
104  p->m_hNotify = h; p->m_bPeriodic = periodic;
105  Result = AddAdvisePacket( p );
106  }
107  else Result = 0;
108 
109  m_Serialize.Unlock();
110 
111  return Result;
112 }
113 
114 HRESULT CAMSchedule::Unadvise(DWORD_PTR dwAdviseCookie)
115 {
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
121  {
122  if ( p_n->m_dwAdviseCookie == dwAdviseCookie )
123  {
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())
130  {
131  ASSERT(p_n->m_dwAdviseCookie != dwAdviseCookie);
132  p_prev = p_n;
133  }
134  #endif
135  break;
136  }
137  p_prev = p_n;
138  };
139  m_Serialize.Unlock();
140  return hr;
141 }
142 
143 REFERENCE_TIME CAMSchedule::Advise( const REFERENCE_TIME & rtTime )
144 {
145  REFERENCE_TIME rtNextTime;
146  CAdvisePacket * pAdvise;
147 
148  DbgLog((LOG_TIMING, 2,
149  TEXT("CAMSchedule::Advise( %lu ms )"), ULONG(rtTime / (UNITS / MILLISECONDS))));
150 
151  CAutoLock lck(&m_Serialize);
152 
153  #ifdef DEBUG
155  #endif
156 
157  // Note - DON'T cache the difference, it might overflow
158  while ( rtTime >= (rtNextTime = (pAdvise=head.m_next)->m_rtEventTime) &&
159  !pAdvise->IsZ() )
160  {
161  ASSERT(pAdvise->m_dwAdviseCookie); // If this is zero, its the head or the tail!!
162 
163  ASSERT(pAdvise->m_hNotify != INVALID_HANDLE_VALUE);
164 
165  if (pAdvise->m_bPeriodic == TRUE)
166  {
167  ReleaseSemaphore(pAdvise->m_hNotify,1,NULL);
168  pAdvise->m_rtEventTime += pAdvise->m_rtPeriod;
169  ShuntHead();
170  }
171  else
172  {
173  ASSERT( pAdvise->m_bPeriodic == FALSE );
174  EXECUTE_ASSERT(SetEvent(pAdvise->m_hNotify));
175  --m_dwAdviseCount;
176  Delete( head.RemoveNext() );
177  }
178 
179  }
180 
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 ));
184 
185  return rtNextTime;
186 }
187 
188 /* Private methods */
189 
190 DWORD_PTR CAMSchedule::AddAdvisePacket( __inout CAdvisePacket * pPacket )
191 {
192  ASSERT(pPacket->m_rtEventTime >= 0 && pPacket->m_rtEventTime < MAX_TIME);
193  ASSERT(CritCheckIn(&m_Serialize));
194 
195  CAdvisePacket * p_prev = &head;
196  CAdvisePacket * p_n;
197 
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)
201  {
202  p_n = p_prev->m_next;
203  if ( p_n->m_rtEventTime >= pPacket->m_rtEventTime ) break;
204  }
205  p_prev->InsertAfter( pPacket );
206  ++m_dwAdviseCount;
207 
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)) ));
210 
211  // If packet added at the head, then clock needs to re-evaluate wait time.
212  if ( p_prev == &head ) SetEvent( m_ev );
213 
214  return Result;
215 }
216 
217 void CAMSchedule::Delete( __inout CAdvisePacket * pPacket )
218 {
219  if ( m_dwCacheCount >= dwCacheMax ) delete pPacket;
220  else
221  {
222  m_Serialize.Lock();
223  pPacket->m_next = m_pAdviseCache;
224  m_pAdviseCache = pPacket;
225  ++m_dwCacheCount;
226  m_Serialize.Unlock();
227  }
228 }
229 
230 
231 // Takes the head of the list & repositions it
232 void CAMSchedule::ShuntHead()
233 {
234  CAdvisePacket * p_prev = &head;
235  CAdvisePacket * p_n;
236 
237  m_Serialize.Lock();
238  CAdvisePacket *const pPacket = head.m_next;
239 
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 );
244 
245  // This relies on the fact that z is a sentry with a maximal m_rtEventTime
246  for(;;p_prev = p_n)
247  {
248  p_n = p_prev->m_next;
249  if ( p_n->m_rtEventTime > pPacket->m_rtEventTime ) break;
250  }
251  // If p_prev == pPacket then we're already in the right place
252  if (p_prev != pPacket)
253  {
254  head.m_next = pPacket->m_next;
255  (p_prev->m_next = pPacket)->m_next = p_n;
256  }
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();
262 }
263 
264 
265 #ifdef DEBUG
267 {
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
272  ; p
273  ; p = p->m_next , i++
274  )
275  {
276  DbgLog((LOG_TIMING, 1, TEXT("Advise List # %lu, Cookie %d, RefTime %lu"),
277  i,
278  p->m_dwAdviseCookie,
279  p->m_rtEventTime / (UNITS / MILLISECONDS)
280  ));
281  }
282  m_Serialize.Unlock();
283 }
284 #endif
CritCheckIn
#define CritCheckIn(x)
Definition: wxutil.h:75
HANDLE
short HANDLE
Definition: ajatypes.h:338
CAMSchedule::Advise
REFERENCE_TIME Advise(const REFERENCE_TIME &rtTime)
Definition: schedule.cpp:143
streams.h
NULL
#define NULL
Definition: ntv2caption608types.h:19
CCritSec::Unlock
void Unlock()
Definition: wxutil.h:52
MAX_TIME
const LONGLONG MAX_TIME
Definition: refclock.h:17
CAMSchedule::CAMSchedule
CAMSchedule(HANDLE ev)
Definition: schedule.cpp:20
CAutoLock
Definition: wxutil.h:83
CAMSchedule::Unadvise
HRESULT Unadvise(DWORD_PTR dwAdviseCookie)
Definition: schedule.cpp:114
MILLISECONDS
const LONGLONG MILLISECONDS
Definition: reftime.h:39
DbgCheckModuleLevel
#define DbgCheckModuleLevel(Type, Level)
Definition: wxdebug.h:191
DbgLog
#define DbgLog(_x_)
Definition: wxdebug.h:183
CAMSchedule::~CAMSchedule
virtual ~CAMSchedule()
Definition: schedule.cpp:30
EXECUTE_ASSERT
#define EXECUTE_ASSERT(_x_)
Definition: wxdebug.h:207
ULONG
ULONG(__stdcall *_RegisterTraceGuids)(__in IN WMIDPREQUEST RequestAddress
CAMSchedule::DumpLinkedList
void DumpLinkedList()
Definition: schedule.h:123
UNITS
const LONGLONG UNITS
Definition: reftime.h:41
LOG_TIMING
@ LOG_TIMING
Definition: wxdebug.h:44
CAMSchedule::AddAdvisePacket
DWORD_PTR AddAdvisePacket(const REFERENCE_TIME &time1, const REFERENCE_TIME &time2, HANDLE h, BOOL periodic)
Definition: schedule.cpp:78
CCritSec::Lock
void Lock()
Definition: wxutil.h:48
CAMSchedule::GetNextAdviseTime
REFERENCE_TIME GetNextAdviseTime()
Definition: schedule.cpp:71
INVALID_HANDLE_VALUE
#define INVALID_HANDLE_VALUE
Definition: ajatypes.h:352
CAMSchedule::GetAdviseCount
DWORD GetAdviseCount()
Definition: schedule.cpp:65
ASSERT
#define ASSERT(_x_)
Definition: wxdebug.h:205
hr
__out HRESULT & hr
Definition: pstream.cpp:145
CBaseObject
Definition: combase.h:158