252 lines
4.7 KiB
C++
252 lines
4.7 KiB
C++
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1995 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
timer.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
Wrap-proof timer routines.
|
|||
|
|
|||
|
The purpose of this module is to create a timer function which
|
|||
|
returns a time in seconds and eliminates all timer wrapping issues.
|
|||
|
|
|||
|
These routines are non-DNS specific and may be picked up
|
|||
|
cleanly by any module.
|
|||
|
|
|||
|
For DNS the added instructions are well worth the cost in that it
|
|||
|
eliminates any issue involving cleaning packet queues or resetting
|
|||
|
cache timeouts when millisecond timer (GetCurrentTime) wraps.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Jim Gilroy (jamesg) 9-Sep-1995
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Win32 User Mode
|
|||
|
|
|||
|
Project:
|
|||
|
|
|||
|
Common Code for Internet Services
|
|||
|
|
|||
|
Functions Exported:
|
|||
|
|
|||
|
InitializeSecondsTimer()
|
|||
|
TerminateSecondsTimer()
|
|||
|
GetCurrentTimeInSeconds()
|
|||
|
GetCurrentTimeInMilliseconds()
|
|||
|
|
|||
|
Revision History:
|
|||
|
MuraliK 14-Nov-1995 Made multi thread safe.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
#include "precomp.hxx"
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Timer globals
|
|||
|
//
|
|||
|
|
|||
|
CRITICAL_SECTION g_csTimerWrap;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
InitializeSecondsTimer(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Initialize DNS timer.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
INITIALIZE_CRITICAL_SECTION( &g_csTimerWrap );
|
|||
|
|
|||
|
} // InitializeSecondsTimer()
|
|||
|
|
|||
|
VOID
|
|||
|
TerminateSecondsTimer(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Terminate DNS timer.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DeleteCriticalSection( &g_csTimerWrap );
|
|||
|
|
|||
|
} // TerminateSecondsTimer()
|
|||
|
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
GetCurrentTimeInSeconds(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Get current time in seconds.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Time since boot in seconds.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD dwCurrentTime;
|
|||
|
static DWORD dwPreviousTime = 0; // previous GetCurrentTime()
|
|||
|
static DWORD dwWrapTime = 0; // accumulated time (s) from timer
|
|||
|
// wraps
|
|||
|
|
|||
|
dwCurrentTime = GetCurrentTime();
|
|||
|
|
|||
|
//
|
|||
|
// check for timer wrap
|
|||
|
//
|
|||
|
// Check that previous time is bigger, but since multi-threaded,
|
|||
|
// occasionally preempted before making test and another thread
|
|||
|
// may reset dwPreviousTime. So we also explicitly verify the
|
|||
|
// switch from a very large DWORD to a small one.
|
|||
|
//
|
|||
|
// Note: that we completely avoid using the CS, except right at
|
|||
|
// an actual timer wrap. Hence the cost for this function
|
|||
|
// remains low.
|
|||
|
//
|
|||
|
|
|||
|
if ( dwPreviousTime > dwCurrentTime
|
|||
|
&&
|
|||
|
(LONG)dwPreviousTime < 0
|
|||
|
&&
|
|||
|
(LONG)dwCurrentTime > 0 )
|
|||
|
{
|
|||
|
//
|
|||
|
// detected timer wrap
|
|||
|
//
|
|||
|
// inside CS, verify actual wrap and reset dwPreviousTime
|
|||
|
// so other waiting threads will NOT count wrap
|
|||
|
//
|
|||
|
|
|||
|
EnterCriticalSection( &g_csTimerWrap );
|
|||
|
|
|||
|
if ( (LONG)dwPreviousTime < 0
|
|||
|
&&
|
|||
|
(LONG)dwCurrentTime > 0 )
|
|||
|
{
|
|||
|
dwPreviousTime = dwCurrentTime;
|
|||
|
dwWrapTime += (0xffffffff / 1000);
|
|||
|
}
|
|||
|
LeaveCriticalSection( &g_csTimerWrap );
|
|||
|
}
|
|||
|
dwPreviousTime = dwCurrentTime;
|
|||
|
|
|||
|
return (dwCurrentTime / 1000 + dwWrapTime);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
__int64
|
|||
|
GetCurrentTimeInMilliseconds(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Get current time in milliseconds.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Time since boot in seconds.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD dwCurrentTime;
|
|||
|
static DWORD dwPreviousTime = 0; // previous GetCurrentTime()
|
|||
|
static DWORD dwWrapTime = 0; // accumulated time (s) from timer
|
|||
|
// wraps
|
|||
|
|
|||
|
dwCurrentTime = GetTickCount();
|
|||
|
|
|||
|
//
|
|||
|
// check for timer wrap
|
|||
|
//
|
|||
|
// Check that previous time is bigger, but since multi-threaded,
|
|||
|
// occasionally preempted before making test and another thread
|
|||
|
// may reset dwPreviousTime. So we also explicitly verify the
|
|||
|
// switch from a very large DWORD to a small one.
|
|||
|
//
|
|||
|
// Note: that we completely avoid using the CS, except right at
|
|||
|
// an actual timer wrap. Hence the cost for this function
|
|||
|
// remains low.
|
|||
|
//
|
|||
|
|
|||
|
if ( dwPreviousTime > dwCurrentTime
|
|||
|
&&
|
|||
|
(LONG)dwPreviousTime < 0
|
|||
|
&&
|
|||
|
(LONG)dwCurrentTime > 0 )
|
|||
|
{
|
|||
|
//
|
|||
|
// detected timer wrap
|
|||
|
//
|
|||
|
// inside CS, verify actual wrap and reset dwPreviousTime
|
|||
|
// so other waiting threads will NOT count wrap
|
|||
|
//
|
|||
|
|
|||
|
EnterCriticalSection( &g_csTimerWrap );
|
|||
|
|
|||
|
if ( (LONG)dwPreviousTime < 0
|
|||
|
&&
|
|||
|
(LONG)dwCurrentTime > 0 )
|
|||
|
{
|
|||
|
dwPreviousTime = dwCurrentTime;
|
|||
|
++dwWrapTime;
|
|||
|
}
|
|||
|
LeaveCriticalSection( &g_csTimerWrap );
|
|||
|
}
|
|||
|
dwPreviousTime = dwCurrentTime;
|
|||
|
|
|||
|
return (((__int64)dwWrapTime)<<32) | dwCurrentTime;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// End of timer.c
|
|||
|
//
|