Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

251 lines
4.7 KiB

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