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
|
||
//
|