summaryrefslogtreecommitdiffstats
path: root/win/tclWinTime.c
diff options
context:
space:
mode:
Diffstat (limited to 'win/tclWinTime.c')
-rw-r--r--win/tclWinTime.c1003
1 files changed, 570 insertions, 433 deletions
diff --git a/win/tclWinTime.c b/win/tclWinTime.c
index 8bbd8fd..f34884a 100644
--- a/win/tclWinTime.c
+++ b/win/tclWinTime.c
@@ -1,29 +1,30 @@
-/*
+/*
* tclWinTime.c --
*
- * Contains Windows specific versions of Tcl functions that
- * obtain time values from the operating system.
+ * Contains Windows specific versions of Tcl functions that obtain time
+ * values from the operating system.
*
* Copyright 1995-1998 by Sun Microsystems, Inc.
*
- * See the file "license.terms" for information on usage and redistribution
- * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ * See the file "license.terms" for information on usage and redistribution of
+ * this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
-#include "tclWinInt.h"
+#include "tclInt.h"
-#define SECSPERDAY (60L * 60L * 24L)
-#define SECSPERYEAR (SECSPERDAY * 365L)
-#define SECSPER4YEAR (SECSPERYEAR * 4L + SECSPERDAY)
+#define SECSPERDAY (60L * 60L * 24L)
+#define SECSPERYEAR (SECSPERDAY * 365L)
+#define SECSPER4YEAR (SECSPERYEAR * 4L + SECSPERDAY)
/*
- * Number of samples over which to estimate the performance counter
+ * Number of samples over which to estimate the performance counter.
*/
-#define SAMPLES 64
+
+#define SAMPLES 64
/*
- * The following arrays contain the day of year for the last day of
- * each month, where index 1 is January.
+ * The following arrays contain the day of year for the last day of each
+ * month, where index 1 is January.
*/
static const int normalDays[] = {
@@ -45,38 +46,29 @@ static Tcl_ThreadDataKey dataKey;
*/
typedef struct TimeInfo {
-
- CRITICAL_SECTION cs; /* Mutex guarding this structure */
-
+ CRITICAL_SECTION cs; /* Mutex guarding this structure. */
int initialized; /* Flag == 1 if this structure is
* initialized. */
-
- int perfCounterAvailable; /* Flag == 1 if the hardware has a
- * performance counter */
-
- HANDLE calibrationThread; /* Handle to the thread that keeps the
- * virtual clock calibrated. */
-
- HANDLE readyEvent; /* System event used to
- * trigger the requesting thread
- * when the clock calibration procedure
- * is initialized for the first time */
-
- HANDLE exitEvent; /* Event to signal out of an exit handler
- * to tell the calibration loop to
- * terminate */
-
- LARGE_INTEGER nominalFreq; /* Nominal frequency of the system
- * performance counter, that is, the value
- * returned from QueryPerformanceFrequency. */
+ int perfCounterAvailable; /* Flag == 1 if the hardware has a performance
+ * counter. */
+ HANDLE calibrationThread; /* Handle to the thread that keeps the virtual
+ * clock calibrated. */
+ HANDLE readyEvent; /* System event used to trigger the requesting
+ * thread when the clock calibration procedure
+ * is initialized for the first time. */
+ HANDLE exitEvent; /* Event to signal out of an exit handler to
+ * tell the calibration loop to terminate. */
+ LARGE_INTEGER nominalFreq; /* Nominal frequency of the system performance
+ * counter, that is, the value returned from
+ * QueryPerformanceFrequency. */
/*
- * The following values are used for calculating virtual time.
- * Virtual time is always equal to:
- * lastFileTime + (current perf counter - lastCounter)
+ * The following values are used for calculating virtual time. Virtual
+ * time is always equal to:
+ * lastFileTime + (current perf counter - lastCounter)
* * 10000000 / curCounterFreq
- * and lastFileTime and lastCounter are updated any time that
- * virtual time is returned to a caller.
+ * and lastFileTime and lastCounter are updated any time that virtual time
+ * is returned to a caller.
*/
ULARGE_INTEGER fileTimeLastCall;
@@ -84,16 +76,14 @@ typedef struct TimeInfo {
LARGE_INTEGER curCounterFreq;
/*
- * Data used in developing the estimate of performance counter
- * frequency
+ * Data used in developing the estimate of performance counter frequency
*/
+
Tcl_WideUInt fileTimeSample[SAMPLES];
- /* Last 64 samples of system time */
+ /* Last 64 samples of system time. */
Tcl_WideInt perfCounterSample[SAMPLES];
- /* Last 64 samples of performance counter */
- int sampleNo; /* Current sample number */
-
-
+ /* Last 64 samples of performance counter. */
+ int sampleNo; /* Current sample number. */
} TimeInfo;
static TimeInfo timeInfo = {
@@ -119,33 +109,38 @@ static TimeInfo timeInfo = {
0
};
-static CONST FILETIME posixEpoch = { 0xD53E8000, 0x019DB1DE };
-
/*
* Declarations for functions defined later in this file.
*/
-static struct tm * ComputeGMT _ANSI_ARGS_((const time_t *tp));
-static void StopCalibration _ANSI_ARGS_(( ClientData ));
-static DWORD WINAPI CalibrationThread _ANSI_ARGS_(( LPVOID arg ));
-static void UpdateTimeEachSecond _ANSI_ARGS_(( void ));
-static void ResetCounterSamples _ANSI_ARGS_((
- Tcl_WideUInt fileTime,
- Tcl_WideInt perfCounter,
- Tcl_WideInt perfFreq
- ));
-static Tcl_WideInt AccumulateSample _ANSI_ARGS_((
- Tcl_WideInt perfCounter,
- Tcl_WideUInt fileTime
- ));
+static struct tm * ComputeGMT(const time_t *tp);
+static void StopCalibration(ClientData clientData);
+static DWORD WINAPI CalibrationThread(LPVOID arg);
+static void UpdateTimeEachSecond(void);
+static void ResetCounterSamples(Tcl_WideUInt fileTime,
+ Tcl_WideInt perfCounter, Tcl_WideInt perfFreq);
+static Tcl_WideInt AccumulateSample(Tcl_WideInt perfCounter,
+ Tcl_WideUInt fileTime);
+static void NativeScaleTime(Tcl_Time* timebuf,
+ ClientData clientData);
+static void NativeGetTime(Tcl_Time* timebuf,
+ ClientData clientData);
+
+/*
+ * TIP #233 (Virtualized Time): Data for the time hooks, if any.
+ */
+
+Tcl_GetTimeProc *tclGetTimeProcPtr = NativeGetTime;
+Tcl_ScaleTimeProc *tclScaleTimeProcPtr = NativeScaleTime;
+ClientData tclTimeClientData = NULL;
/*
*----------------------------------------------------------------------
*
* TclpGetSeconds --
*
- * This procedure returns the number of seconds from the epoch.
- * On most Unix systems the epoch is Midnight Jan 1, 1970 GMT.
+ * This procedure returns the number of seconds from the epoch. On most
+ * Unix systems the epoch is Midnight Jan 1, 1970 GMT.
*
* Results:
* Number of seconds from the epoch.
@@ -157,10 +152,11 @@ static Tcl_WideInt AccumulateSample _ANSI_ARGS_((
*/
unsigned long
-TclpGetSeconds()
+TclpGetSeconds(void)
{
Tcl_Time t;
- Tcl_GetTime( &t );
+
+ (*tclGetTimeProcPtr) (&t, tclTimeClientData); /* Tcl_GetTime inlined. */
return t.sec;
}
@@ -169,11 +165,10 @@ TclpGetSeconds()
*
* TclpGetClicks --
*
- * This procedure returns a value that represents the highest
- * resolution clock available on the system. There are no
- * guarantees on what the resolution will be. In Tcl we will
- * call this value a "click". The start time is also system
- * dependant.
+ * This procedure returns a value that represents the highest resolution
+ * clock available on the system. There are no guarantees on what the
+ * resolution will be. In Tcl we will call this value a "click". The
+ * start time is also system dependant.
*
* Results:
* Number of clicks from some start time.
@@ -185,18 +180,19 @@ TclpGetSeconds()
*/
unsigned long
-TclpGetClicks()
+TclpGetClicks(void)
{
/*
- * Use the Tcl_GetTime abstraction to get the time in microseconds,
- * as nearly as we can, and return it.
+ * Use the Tcl_GetTime abstraction to get the time in microseconds, as
+ * nearly as we can, and return it.
*/
Tcl_Time now; /* Current Tcl time */
unsigned long retval; /* Value to return */
- Tcl_GetTime( &now );
- retval = ( now.sec * 1000000 ) + now.usec;
+ (*tclGetTimeProcPtr) (&now, tclTimeClientData); /* Tcl_GetTime inlined */
+
+ retval = (now.sec * 1000000) + now.usec;
return retval;
}
@@ -206,9 +202,8 @@ TclpGetClicks()
*
* TclpGetTimeZone --
*
- * Determines the current timezone. The method varies wildly
- * between different Platform implementations, so its hidden in
- * this function.
+ * Determines the current timezone. The method varies wildly between
+ * different Platform implementations, so its hidden in this function.
*
* Results:
* Minutes west of GMT.
@@ -220,13 +215,13 @@ TclpGetClicks()
*/
int
-TclpGetTimeZone (currentTime)
- Tcl_WideInt currentTime;
+TclpGetTimeZone(
+ unsigned long currentTime)
{
int timeZone;
tzset();
- timeZone = _timezone / 60;
+ timeZone = timezone / 60;
return timeZone;
}
@@ -236,79 +231,137 @@ TclpGetTimeZone (currentTime)
*
* Tcl_GetTime --
*
- * Gets the current system time in seconds and microseconds
- * since the beginning of the epoch: 00:00 UCT, January 1, 1970.
+ * Gets the current system time in seconds and microseconds since the
+ * beginning of the epoch: 00:00 UCT, January 1, 1970.
*
* Results:
* Returns the current time in timePtr.
*
* Side effects:
- * On the first call, initializes a set of static variables to
- * keep track of the base value of the performance counter, the
- * corresponding wall clock (obtained through ftime) and the
- * frequency of the performance counter. Also spins a thread
- * whose function is to wake up periodically and monitor these
- * values, adjusting them as necessary to correct for drift
- * in the performance counter's oscillator.
+ * On the first call, initializes a set of static variables to keep track
+ * of the base value of the performance counter, the corresponding wall
+ * clock (obtained through ftime) and the frequency of the performance
+ * counter. Also spins a thread whose function is to wake up periodically
+ * and monitor these values, adjusting them as necessary to correct for
+ * drift in the performance counter's oscillator.
*
*----------------------------------------------------------------------
*/
void
-Tcl_GetTime(timePtr)
- Tcl_Time *timePtr; /* Location to store time information. */
+Tcl_GetTime(
+ Tcl_Time *timePtr) /* Location to store time information. */
{
- struct timeb t;
+ (*tclGetTimeProcPtr) (timePtr, tclTimeClientData);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * NativeScaleTime --
+ *
+ * TIP #233: Scale from virtual time to the real-time. For native scaling
+ * the relationship is 1:1 and nothing has to be done.
+ *
+ * Results:
+ * Scales the time in timePtr.
+ *
+ * Side effects:
+ * See above.
+ *
+ *----------------------------------------------------------------------
+ */
- int useFtime = 1; /* Flag == TRUE if we need to fall back
- * on ftime rather than using the perf
- * counter */
+static void
+NativeScaleTime(
+ Tcl_Time *timePtr,
+ ClientData clientData)
+{
+ /*
+ * Native scale is 1:1. Nothing is done.
+ */
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * NativeGetTime --
+ *
+ * TIP #233: Gets the current system time in seconds and microseconds
+ * since the beginning of the epoch: 00:00 UCT, January 1, 1970.
+ *
+ * Results:
+ * Returns the current time in timePtr.
+ *
+ * Side effects:
+ * On the first call, initializes a set of static variables to keep track
+ * of the base value of the performance counter, the corresponding wall
+ * clock (obtained through ftime) and the frequency of the performance
+ * counter. Also spins a thread whose function is to wake up periodically
+ * and monitor these values, adjusting them as necessary to correct for
+ * drift in the performance counter's oscillator.
+ *
+ *----------------------------------------------------------------------
+ */
- /* Initialize static storage on the first trip through. */
+static void
+NativeGetTime(
+ Tcl_Time *timePtr,
+ ClientData clientData)
+{
+ struct timeb t;
+ int useFtime = 1; /* Flag == TRUE if we need to fall back on
+ * ftime rather than using the perf counter. */
/*
- * Note: Outer check for 'initialized' is a performance win
- * since it avoids an extra mutex lock in the common case.
+ * Initialize static storage on the first trip through.
+ *
+ * Note: Outer check for 'initialized' is a performance win since it
+ * avoids an extra mutex lock in the common case.
*/
- if ( !timeInfo.initialized ) {
+ if (!timeInfo.initialized) {
TclpInitLock();
- if ( !timeInfo.initialized ) {
- timeInfo.perfCounterAvailable
- = QueryPerformanceFrequency( &timeInfo.nominalFreq );
+ if (!timeInfo.initialized) {
+ timeInfo.perfCounterAvailable =
+ QueryPerformanceFrequency(&timeInfo.nominalFreq);
/*
- * Some hardware abstraction layers use the CPU clock
- * in place of the real-time clock as a performance counter
- * reference. This results in:
+ * Some hardware abstraction layers use the CPU clock in place of
+ * the real-time clock as a performance counter reference. This
+ * results in:
* - inconsistent results among the processors on
* multi-processor systems.
- * - unpredictable changes in performance counter frequency
- * on "gearshift" processors such as Transmeta and
- * SpeedStep.
+ * - unpredictable changes in performance counter frequency on
+ * "gearshift" processors such as Transmeta and SpeedStep.
*
* There seems to be no way to test whether the performance
- * counter is reliable, but a useful heuristic is that
- * if its frequency is 1.193182 MHz or 3.579545 MHz, it's
- * derived from a colorburst crystal and is therefore
- * the RTC rather than the TSC.
+ * counter is reliable, but a useful heuristic is that if its
+ * frequency is 1.193182 MHz or 3.579545 MHz, it's derived from a
+ * colorburst crystal and is therefore the RTC rather than the
+ * TSC.
+ *
+ * A sloppier but serviceable heuristic is that the RTC crystal is
+ * normally less than 15 MHz while the TSC crystal is virtually
+ * assured to be greater than 100 MHz. Since Win98SE appears to
+ * fiddle with the definition of the perf counter frequency
+ * (perhaps in an attempt to calibrate the clock?), we use the
+ * latter rule rather than an exact match.
*
- * A sloppier but serviceable heuristic is that the RTC crystal
- * is normally less than 15 MHz while the TSC crystal is
- * virtually assured to be greater than 100 MHz. Since Win98SE
- * appears to fiddle with the definition of the perf counter
- * frequency (perhaps in an attempt to calibrate the clock?)
- * we use the latter rule rather than an exact match.
+ * We also assume (perhaps questionably) that the vendors have
+ * gotten their act together on Win64, so bypass all this rubbish
+ * on that platform.
*/
- if ( timeInfo.perfCounterAvailable
- /* The following lines would do an exact match on
- * crystal frequency:
- * && timeInfo.nominalFreq.QuadPart != (Tcl_WideInt) 1193182
- * && timeInfo.nominalFreq.QuadPart != (Tcl_WideInt) 3579545
- */
- && timeInfo.nominalFreq.QuadPart > (Tcl_WideInt) 15000000 ) {
-
+#if !defined(_WIN64)
+ if (timeInfo.perfCounterAvailable
+ /*
+ * The following lines would do an exact match on crystal
+ * frequency:
+ * && timeInfo.nominalFreq.QuadPart != (Tcl_WideInt)1193182
+ * && timeInfo.nominalFreq.QuadPart != (Tcl_WideInt)3579545
+ */
+ && timeInfo.nominalFreq.QuadPart > (Tcl_WideInt) 15000000){
/*
* As an exception, if every logical processor on the system
* is on the same chip, we use the performance counter anyway,
@@ -318,118 +371,109 @@ Tcl_GetTime(timePtr)
SYSTEM_INFO systemInfo;
unsigned int regs[4];
- GetSystemInfo( &systemInfo );
- if ( TclWinCPUID( 0, regs ) == TCL_OK
-
- && regs[1] == 0x756e6547 /* "Genu" */
- && regs[3] == 0x49656e69 /* "ineI" */
- && regs[2] == 0x6c65746e /* "ntel" */
-
- && TclWinCPUID( 1, regs ) == TCL_OK
-
- && ( (regs[0] & 0x00000F00) == 0x00000F00 /* Pentium 4 */
- || ( (regs[0] & 0x00F00000) /* Extended family */
- && (regs[3] & 0x10000000) ) ) /* Hyperthread */
- && ( ( ( regs[1] & 0x00FF0000 ) >> 16 ) /* CPU count */
- == systemInfo.dwNumberOfProcessors )
- ) {
+ GetSystemInfo(&systemInfo);
+ if (TclWinCPUID(0, regs) == TCL_OK
+ && regs[1] == 0x756e6547 /* "Genu" */
+ && regs[3] == 0x49656e69 /* "ineI" */
+ && regs[2] == 0x6c65746e /* "ntel" */
+ && TclWinCPUID(1, regs) == TCL_OK
+ && ((regs[0]&0x00000F00) == 0x00000F00 /* Pentium 4 */
+ || ((regs[0] & 0x00F00000) /* Extended family */
+ && (regs[3] & 0x10000000))) /* Hyperthread */
+ && (((regs[1]&0x00FF0000) >> 16)/* CPU count */
+ == systemInfo.dwNumberOfProcessors)) {
timeInfo.perfCounterAvailable = TRUE;
} else {
- timeInfo.perfCounterAvailable = FALSE;
- }
-
+ timeInfo.perfCounterAvailable = FALSE;
+ }
}
+#endif /* above code is Win32 only */
/*
* If the performance counter is available, start a thread to
* calibrate it.
*/
- if ( timeInfo.perfCounterAvailable ) {
+ if (timeInfo.perfCounterAvailable) {
DWORD id;
- InitializeCriticalSection( &timeInfo.cs );
- timeInfo.readyEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
- timeInfo.exitEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
- timeInfo.calibrationThread = CreateThread( NULL,
- 256,
- CalibrationThread,
- (LPVOID) NULL,
- 0,
- &id );
- SetThreadPriority( timeInfo.calibrationThread,
- THREAD_PRIORITY_HIGHEST );
+
+ InitializeCriticalSection(&timeInfo.cs);
+ timeInfo.readyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ timeInfo.exitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ timeInfo.calibrationThread = CreateThread(NULL, 256,
+ CalibrationThread, (LPVOID) NULL, 0, &id);
+ SetThreadPriority(timeInfo.calibrationThread,
+ THREAD_PRIORITY_HIGHEST);
/*
- * Wait for the thread just launched to start running,
- * and create an exit handler that kills it so that it
- * doesn't outlive unloading tclXX.dll
+ * Wait for the thread just launched to start running, and
+ * create an exit handler that kills it so that it doesn't
+ * outlive unloading tclXX.dll
*/
- WaitForSingleObject( timeInfo.readyEvent, INFINITE );
- CloseHandle( timeInfo.readyEvent );
- Tcl_CreateExitHandler( StopCalibration, (ClientData) NULL );
+ WaitForSingleObject(timeInfo.readyEvent, INFINITE);
+ CloseHandle(timeInfo.readyEvent);
+ Tcl_CreateExitHandler(StopCalibration, (ClientData) NULL);
}
timeInfo.initialized = TRUE;
}
TclpInitUnlock();
}
- if ( timeInfo.perfCounterAvailable ) {
+ if (timeInfo.perfCounterAvailable && timeInfo.curCounterFreq.QuadPart!=0) {
/*
- * Query the performance counter and use it to calculate the
- * current time.
+ * Query the performance counter and use it to calculate the current
+ * time.
*/
LARGE_INTEGER curCounter;
- /* Current performance counter */
-
- Tcl_WideInt curFileTime;
- /* Current estimated time, expressed
- * as 100-ns ticks since the Windows epoch */
-
+ /* Current performance counter. */
+ Tcl_WideInt curFileTime;/* Current estimated time, expressed as 100-ns
+ * ticks since the Windows epoch. */
static LARGE_INTEGER posixEpoch;
- /* Posix epoch expressed as 100-ns ticks
- * since the windows epoch */
-
+ /* Posix epoch expressed as 100-ns ticks since
+ * the windows epoch. */
Tcl_WideInt usecSincePosixEpoch;
- /* Current microseconds since Posix epoch */
+ /* Current microseconds since Posix epoch. */
posixEpoch.LowPart = 0xD53E8000;
posixEpoch.HighPart = 0x019DB1DE;
- EnterCriticalSection( &timeInfo.cs );
+ EnterCriticalSection(&timeInfo.cs);
- QueryPerformanceCounter( &curCounter );
+ QueryPerformanceCounter(&curCounter);
- /*
+ /*
* If it appears to be more than 1.1 seconds since the last trip
- * through the calibration loop, the performance counter may
- * have jumped forward. (See MSDN Knowledge Base article
- * Q274323 for a description of the hardware problem that makes
- * this test necessary.) If the counter jumps, we don't want
- * to use it directly. Instead, we must return system time.
- * Eventually, the calibration loop should recover.
+ * through the calibration loop, the performance counter may have
+ * jumped forward. (See MSDN Knowledge Base article Q274323 for a
+ * description of the hardware problem that makes this test
+ * necessary.) If the counter jumps, we don't want to use it directly.
+ * Instead, we must return system time. Eventually, the calibration
+ * loop should recover.
*/
- if ( curCounter.QuadPart - timeInfo.perfCounterLastCall.QuadPart
- < 11 * timeInfo.curCounterFreq.QuadPart / 10 ) {
- curFileTime = timeInfo.fileTimeLastCall.QuadPart
- + ( ( curCounter.QuadPart - timeInfo.perfCounterLastCall.QuadPart )
- * 10000000 / timeInfo.curCounterFreq.QuadPart );
+ if (curCounter.QuadPart - timeInfo.perfCounterLastCall.QuadPart <
+ 11 * timeInfo.curCounterFreq.QuadPart / 10) {
+ curFileTime = timeInfo.fileTimeLastCall.QuadPart +
+ ((curCounter.QuadPart - timeInfo.perfCounterLastCall.QuadPart)
+ * 10000000 / timeInfo.curCounterFreq.QuadPart);
timeInfo.fileTimeLastCall.QuadPart = curFileTime;
timeInfo.perfCounterLastCall.QuadPart = curCounter.QuadPart;
- usecSincePosixEpoch = ( curFileTime - posixEpoch.QuadPart ) / 10;
- timePtr->sec = (long) ( usecSincePosixEpoch / 1000000 );
- timePtr->usec = (unsigned long ) ( usecSincePosixEpoch % 1000000 );
+ usecSincePosixEpoch = (curFileTime - posixEpoch.QuadPart) / 10;
+ timePtr->sec = (long) (usecSincePosixEpoch / 1000000);
+ timePtr->usec = (unsigned long) (usecSincePosixEpoch % 1000000);
useFtime = 0;
}
- LeaveCriticalSection( &timeInfo.cs );
+ LeaveCriticalSection(&timeInfo.cs);
}
- if ( useFtime ) {
- /* High resolution timer is not available. Just use ftime */
+ if (useFtime) {
+ /*
+ * High resolution timer is not available. Just use ftime.
+ */
ftime(&t);
timePtr->sec = (long)t.time;
@@ -449,20 +493,26 @@ Tcl_GetTime(timePtr)
* None.
*
* Side effects:
- * Sets the 'exitEvent' event in the 'timeInfo' structure to ask
- * the thread in question to exit, and waits for it to do so.
+ * Sets the 'exitEvent' event in the 'timeInfo' structure to ask the
+ * thread in question to exit, and waits for it to do so.
*
*----------------------------------------------------------------------
*/
static void
-StopCalibration( ClientData unused )
- /* Client data is unused */
+StopCalibration(
+ ClientData unused) /* Client data is unused */
{
- SetEvent( timeInfo.exitEvent );
- WaitForSingleObject( timeInfo.calibrationThread, INFINITE );
- CloseHandle( timeInfo.exitEvent );
- CloseHandle( timeInfo.calibrationThread );
+ SetEvent(timeInfo.exitEvent);
+
+ /*
+ * If Tcl_Finalize was called from DllMain, the calibration thread is in a
+ * paused state so we need to timeout and continue.
+ */
+
+ WaitForSingleObject(timeInfo.calibrationThread, 100);
+ CloseHandle(timeInfo.exitEvent);
+ CloseHandle(timeInfo.calibrationThread);
}
/*
@@ -482,9 +532,10 @@ StopCalibration( ClientData unused )
*/
char *
-TclpGetTZName(int dst)
+TclpGetTZName(
+ int dst)
{
- size_t len;
+ int len;
char *zone, *p;
TIME_ZONE_INFORMATION tz;
Tcl_Encoding encoding;
@@ -495,9 +546,9 @@ TclpGetTZName(int dst)
* tzset() under Borland doesn't seem to set up tzname[] at all.
* tzset() under MSVC has the following weird observed behavior:
* First time we call "clock format [clock seconds] -format %Z -gmt 1"
- * we get "GMT", but on all subsequent calls we get the current time
- * zone string, even though env(TZ) is GMT and the variable _timezone
- * is 0.
+ * we get "GMT", but on all subsequent calls we get the current time
+ * ezone string, even though env(TZ) is GMT and the variable _timezone
+ * is 0.
*/
name[0] = '\0';
@@ -505,11 +556,10 @@ TclpGetTZName(int dst)
zone = getenv("TZ");
if (zone != NULL) {
/*
- * TZ is of form "NST-4:30NDT", where "NST" would be the
- * name of the standard time zone for this area, "-4:30" is
- * the offset from GMT in hours, and "NDT is the name of
- * the daylight savings time zone in this area. The offset
- * and DST strings are optional.
+ * TZ is of form "NST-4:30NDT", where "NST" would be the name of the
+ * standard time zone for this area, "-4:30" is the offset from GMT in
+ * hours, and "NDT is the name of the daylight savings time zone in
+ * this area. The offset and DST strings are optional.
*/
len = strlen(zone);
@@ -531,23 +581,24 @@ TclpGetTZName(int dst)
}
}
}
- Tcl_ExternalToUtf(NULL, NULL, zone, (int)len, 0, NULL, name,
+ Tcl_ExternalToUtf(NULL, NULL, zone, len, 0, NULL, name,
sizeof(tsdPtr->tzName), NULL, NULL, NULL);
}
if (name[0] == '\0') {
if (GetTimeZoneInformation(&tz) == TIME_ZONE_ID_UNKNOWN) {
/*
- * MSDN: On NT this is returned if DST is not used in
- * the current TZ
+ * MSDN: On NT this is returned if DST is not used in the current
+ * TZ
*/
+
dst = 0;
}
encoding = Tcl_GetEncoding(NULL, "unicode");
- Tcl_ExternalToUtf(NULL, encoding,
- (char *) ((dst) ? tz.DaylightName : tz.StandardName), -1,
+ Tcl_ExternalToUtf(NULL, encoding,
+ (char *) ((dst) ? tz.DaylightName : tz.StandardName), -1,
0, NULL, name, sizeof(tsdPtr->tzName), NULL, NULL, NULL);
Tcl_FreeEncoding(encoding);
- }
+ }
return name;
}
@@ -556,9 +607,9 @@ TclpGetTZName(int dst)
*
* TclpGetDate --
*
- * This function converts between seconds and struct tm. If
- * useGMT is true, then the returned date will be in Greenwich
- * Mean Time (GMT). Otherwise, it will be in the local time zone.
+ * This function converts between seconds and struct tm. If useGMT is
+ * true, then the returned date will be in Greenwich Mean Time (GMT).
+ * Otherwise, it will be in the local time zone.
*
* Results:
* Returns a static tm structure.
@@ -570,11 +621,10 @@ TclpGetTZName(int dst)
*/
struct tm *
-TclpGetDate(t, useGMT)
- TclpTime_t t;
- int useGMT;
+TclpGetDate(
+ CONST time_t *t,
+ int useGMT)
{
- const time_t *tp = (const time_t *) t;
struct tm *tmPtr;
time_t time;
@@ -582,28 +632,44 @@ TclpGetDate(t, useGMT)
tzset();
/*
- * If we are in the valid range, let the C run-time library
- * handle it. Otherwise we need to fake it. Note that this
- * algorithm ignores daylight savings time before the epoch.
+ * If we are in the valid range, let the C run-time library handle it.
+ * Otherwise we need to fake it. Note that this algorithm ignores
+ * daylight savings time before the epoch.
*/
- if (*tp >= 0) {
- return localtime(tp);
+ /*
+ * Hm, Borland's localtime manages to return NULL under certain
+ * circumstances (e.g. wintime.test, test 1.2). Nobody tests for this,
+ * since 'localtime' isn't supposed to do this, possibly leading to
+ * crashes.
+ *
+ * Patch: We only call this function if we are at least one day into
+ * the epoch, else we handle it ourselves (like we do for times < 0).
+ * H. Giese, June 2003
+ */
+
+#ifdef __BORLANDC__
+#define LOCALTIME_VALIDITY_BOUNDARY SECSPERDAY
+#else
+#define LOCALTIME_VALIDITY_BOUNDARY 0
+#endif
+
+ if (*t >= LOCALTIME_VALIDITY_BOUNDARY) {
+ return TclpLocaltime(t);
}
- time = *tp - _timezone;
+ time = *t - timezone;
/*
* If we aren't near to overflowing the long, just add the bias and
- * use the normal calculation. Otherwise we will need to adjust
- * the result at the end.
+ * use the normal calculation. Otherwise we will need to adjust the
+ * result at the end.
*/
- if (*tp < (LONG_MAX - 2 * SECSPERDAY)
- && *tp > (LONG_MIN + 2 * SECSPERDAY)) {
+ if (*t < (LONG_MAX - 2*SECSPERDAY) && *t > (LONG_MIN + 2*SECSPERDAY)) {
tmPtr = ComputeGMT(&time);
} else {
- tmPtr = ComputeGMT(tp);
+ tmPtr = ComputeGMT(t);
tzset();
@@ -612,7 +678,7 @@ TclpGetDate(t, useGMT)
* Propagate seconds overflow into minutes, hours and days.
*/
- time = tmPtr->tm_sec - _timezone;
+ time = tmPtr->tm_sec - timezone;
tmPtr->tm_sec = (int)(time % 60);
if (tmPtr->tm_sec < 0) {
tmPtr->tm_sec += 60;
@@ -639,7 +705,7 @@ TclpGetDate(t, useGMT)
tmPtr->tm_wday = (tmPtr->tm_wday + (int)time) % 7;
}
} else {
- tmPtr = ComputeGMT(tp);
+ tmPtr = ComputeGMT(t);
}
return tmPtr;
}
@@ -649,8 +715,8 @@ TclpGetDate(t, useGMT)
*
* ComputeGMT --
*
- * This function computes GMT given the number of seconds since
- * the epoch (midnight Jan 1 1970).
+ * This function computes GMT given the number of seconds since the epoch
+ * (midnight Jan 1 1970).
*
* Results:
* Returns a (per thread) statically allocated struct tm.
@@ -662,8 +728,8 @@ TclpGetDate(t, useGMT)
*/
static struct tm *
-ComputeGMT(tp)
- const time_t *tp;
+ComputeGMT(
+ const time_t *tp)
{
struct tm *tmPtr;
long tmp, rem;
@@ -678,7 +744,7 @@ ComputeGMT(tp)
*/
tmp = (long)(*tp / SECSPER4YEAR);
- rem = (LONG)(*tp % SECSPER4YEAR);
+ rem = (long)(*tp % SECSPER4YEAR);
/*
* Correct for weird mod semantics so the remainder is always positive.
@@ -690,9 +756,9 @@ ComputeGMT(tp)
}
/*
- * Compute the year after 1900 by taking the 4 year span and adjusting
- * for the remainder. This works because 2000 is a leap year, and
- * 1900/2100 are out of the range.
+ * Compute the year after 1900 by taking the 4 year span and adjusting for
+ * the remainder. This works because 2000 is a leap year, and 1900/2100
+ * are out of the range.
*/
tmp = (tmp * 4) + 70;
@@ -714,13 +780,13 @@ ComputeGMT(tp)
tmPtr->tm_year = tmp;
/*
- * Compute the day of year and leave the seconds in the current day in
- * the remainder.
+ * Compute the day of year and leave the seconds in the current day in the
+ * remainder.
*/
tmPtr->tm_yday = rem / SECSPERDAY;
rem %= SECSPERDAY;
-
+
/*
* Compute the time of day.
*/
@@ -736,6 +802,7 @@ ComputeGMT(tp)
days = (isLeap) ? leapDays : normalDays;
for (tmp = 1; days[tmp] < tmPtr->tm_yday; tmp++) {
+ /* empty body */
}
tmPtr->tm_mon = --tmp;
tmPtr->tm_mday = tmPtr->tm_yday - days[tmp];
@@ -761,60 +828,66 @@ ComputeGMT(tp)
*
* CalibrationThread --
*
- * Thread that manages calibration of the hi-resolution time
- * derived from the performance counter, to keep it synchronized
- * with the system clock.
+ * Thread that manages calibration of the hi-resolution time derived from
+ * the performance counter, to keep it synchronized with the system
+ * clock.
*
* Parameters:
- * arg -- Client data from the CreateThread call. This parameter
- * points to the static TimeInfo structure.
+ * arg - Client data from the CreateThread call. This parameter points to
+ * the static TimeInfo structure.
*
* Return value:
- * None. This thread embeds an infinite loop.
+ * None. This thread embeds an infinite loop.
*
* Side effects:
- * At an interval of 1 s, this thread performs virtual time discipline.
+ * At an interval of 1s, this thread performs virtual time discipline.
*
- * Note: When this thread is entered, TclpInitLock has been called
- * to safeguard the static storage. There is therefore no synchronization
- * in the body of this procedure.
+ * Note: When this thread is entered, TclpInitLock has been called to
+ * safeguard the static storage. There is therefore no synchronization in the
+ * body of this procedure.
*
*----------------------------------------------------------------------
*/
static DWORD WINAPI
-CalibrationThread( LPVOID arg )
+CalibrationThread(
+ LPVOID arg)
{
FILETIME curFileTime;
DWORD waitResult;
- /* Get initial system time and performance counter */
+ /*
+ * Get initial system time and performance counter.
+ */
- GetSystemTimeAsFileTime( &curFileTime );
- QueryPerformanceCounter( &timeInfo.perfCounterLastCall );
- QueryPerformanceFrequency( &timeInfo.curCounterFreq );
+ GetSystemTimeAsFileTime(&curFileTime);
+ QueryPerformanceCounter(&timeInfo.perfCounterLastCall);
+ QueryPerformanceFrequency(&timeInfo.curCounterFreq);
timeInfo.fileTimeLastCall.LowPart = curFileTime.dwLowDateTime;
timeInfo.fileTimeLastCall.HighPart = curFileTime.dwHighDateTime;
- ResetCounterSamples( timeInfo.fileTimeLastCall.QuadPart,
- timeInfo.perfCounterLastCall.QuadPart,
- timeInfo.curCounterFreq.QuadPart );
+ ResetCounterSamples(timeInfo.fileTimeLastCall.QuadPart,
+ timeInfo.perfCounterLastCall.QuadPart,
+ timeInfo.curCounterFreq.QuadPart);
/*
- * Wake up the calling thread. When it wakes up, it will release the
+ * Wake up the calling thread. When it wakes up, it will release the
* initialization lock.
*/
- SetEvent( timeInfo.readyEvent );
+ SetEvent(timeInfo.readyEvent);
- /* Run the calibration once a second */
-
- for ( ; ; ) {
+ /*
+ * Run the calibration once a second.
+ */
- /* If the exitEvent is set, break out of the loop. */
+ while (timeInfo.perfCounterAvailable) {
+ /*
+ * If the exitEvent is set, break out of the loop.
+ */
waitResult = WaitForSingleObjectEx(timeInfo.exitEvent, 1000, FALSE);
- if ( waitResult == WAIT_OBJECT_0 ) {
+ if (waitResult == WAIT_OBJECT_0) {
break;
}
UpdateTimeEachSecond();
@@ -829,11 +902,11 @@ CalibrationThread( LPVOID arg )
*
* UpdateTimeEachSecond --
*
- * Callback from the waitable timer in the clock calibration thread
- * that updates system time.
+ * Callback from the waitable timer in the clock calibration thread that
+ * updates system time.
*
* Parameters:
- * info -- Pointer to the static TimeInfo structure
+ * info - Pointer to the static TimeInfo structure
*
* Results:
* None.
@@ -845,113 +918,116 @@ CalibrationThread( LPVOID arg )
*/
static void
-UpdateTimeEachSecond()
+UpdateTimeEachSecond(void)
{
-
LARGE_INTEGER curPerfCounter;
/* Current value returned from
- * QueryPerformanceCounter */
-
- FILETIME curSysTime; /* Current system time */
-
- LARGE_INTEGER curFileTime; /* File time at the time this callback
- * was scheduled. */
-
- Tcl_WideInt estFreq; /* Estimated perf counter frequency */
-
- Tcl_WideInt vt0; /* Tcl time right now */
- Tcl_WideInt vt1; /* Tcl time one second from now */
-
- Tcl_WideInt tdiff; /* Difference between system clock and
- * Tcl time. */
-
- Tcl_WideInt driftFreq; /* Frequency needed to drift virtual time
- * into step over 1 second */
+ * QueryPerformanceCounter. */
+ FILETIME curSysTime; /* Current system time. */
+ LARGE_INTEGER curFileTime; /* File time at the time this callback was
+ * scheduled. */
+ Tcl_WideInt estFreq; /* Estimated perf counter frequency. */
+ Tcl_WideInt vt0; /* Tcl time right now. */
+ Tcl_WideInt vt1; /* Tcl time one second from now. */
+ Tcl_WideInt tdiff; /* Difference between system clock and Tcl
+ * time. */
+ Tcl_WideInt driftFreq; /* Frequency needed to drift virtual time into
+ * step over 1 second. */
/*
* Sample performance counter and system time.
*/
- QueryPerformanceCounter( &curPerfCounter );
- GetSystemTimeAsFileTime( &curSysTime );
+ QueryPerformanceCounter(&curPerfCounter);
+ GetSystemTimeAsFileTime(&curSysTime);
curFileTime.LowPart = curSysTime.dwLowDateTime;
curFileTime.HighPart = curSysTime.dwHighDateTime;
- EnterCriticalSection( &timeInfo.cs );
+ EnterCriticalSection(&timeInfo.cs);
/*
- * Several things may have gone wrong here that have to
- * be checked for.
- * (1) The performance counter may have jumped.
- * (2) The system clock may have been reset.
- *
- * In either case, we'll need to reinitialize the circular buffer
- * with samples relative to the current system time and the NOMINAL
- * performance frequency (not the actual, because the actual has
- * probably run slow in the first case). Our estimated frequency
- * will be the nominal frequency.
+ * We devide by timeInfo.curCounterFreq.QuadPart in several places. That
+ * value should always be positive on a correctly functioning system. But
+ * it is good to be defensive about such matters. So if something goes
+ * wrong and the value does goes to zero, we clear the
+ * timeInfo.perfCounterAvailable in order to cause the calibration thread
+ * to shut itself down, then return without additional processing.
*/
+ if (timeInfo.curCounterFreq.QuadPart == 0){
+ LeaveCriticalSection(&timeInfo.cs);
+ timeInfo.perfCounterAvailable = 0;
+ return;
+ }
+
/*
- * Store the current sample into the circular buffer of samples,
- * and estimate the performance counter frequency.
+ * Several things may have gone wrong here that have to be checked for.
+ * (1) The performance counter may have jumped.
+ * (2) The system clock may have been reset.
+ *
+ * In either case, we'll need to reinitialize the circular buffer with
+ * samples relative to the current system time and the NOMINAL performance
+ * frequency (not the actual, because the actual has probably run slow in
+ * the first case). Our estimated frequency will be the nominal frequency.
+ *
+ * Store the current sample into the circular buffer of samples, and
+ * estimate the performance counter frequency.
*/
- estFreq = AccumulateSample( curPerfCounter.QuadPart,
- (Tcl_WideUInt) curFileTime.QuadPart );
+ estFreq = AccumulateSample(curPerfCounter.QuadPart,
+ (Tcl_WideUInt) curFileTime.QuadPart);
/*
* We want to adjust things so that time appears to be continuous.
- * Virtual file time, right now, is
+ * Virtual file time, right now, is
*
- * vt0 = 10000000 * ( curPerfCounter - perfCounterLastCall )
- * / curCounterFreq
- * + fileTimeLastCall
+ * vt0 = 10000000 * (curPerfCounter - perfCounterLastCall)
+ * / curCounterFreq
+ * + fileTimeLastCall
*
- * Ideally, we would like to drift the clock into place over a
- * period of 2 sec, so that virtual time 2 sec from now will be
+ * Ideally, we would like to drift the clock into place over a period of 2
+ * sec, so that virtual time 2 sec from now will be
*
* vt1 = 20000000 + curFileTime
- *
- * The frequency that we need to use to drift the counter back into
- * place is estFreq * 20000000 / ( vt1 - vt0 )
+ *
+ * The frequency that we need to use to drift the counter back into place
+ * is estFreq * 20000000 / (vt1 - vt0)
*/
-
- vt0 = 10000000 * ( curPerfCounter.QuadPart
- - timeInfo.perfCounterLastCall.QuadPart )
- / timeInfo.curCounterFreq.QuadPart
- + timeInfo.fileTimeLastCall.QuadPart;
+
+ vt0 = 10000000 * (curPerfCounter.QuadPart
+ - timeInfo.perfCounterLastCall.QuadPart)
+ / timeInfo.curCounterFreq.QuadPart
+ + timeInfo.fileTimeLastCall.QuadPart;
vt1 = 20000000 + curFileTime.QuadPart;
/*
- * If we've gotten more than a second away from system time,
- * then drifting the clock is going to be pretty hopeless.
- * Just let it jump. Otherwise, compute the drift frequency and
- * fill in everything.
+ * If we've gotten more than a second away from system time, then drifting
+ * the clock is going to be pretty hopeless. Just let it jump. Otherwise,
+ * compute the drift frequency and fill in everything.
*/
tdiff = vt0 - curFileTime.QuadPart;
- if ( tdiff > 10000000 || tdiff < -10000000 ) {
+ if (tdiff > 10000000 || tdiff < -10000000) {
timeInfo.fileTimeLastCall.QuadPart = curFileTime.QuadPart;
timeInfo.curCounterFreq.QuadPart = estFreq;
} else {
- driftFreq = estFreq * 20000000 / ( vt1 - vt0 );
- if ( driftFreq > 1003 * estFreq / 1000 ) {
- driftFreq = 1003 * estFreq / 1000;
- }
- if ( driftFreq < 997 * estFreq / 1000 ) {
- driftFreq = 997 * estFreq / 1000;
+ driftFreq = estFreq * 20000000 / (vt1 - vt0);
+
+ if (driftFreq > 1003*estFreq/1000) {
+ driftFreq = 1003*estFreq/1000;
+ } else if (driftFreq < 997*estFreq/1000) {
+ driftFreq = 997*estFreq/1000;
}
+
timeInfo.fileTimeLastCall.QuadPart = vt0;
timeInfo.curCounterFreq.QuadPart = driftFreq;
}
timeInfo.perfCounterLastCall.QuadPart = curPerfCounter.QuadPart;
- LeaveCriticalSection( &timeInfo.cs );
-
+ LeaveCriticalSection(&timeInfo.cs);
}
-
+
/*
*----------------------------------------------------------------------
*
@@ -964,23 +1040,21 @@ UpdateTimeEachSecond()
* None.
*
* Side effects:
- * The array of samples is filled in so that it appears that there
- * are SAMPLES samples at one-second intervals, separated by precisely
- * the given frequency.
+ * The array of samples is filled in so that it appears that there are
+ * SAMPLES samples at one-second intervals, separated by precisely the
+ * given frequency.
*
*----------------------------------------------------------------------
*/
static void
-ResetCounterSamples( Tcl_WideUInt fileTime,
- /* Current file time */
- Tcl_WideInt perfCounter,
- /* Current performance counter */
- Tcl_WideInt perfFreq )
- /* Target performance frequency */
+ResetCounterSamples(
+ Tcl_WideUInt fileTime, /* Current file time */
+ Tcl_WideInt perfCounter, /* Current performance counter */
+ Tcl_WideInt perfFreq) /* Target performance frequency */
{
int i;
- for ( i = SAMPLES-1; i >= 0; --i ) {
+ for (i=SAMPLES-1 ; i>=0 ; --i) {
timeInfo.perfCounterSample[i] = perfCounter;
timeInfo.fileTimeSample[i] = fileTime;
perfCounter -= perfFreq;
@@ -994,87 +1068,84 @@ ResetCounterSamples( Tcl_WideUInt fileTime,
*
* AccumulateSample --
*
- * Updates the circular buffer of performance counter and system
- * time samples with a new data point.
+ * Updates the circular buffer of performance counter and system time
+ * samples with a new data point.
*
* Results:
* None.
*
* Side effects:
- * The new data point replaces the oldest point in the circular
- * buffer, and the descriptive statistics are updated to accumulate
- * the new point.
- *
- * Several things may have gone wrong here that have to
- * be checked for.
- * (1) The performance counter may have jumped.
- * (2) The system clock may have been reset.
- *
- * In either case, we'll need to reinitialize the circular buffer
- * with samples relative to the current system time and the NOMINAL
- * performance frequency (not the actual, because the actual has
- * probably run slow in the first case).
+ * The new data point replaces the oldest point in the circular buffer,
+ * and the descriptive statistics are updated to accumulate the new
+ * point.
+ *
+ * Several things may have gone wrong here that have to be checked for.
+ * (1) The performance counter may have jumped.
+ * (2) The system clock may have been reset.
+ *
+ * In either case, we'll need to reinitialize the circular buffer with samples
+ * relative to the current system time and the NOMINAL performance frequency
+ * (not the actual, because the actual has probably run slow in the first
+ * case).
*/
static Tcl_WideInt
-AccumulateSample( Tcl_WideInt perfCounter,
- Tcl_WideUInt fileTime )
+AccumulateSample(
+ Tcl_WideInt perfCounter,
+ Tcl_WideUInt fileTime)
{
- Tcl_WideUInt workFTSample; /* File time sample being removed
- * from or added to the circular buffer */
-
- Tcl_WideInt workPCSample; /* Performance counter sample being
- * removed from or added to the circular
- * buffer */
-
+ Tcl_WideUInt workFTSample; /* File time sample being removed from or
+ * added to the circular buffer. */
+ Tcl_WideInt workPCSample; /* Performance counter sample being removed
+ * from or added to the circular buffer. */
Tcl_WideUInt lastFTSample; /* Last file time sample recorded */
-
Tcl_WideInt lastPCSample; /* Last performance counter sample recorded */
-
Tcl_WideInt FTdiff; /* Difference between last FT and current */
-
Tcl_WideInt PCdiff; /* Difference between last PC and current */
-
Tcl_WideInt estFreq; /* Estimated performance counter frequency */
- /* Test for jumps and reset the samples if we have one. */
+ /*
+ * Test for jumps and reset the samples if we have one.
+ */
- if ( timeInfo.sampleNo == 0 ) {
- lastPCSample = timeInfo.perfCounterSample[ timeInfo.sampleNo
- + SAMPLES - 1 ];
- lastFTSample = timeInfo.fileTimeSample[ timeInfo.sampleNo
- + SAMPLES - 1 ];
+ if (timeInfo.sampleNo == 0) {
+ lastPCSample =
+ timeInfo.perfCounterSample[timeInfo.sampleNo + SAMPLES - 1];
+ lastFTSample =
+ timeInfo.fileTimeSample[timeInfo.sampleNo + SAMPLES - 1];
} else {
- lastPCSample = timeInfo.perfCounterSample[ timeInfo.sampleNo - 1 ];
- lastFTSample = timeInfo.fileTimeSample[ timeInfo.sampleNo - 1 ];
+ lastPCSample = timeInfo.perfCounterSample[timeInfo.sampleNo - 1];
+ lastFTSample = timeInfo.fileTimeSample[timeInfo.sampleNo - 1];
}
+
PCdiff = perfCounter - lastPCSample;
FTdiff = fileTime - lastFTSample;
- if ( PCdiff < timeInfo.nominalFreq.QuadPart * 9 / 10
- || PCdiff > timeInfo.nominalFreq.QuadPart * 11 / 10
- || FTdiff < 9000000
- || FTdiff > 11000000 ) {
- ResetCounterSamples( fileTime, perfCounter,
- timeInfo.nominalFreq.QuadPart );
+ if (PCdiff < timeInfo.nominalFreq.QuadPart * 9 / 10
+ || PCdiff > timeInfo.nominalFreq.QuadPart * 11 / 10
+ || FTdiff < 9000000 || FTdiff > 11000000) {
+ ResetCounterSamples(fileTime, perfCounter,
+ timeInfo.nominalFreq.QuadPart);
return timeInfo.nominalFreq.QuadPart;
-
} else {
-
- /* Estimate the frequency */
-
- workPCSample = timeInfo.perfCounterSample[ timeInfo.sampleNo ];
- workFTSample = timeInfo.fileTimeSample[ timeInfo.sampleNo ];
- estFreq = 10000000 * ( perfCounter - workPCSample )
- / ( fileTime - workFTSample );
- timeInfo.perfCounterSample[ timeInfo.sampleNo ] = perfCounter;
- timeInfo.fileTimeSample[ timeInfo.sampleNo ] = (Tcl_WideInt) fileTime;
-
- /* Advance the sample number */
-
- if ( ++timeInfo.sampleNo >= SAMPLES ) {
+ /*
+ * Estimate the frequency.
+ */
+
+ workPCSample = timeInfo.perfCounterSample[timeInfo.sampleNo];
+ workFTSample = timeInfo.fileTimeSample[timeInfo.sampleNo];
+ estFreq = 10000000 * (perfCounter - workPCSample)
+ / (fileTime - workFTSample);
+ timeInfo.perfCounterSample[timeInfo.sampleNo] = perfCounter;
+ timeInfo.fileTimeSample[timeInfo.sampleNo] = (Tcl_WideInt) fileTime;
+
+ /*
+ * Advance the sample number.
+ */
+
+ if (++timeInfo.sampleNo >= SAMPLES) {
timeInfo.sampleNo = 0;
- }
-
+ }
+
return estFreq;
}
}
@@ -1084,8 +1155,7 @@ AccumulateSample( Tcl_WideInt perfCounter,
*
* TclpGmtime --
*
- * Wrapper around the 'gmtime' library function to make it thread
- * safe.
+ * Wrapper around the 'gmtime' library function to make it thread safe.
*
* Results:
* Returns a pointer to a 'struct tm' in thread-specific data.
@@ -1097,18 +1167,17 @@ AccumulateSample( Tcl_WideInt perfCounter,
*/
struct tm *
-TclpGmtime( tt )
- TclpTime_t_CONST tt;
+TclpGmtime(
+ CONST time_t *timePtr) /* Pointer to the number of seconds since the
+ * local system's epoch */
{
- CONST time_t *timePtr = (CONST time_t *) tt;
- /* Pointer to the number of seconds
- * since the local system's epoch */
/*
- * The MS implementation of gmtime is thread safe because
- * it returns the time in a block of thread-local storage,
- * and Windows does not provide a Posix gmtime_r function.
+ * The MS implementation of gmtime is thread safe because it returns the
+ * time in a block of thread-local storage, and Windows does not provide a
+ * Posix gmtime_r function.
*/
- return gmtime( timePtr );
+
+ return gmtime(timePtr);
}
/*
@@ -1129,17 +1198,85 @@ TclpGmtime( tt )
*/
struct tm *
-TclpLocaltime( tt )
- TclpTime_t_CONST tt;
-{
- CONST time_t *timePtr = (CONST time_t *) tt;
- /* Pointer to the number of seconds
- * since the local system's epoch */
+TclpLocaltime(
+ CONST time_t *timePtr) /* Pointer to the number of seconds since the
+ * local system's epoch */
+{
/*
- * The MS implementation of localtime is thread safe because
- * it returns the time in a block of thread-local storage,
- * and Windows does not provide a Posix localtime_r function.
+ * The MS implementation of localtime is thread safe because it returns
+ * the time in a block of thread-local storage, and Windows does not
+ * provide a Posix localtime_r function.
*/
- return localtime( timePtr );
+
+ return localtime(timePtr);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_SetTimeProc --
+ *
+ * TIP #233 (Virtualized Time): Registers two handlers for the
+ * virtualization of Tcl's access to time information.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Remembers the handlers, alters core behaviour.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_SetTimeProc(
+ Tcl_GetTimeProc *getProc,
+ Tcl_ScaleTimeProc *scaleProc,
+ ClientData clientData)
+{
+ tclGetTimeProcPtr = getProc;
+ tclScaleTimeProcPtr = scaleProc;
+ tclTimeClientData = clientData;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_QueryTimeProc --
+ *
+ * TIP #233 (Virtualized Time): Query which time handlers are registered.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_QueryTimeProc(
+ Tcl_GetTimeProc **getProc,
+ Tcl_ScaleTimeProc **scaleProc,
+ ClientData *clientData)
+{
+ if (getProc) {
+ *getProc = tclGetTimeProcPtr;
+ }
+ if (scaleProc) {
+ *scaleProc = tclScaleTimeProcPtr;
+ }
+ if (clientData) {
+ *clientData = tclTimeClientData;
+ }
}
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 4
+ * fill-column: 78
+ * End:
+ */