You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
292 lines
11 KiB
292 lines
11 KiB
//-----------------------------------------------------------------------------
|
|
//
|
|
//
|
|
// File: qwiktime.cpp
|
|
//
|
|
// Description: Implementation of CAQQuickTime class
|
|
//
|
|
// Author: Mike Swafford (MikeSwa)
|
|
//
|
|
// History:
|
|
// 7/9/98 - MikeSwa Created
|
|
//
|
|
// Copyright (C) 1998 Microsoft Corporation
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "aqprecmp.h"
|
|
#include "qwiktime.h"
|
|
|
|
//The basic premise is to use GetTickCount to get a reasonable accurate
|
|
//time information in a DWORD. GetTickCount is only valid for 50 days, and
|
|
//has an accuracy of 1 ms. 50 days is just not long enough.
|
|
//MSchofie was kind enough to prepare the following table:
|
|
//Bit shift Resolution (seconds) Uptime(years)
|
|
//3 0.008 1.088824217
|
|
//4 0.016 2.177648434
|
|
//5 0.032 4.355296868
|
|
//6 0.064 8.710593736
|
|
//7 0.128 17.42118747
|
|
//8 0.256 34.84237495
|
|
//9 0.512 69.68474989
|
|
//10 1.024 139.3694998
|
|
//11 2.048 278.7389996
|
|
//12 4.096 557.4779991
|
|
//13 8.192 1114.955998
|
|
//14 16.384 2229.911997
|
|
//15 32.768 4459.823993
|
|
//16 65.536 8919.647986
|
|
|
|
//The initial implementation used 16 bits, which had an error of about 66
|
|
//seconds, which drove our poor Y2K tester nuts. 8 bits (34 years uptime)
|
|
//seems much more reasonable.
|
|
|
|
//The system tick is shifted right INTERNAL_TIME_TICK_BITS and stored in
|
|
//the least significant INTERNAL_TIME_TICK_BITS bits of the internal time.
|
|
//The upper 32-INTERNAL_TIME_TICK_BITS bits
|
|
//is used to count the number of times the count rolls over
|
|
#define INTERNAL_TIME_TICK_BITS 8
|
|
#define INTERNAL_TIME_TICK_MASK 0x00FFFFFF
|
|
|
|
//Number where tick count has wrapped
|
|
const LONGLONG INTERNAL_TIME_TICK_ROLLOVER_COUNT
|
|
= (1 << (32-INTERNAL_TIME_TICK_BITS));
|
|
const LONGLONG TICKS_PER_INTERNAL_TIME = (1 << INTERNAL_TIME_TICK_BITS);
|
|
|
|
//conversion constants
|
|
//There are 10^6 milliseconds per nanosecond (FILETIME is in 100 nanosecond counts)
|
|
const LONGLONG FILETIMES_PER_TICK = 10000;
|
|
const LONGLONG FILETIMES_PER_INTERNAL_TIME = (FILETIMES_PER_TICK*TICKS_PER_INTERNAL_TIME);
|
|
const LONGLONG FILETIMES_PER_MINUTE = (FILETIMES_PER_TICK*1000*60);
|
|
|
|
//---[ CAQQuickTime::CAQQuickTime ]--------------------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Default Constructor for CAQQuickTime. Will call GetSystemTime once to
|
|
// get start up time... GetTickCount is used for all other calls.
|
|
// Parameters:
|
|
// -
|
|
// Returns:
|
|
//
|
|
// History:
|
|
// 7/9/98 - MikeSwa Created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
CAQQuickTime::CAQQuickTime()
|
|
{
|
|
DWORD dwTickCount = GetTickCount();
|
|
LARGE_INTEGER *pLargeIntSystemStart = (LARGE_INTEGER *) &m_ftSystemStart;
|
|
|
|
m_dwSignature = QUICK_TIME_SIG;
|
|
|
|
//Get internal time and start file time
|
|
GetSystemTimeAsFileTime(&m_ftSystemStart);
|
|
|
|
//convert tick count to internal time
|
|
m_dwLastInternalTime = dwTickCount >> INTERNAL_TIME_TICK_BITS;
|
|
|
|
//adjust start time so that it is the time when the tick count was zero
|
|
pLargeIntSystemStart->QuadPart -= (LONGLONG) dwTickCount * FILETIMES_PER_TICK;
|
|
|
|
//Some asserts to validate constants
|
|
_ASSERT(!(INTERNAL_TIME_TICK_ROLLOVER_COUNT & INTERNAL_TIME_TICK_MASK));
|
|
_ASSERT((INTERNAL_TIME_TICK_ROLLOVER_COUNT >> 1) & INTERNAL_TIME_TICK_MASK);
|
|
|
|
}
|
|
|
|
//---[ CAQQuickTime::dwGetInternalTime ]---------------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Gets internal time using GetTickCount... and makes sure that when
|
|
// GetTickCount wraps, the correct time is returned.
|
|
// Parameters:
|
|
// -
|
|
// Returns:
|
|
// DWORD internal time
|
|
// History:
|
|
// 7/9/98 - MikeSwa Created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
DWORD CAQQuickTime::dwGetInternalTime()
|
|
{
|
|
DWORD dwCurrentTick = GetTickCount();
|
|
DWORD dwLastInternalTime = m_dwLastInternalTime;
|
|
DWORD dwCurrentInternalTime;
|
|
DWORD dwCheck;
|
|
|
|
dwCurrentInternalTime = dwCurrentTick >> INTERNAL_TIME_TICK_BITS;
|
|
|
|
_ASSERT(dwCurrentInternalTime == (INTERNAL_TIME_TICK_MASK & dwCurrentInternalTime));
|
|
|
|
//see if rolled over our tick count
|
|
while ((dwLastInternalTime & INTERNAL_TIME_TICK_MASK) > dwCurrentInternalTime)
|
|
{
|
|
dwLastInternalTime = m_dwLastInternalTime;
|
|
|
|
//it is possible that we have rolled over the tick count
|
|
//first make sure it is not just a thread-timing issue
|
|
dwCurrentTick = GetTickCount();
|
|
dwCurrentInternalTime = dwCurrentTick >> INTERNAL_TIME_TICK_BITS;
|
|
|
|
if ((dwLastInternalTime & INTERNAL_TIME_TICK_MASK) > dwCurrentInternalTime)
|
|
{
|
|
dwCurrentInternalTime |= (~INTERNAL_TIME_TICK_MASK & dwLastInternalTime);
|
|
dwCurrentInternalTime += INTERNAL_TIME_TICK_ROLLOVER_COUNT;
|
|
|
|
//attempt interlocked exchange to update internal last internal time
|
|
dwCheck = (DWORD) InterlockedCompareExchange((PLONG) &m_dwLastInternalTime,
|
|
(LONG) dwCurrentInternalTime,
|
|
(LONG) dwLastInternalTime);
|
|
|
|
if (dwCheck == dwLastInternalTime) //exchange worked
|
|
goto Exit;
|
|
}
|
|
|
|
}
|
|
|
|
_ASSERT(dwCurrentInternalTime == (INTERNAL_TIME_TICK_MASK & dwCurrentInternalTime));
|
|
dwCurrentInternalTime |= (~INTERNAL_TIME_TICK_MASK & m_dwLastInternalTime);
|
|
|
|
Exit:
|
|
return dwCurrentInternalTime;
|
|
}
|
|
|
|
//---[ CAQQuickTime::GetExpireTime ]-------------------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Get the expriation time for cMinutesExpireTime from now.
|
|
// Parameters:
|
|
// IN cMinutesExpireTime # of minutes in future to set time
|
|
// IN OUT pftExpireTime Filetime to store new expire time
|
|
// IN OUT pdwExpireContext If non-zero will use the same tick count
|
|
// as previous calls (saves call to GetTickCount)
|
|
// Returns:
|
|
//
|
|
// History:
|
|
// 7/10/98 - MikeSwa Created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void CAQQuickTime::GetExpireTime(
|
|
IN DWORD cMinutesExpireTime,
|
|
IN OUT FILETIME *pftExpireTime,
|
|
IN OUT DWORD *pdwExpireContext)
|
|
{
|
|
TraceFunctEnterEx((LPARAM) this, "CAQQuickTime::GetExpireTime");
|
|
_ASSERT(pftExpireTime);
|
|
DWORD dwInternalTime = 0;
|
|
LARGE_INTEGER *pLargeIntTime = (LARGE_INTEGER *) pftExpireTime;
|
|
|
|
if (pdwExpireContext)
|
|
dwInternalTime = *pdwExpireContext;
|
|
|
|
if (!dwInternalTime)
|
|
{
|
|
dwInternalTime = dwGetInternalTime();
|
|
//save internal time as context
|
|
if (pdwExpireContext)
|
|
*pdwExpireContext = dwInternalTime;
|
|
}
|
|
|
|
memcpy(pftExpireTime, &m_ftSystemStart, sizeof(FILETIME));
|
|
|
|
//set to current time
|
|
pLargeIntTime->QuadPart += (LONGLONG) dwInternalTime * FILETIMES_PER_INTERNAL_TIME;
|
|
|
|
//set cMinutesExpireTime into the future
|
|
pLargeIntTime->QuadPart += (LONGLONG) cMinutesExpireTime * FILETIMES_PER_MINUTE;
|
|
|
|
DebugTrace((LPARAM) this, "INFO: Creating file time for %d minutes of 0x%08X %08X",
|
|
cMinutesExpireTime, pLargeIntTime->HighPart, pLargeIntTime->LowPart);
|
|
TraceFunctLeave();
|
|
|
|
}
|
|
|
|
//---[ CAQQuickTime::GetExpireTime ]-------------------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Get the expriation time for cMinutesExpireTime from ftStartTime
|
|
// Parameters:
|
|
// IN cMinutesExpireTime # of minutes in future to set time
|
|
// IN OUT pftExpireTime Filetime to store new expire time
|
|
// IN ftStartTime Time to add expire minutes to
|
|
// Returns:
|
|
//
|
|
// History:
|
|
// 5/16/2001 - dbraun created from GetExpireTime above
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void CAQQuickTime::GetExpireTime(
|
|
IN FILETIME ftStartTime,
|
|
IN DWORD cMinutesExpireTime,
|
|
IN OUT FILETIME *pftExpireTime)
|
|
{
|
|
TraceFunctEnterEx((LPARAM) this, "CAQQuickTime::GetExpireTime");
|
|
_ASSERT(pftExpireTime);
|
|
|
|
LARGE_INTEGER *pLargeIntTime = (LARGE_INTEGER *) pftExpireTime;
|
|
|
|
// Set to start time
|
|
memcpy(pftExpireTime, &ftStartTime, sizeof(FILETIME));
|
|
|
|
//set cMinutesExpireTime into the future
|
|
pLargeIntTime->QuadPart += (LONGLONG) cMinutesExpireTime * FILETIMES_PER_MINUTE;
|
|
|
|
DebugTrace((LPARAM) this, "INFO: Creating file time for %d minutes of 0x%08X %08X",
|
|
cMinutesExpireTime, pLargeIntTime->HighPart, pLargeIntTime->LowPart);
|
|
TraceFunctLeave();
|
|
|
|
}
|
|
|
|
|
|
//---[ CAQQuickTime::fInPast ]-------------------------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Determines if a given file time has already happened
|
|
// Parameters:
|
|
// IN pftExpireTime FILETIME with expiration
|
|
// IN OUT pdwExpireContext If non-zero will use the same tick count
|
|
// as previous calls (saves call to GetTickCount)
|
|
// Returns:
|
|
// TRUE if expire time is in the past
|
|
// FALSE if expire time is in the future
|
|
// History:
|
|
// 7/11/98 - MikeSwa Created
|
|
// Note:
|
|
// You should NOT use the same context used to get the filetime, because
|
|
// it will always return FALSE
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL CAQQuickTime::fInPast(IN FILETIME *pftExpireTime,
|
|
IN OUT DWORD *pdwExpireContext)
|
|
{
|
|
_ASSERT(pftExpireTime);
|
|
DWORD dwInternalTime = 0;
|
|
FILETIME ftCurrentTime = m_ftSystemStart;
|
|
LARGE_INTEGER *pLargeIntCurrentTime = (LARGE_INTEGER *) &ftCurrentTime;
|
|
LARGE_INTEGER *pLargeIntExpireTime = (LARGE_INTEGER *) pftExpireTime;
|
|
BOOL fInPast = FALSE;
|
|
|
|
if (pdwExpireContext)
|
|
dwInternalTime = *pdwExpireContext;
|
|
|
|
if (!dwInternalTime)
|
|
{
|
|
dwInternalTime = dwGetInternalTime();
|
|
//save internal time as context
|
|
if (pdwExpireContext)
|
|
*pdwExpireContext = dwInternalTime;
|
|
}
|
|
|
|
//Get current time
|
|
pLargeIntCurrentTime->QuadPart += (LONGLONG) dwInternalTime * FILETIMES_PER_INTERNAL_TIME;
|
|
|
|
if (pLargeIntCurrentTime->QuadPart > pLargeIntExpireTime->QuadPart)
|
|
fInPast = TRUE;
|
|
|
|
return fInPast;
|
|
}
|