windows-nt/Source/XPSP1/NT/net/tapi/skywalker/termmgr/timerq.h

228 lines
5.1 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*
Copyright (c) 1998-1999 Microsoft Corporation
*/
#ifndef __TIMER_QUEUE__
#define __TIMER_QUEUE__
#include "meterf.h"
// we don't allow timeouts greater than 1 day
// this ensures that we don't get multiple wraparounds in the timerqueue,
// which has a wraparound time of 49 days
const DWORD MAX_TIMEOUT = 1000 * 60 * 60 * 24;
const DWORD MAX_DWORD = DWORD(-1);
class CTimerQueue;
class CMediaPump;
class CFilterInfo
{
friend CTimerQueue;
friend CMediaPump;
public:
// null entries
inline CFilterInfo(
IN CMediaTerminalFilter *pFilter = NULL,
IN HANDLE hWaitEvent = NULL
);
inline BOOL InQueue();
inline void ScheduleNextTimeout(
IN CTimerQueue &TimerQueue,
IN DWORD TimeOut
);
LONG AddRef()
{
return InterlockedIncrement(&m_lRefCount);
}
LONG Release()
{
LONG l = InterlockedDecrement(&m_lRefCount);
if (0 == l)
{
delete this;
}
return l;
}
private:
LONG m_lRefCount;
protected:
//
// the only way to destroy filterinfo is through Release()
//
inline ~CFilterInfo();
// m_pFilter holds a refcnt.
// the wait event is signaled when a new sample
// is available
CMediaTerminalFilter *m_pFilter;
HANDLE m_hWaitEvent;
// contains the absolute time to trigger the timeout event
// this is based upon the value returned by timeGetTime()
DWORD m_WaitTime;
// prev and next ptrs in an intrusive doubly linked list
CFilterInfo *m_pPrev;
CFilterInfo *m_pNext;
};
// null entries
inline
CFilterInfo::CFilterInfo(
IN CMediaTerminalFilter *pFilter, /* = NULL */
IN HANDLE hWaitEvent /* = NULL */
)
: m_pFilter(pFilter),
m_hWaitEvent(hWaitEvent),
m_pPrev(NULL),
m_pNext(NULL),
m_lRefCount(0)
{
// either both pFilter and hWaitEvent are null, or both are non-null
// enough to assert on this
TM_ASSERT((NULL == pFilter) == (NULL == hWaitEvent));
if (NULL != m_pFilter) m_pFilter->GetControllingUnknown()->AddRef();
}
CFilterInfo::~CFilterInfo(
)
{
// release refcnt on the filter
if (NULL != m_pFilter) m_pFilter->GetControllingUnknown()->Release();
}
inline BOOL
CFilterInfo::InQueue(
)
{
// either both prev/next are null or both are not null
TM_ASSERT((NULL == m_pPrev) == (NULL == m_pNext));
return (NULL != m_pPrev) ? TRUE : FALSE;
}
// ScheduleNextTimeout(2 params) - declared at the end of the file
// as it uses CTimerQueue::Insert and has to be inline
// CTimerQueue is a doubly linked intrusive list of CFilterInfo
// the wait time values in the entries represents the absolute time at which
// they must be fired.
// we assume that the timeout values are small (<=MAX_TIMEOUT) and,
// therefore, we can have atmost one wrap around in the list at a time.
// to deal with a wrap around, when computing the time difference between two
// time values, we use the least time to get to one time from the other
// ex. MAX_DWORD-1, 5 - the difference is (MAX_DWORD - (MAX_DWORD-1) + 5)
// this is quite reasonable as the value range is 49.1 days (MAX_DWORD)
class CTimerQueue
{
public:
inline CTimerQueue()
{
m_Head.m_pNext = m_Head.m_pPrev = &m_Head;
}
inline BOOL IsEmpty();
DWORD GetTimeToTimeout();
inline CFilterInfo *RemoveFirst();
void Insert(
IN CFilterInfo *pNewFilterInfo
);
BOOL Remove(
IN CFilterInfo *pFilterInfo
);
protected:
// no need to call Init
CFilterInfo m_Head;
inline BOOL IsHead(
IN const CFilterInfo *pFilterInfo
)
{
return (&m_Head == pFilterInfo) ? TRUE : FALSE;
}
// to deal with a wrap around, when computing the time difference
// between two time values, we use the least time to get to one time
// from the other - ex. MAX_DWORD-1, 5 - the difference is
// (MAX_DWORD - (MAX_DWORD-1) + 5). this is quite reasonable as the
// value range is 49.1 days (MAX_DWORD)
DWORD GetMinDiff(
IN DWORD Time1,
IN DWORD Time2,
OUT BOOL &bIsWrap
);
};
inline BOOL
CTimerQueue::IsEmpty(
)
{
return IsHead(m_Head.m_pNext);
}
CFilterInfo *
CTimerQueue::RemoveFirst(
)
{
TM_ASSERT(!IsEmpty());
CFilterInfo *ToReturn = m_Head.m_pNext;
Remove(ToReturn);
return ToReturn;
}
// this method has to be declared after the CTimerQueue declaration as it
// uses its Insert method
// this is called after returning from GetFilledBuffer. the filter suggests
// a timeout offset for the next call into GetFilledBuffer, but the timer
// puts a limit on the time out value to a max of MAX_TIMEOUT
inline void
CFilterInfo::ScheduleNextTimeout(
IN CTimerQueue &TimerQueue,
IN DWORD TimeOut
)
{
TM_ASSERT(!InQueue());
if (MAX_TIMEOUT < TimeOut) TimeOut = MAX_TIMEOUT;
m_WaitTime = TimeOut + timeGetTime();
TimerQueue.Insert(this);
}
#endif // __TIMER_QUEUE__