windows-nt/Source/XPSP1/NT/net/upnp/ssdp/common/ssdptimer/timer.cpp
2020-09-26 16:20:57 +08:00

339 lines
7 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 2000.
//
// File: T I M E R . C P P
//
// Contents: Timer queue helper class
//
// Notes:
//
// Author: mbend 3 Nov 2000
//
//----------------------------------------------------------------------------
#include "pch.h"
#pragma hdrstop
#include "timer.h"
#include "ncdefine.h"
#include "ncbase.h"
CTimerQueue CTimerQueue::s_instance;
CTimerQueue::CTimerQueue() : m_hTimerQueue(NULL), m_nRefCount(0)
{
}
CTimerQueue::~CTimerQueue()
{
if (!m_hTimerQueue)
{
TraceError("CTimerQueue::~CTimerQueue", E_FAIL);
}
}
CTimerQueue & CTimerQueue::Instance()
{
return s_instance;
}
HRESULT CTimerQueue::HrInitialize()
{
CLock lock(m_critSec);
++m_nRefCount;
if(m_nRefCount > 1)
{
return S_OK;
}
HRESULT hr = S_OK;
m_hTimerQueue = CreateTimerQueue();
if(!m_hTimerQueue)
{
hr = HrFromLastWin32Error();
}
TraceHr(ttidSsdpTimer, FAL, hr, FALSE, "CTimerQueue::HrInitialize");
return hr;
}
HRESULT CTimerQueue::HrShutdown(HANDLE hCompletionEvent)
{
HRESULT hr = S_OK;
HANDLE hTimerQueue = NULL;
{
CLock lock(m_critSec);
if(!m_nRefCount)
{
hr = E_UNEXPECTED;
TraceHr(ttidSsdpTimer, FAL, hr, FALSE, "CTimerQueue::HrShutdown - Can't call SsdpCleanup without calling SsdpStartup");
}
if(SUCCEEDED(hr))
{
--m_nRefCount;
if(!m_nRefCount)
{
Assert(m_hTimerQueue);
hTimerQueue = m_hTimerQueue;
m_hTimerQueue = NULL;
}
}
}
if(SUCCEEDED(hr) && hTimerQueue)
{
if(!DeleteTimerQueueEx(hTimerQueue, hCompletionEvent))
{
hr = HrFromLastWin32Error();
}
}
TraceHr(ttidSsdpTimer, FAL, hr, FALSE, "CTimerQueue::HrShutdown");
return hr;
}
HRESULT CTimerQueue::HrGetHandle(HANDLE * phTimerQueue)
{
CLock lock(m_critSec);
HRESULT hr = S_OK;
if(phTimerQueue)
{
*phTimerQueue = m_hTimerQueue;
}
else
{
hr = E_POINTER;
}
TraceHr(ttidSsdpTimer, FAL, hr, FALSE, "CTimerQueue::HrGetHandle");
return hr;
}
#ifdef DBG
long CTimerBase::s_nCallbackEnter = 0;
long CTimerBase::s_nCallbackExit = 0;
#endif // DBG
CTimerBase::CTimerBase() : m_bShutdown(FALSE), m_hTimerQueueTimer(NULL)
{
#ifdef DBG
m_nSetTimer = 0;
m_nSetTimerSuccess = 0;
m_nDeleteTimer = 0;
m_nDeleteTimerActual = 0;
m_nTimerFiredEnter = 0;
m_nTimerFiredExit = 0;
m_nCallbackEnter = 0;
#endif // DBG
}
CTimerBase::~CTimerBase()
{
HRESULT hr = S_OK;
if(m_hTimerQueueTimer)
{
HANDLE hTimerQueue = NULL;
hr = CTimerQueue::Instance().HrGetHandle(&hTimerQueue);
if(SUCCEEDED(hr))
{
if(!DeleteTimerQueueTimer(hTimerQueue, m_hTimerQueueTimer, NULL))
{
hr = HrFromLastWin32Error();
}
else
{
m_hTimerQueueTimer = NULL;
}
}
}
}
HRESULT CTimerBase::HrSetTimer(
DWORD dwIntervalInMillis)
{
HRESULT hr = E_FAIL;
CLock lock(m_critSec);
Assert(!m_hTimerQueueTimer);
#ifdef DBG
InterlockedIncrement(&m_nSetTimer);
#endif // DBG
// Check for shutdown
if(!m_bShutdown)
{
HANDLE hTimerQueue = NULL;
hr = CTimerQueue::Instance().HrGetHandle(&hTimerQueue);
if(SUCCEEDED(hr))
{
if(!CreateTimerQueueTimer(&m_hTimerQueueTimer, hTimerQueue, &CTimerBase::Callback, this, dwIntervalInMillis, 0, 0))
{
hr = HrFromLastWin32Error();
}
}
}
#ifdef DBG
if(SUCCEEDED(hr))
{
InterlockedIncrement(&m_nSetTimerSuccess);
}
#endif // DBG
TraceHr(ttidSsdpTimer, FAL, hr, FALSE, "CTimerBase::HrSetTimer");
return hr;
}
HRESULT CTimerBase::HrSetTimerInFired(
DWORD dwIntervalInMillis)
{
HRESULT hr = E_FAIL;
CLock lock(m_critSec);
if(!m_bShutdown)
{
if(m_hTimerQueueTimer)
{
HrDelete(NULL);
m_bShutdown = FALSE;
}
hr = HrSetTimer(dwIntervalInMillis);
}
TraceHr(ttidSsdpTimer, FAL, hr, FALSE, "CTimerBase::HrSetTimerInFired");
return hr;
}
HRESULT CTimerBase::HrDelete(HANDLE hCompletionEvent)
{
HRESULT hr = S_OK;
#ifdef DBG
InterlockedIncrement(&m_nDeleteTimer);
#endif // DBG
HANDLE hTimerQueueTimer = NULL;
{
CLock lock(m_critSec);
m_bShutdown = TRUE;
hTimerQueueTimer = m_hTimerQueueTimer;
m_hTimerQueueTimer = NULL;
}
if(hTimerQueueTimer)
{
HANDLE hTimerQueue = NULL;
hr = CTimerQueue::Instance().HrGetHandle(&hTimerQueue);
if(SUCCEEDED(hr))
{
if(!DeleteTimerQueueTimer(hTimerQueue, hTimerQueueTimer, hCompletionEvent))
{
hr = HrFromLastWin32Error();
if (HRESULT_FROM_WIN32(ERROR_IO_PENDING) == hr)
{
hr = S_OK;
}
}
#ifdef DBG
if(SUCCEEDED(hr))
{
InterlockedIncrement(&m_nDeleteTimerActual);
}
#endif // DBG
}
}
else
{
if(hCompletionEvent != NULL && hCompletionEvent != INVALID_HANDLE_VALUE)
{
SetEvent(hCompletionEvent);
}
}
TraceHr(ttidSsdpTimer, FAL, hr, FALSE, "CTimerBase::HrDelete");
return hr;
}
HRESULT CTimerBase::HrResetTimer(
DWORD dwIntervalInMillis)
{
HRESULT hr = S_OK;
// Can't hold lock during whole operation or this can deadlock waiting for timer to exit
HrDelete(INVALID_HANDLE_VALUE);
m_bShutdown = FALSE;
hr = HrSetTimer(dwIntervalInMillis);
TraceHr(ttidSsdpTimer, FAL, hr, FALSE, "CTimerBase::HrResetTimer");
return hr;
}
void CALLBACK CTimerBase::Callback(void * pvParam, BOOLEAN)
{
CTimerBase * pTimer = reinterpret_cast<CTimerBase*>(pvParam);
#ifdef DBG
InterlockedIncrement(&s_nCallbackEnter);
InterlockedIncrement(&pTimer->m_nCallbackEnter);
#endif // DBG
while(true)
{
CLock lock(pTimer->m_critSec);
if(pTimer->m_bShutdown)
{
break;
}
if(pTimer->OnTryToLock())
{
pTimer->OnExecute();
pTimer->OnUnlock();
break;
}
Sleep(1);
}
#ifdef DBG
InterlockedIncrement(&s_nCallbackExit);
#endif // DBG
}
VOID FileTimeToString(FILETIME FileTime, CHAR *szBuf, INT BufSize)
{
SYSTEMTIME SystemTime;
INT Size;
FileTimeToLocalFileTime(&FileTime, &FileTime);
FileTimeToSystemTime(&FileTime,&SystemTime);
Size = GetDateFormatA(LOCALE_SYSTEM_DEFAULT, 0, &SystemTime, NULL,
szBuf, BufSize-1 );
if (Size > 0)
{
szBuf[Size-1] = ' ';
}
GetTimeFormatA(LOCALE_SYSTEM_DEFAULT, 0, &SystemTime, NULL,
szBuf+Size, BufSize-Size);
}