1079 lines
25 KiB
C++
1079 lines
25 KiB
C++
|
|
|
|
#include "pch.cxx"
|
|
#pragma hdrstop
|
|
|
|
#define TRKDATA_ALLOCATE
|
|
#include "trkwks.hxx"
|
|
|
|
|
|
const TCHAR *g_tszDefaultName = TEXT("TimerTestDefault");
|
|
const TCHAR *g_tszContinueName = TEXT("TimerTestContinue");
|
|
|
|
DWORD g_Debug = TRKDBG_ERROR | TRKDBG_TIMER;
|
|
ULONG g_ulDefaultPeriod = 4; // Seconds
|
|
ULONG g_ulMinRetry = g_ulDefaultPeriod * 3 / 2;
|
|
ULONG g_ulMaxRetry = g_ulMinRetry * 4;
|
|
ULONG g_ulTimerContext = 0;
|
|
|
|
CFILETIME g_cftDeltaMargin = 10*1000*1000; // 1 second
|
|
|
|
#include "ttimer.hxx"
|
|
|
|
|
|
void
|
|
CTimerTest::Initialize( PTimerCallback *pTimerCallback,
|
|
const TCHAR *ptszName,
|
|
ULONG ulTimerContext,
|
|
ULONG ulPeriodInSeconds,
|
|
CNewTimer::TimerRetryType retrytype,
|
|
ULONG ulLowerRetryTime,
|
|
ULONG ulUpperRetryTime,
|
|
ULONG ulMaxLifetime )
|
|
{
|
|
_ptszName = ptszName;
|
|
|
|
_fInitialized = TRUE;
|
|
|
|
_timer.Initialize(pTimerCallback, ptszName,
|
|
ulTimerContext, ulPeriodInSeconds, retrytype,
|
|
ulLowerRetryTime, ulUpperRetryTime, ulMaxLifetime );
|
|
|
|
_hEvent = CreateEvent( NULL, FALSE, FALSE, TEXT("TTimer Test") );
|
|
if( INVALID_HANDLE_VALUE == _hEvent )
|
|
TrkRaiseLastError( );
|
|
|
|
}
|
|
|
|
|
|
void
|
|
CTimerTest::SetTimerRegistryValue( const TCHAR *ptszName,
|
|
const CFILETIME &cftSet, const CFILETIME cftDue,
|
|
ULONG ulRetry )
|
|
{
|
|
HKEY hkey;
|
|
LONG lRet;
|
|
|
|
if( ERROR_SUCCESS != RegOpenKeyEx( HKEY_LOCAL_MACHINE, s_tszKeyNameLinkTrack,
|
|
0, KEY_ALL_ACCESS, &hkey ))
|
|
{
|
|
TrkLog((TRKDBG_ERROR, TEXT("Couldn't open persistent registry key") ));
|
|
TrkRaiseLastError( );
|
|
}
|
|
|
|
CNewTimer::PersistentState TimerPersistence;
|
|
|
|
TimerPersistence.cftDue = cftDue;
|
|
TimerPersistence.cftSet = cftSet;
|
|
TimerPersistence.ulCurrentRetryTime = ulRetry;
|
|
|
|
RegDeleteValue( hkey, ptszName );
|
|
lRet = RegSetValueEx( hkey,
|
|
ptszName,
|
|
0,
|
|
REG_BINARY,
|
|
(CONST BYTE *)&TimerPersistence,
|
|
sizeof(TimerPersistence) );
|
|
|
|
if( ERROR_SUCCESS != lRet )
|
|
{
|
|
TrkLog((TRKDBG_ERROR, TEXT("Couldn't write to registry") ));
|
|
TrkRaiseWin32Error( lRet );
|
|
}
|
|
|
|
RegCloseKey( hkey );
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CTimerTest::VerifyRegistryDataCorrect()
|
|
{
|
|
LONG lRet = ERROR_SUCCESS;
|
|
CFILETIME cftDelta(0), cftNow;
|
|
CNewTimer::PersistentState persist;
|
|
DWORD dwType = 0, cbData = sizeof(persist);
|
|
HKEY hkey;
|
|
|
|
lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE, s_tszKeyNameLinkTrack,
|
|
0, KEY_ALL_ACCESS, &hkey );
|
|
if( ERROR_SUCCESS != lRet )
|
|
{
|
|
TrkLog((TRKDBG_ERROR, TEXT("Couldn't open primary registry key")));
|
|
TrkRaiseWin32Error( lRet );
|
|
}
|
|
|
|
lRet = RegQueryValueEx( hkey,
|
|
_ptszName,
|
|
NULL,
|
|
&dwType,
|
|
(BYTE *)&persist,
|
|
&cbData );
|
|
RegCloseKey( hkey );
|
|
|
|
cftDelta = _cftExpected - persist.cftDue;
|
|
|
|
if( lRet != ERROR_SUCCESS
|
|
||
|
|
dwType != REG_BINARY
|
|
||
|
|
cbData != sizeof(persist)
|
|
||
|
|
persist.cftDue > _cftExpected
|
|
||
|
|
cftDelta > g_cftDeltaMargin )
|
|
{
|
|
TrkLog(( TRKDBG_ERROR, TEXT("Registry data isn't correct (%d, %d, %d,\n %s,\n %s"),
|
|
lRet, dwType, cbData, CDebugString(persist.cftDue)._tsz, CDebugString(_cftExpected)._tsz ));
|
|
TrkRaiseWin32Error( E_FAIL );
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
CTimerTest::VerifyRegistryDataRemoved()
|
|
{
|
|
LONG lRet = ERROR_SUCCESS;
|
|
CNewTimer::PersistentState persist;
|
|
DWORD dwType = 0, cbData = sizeof(persist);
|
|
HKEY hkey;
|
|
|
|
lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE, s_tszKeyNameLinkTrack,
|
|
0, KEY_ALL_ACCESS, &hkey );
|
|
if( ERROR_SUCCESS != lRet )
|
|
{
|
|
TrkLog((TRKDBG_ERROR, TEXT("Couldn't open primary registry key")));
|
|
TrkRaiseWin32Error( lRet );
|
|
}
|
|
|
|
lRet = RegQueryValueEx( hkey, g_tszDefaultName, NULL, &dwType, (BYTE*)&persist, &cbData );
|
|
RegCloseKey( hkey );
|
|
|
|
if( ERROR_FILE_NOT_FOUND != lRet )
|
|
{
|
|
TrkLog(( TRKDBG_ERROR, TEXT("Registry data wasn't removed") ));
|
|
TrkRaiseWin32Error( E_FAIL );
|
|
return;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
PTimerCallback::TimerContinuation
|
|
CTimerTest0::Timer( ULONG ulTimerContext)
|
|
{
|
|
CFILETIME cftDelta(0);
|
|
|
|
if( ulTimerContext != 0 )
|
|
{
|
|
TrkLog((TRKDBG_ERROR, TEXT("Incorrect context from timer")));
|
|
TrkRaiseWin32Error( E_FAIL );
|
|
}
|
|
|
|
// Verify that we got called at approximately the right time.
|
|
|
|
cftDelta = abs( static_cast<int>(CFILETIME() - _cftExpected) );
|
|
if( cftDelta > g_cftDeltaMargin )
|
|
{
|
|
TrkLog((TRKDBG_ERROR, TEXT("Timer expired too late in phase 0")));
|
|
TrkRaiseWin32Error( E_FAIL );
|
|
}
|
|
|
|
// Release the main test controller
|
|
|
|
MarkTestCompleted();
|
|
|
|
return( CONTINUE_TIMER );
|
|
}
|
|
|
|
|
|
PTimerCallback::TimerContinuation
|
|
CTimerTest1::Timer( ULONG ulTimerContext)
|
|
{
|
|
TimerContinuation continuation = BREAK_TIMER;
|
|
|
|
CFILETIME cftDelta(0), cftNow;
|
|
CNewTimer::PersistentState persist;
|
|
DWORD dwType = 0, cbData = sizeof(persist);
|
|
HKEY hkey;
|
|
LONG lRet = ERROR_SUCCESS;
|
|
ULONG ulRetryPeriod;
|
|
static CFILETIME cftBeforeRetries(0);
|
|
|
|
if( ulTimerContext != 1 )
|
|
{
|
|
TrkLog((TRKDBG_ERROR, TEXT("Incorrect context from timer")));
|
|
TrkRaiseWin32Error( E_FAIL );
|
|
}
|
|
|
|
// We shouldn't be called in the final sub-phase.
|
|
|
|
if( FINAL == _SubPhase )
|
|
{
|
|
TrkLog(( TRKDBG_ERROR, TEXT("Called after the timer was stopped\n")));
|
|
TrkRaiseWin32Error( E_FAIL );
|
|
}
|
|
|
|
// Verify that we got called at approximately the right time.
|
|
|
|
cftDelta = abs(static_cast<int>(cftNow - _cftExpected));
|
|
if( cftDelta > g_cftDeltaMargin )
|
|
{
|
|
TrkLog((TRKDBG_ERROR, TEXT("Timer expired too late in phase 1")));
|
|
TrkRaiseWin32Error( E_FAIL );
|
|
}
|
|
|
|
// Verify that this time was stored in the Registry
|
|
|
|
lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE, s_tszKeyNameLinkTrack,
|
|
0, KEY_ALL_ACCESS, &hkey );
|
|
if( ERROR_SUCCESS != lRet )
|
|
{
|
|
TrkLog((TRKDBG_ERROR, TEXT("Couldn't open primary registry key") ));
|
|
TrkRaiseWin32Error( lRet );
|
|
}
|
|
|
|
lRet = RegQueryValueEx( hkey,
|
|
_ptszName,
|
|
NULL,
|
|
&dwType,
|
|
(BYTE *)&persist,
|
|
&cbData );
|
|
RegCloseKey( hkey );
|
|
|
|
if( lRet != ERROR_SUCCESS
|
|
||
|
|
dwType != REG_BINARY
|
|
||
|
|
cbData != sizeof(persist)
|
|
||
|
|
cftNow - persist.cftDue > g_cftDeltaMargin )
|
|
{
|
|
TrkLog((TRKDBG_ERROR, TEXT("Value in registry wasn't correct") ));
|
|
TrkRaiseWin32Error( E_FAIL );
|
|
}
|
|
|
|
// -----------------------------
|
|
// Move on to the next sub-phase
|
|
// -----------------------------
|
|
|
|
ulRetryPeriod = g_ulMinRetry;
|
|
|
|
// Switch on the sub-phase which just completed.
|
|
|
|
switch( _SubPhase )
|
|
{
|
|
|
|
case INITIAL:
|
|
|
|
_tprintf( TEXT(" Letting recur\n") );
|
|
|
|
continuation = CONTINUE_TIMER;
|
|
_cftExpected.SetToUTC();
|
|
_cftExpected.IncrementSeconds( g_ulDefaultPeriod );
|
|
|
|
break;
|
|
|
|
case THIRD_RETRY:
|
|
case SECOND_RETRY:
|
|
|
|
ulRetryPeriod *= 2;
|
|
|
|
case FIRST_RETRY:
|
|
|
|
ulRetryPeriod *= 2;
|
|
|
|
case FIRST_RECURRENCE:
|
|
|
|
_tprintf( TEXT(" Retrying timer (%ds)\n"), ulRetryPeriod );
|
|
_cftExpected.SetToUTC();
|
|
_cftExpected.IncrementSeconds( ulRetryPeriod );
|
|
|
|
continuation = RETRY_TIMER;
|
|
|
|
break;
|
|
|
|
case FOURTH_RETRY:
|
|
|
|
_tprintf( TEXT(" Letting timer recur\n") );
|
|
continuation = CONTINUE_TIMER;
|
|
|
|
_cftExpected.SetToUTC();
|
|
_cftExpected.IncrementSeconds( g_ulDefaultPeriod );
|
|
|
|
break;
|
|
|
|
case SECOND_RECURRENCE:
|
|
|
|
VerifyRegistryDataCorrect();
|
|
|
|
_tprintf( TEXT(" Retrying one more time (%ds)\n"), g_ulMinRetry );
|
|
|
|
_cftExpected.SetToUTC();
|
|
_cftExpected.IncrementSeconds( g_ulMinRetry );
|
|
|
|
continuation = RETRY_TIMER;
|
|
break;
|
|
|
|
case LAST_RETRY:
|
|
|
|
_tprintf( TEXT(" Stopping timer\n") );
|
|
continuation = BREAK_TIMER;
|
|
MarkTestCompleted();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
TrkLog((TRKDBG_ERROR, TEXT("Invalid sub-phase in phase 1 (%d)"), _SubPhase ));
|
|
TrkRaiseWin32Error( E_FAIL );
|
|
break;
|
|
|
|
} // switch
|
|
|
|
_SubPhase++;
|
|
|
|
return( continuation );
|
|
}
|
|
|
|
|
|
PTimerCallback::TimerContinuation
|
|
CTimerTest2::Timer( ULONG ulTimerContext)
|
|
{
|
|
TimerContinuation continuation = BREAK_TIMER;
|
|
|
|
CFILETIME cftDelta(0), cftNow;
|
|
CNewTimer::PersistentState persist;
|
|
DWORD dwType = 0, cbData = sizeof(persist);
|
|
HKEY hkey;
|
|
LONG lRet = ERROR_SUCCESS;
|
|
ULONG ulRetryPeriod;
|
|
static CFILETIME cftBeforeRetries(0);
|
|
|
|
if( ulTimerContext != 2 )
|
|
{
|
|
TrkLog((TRKDBG_ERROR, TEXT("Incorrect context from timer")));
|
|
TrkRaiseWin32Error( E_FAIL );
|
|
}
|
|
|
|
// We shouldn't be called in the final sub-phase.
|
|
|
|
if( FINAL == _SubPhase )
|
|
{
|
|
TrkLog(( TRKDBG_ERROR, TEXT("Called after the timer was stopped\n")));
|
|
TrkRaiseWin32Error( E_FAIL );
|
|
}
|
|
|
|
// Verify that we got called at approximately the right time.
|
|
|
|
cftDelta = abs(static_cast<int>(cftNow - _cftExpected));
|
|
if( cftDelta > g_cftDeltaMargin )
|
|
{
|
|
TrkLog((TRKDBG_ERROR, TEXT("Timer expired too late in phase 1")));
|
|
TrkRaiseWin32Error( E_FAIL );
|
|
}
|
|
|
|
// -----------------------------
|
|
// Move on to the next sub-phase
|
|
// -----------------------------
|
|
|
|
switch( _SubPhase )
|
|
{
|
|
case INITIAL:
|
|
|
|
// Verify that the registry was set correctly
|
|
VerifyRegistryDataCorrect();
|
|
|
|
// Restart the timer to a new time
|
|
|
|
_tprintf( TEXT(" Restarting timer (%ds), still recurring and non-retrying\n"),
|
|
g_ulDefaultPeriod * 2 );
|
|
_timer.ReInitialize( g_ulDefaultPeriod * 2 );
|
|
continuation = CONTINUE_TIMER;
|
|
|
|
_cftExpected.SetToUTC();
|
|
_cftExpected.IncrementSeconds( g_ulDefaultPeriod * 2 );
|
|
|
|
break;
|
|
|
|
case RESET:
|
|
|
|
// Verify that the registry was set correctly
|
|
VerifyRegistryDataCorrect();
|
|
|
|
// Release the main test controller
|
|
MarkTestCompleted();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
TrkLog((TRKDBG_ERROR, TEXT("Invalid sub-phase in phase 2 (%d)"), _SubPhase ));
|
|
TrkRaiseWin32Error( E_FAIL );
|
|
break;
|
|
|
|
} // switch( (SUB_PHASE2_ENUM) g_SubPhase )
|
|
|
|
_SubPhase++;
|
|
|
|
|
|
return( continuation );
|
|
}
|
|
|
|
|
|
|
|
PTimerCallback::TimerContinuation
|
|
CTimerTest3::Timer( ULONG ulTimerContext)
|
|
{
|
|
TimerContinuation continuation = BREAK_TIMER;
|
|
|
|
CFILETIME cftDelta(0), cftNow;
|
|
|
|
if( ulTimerContext != 3 )
|
|
{
|
|
TrkLog((TRKDBG_ERROR, TEXT("Incorrect context from timer")));
|
|
TrkRaiseWin32Error( E_FAIL );
|
|
}
|
|
|
|
|
|
// Verify that we got called at approximately the right time.
|
|
|
|
cftDelta = abs(static_cast<int>(cftNow - _cftExpected));
|
|
if( cftDelta > g_cftDeltaMargin )
|
|
{
|
|
TrkLog((TRKDBG_ERROR, TEXT("Timer expired too late in phase 3")));
|
|
TrkRaiseWin32Error( E_FAIL );
|
|
}
|
|
|
|
|
|
// Switch on the sub-phase which *just completed* to determine what to
|
|
// do next.
|
|
|
|
switch( _SubPhase )
|
|
{
|
|
case INITIAL:
|
|
|
|
VerifyRegistryDataCorrect();
|
|
|
|
// We're done
|
|
|
|
continuation = BREAK_TIMER;
|
|
|
|
// Release the main test controller
|
|
MarkTestCompleted();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
TrkLog((TRKDBG_ERROR, TEXT("Invalid sub-phase in phase 3 (%d)"), _SubPhase ));
|
|
TrkRaiseWin32Error( E_FAIL );
|
|
break;
|
|
|
|
} // switch( _SubPhase )
|
|
|
|
_SubPhase++;
|
|
|
|
return( continuation );
|
|
}
|
|
|
|
|
|
|
|
PTimerCallback::TimerContinuation
|
|
CTimerTest4::Timer( ULONG ulTimerContext)
|
|
{
|
|
TimerContinuation continuation = BREAK_TIMER;
|
|
|
|
CFILETIME cftDelta(0), cftNow;
|
|
|
|
if( ulTimerContext != 4 )
|
|
{
|
|
TrkLog((TRKDBG_ERROR, TEXT("Incorrect context from timer")));
|
|
TrkRaiseWin32Error( E_FAIL );
|
|
}
|
|
|
|
|
|
// Verify that we got called at approximately the right time.
|
|
|
|
cftDelta = abs(static_cast<int>(cftNow - _cftExpected));
|
|
if( cftDelta > g_cftDeltaMargin )
|
|
{
|
|
TrkLog((TRKDBG_ERROR, TEXT("Timer expired too late in phase 1")));
|
|
TrkRaiseWin32Error( E_FAIL );
|
|
}
|
|
|
|
|
|
|
|
// Switch on the sub-phase which *just completed* to determine what to
|
|
// do next.
|
|
|
|
switch( _SubPhase )
|
|
{
|
|
case INITIAL:
|
|
|
|
_tprintf( TEXT(" Retrying (%ds)\n"), g_ulDefaultPeriod/2 );
|
|
VerifyRegistryDataRemoved();
|
|
|
|
continuation = RETRY_TIMER;
|
|
_cftExpected.SetToUTC();
|
|
_cftExpected.IncrementSeconds( g_ulDefaultPeriod / 2 );
|
|
|
|
break;
|
|
|
|
case SECOND:
|
|
|
|
_tprintf( TEXT(" Retrying (%ds)\n"), g_ulDefaultPeriod );
|
|
continuation = RETRY_TIMER;
|
|
|
|
_cftExpected.SetToUTC();
|
|
_cftExpected.IncrementSeconds( g_ulDefaultPeriod );
|
|
|
|
break;
|
|
|
|
case THIRD:
|
|
|
|
_tprintf( TEXT(" Retrying (%ds)\n"), g_ulDefaultPeriod*2 );
|
|
continuation = RETRY_TIMER;
|
|
|
|
_cftExpected.SetToUTC();
|
|
_cftExpected.IncrementSeconds( g_ulDefaultPeriod * 2 );
|
|
|
|
break;
|
|
|
|
case FOURTH:
|
|
|
|
_tprintf( TEXT(" Retrying (%ds)\n"), g_ulDefaultPeriod/4 );
|
|
continuation = RETRY_TIMER;
|
|
|
|
_cftExpected.SetToUTC();
|
|
_cftExpected.IncrementSeconds( g_ulDefaultPeriod / 4 );
|
|
|
|
break;
|
|
|
|
case FINAL:
|
|
|
|
continuation = BREAK_TIMER;
|
|
MarkTestCompleted();
|
|
break;
|
|
|
|
default:
|
|
|
|
TrkLog((TRKDBG_ERROR, TEXT("Unexpected sub-phase in phase 4"), _SubPhase ));
|
|
TrkRaiseWin32Error( E_FAIL );
|
|
break;
|
|
|
|
} // switch( _SubPhase )
|
|
|
|
_SubPhase++;
|
|
|
|
return( continuation );
|
|
}
|
|
|
|
|
|
|
|
PTimerCallback::TimerContinuation
|
|
CTimerTest5::Timer( ULONG ulTimerContext)
|
|
{
|
|
TimerContinuation continuation = BREAK_TIMER;
|
|
|
|
CFILETIME cftDelta(0), cftNow;
|
|
|
|
if( ulTimerContext != 5 )
|
|
{
|
|
TrkLog((TRKDBG_ERROR, TEXT("Incorrect context from timer")));
|
|
TrkRaiseWin32Error( E_FAIL );
|
|
}
|
|
|
|
|
|
// Verify that we got called at approximately the right time.
|
|
|
|
cftDelta = abs(static_cast<int>(cftNow - _cftExpected));
|
|
if( cftDelta > g_cftDeltaMargin )
|
|
{
|
|
TrkLog((TRKDBG_ERROR, TEXT("Timer expired too late in phase 1")));
|
|
TrkRaiseWin32Error( E_FAIL );
|
|
}
|
|
|
|
|
|
|
|
// Switch on the sub-phase which *just completed* to determine what to
|
|
// do next.
|
|
|
|
switch( _SubPhase )
|
|
{
|
|
case INITIAL:
|
|
|
|
continuation = BREAK_TIMER;
|
|
VerifyRegistryDataRemoved(); // Since this is a non-persistent timer
|
|
MarkTestCompleted();
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
TrkLog((TRKDBG_ERROR, TEXT("Unexpected sub-phase in phase 5"), _SubPhase ));
|
|
TrkRaiseWin32Error( E_FAIL );
|
|
break;
|
|
|
|
} // switch( _SubPhase )
|
|
|
|
_SubPhase++;
|
|
|
|
return( continuation );
|
|
}
|
|
|
|
|
|
|
|
PTimerCallback::TimerContinuation
|
|
CTimerTest6::Timer( ULONG ulTimerContext )
|
|
{
|
|
CFILETIME cftDelta(0), cftNow;
|
|
PTimerCallback::TimerContinuation continuation = BREAK_TIMER;
|
|
|
|
if( ulTimerContext != 6 )
|
|
{
|
|
TrkLog((TRKDBG_ERROR, TEXT("Incorrect context from timer")));
|
|
TrkRaiseWin32Error( E_FAIL );
|
|
}
|
|
|
|
// Validate the fire time
|
|
|
|
if( _SubPhase == INITIAL )
|
|
{
|
|
cftDelta = abs(static_cast<int>(cftNow - _cftExpected));
|
|
if( cftDelta > g_cftDeltaMargin )
|
|
{
|
|
TrkLog((TRKDBG_ERROR, TEXT("Timer expired too soon/late in phase 4") ));
|
|
TrkRaiseWin32Error( E_FAIL );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( cftNow < _cftLower - g_cftDeltaMargin
|
|
||
|
|
cftNow > _cftUpper + g_cftDeltaMargin )
|
|
{
|
|
TrkLog((TRKDBG_ERROR, TEXT("Timer expired too soon/late in phase 6") ));
|
|
TrkRaiseWin32Error( E_FAIL );
|
|
}
|
|
}
|
|
|
|
// Switch on the sub-phase which *just completed* to determine what to
|
|
// do next.
|
|
|
|
switch( _SubPhase )
|
|
{
|
|
case INITIAL:
|
|
|
|
_tprintf( TEXT(" Letting recur\n") );
|
|
continuation = CONTINUE_TIMER;
|
|
|
|
// Set the due time
|
|
_cftLastSet = _cftLower = cftNow;
|
|
_cftLower.IncrementSeconds( g_ulDefaultPeriod );
|
|
_cftUpper = _cftLower;
|
|
|
|
break;
|
|
|
|
case FIRST_RECURRENCE:
|
|
|
|
_tprintf( TEXT(" Retrying ") );
|
|
continuation = RETRY_TIMER;
|
|
|
|
_cftLastSet = _cftLower = _cftUpper = cftNow;
|
|
_cftLower.IncrementSeconds( g_ulMinRetry );
|
|
_cftUpper.IncrementSeconds( g_ulMaxRetry );
|
|
|
|
break;
|
|
|
|
case FIRST_RETRY:
|
|
case SECOND_RETRY:
|
|
case THIRD_RETRY:
|
|
|
|
// Show how long the retry was
|
|
_tprintf( TEXT("(%2ds)\n"), static_cast<LONG>(cftNow-_cftLastSet)/10000000 );
|
|
|
|
_tprintf( TEXT(" Retrying ") );
|
|
continuation = RETRY_TIMER;
|
|
|
|
_cftLastSet = _cftLower = _cftUpper = cftNow;
|
|
_cftLower.IncrementSeconds( g_ulMinRetry );
|
|
_cftUpper.IncrementSeconds( g_ulMaxRetry );
|
|
|
|
break;
|
|
|
|
case FOURTH_RETRY:
|
|
|
|
// Show how long the retry was
|
|
_tprintf( TEXT("(%2ds)\n"), static_cast<LONG>(cftNow-_cftLastSet)/10000000 );
|
|
|
|
_tprintf( TEXT(" Recurring one last time (%ds)\n"), g_ulDefaultPeriod );
|
|
continuation = CONTINUE_TIMER;
|
|
|
|
_cftLastSet = _cftLower = cftNow;
|
|
_cftLower.IncrementSeconds( g_ulDefaultPeriod );
|
|
_cftUpper = _cftLower;
|
|
|
|
break;
|
|
|
|
case FINAL:
|
|
|
|
continuation = BREAK_TIMER;
|
|
MarkTestCompleted();
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
TrkLog((TRKDBG_ERROR, TEXT("Unexpected sub-phase %d in test 6"), _SubPhase ));
|
|
TrkRaiseWin32Error( E_FAIL );
|
|
break;
|
|
|
|
} // switch( (SUB_PHASE4_ENUM) g_SubPhase )
|
|
|
|
_SubPhase++;
|
|
|
|
return( continuation );
|
|
}
|
|
|
|
|
|
|
|
PTimerCallback::TimerContinuation
|
|
CTimerTest7::Timer( ULONG ulTimerContext )
|
|
{
|
|
CFILETIME cftDelta(0), cftNow;
|
|
PTimerCallback::TimerContinuation continuation = BREAK_TIMER;
|
|
|
|
if( ulTimerContext != 7 )
|
|
{
|
|
TrkLog((TRKDBG_ERROR, TEXT("Incorrect context from timer")));
|
|
TrkRaiseWin32Error( E_FAIL );
|
|
}
|
|
|
|
// Verify that we got called at approximately the right time.
|
|
|
|
cftDelta = abs(static_cast<int>(cftNow - _cftExpected));
|
|
if( cftDelta > g_cftDeltaMargin )
|
|
{
|
|
TrkLog((TRKDBG_ERROR, TEXT("Timer expired too late in phase 1")));
|
|
TrkRaiseWin32Error( E_FAIL );
|
|
}
|
|
|
|
|
|
// Switch on the sub-phase which *just completed* to determine what to
|
|
// do next.
|
|
|
|
switch( _SubPhase )
|
|
{
|
|
case INITIAL:
|
|
|
|
_tprintf( TEXT(" Starting again from the callback, while returning retry_timer\n") );
|
|
|
|
_tprintf( TEXT(" Ensure the timer doesn't fire while we're in the callback\n") );
|
|
Set();
|
|
Sleep( _ulPeriod * 2 );
|
|
|
|
_timer.Cancel();
|
|
Set();
|
|
|
|
continuation = RETRY_TIMER;
|
|
break;
|
|
|
|
case FINAL:
|
|
|
|
continuation = BREAK_TIMER;
|
|
MarkTestCompleted();
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
TrkLog((TRKDBG_ERROR, TEXT("Unexpected sub-phase %d in test 7"), _SubPhase ));
|
|
TrkRaiseWin32Error( E_FAIL );
|
|
break;
|
|
|
|
} // switch( g_SubPhase )
|
|
|
|
_SubPhase++;
|
|
|
|
return( continuation );
|
|
}
|
|
|
|
|
|
|
|
PTimerCallback::TimerContinuation
|
|
CTimerTest8::Timer( ULONG ulTimerContext)
|
|
{
|
|
TimerContinuation continuation = BREAK_TIMER;
|
|
|
|
CFILETIME cftDelta(0), cftNow;
|
|
|
|
if( ulTimerContext != 8 )
|
|
{
|
|
TrkLog((TRKDBG_ERROR, TEXT("Incorrect context from timer")));
|
|
TrkRaiseWin32Error( E_FAIL );
|
|
}
|
|
|
|
|
|
// Verify that we got called at approximately the right time.
|
|
|
|
cftDelta = abs(static_cast<int>(cftNow - _cftExpected));
|
|
if( cftDelta > g_cftDeltaMargin )
|
|
{
|
|
TrkLog((TRKDBG_ERROR, TEXT("Timer expired too late in phase 8 (%s - %s)"),
|
|
CDebugString(cftNow)._tsz, CDebugString(_cftExpected)._tsz ));
|
|
TrkRaiseWin32Error( E_FAIL );
|
|
}
|
|
|
|
|
|
|
|
// Switch on the sub-phase which *just completed* to determine what to
|
|
// do next.
|
|
|
|
switch( _SubPhase )
|
|
{
|
|
case INITIAL:
|
|
|
|
continuation = RETRY_TIMER;
|
|
|
|
_cftExpected = CFILETIME();
|
|
_cftExpected.IncrementSeconds( _ulPeriod*4 ); // The second retry
|
|
|
|
break;
|
|
|
|
case FIRST_RETRY:
|
|
|
|
continuation = RETRY_TIMER;
|
|
|
|
_cftExpected = CFILETIME();
|
|
_cftExpected.IncrementSeconds( _ulPeriod ); // Up to max lifetime
|
|
|
|
break;
|
|
|
|
case FINAL:
|
|
|
|
continuation = BREAK_TIMER;
|
|
MarkTestCompleted();
|
|
break;
|
|
|
|
default:
|
|
|
|
TrkLog((TRKDBG_ERROR, TEXT("Unexpected sub-phase in phase 8"), _SubPhase ));
|
|
TrkRaiseWin32Error( E_FAIL );
|
|
break;
|
|
|
|
} // switch( _SubPhase )
|
|
|
|
_SubPhase++;
|
|
|
|
return( continuation );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
IsRegistryEntryExtant()
|
|
{
|
|
LONG lRet = ERROR_SUCCESS;
|
|
CNewTimer::PersistentState persist;
|
|
DWORD dwType = 0, cbData = sizeof(persist);
|
|
HKEY hkey;
|
|
|
|
lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE, s_tszKeyNameLinkTrack,
|
|
0, KEY_ALL_ACCESS, &hkey );
|
|
if( ERROR_SUCCESS != lRet )
|
|
{
|
|
TrkLog((TRKDBG_ERROR, TEXT("Couldn't open primary registry key")));
|
|
TrkRaiseWin32Error( lRet );
|
|
}
|
|
|
|
lRet = RegQueryValueEx( hkey, g_tszDefaultName, NULL, &dwType, (BYTE*)&persist, &cbData );
|
|
RegCloseKey( hkey );
|
|
|
|
if( ERROR_FILE_NOT_FOUND == lRet )
|
|
return FALSE;
|
|
else
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IsRegistryEntryCorrect( const CFILETIME &cftExpected )
|
|
{
|
|
LONG lRet = ERROR_SUCCESS;
|
|
CFILETIME cftDelta(0), cftNow;
|
|
CNewTimer::PersistentState persist;
|
|
DWORD dwType = 0, cbData = sizeof(persist);
|
|
HKEY hkey;
|
|
|
|
lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE, s_tszKeyNameLinkTrack,
|
|
0, KEY_ALL_ACCESS, &hkey );
|
|
if( ERROR_SUCCESS != lRet )
|
|
{
|
|
TrkLog((TRKDBG_ERROR, TEXT("Couldn't open primary registry key")));
|
|
TrkRaiseWin32Error( lRet );
|
|
}
|
|
|
|
lRet = RegQueryValueEx( hkey,
|
|
g_tszDefaultName,
|
|
NULL,
|
|
&dwType,
|
|
(BYTE *)&persist,
|
|
&cbData );
|
|
RegCloseKey( hkey );
|
|
|
|
cftDelta = cftExpected - persist.cftDue;
|
|
|
|
if( lRet != ERROR_SUCCESS
|
|
||
|
|
dwType != REG_BINARY
|
|
||
|
|
cbData != sizeof(persist)
|
|
||
|
|
persist.cftDue > cftExpected
|
|
||
|
|
cftDelta > g_cftDeltaMargin )
|
|
{
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
EXTERN_C void __cdecl _tmain( int argc, TCHAR **argv )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CNewTimer::PersistentState TimerPersistence;
|
|
|
|
__try
|
|
{
|
|
|
|
LONG lRet = ERROR_SUCCESS;
|
|
ULONG ulMaxLifetime;
|
|
CFILETIME cftTimer0(0);
|
|
|
|
TrkDebugCreate( TRK_DBG_FLAGS_WRITE_TO_DBG | TRK_DBG_FLAGS_WRITE_TO_STDOUT, "TTimer" );
|
|
RegDeleteValue( HKEY_LOCAL_MACHINE, s_tszKeyNameLinkTrack );
|
|
|
|
CTimerTest0 cTimer0;
|
|
CTimerTest1 cTimer1;
|
|
CTimerTest2 cTimer2;
|
|
CTimerTest3 cTimer3;
|
|
CTimerTest4 cTimer4;
|
|
CTimerTest5 cTimer5;
|
|
CTimerTest6 cTimer6;
|
|
CTimerTest7 cTimer7;
|
|
CTimerTest8 cTimer8;
|
|
|
|
//goto phase8;
|
|
|
|
// -------
|
|
// Phase 0
|
|
// -------
|
|
|
|
cTimer0.Initialize( );
|
|
cTimer0.Set();
|
|
cTimer0.WaitForTestToComplete();
|
|
cTimer0.EnsureTimerIsStopped( );
|
|
|
|
// -------
|
|
// Phase 1
|
|
// -------
|
|
phase1:
|
|
cTimer1.Initialize( );
|
|
cTimer1.Set();
|
|
cTimer1.WaitForTestToComplete();
|
|
cTimer1.EnsureTimerIsStopped( );
|
|
|
|
|
|
// -------
|
|
// Phase 2
|
|
// -------
|
|
|
|
cTimer2.Initialize( );
|
|
cTimer2.Set();
|
|
cTimer2.WaitForTestToComplete();
|
|
cTimer2.EnsureTimerIsStopped( );
|
|
|
|
// -------
|
|
// Phase 3
|
|
// -------
|
|
phase3:
|
|
cTimer3.Initialize();
|
|
cTimer3.Set();
|
|
cTimer3.WaitForTestToComplete();
|
|
cTimer3.EnsureTimerIsStopped();
|
|
|
|
// Pause to ensure that the timer clears itself
|
|
Sleep( 1000 );
|
|
|
|
// -------
|
|
// Phase 4
|
|
// -------
|
|
|
|
cTimer4.Initialize();
|
|
cTimer4.Set();
|
|
cTimer4.WaitForTestToComplete();
|
|
cTimer3.EnsureTimerIsStopped();
|
|
|
|
// -------
|
|
// Phase 5
|
|
// -------
|
|
|
|
phase5:
|
|
cTimer5.Initialize();
|
|
cTimer5.Set();
|
|
cTimer5.WaitForTestToComplete();
|
|
cTimer5.EnsureTimerIsStopped();
|
|
|
|
// -------
|
|
// Phase 6
|
|
// -------
|
|
phase6:
|
|
cTimer6.Initialize( );
|
|
cTimer6.Set();
|
|
cTimer6.WaitForTestToComplete();
|
|
cTimer6.EnsureTimerIsStopped( );
|
|
|
|
phase7:
|
|
|
|
cTimer7.Initialize();
|
|
cTimer7.Set();
|
|
cTimer7.WaitForTestToComplete();
|
|
cTimer7.EnsureTimerIsStopped();
|
|
|
|
phase8:
|
|
|
|
cTimer8.Initialize();
|
|
cTimer8.Set();
|
|
cTimer8.WaitForTestToComplete();
|
|
cTimer8.EnsureTimerIsStopped();
|
|
|
|
}
|
|
__except( BreakOnDebuggableException() )
|
|
{
|
|
hr = GetExceptionCode();
|
|
}
|
|
|
|
|
|
if( FAILED(hr) )
|
|
_tprintf( TEXT("\nFailed: hr = %#08x\n"), hr );
|
|
else
|
|
_tprintf( TEXT("\nPassed\n") );
|
|
|
|
|
|
}
|