windows-nt/Source/XPSP1/NT/shell/shlwapi/tpstimer.h
2020-09-26 16:20:57 +08:00

522 lines
10 KiB
C++

/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
tpstimer.h
Abstract:
Timer classes. Moved out of tpsclass.h
Contents:
CTimer
CTimerQueueEntry
CTimerQueueList
CTimerQueue
CTimerRequest
CTimerQueueDeleteRequest
CTimerAddRequest
CTimerChangeRequest
CTimerCancelRequest
Author:
Richard L Firth (rfirth) 08-Aug-1998
Revision History:
08-Aug-1998 rfirth
Created
--*/
//
// manifests
//
#define TPS_TIMER_IN_USE 0x80000000
#define TPS_TIMER_CANCELLED 0x40000000
//
// external data
//
extern LONG g_UID;
//
// classes
//
//
// CTimer
//
class CTimer {
private:
HANDLE m_hQueue; // address of owning queue
HANDLE m_hTimer; // timer ordinal
WAITORTIMERCALLBACKFUNC m_pfnCallback;
LPVOID m_pContext;
DWORD m_dwPeriod;
DWORD m_dwFlags;
public:
CTimer(HANDLE hQueue,
WAITORTIMERCALLBACKFUNC pfnCallback,
LPVOID pContext,
DWORD dwPeriod,
DWORD dwFlags
)
{
m_hQueue = hQueue;
//
// FEATURE - (prevent this scenario) not industrial-strength: can have 2 timers with same ID
//
m_hTimer = IntToPtr(InterlockedIncrement(&g_UID));
m_pfnCallback = pfnCallback;
m_pContext = pContext;
m_dwPeriod = dwPeriod;
m_dwFlags = dwFlags;
}
HANDLE GetHandle(VOID) const {
return m_hTimer;
}
HANDLE GetQueue(VOID) const {
return m_hQueue;
}
VOID Execute(VOID) {
if (m_dwFlags & TPS_EXECUTEIO) {
//
// NT code does nothing with this flag. We should queue
// request to I/O worker thread
//
ASSERT(!(m_dwFlags & TPS_EXECUTEIO));
}
m_pfnCallback(m_pContext, TRUE);
}
VOID SetPeriod(DWORD dwPeriod) {
m_dwPeriod = dwPeriod;
}
DWORD GetPeriod(VOID) const {
return m_dwPeriod;
}
BOOL IsOneShot(VOID) {
return GetPeriod() == 0;
}
VOID SetInUse(VOID) {
m_dwFlags |= TPS_TIMER_IN_USE;
}
VOID ResetInUse(VOID) {
m_dwFlags &= ~TPS_TIMER_IN_USE;
}
BOOL IsInUse(VOID) {
return (m_dwFlags & TPS_TIMER_IN_USE) ? TRUE : FALSE;
}
VOID SetCancelled(VOID) {
m_dwFlags |= TPS_TIMER_CANCELLED;
}
BOOL IsCancelled(VOID) {
return (m_dwFlags & TPS_TIMER_CANCELLED) ? TRUE : FALSE;
}
};
//
// CTimerQueueEntry
//
class CTimerQueueEntry : public CTimedListEntry, public CTimer {
private:
public:
CDoubleLinkedList m_TimerList;
CTimerQueueEntry(HANDLE hQueue,
WAITORTIMERCALLBACKFUNC pfnCallback,
LPVOID pContext,
DWORD dwDueTime,
DWORD dwPeriod,
DWORD dwFlags
) :
CTimedListEntry(dwDueTime),
CTimer(hQueue,
pfnCallback,
pContext,
dwPeriod,
dwFlags
)
{
CDoubleLinkedListEntry::Init();
m_TimerList.Init();
}
~CTimerQueueEntry() {
m_TimerList.Remove();
}
VOID SetPeriodicTime(VOID) {
SetTimeStamp(ExpiryTime());
SetWaitTime(GetPeriod());
}
CDoubleLinkedList * TimerListHead(VOID) {
return m_TimerList.Head();
}
};
//
// CTimerQueueList
//
class CTimerQueueList {
private:
CDoubleLinkedList m_QueueList;
CDoubleLinkedList m_TimerList;
public:
VOID Init(VOID) {
m_QueueList.Init();
m_TimerList.Init();
}
CDoubleLinkedList * QueueListHead(VOID) {
return m_QueueList.Head();
}
CDoubleLinkedList * TimerListHead(VOID) {
return m_TimerList.Head();
}
CDoubleLinkedListEntry * FindQueue(CDoubleLinkedListEntry * pEntry) {
return m_QueueList.FindEntry(pEntry);
}
BOOL Wait(VOID) {
DWORD dwWaitTime = INFINITE;
CTimedListEntry * pTimer = (CTimedListEntry * )m_TimerList.Next();
ASSERT(pTimer != NULL);
if (pTimer != (CTimedListEntry * )m_TimerList.Head()) {
dwWaitTime = pTimer->TimeToWait();
}
//
// HACKHACK (tnoonan): Can't just check for 0 since
// Win95 will always return WAIT_TIMEOUT (despite what
// the docs say).
//
DWORD dwResult = SleepEx(dwWaitTime, TRUE);
return (dwResult == 0) || (dwResult == WAIT_TIMEOUT);
}
VOID ProcessCompletions(VOID) {
//
// run down list of all timers; for each expired timer, execute its
// completion handler. If one-shot timer, delete it, else reset the
// timer and re-insert it in the list
//
// If a timer is re-inserted further down the list, we may visit it
// again before we have completed the traversal. This is OK: either it
// has already expired, in which case we execute again, or it hasn't
// expired, in which case we terminate the traversal
//
CTimerQueueEntry * pTimer;
CTimerQueueEntry * pNext = (CTimerQueueEntry *)m_TimerList.Next();
do {
pTimer = pNext;
if ((pTimer == (CTimerQueueEntry *)m_TimerList.Head())
|| !pTimer->IsTimedOut()) {
break;
}
pNext = (CTimerQueueEntry * )pTimer->Next();
pTimer->Remove();
pTimer->SetInUse();
pTimer->Execute();
if (pTimer->IsOneShot() || pTimer->IsCancelled()) {
delete pTimer;
} else {
pTimer->SetPeriodicTime();
pTimer->ResetInUse();
pTimer->InsertBack(m_TimerList.Head());
}
} while (TRUE);
}
};
//
// CTimerQueue
//
class CTimerQueue : public CDoubleLinkedList {
private:
CDoubleLinkedList m_TimerList;
public:
CTimerQueue(CTimerQueueList * pList) {
CDoubleLinkedList::Init();
m_TimerList.Init();
InsertTail(pList->QueueListHead());
}
~CTimerQueue() {
Remove();
}
CDoubleLinkedList * TimerListHead(VOID) {
return m_TimerList.Head();
}
CTimerQueueEntry * FindTimer(HANDLE hTimer) {
CDoubleLinkedListEntry * pEntry;
for (pEntry = m_TimerList.Next();
pEntry != m_TimerList.Head();
pEntry = pEntry->Next()) {
CTimerQueueEntry * pTimer;
pTimer = CONTAINING_RECORD(pEntry, CTimerQueueEntry, m_TimerList);
if (pTimer->GetHandle() == hTimer) {
return pTimer;
}
}
return NULL;
}
VOID DeleteTimers(VOID) {
CDoubleLinkedListEntry * pEntry;
for (pEntry = m_TimerList.Next();
pEntry != m_TimerList.Head();
pEntry = m_TimerList.Next()) {
CTimerQueueEntry * pTimer;
pTimer = CONTAINING_RECORD(pEntry, CTimerQueueEntry, m_TimerList);
//
// remove timer from global timer list (linked on CDoubleLinkedList)
//
pTimer->Remove();
//
// timer will be removed from m_TimerList by its destructor
//
delete pTimer;
}
}
};
//
// CTimerRequest
//
class CTimerRequest {
private:
BOOL m_bCompleted;
DWORD m_dwStatus;
public:
CTimerRequest() {
m_bCompleted = FALSE;
m_dwStatus = ERROR_SUCCESS;
}
VOID SetComplete(VOID) {
m_bCompleted = TRUE;
}
VOID WaitForCompletion(VOID) {
while (!m_bCompleted) {
SleepEx(0, TRUE);
}
}
VOID SetStatus(DWORD dwStatus) {
m_dwStatus = dwStatus;
}
VOID SetCompletionStatus(DWORD dwStatus) {
SetStatus(dwStatus);
SetComplete();
}
BOOL SetThreadStatus(VOID) {
if (m_dwStatus == ERROR_SUCCESS) {
return TRUE;
}
SetLastError(m_dwStatus);
return FALSE;
}
};
//
// CTimerQueueDeleteRequest
//
class CTimerQueueDeleteRequest : public CTimerRequest {
private:
HANDLE m_hQueue;
public:
CTimerQueueDeleteRequest(HANDLE hQueue) : CTimerRequest() {
m_hQueue = hQueue;
}
HANDLE GetQueue(VOID) const {
return m_hQueue;
}
};
//
// CTimerAddRequest
//
class CTimerAddRequest : public CTimerQueueEntry, public CTimerRequest {
public:
CTimerAddRequest(HANDLE hQueue,
WAITORTIMERCALLBACKFUNC pfnCallback,
LPVOID pContext,
DWORD dwDueTime,
DWORD dwPeriod,
DWORD dwFlags
) :
CTimerQueueEntry(hQueue,
pfnCallback,
pContext,
dwDueTime,
dwPeriod,
dwFlags
),
CTimerRequest()
{
}
HANDLE GetHandle(VOID) const {
return CTimer::GetHandle();
}
CTimerQueue * GetQueue(VOID) const {
return (CTimerQueue *)CTimer::GetQueue();
}
};
//
// CTimerChangeRequest
//
class CTimerChangeRequest : public CTimerRequest {
private:
HANDLE m_hQueue;
HANDLE m_hTimer;
DWORD m_dwDueTime;
DWORD m_dwPeriod;
public:
CTimerChangeRequest(HANDLE hQueue,
HANDLE hTimer,
DWORD dwDueTime,
DWORD dwPeriod
) :
CTimerRequest()
{
m_hQueue = hQueue;
m_hTimer = hTimer;
m_dwDueTime = dwDueTime;
m_dwPeriod = dwPeriod;
}
HANDLE GetQueue(VOID) const {
return m_hQueue;
}
HANDLE GetTimer(VOID) const {
return m_hTimer;
}
DWORD GetDueTime(VOID) const {
return m_dwDueTime;
}
DWORD GetPeriod(VOID) const {
return m_dwPeriod;
}
};
//
// CTimerCancelRequest
//
class CTimerCancelRequest : public CTimerRequest {
private:
HANDLE m_hQueue;
HANDLE m_hTimer;
public:
CTimerCancelRequest(HANDLE hQueue, HANDLE hTimer) : CTimerRequest() {
m_hQueue = hQueue;
m_hTimer = hTimer;
}
HANDLE GetQueue(VOID) const {
return m_hQueue;
}
HANDLE GetTimer(VOID) const {
return m_hTimer;
}
};