IIS.Common/open-inc/sttimer.h

232 строки
5.3 KiB
C++

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
#ifndef _STTIMER_H
#define _STTIMER_H
class STTIMER
{
public:
STTIMER()
: _pTimer( NULL )
{
}
virtual
~STTIMER()
{
if ( _pTimer )
{
CancelTimer();
CloseThreadpoolTimer( _pTimer );
_pTimer = NULL;
}
}
HRESULT
InitializeTimer(
PTP_TIMER_CALLBACK pfnCallback,
VOID * pContext,
DWORD dwInitialWait = 0,
DWORD dwPeriod = 0
)
{
_pTimer = CreateThreadpoolTimer( pfnCallback,
pContext,
NULL );
if ( !_pTimer )
{
return HRESULT_FROM_WIN32( GetLastError() );
}
if ( dwInitialWait )
{
SetTimer( dwInitialWait,
dwPeriod );
}
return S_OK;
}
VOID
SetTimer(
DWORD dwInitialWait,
DWORD dwPeriod = 0
)
{
FILETIME ftInitialWait;
if ( dwInitialWait == 0 && dwPeriod == 0 )
{
//
// Special case. We are preventing new callbacks
// from being queued. Any existing callbacks in the
// queue will still run.
//
// This effectively disables the timer. It can be
// re-enabled by setting non-zero initial wait or
// period values.
//
SetThreadpoolTimer( _pTimer, NULL, 0, 0 );
return;
}
InitializeRelativeFileTime( &ftInitialWait, dwInitialWait );
SetThreadpoolTimer( _pTimer,
&ftInitialWait,
dwPeriod,
0 );
}
VOID
CancelTimer()
{
//
// Disable the timer
//
SetTimer( 0 );
//
// Wait until any callbacks queued prior to disabling
// have completed.
//
WaitForThreadpoolTimerCallbacks( _pTimer, TRUE );
}
private:
VOID
InitializeRelativeFileTime(
FILETIME * pft,
DWORD dwMilliseconds
)
{
LARGE_INTEGER li;
//
// The pftDueTime parameter expects the time to be
// expressed as the number of 100 nanosecond intervals
// times -1.
//
// To convert from milliseconds, we'll multiply by
// -10000
//
li.QuadPart = (LONGLONG)dwMilliseconds * -10000;
pft->dwHighDateTime = li.HighPart;
pft->dwLowDateTime = li.LowPart;
};
TP_TIMER * _pTimer;
};
class STELAPSED
{
public:
STELAPSED()
: _dwInitTime( 0 ),
_dwInitTickCount( 0 ),
_dwPerfCountsPerMillisecond( 0 ),
_fUsingHighResolution( FALSE )
{
LARGE_INTEGER li;
BOOL fResult;
_dwInitTickCount = GetTickCount64();
fResult = QueryPerformanceFrequency( &li );
if ( !fResult )
{
goto Finished;
}
_dwPerfCountsPerMillisecond = li.QuadPart / 1000;
fResult = QueryPerformanceCounter( &li );
if ( !fResult )
{
goto Finished;
}
_dwInitTime = li.QuadPart / _dwPerfCountsPerMillisecond;
_fUsingHighResolution = TRUE;
Finished:
return;
}
virtual
~STELAPSED()
{
}
LONGLONG
QueryElapsedTime()
{
LARGE_INTEGER li;
if ( _fUsingHighResolution && QueryPerformanceCounter( &li ) )
{
DWORD64 dwCurrentTime = li.QuadPart / _dwPerfCountsPerMillisecond;
if ( dwCurrentTime < _dwInitTime )
{
//
// It's theoretically possible that QueryPerformanceCounter
// may return slightly different values on different CPUs.
// In this case, we don't want to return an unexpected value
// so we'll return zero. This is acceptable because
// presumably such a case would only happen for a very short
// time window.
//
// It would be possible to prevent this by ensuring processor
// affinity for all calls to QueryPerformanceCounter, but that
// would be undesirable in the general case because it could
// introduce unnecessary context switches and potentially a
// CPU bottleneck.
//
// Note that this issue also applies to callers doing rapid
// calls to this function. If a caller wants to mitigate
// that, they could enforce the affinitization, or they
// could implement a similar sanity check when comparing
// returned values from this function.
//
return 0;
}
return dwCurrentTime - _dwInitTime;
}
return GetTickCount64() - _dwInitTickCount;
}
BOOL
QueryUsingHighResolution()
{
return _fUsingHighResolution;
}
private:
DWORD64 _dwInitTime;
DWORD64 _dwInitTickCount;
DWORD64 _dwPerfCountsPerMillisecond;
BOOL _fUsingHighResolution;
};
#endif // _STTIMER_H