summaryrefslogtreecommitdiffstats
path: root/win/tclWinTime.c
diff options
context:
space:
mode:
Diffstat (limited to 'win/tclWinTime.c')
-rw-r--r--win/tclWinTime.c922
1 files changed, 320 insertions, 602 deletions
diff --git a/win/tclWinTime.c b/win/tclWinTime.c
index 438a8ec..0163723 100644
--- a/win/tclWinTime.c
+++ b/win/tclWinTime.c
@@ -4,7 +4,7 @@
* Contains Windows specific versions of Tcl functions that obtain time
* values from the operating system.
*
- * Copyright © 1995-1998 Sun Microsystems, Inc.
+ * 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.
@@ -27,7 +27,6 @@
* month, where index 1 is January.
*/
-#ifndef TCL_NO_DEPRECATED
static const int normalDays[] = {
-1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364
};
@@ -36,25 +35,22 @@ static const int leapDays[] = {
-1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
};
-typedef struct {
+typedef struct ThreadSpecificData {
char tzName[64]; /* Time zone name */
struct tm tm; /* time information */
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
-#endif /* TCL_NO_DEPRECATED */
/*
* Data for managing high-resolution timers.
*/
-typedef struct {
+typedef struct TimeInfo {
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. */
- DWORD calibrationInterv; /* Calibration interval in seconds (start 1
- * sec) */
HANDLE calibrationThread; /* Handle to the thread that keeps the virtual
* clock calibrated. */
HANDLE readyEvent; /* System event used to trigger the requesting
@@ -65,6 +61,7 @@ typedef struct {
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:
@@ -77,40 +74,35 @@ typedef struct {
ULARGE_INTEGER fileTimeLastCall;
LARGE_INTEGER perfCounterLastCall;
LARGE_INTEGER curCounterFreq;
- LARGE_INTEGER posixEpoch; /* Posix epoch expressed as 100-ns ticks since
- * the windows epoch. */
/*
* Data used in developing the estimate of performance counter frequency
*/
- unsigned long long fileTimeSample[SAMPLES];
+ Tcl_WideUInt fileTimeSample[SAMPLES];
/* Last 64 samples of system time. */
- long long perfCounterSample[SAMPLES];
+ Tcl_WideInt perfCounterSample[SAMPLES];
/* Last 64 samples of performance counter. */
int sampleNo; /* Current sample number. */
} TimeInfo;
static TimeInfo timeInfo = {
- { NULL, 0, 0, NULL, NULL, 0 },
+ { NULL },
0,
0,
- 1,
(HANDLE) NULL,
(HANDLE) NULL,
(HANDLE) NULL,
-#if defined(HAVE_CAST_TO_UNION) && !defined(__cplusplus)
- (LARGE_INTEGER) (long long) 0,
+#ifdef HAVE_CAST_TO_UNION
+ (LARGE_INTEGER) (Tcl_WideInt) 0,
(ULARGE_INTEGER) (DWORDLONG) 0,
- (LARGE_INTEGER) (long long) 0,
- (LARGE_INTEGER) (long long) 0,
- (LARGE_INTEGER) (long long) 0,
+ (LARGE_INTEGER) (Tcl_WideInt) 0,
+ (LARGE_INTEGER) (Tcl_WideInt) 0,
#else
- {0, 0},
- {0, 0},
- {0, 0},
- {0, 0},
- {0, 0},
+ 0,
+ 0,
+ 0,
+ 0,
#endif
{ 0 },
{ 0 },
@@ -118,36 +110,21 @@ static TimeInfo timeInfo = {
};
/*
- * Scale to convert wide click values from the TclpGetWideClicks native
- * resolution to microsecond resolution and back.
- */
-static struct {
- int initialized; /* 1 if initialized, 0 otherwise */
- int perfCounter; /* 1 if performance counter usable for wide
- * clicks */
- double microsecsScale; /* Denominator scale between clock / microsecs */
-} wideClick = {0, 0, 0.0};
-
-
-/*
* Declarations for functions defined later in this file.
*/
-#ifndef TCL_NO_DEPRECATED
static struct tm * ComputeGMT(const time_t *tp);
-#endif /* TCL_NO_DEPRECATED */
-static void StopCalibration(void *clientData);
+static void StopCalibration(ClientData clientData);
static DWORD WINAPI CalibrationThread(LPVOID arg);
static void UpdateTimeEachSecond(void);
-static void ResetCounterSamples(unsigned long long fileTime,
- long long perfCounter, long long perfFreq);
-static long long AccumulateSample(long long perfCounter,
- unsigned long long fileTime);
+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,
- void *clientData);
-static long long NativeGetMicroseconds(void);
+ ClientData clientData);
static void NativeGetTime(Tcl_Time* timebuf,
- void *clientData);
+ ClientData clientData);
/*
* TIP #233 (Virtualized Time): Data for the time hooks, if any.
@@ -155,24 +132,7 @@ static void NativeGetTime(Tcl_Time* timebuf,
Tcl_GetTimeProc *tclGetTimeProcPtr = NativeGetTime;
Tcl_ScaleTimeProc *tclScaleTimeProcPtr = NativeScaleTime;
-void *tclTimeClientData = NULL;
-
-/*
- * Inlined version of Tcl_GetTime.
- */
-
-static inline void
-GetTime(
- Tcl_Time *timePtr)
-{
- tclGetTimeProcPtr(timePtr, tclTimeClientData);
-}
-
-static inline int
-IsTimeNative(void)
-{
- return tclGetTimeProcPtr == NativeGetTime;
-}
+ClientData tclTimeClientData = NULL;
/*
*----------------------------------------------------------------------
@@ -194,20 +154,10 @@ IsTimeNative(void)
unsigned long
TclpGetSeconds(void)
{
- long long usecSincePosixEpoch;
+ Tcl_Time t;
- /*
- * Try to use high resolution timer
- */
-
- if (IsTimeNative() && (usecSincePosixEpoch = NativeGetMicroseconds())) {
- return usecSincePosixEpoch / 1000000;
- } else {
- Tcl_Time t;
-
- GetTime(&t);
- return t.sec;
- }
+ (*tclGetTimeProcPtr) (&t, tclTimeClientData); /* Tcl_GetTime inlined. */
+ return t.sec;
}
/*
@@ -218,7 +168,7 @@ TclpGetSeconds(void)
* 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 dependent.
+ * start time is also system dependant.
*
* Results:
* Number of clicks from some start time.
@@ -232,121 +182,31 @@ TclpGetSeconds(void)
unsigned long
TclpGetClicks(void)
{
- long long usecSincePosixEpoch;
-
/*
- * Try to use high resolution timer.
+ * Use the Tcl_GetTime abstraction to get the time in microseconds, as
+ * nearly as we can, and return it.
*/
- if (IsTimeNative() && (usecSincePosixEpoch = NativeGetMicroseconds())) {
- return (unsigned long) usecSincePosixEpoch;
- } else {
- /*
- * 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_Time now; /* Current Tcl time */
+ (*tclGetTimeProcPtr) (&now, tclTimeClientData); /* Tcl_GetTime inlined */
- GetTime(&now);
- return ((unsigned long)(now.sec)*1000000UL) + (unsigned long)(now.usec);
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclpGetWideClicks --
- *
- * This procedure returns a WideInt value that represents the highest
- * resolution clock in microseconds available on the system.
- *
- * Results:
- * Number of microseconds (from some start time).
- *
- * Side effects:
- * This should be used for time-delta resp. for measurement purposes
- * only, because on some platforms can return microseconds from some
- * start time (not from the epoch).
- *
- *----------------------------------------------------------------------
- */
-
-long long
-TclpGetWideClicks(void)
-{
- LARGE_INTEGER curCounter;
-
- if (!wideClick.initialized) {
- LARGE_INTEGER perfCounterFreq;
-
- /*
- * The frequency of the performance counter is fixed at system boot and
- * is consistent across all processors. Therefore, the frequency need
- * only be queried upon application initialization.
- */
-
- if (QueryPerformanceFrequency(&perfCounterFreq)) {
- wideClick.perfCounter = 1;
- wideClick.microsecsScale = 1000000.0 / perfCounterFreq.QuadPart;
- } else {
- /* fallback using microseconds */
- wideClick.perfCounter = 0;
- wideClick.microsecsScale = 1;
- }
-
- wideClick.initialized = 1;
- }
- if (wideClick.perfCounter) {
- if (QueryPerformanceCounter(&curCounter)) {
- return (long long)curCounter.QuadPart;
- }
- /* fallback using microseconds */
- wideClick.perfCounter = 0;
- wideClick.microsecsScale = 1;
- return TclpGetMicroseconds();
- } else {
- return TclpGetMicroseconds();
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclpWideClickInMicrosec --
- *
- * This procedure return scale to convert wide click values from the
- * TclpGetWideClicks native resolution to microsecond resolution
- * and back.
- *
- * Results:
- * 1 click in microseconds as double.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
+ retval = (now.sec * 1000000) + now.usec;
+ return retval;
-double
-TclpWideClickInMicrosec(void)
-{
- if (!wideClick.initialized) {
- (void) TclpGetWideClicks(); /* initialize */
- }
- return wideClick.microsecsScale;
}
/*
*----------------------------------------------------------------------
*
- * TclpGetMicroseconds --
+ * TclpGetTimeZone --
*
- * This procedure returns a WideInt value that represents the highest
- * resolution clock in microseconds available on the system.
+ * Determines the current timezone. The method varies wildly between
+ * different Platform implementations, so its hidden in this function.
*
* Results:
- * Number of microseconds (from the epoch).
+ * Minutes west of GMT.
*
* Side effects:
* None.
@@ -354,28 +214,16 @@ TclpWideClickInMicrosec(void)
*----------------------------------------------------------------------
*/
-long long
-TclpGetMicroseconds(void)
+int
+TclpGetTimeZone(
+ unsigned long currentTime)
{
- long long usecSincePosixEpoch;
+ int timeZone;
- /*
- * Try to use high resolution timer.
- */
+ tzset();
+ timeZone = timezone / 60;
- if (IsTimeNative() && (usecSincePosixEpoch = NativeGetMicroseconds())) {
- return usecSincePosixEpoch;
- } else {
- /*
- * Use the Tcl_GetTime abstraction to get the time in microseconds, as
- * nearly as we can, and return it.
- */
-
- Tcl_Time now;
-
- GetTime(&now);
- return (((long long) now.sec) * 1000000) + now.usec;
- }
+ return timeZone;
}
/*
@@ -404,18 +252,7 @@ void
Tcl_GetTime(
Tcl_Time *timePtr) /* Location to store time information. */
{
- long long usecSincePosixEpoch;
-
- /*
- * Try to use high resolution timer.
- */
-
- if (IsTimeNative() && (usecSincePosixEpoch = NativeGetMicroseconds())) {
- timePtr->sec = (long) (usecSincePosixEpoch / 1000000);
- timePtr->usec = (unsigned long) (usecSincePosixEpoch % 1000000);
- } else {
- GetTime(timePtr);
- }
+ (*tclGetTimeProcPtr) (timePtr, tclTimeClientData);
}
/*
@@ -437,8 +274,8 @@ Tcl_GetTime(
static void
NativeScaleTime(
- TCL_UNUSED(Tcl_Time *),
- TCL_UNUSED(void *))
+ Tcl_Time *timePtr,
+ ClientData clientData)
{
/*
* Native scale is 1:1. Nothing is done.
@@ -448,104 +285,13 @@ NativeScaleTime(
/*
*----------------------------------------------------------------------
*
- * IsPerfCounterAvailable --
- *
- * Tests whether the performance counter is available, which is a gnarly
- * problem on 32-bit systems. Also retrieves the nominal frequency of the
- * performance counter.
- *
- * Results:
- * 1 if the counter is available, 0 if not.
- *
- * Side effects:
- * Updates fields of the timeInfo global. Make sure you hold the lock
- * before calling this.
- *
- *----------------------------------------------------------------------
- */
-
-static inline int
-IsPerfCounterAvailable(void)
-{
- 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:
- * - inconsistent results among the processors on multi-processor
- * systems.
- * - 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.
- *
- * 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 !defined(_WIN64)
- if (timeInfo.perfCounterAvailable &&
- /*
- * The following lines would do an exact match on crystal
- * frequency:
- *
- * timeInfo.nominalFreq.QuadPart != (long long) 1193182 &&
- * timeInfo.nominalFreq.QuadPart != (long long) 3579545 &&
- */
- timeInfo.nominalFreq.QuadPart > (long long) 15000000) {
- /*
- * As an exception, if every logical processor on the system is on the
- * same chip, we use the performance counter anyway, presuming that
- * everyone's TSC is locked to the same oscillator.
- */
-
- SYSTEM_INFO systemInfo;
- 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 */
- == (int)systemInfo.dwNumberOfProcessors)) {
- timeInfo.perfCounterAvailable = TRUE;
- } else {
- timeInfo.perfCounterAvailable = FALSE;
- }
- }
-#endif /* above code is Win32 only */
-
- return timeInfo.perfCounterAvailable;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * NativeGetMicroseconds --
+ * NativeGetTime --
*
- * Gets the current system time in microseconds since the beginning
- * of the epoch: 00:00 UCT, January 1, 1970.
+ * 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 wide integer with number of microseconds from the epoch, or
- * 0 if high resolution timer is not available.
+ * Returns the current time in timePtr.
*
* Side effects:
* On the first call, initializes a set of static variables to keep track
@@ -558,20 +304,15 @@ IsPerfCounterAvailable(void)
*----------------------------------------------------------------------
*/
-static inline long long
-NativeCalc100NsTicks(
- ULONGLONG fileTimeLastCall,
- LONGLONG perfCounterLastCall,
- LONGLONG curCounterFreq,
- LONGLONG curCounter)
+static void
+NativeGetTime(
+ Tcl_Time *timePtr,
+ ClientData clientData)
{
- return fileTimeLastCall +
- ((curCounter - perfCounterLastCall) * 10000000 / curCounterFreq);
-}
+ struct _timeb t;
+ int useFtime = 1; /* Flag == TRUE if we need to fall back on
+ * ftime rather than using the perf counter. */
-static long long
-NativeGetMicroseconds(void)
-{
/*
* Initialize static storage on the first trip through.
*
@@ -582,20 +323,84 @@ NativeGetMicroseconds(void)
if (!timeInfo.initialized) {
TclpInitLock();
if (!timeInfo.initialized) {
- timeInfo.posixEpoch.LowPart = 0xD53E8000;
- timeInfo.posixEpoch.HighPart = 0x019DB1DE;
+ 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:
+ * - inconsistent results among the processors on
+ * multi-processor systems.
+ * - 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.
+ *
+ * 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 !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,
+ * presuming that everyone's TSC is locked to the same
+ * oscillator.
+ */
+
+ 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)) {
+ timeInfo.perfCounterAvailable = TRUE;
+ } else {
+ timeInfo.perfCounterAvailable = FALSE;
+ }
+ }
+#endif /* above code is Win32 only */
/*
* If the performance counter is available, start a thread to
* calibrate it.
*/
- if (IsPerfCounterAvailable()) {
+ if (timeInfo.perfCounterAvailable) {
DWORD id;
InitializeCriticalSection(&timeInfo.cs);
- timeInfo.readyEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
- timeInfo.exitEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
+ 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,
@@ -609,7 +414,7 @@ NativeGetMicroseconds(void)
WaitForSingleObject(timeInfo.readyEvent, INFINITE);
CloseHandle(timeInfo.readyEvent);
- Tcl_CreateExitHandler(StopCalibration, NULL);
+ Tcl_CreateExitHandler(StopCalibration, (ClientData) NULL);
}
timeInfo.initialized = TRUE;
}
@@ -622,39 +427,22 @@ NativeGetMicroseconds(void)
* time.
*/
- ULONGLONG fileTimeLastCall;
- LONGLONG perfCounterLastCall, curCounterFreq;
- /* Copy with current data of calibration
- * cycle. */
-
LARGE_INTEGER curCounter;
/* 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. */
+ Tcl_WideInt usecSincePosixEpoch;
+ /* Current microseconds since Posix epoch. */
- QueryPerformanceCounter(&curCounter);
-
- /*
- * Hold time section locked as short as possible
- */
+ posixEpoch.LowPart = 0xD53E8000;
+ posixEpoch.HighPart = 0x019DB1DE;
EnterCriticalSection(&timeInfo.cs);
- fileTimeLastCall = timeInfo.fileTimeLastCall.QuadPart;
- perfCounterLastCall = timeInfo.perfCounterLastCall.QuadPart;
- curCounterFreq = timeInfo.curCounterFreq.QuadPart;
-
- LeaveCriticalSection(&timeInfo.cs);
-
- /*
- * If calibration cycle occurred after we get curCounter
- */
-
- if (curCounter.QuadPart <= perfCounterLastCall) {
- /*
- * Calibrated file-time is saved from Posix in 100-ns ticks
- */
-
- return fileTimeLastCall / 10;
- }
+ QueryPerformanceCounter(&curCounter);
/*
* If it appears to be more than 1.1 seconds since the last trip
@@ -666,65 +454,29 @@ NativeGetMicroseconds(void)
* loop should recover.
*/
- if (curCounter.QuadPart - perfCounterLastCall <
- 11 * curCounterFreq * timeInfo.calibrationInterv / 10) {
- /*
- * Calibrated file-time is saved from Posix in 100-ns ticks.
- */
-
- return NativeCalc100NsTicks(fileTimeLastCall,
- perfCounterLastCall, curCounterFreq,
- curCounter.QuadPart) / 10;
+ 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);
+ useFtime = 0;
}
- }
- /*
- * High resolution timer is not available.
- */
- return 0;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * 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:
- * See NativeGetMicroseconds for more information.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-NativeGetTime(
- Tcl_Time *timePtr,
- TCL_UNUSED(void *))
-{
- long long usecSincePosixEpoch;
-
- /*
- * Try to use high resolution timer.
- */
+ LeaveCriticalSection(&timeInfo.cs);
+ }
- usecSincePosixEpoch = NativeGetMicroseconds();
- if (usecSincePosixEpoch) {
- timePtr->sec = (long) (usecSincePosixEpoch / 1000000);
- timePtr->usec = (unsigned long) (usecSincePosixEpoch % 1000000);
- } else {
+ if (useFtime) {
/*
* High resolution timer is not available. Just use ftime.
*/
- struct _timeb t;
-
_ftime(&t);
- timePtr->sec = (long) t.time;
+ timePtr->sec = (long)t.time;
timePtr->usec = t.millitm * 1000;
}
}
@@ -747,11 +499,9 @@ NativeGetTime(
*----------------------------------------------------------------------
*/
-void TclWinResetTimerResolution(void);
-
static void
StopCalibration(
- TCL_UNUSED(void *))
+ ClientData unused) /* Client data is unused */
{
SetEvent(timeInfo.exitEvent);
@@ -768,6 +518,93 @@ StopCalibration(
/*
*----------------------------------------------------------------------
*
+ * TclpGetTZName --
+ *
+ * Gets the current timezone string.
+ *
+ * Results:
+ * Returns a pointer to a static string, or NULL on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+char *
+TclpGetTZName(
+ int dst)
+{
+ int len;
+ char *zone, *p;
+ TIME_ZONE_INFORMATION tz;
+ Tcl_Encoding encoding;
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ char *name = tsdPtr->tzName;
+
+ /*
+ * 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
+ * ezone string, even though env(TZ) is GMT and the variable _timezone
+ * is 0.
+ */
+
+ name[0] = '\0';
+
+ 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.
+ */
+
+ len = strlen(zone);
+ if (len > 3) {
+ len = 3;
+ }
+ if (dst != 0) {
+ /*
+ * Skip the offset string and get the DST string.
+ */
+
+ p = zone + len;
+ p += strspn(p, "+-:0123456789");
+ if (*p != '\0') {
+ zone = p;
+ len = strlen(zone);
+ if (len > 3) {
+ len = 3;
+ }
+ }
+ }
+ 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
+ */
+
+ dst = 0;
+ }
+ encoding = Tcl_GetEncoding(NULL, "unicode");
+ 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;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* TclpGetDate --
*
* This function converts between seconds and struct tm. If useGMT is
@@ -783,26 +620,15 @@ StopCalibration(
*----------------------------------------------------------------------
*/
-#ifndef TCL_NO_DEPRECATED
struct tm *
TclpGetDate(
- const time_t *t,
+ CONST time_t *t,
int useGMT)
{
struct tm *tmPtr;
time_t time;
-#if defined(_WIN64) || defined(_USE_64BIT_TIME_T)
-# define t2 *t /* no need to cripple time to 32-bit */
-#else
- time_t t2 = *(__time32_t *) t;
-#endif
if (!useGMT) {
-#if defined(_MSC_VER)
-# undef timezone /* prevent conflict with timezone() function */
- long timezone = 0;
-#endif
-
tzset();
/*
@@ -811,15 +637,28 @@ TclpGetDate(
* daylight savings time before the epoch.
*/
- if (t2 >= 0) {
- return TclpLocaltime(&t2);
- }
+ /*
+ * 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
+ */
-#if defined(_MSC_VER)
- _get_timezone(&timezone);
+#ifdef __BORLANDC__
+#define LOCALTIME_VALIDITY_BOUNDARY SECSPERDAY
+#else
+#define LOCALTIME_VALIDITY_BOUNDARY 0
#endif
- time = t2 - timezone;
+ if (*t >= LOCALTIME_VALIDITY_BOUNDARY) {
+ return TclpLocaltime(t);
+ }
+
+ time = *t - timezone;
/*
* If we aren't near to overflowing the long, just add the bias and
@@ -827,10 +666,10 @@ TclpGetDate(
* result at the end.
*/
- if (t2 < (LONG_MAX - 2*SECSPERDAY) && t2 > (LONG_MIN + 2*SECSPERDAY)) {
+ if (*t < (LONG_MAX - 2*SECSPERDAY) && *t > (LONG_MIN + 2*SECSPERDAY)) {
tmPtr = ComputeGMT(&time);
} else {
- tmPtr = ComputeGMT(&t2);
+ tmPtr = ComputeGMT(t);
tzset();
@@ -846,14 +685,14 @@ TclpGetDate(
time -= 60;
}
- time = tmPtr->tm_min + time / 60;
+ time = tmPtr->tm_min + time/60;
tmPtr->tm_min = (int)(time % 60);
if (tmPtr->tm_min < 0) {
tmPtr->tm_min += 60;
time -= 60;
}
- time = tmPtr->tm_hour + time / 60;
+ time = tmPtr->tm_hour + time/60;
tmPtr->tm_hour = (int)(time % 24);
if (tmPtr->tm_hour < 0) {
tmPtr->tm_hour += 24;
@@ -861,12 +700,12 @@ TclpGetDate(
}
time /= 24;
- tmPtr->tm_mday += (int) time;
- tmPtr->tm_yday += (int) time;
- tmPtr->tm_wday = (tmPtr->tm_wday + (int) time) % 7;
+ tmPtr->tm_mday += (int)time;
+ tmPtr->tm_yday += (int)time;
+ tmPtr->tm_wday = (tmPtr->tm_wday + (int)time) % 7;
}
} else {
- tmPtr = ComputeGMT(&t2);
+ tmPtr = ComputeGMT(t);
}
return tmPtr;
}
@@ -904,8 +743,8 @@ ComputeGMT(
* Compute the 4 year span containing the specified time.
*/
- tmp = (long) (*tp / SECSPER4YEAR);
- rem = (long) (*tp % SECSPER4YEAR);
+ tmp = (long)(*tp / SECSPER4YEAR);
+ rem = (long)(*tp % SECSPER4YEAR);
/*
* Correct for weird mod semantics so the remainder is always positive.
@@ -972,7 +811,7 @@ ComputeGMT(
* Compute day of week. Epoch started on a Thursday.
*/
- tmPtr->tm_wday = (long) (*tp / SECSPERDAY) + 4;
+ tmPtr->tm_wday = (long)(*tp / SECSPERDAY) + 4;
if ((*tp % SECSPERDAY) < 0) {
tmPtr->tm_wday--;
}
@@ -983,7 +822,6 @@ ComputeGMT(
return tmPtr;
}
-#endif /* TCL_NO_DEPRECATED */
/*
*----------------------------------------------------------------------
@@ -1013,7 +851,7 @@ ComputeGMT(
static DWORD WINAPI
CalibrationThread(
- TCL_UNUSED(LPVOID))
+ LPVOID arg)
{
FILETIME curFileTime;
DWORD waitResult;
@@ -1028,12 +866,6 @@ CalibrationThread(
timeInfo.fileTimeLastCall.LowPart = curFileTime.dwLowDateTime;
timeInfo.fileTimeLastCall.HighPart = curFileTime.dwHighDateTime;
- /*
- * Calibrated file-time will be saved from Posix in 100-ns ticks.
- */
-
- timeInfo.fileTimeLastCall.QuadPart -= timeInfo.posixEpoch.QuadPart;
-
ResetCounterSamples(timeInfo.fileTimeLastCall.QuadPart,
timeInfo.perfCounterLastCall.QuadPart,
timeInfo.curCounterFreq.QuadPart);
@@ -1061,6 +893,7 @@ CalibrationThread(
UpdateTimeEachSecond();
}
+ /* lint */
return (DWORD) 0;
}
@@ -1091,45 +924,29 @@ UpdateTimeEachSecond(void)
/* Current value returned from
* QueryPerformanceCounter. */
FILETIME curSysTime; /* Current system time. */
- static LARGE_INTEGER lastFileTime;
- /* File time of the previous calibration */
LARGE_INTEGER curFileTime; /* File time at the time this callback was
* scheduled. */
- long long estFreq; /* Estimated perf counter frequency. */
- long long vt0; /* Tcl time right now. */
- long long vt1; /* Tcl time one second from now. */
- long long tdiff; /* Difference between system clock and Tcl
+ 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. */
- long long driftFreq; /* Frequency needed to drift virtual time into
+ Tcl_WideInt driftFreq; /* Frequency needed to drift virtual time into
* step over 1 second. */
/*
- * Sample performance counter and system time (from Posix epoch).
+ * Sample performance counter and system time.
*/
+ QueryPerformanceCounter(&curPerfCounter);
GetSystemTimeAsFileTime(&curSysTime);
curFileTime.LowPart = curSysTime.dwLowDateTime;
curFileTime.HighPart = curSysTime.dwHighDateTime;
- curFileTime.QuadPart -= timeInfo.posixEpoch.QuadPart;
-
- /*
- * If calibration still not needed (check for possible time switch)
- */
-
- if (curFileTime.QuadPart > lastFileTime.QuadPart && curFileTime.QuadPart <
- lastFileTime.QuadPart + (timeInfo.calibrationInterv * 10000000)) {
- /*
- * Look again in next one second.
- */
-
- return;
- }
- QueryPerformanceCounter(&curPerfCounter);
- lastFileTime.QuadPart = curFileTime.QuadPart;
+ EnterCriticalSection(&timeInfo.cs);
/*
- * We divide by timeInfo.curCounterFreq.QuadPart in several places. That
+ * 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
@@ -1138,6 +955,7 @@ UpdateTimeEachSecond(void)
*/
if (timeInfo.curCounterFreq.QuadPart == 0){
+ LeaveCriticalSection(&timeInfo.cs);
timeInfo.perfCounterAvailable = 0;
return;
}
@@ -1157,7 +975,7 @@ UpdateTimeEachSecond(void)
*/
estFreq = AccumulateSample(curPerfCounter.QuadPart,
- (unsigned long long) curFileTime.QuadPart);
+ (Tcl_WideUInt) curFileTime.QuadPart);
/*
* We want to adjust things so that time appears to be continuous.
@@ -1176,9 +994,11 @@ UpdateTimeEachSecond(void)
* is estFreq * 20000000 / (vt1 - vt0)
*/
- vt0 = NativeCalc100NsTicks(timeInfo.fileTimeLastCall.QuadPart,
- timeInfo.perfCounterLastCall.QuadPart,
- timeInfo.curCounterFreq.QuadPart, curPerfCounter.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
@@ -1188,111 +1008,21 @@ UpdateTimeEachSecond(void)
tdiff = vt0 - curFileTime.QuadPart;
if (tdiff > 10000000 || tdiff < -10000000) {
- /*
- * Jump to current system time, use curent estimated frequency.
- */
-
- vt0 = curFileTime.QuadPart;
+ timeInfo.fileTimeLastCall.QuadPart = curFileTime.QuadPart;
+ timeInfo.curCounterFreq.QuadPart = estFreq;
} else {
- /*
- * Calculate new frequency and estimate drift to the next second.
- */
-
- vt1 = 20000000 + curFileTime.QuadPart;
- driftFreq = (estFreq * 20000000 / (vt1 - vt0));
-
- /*
- * Avoid too large drifts (only half of the current difference), that
- * allows also be more accurate (aspire to the smallest tdiff), so
- * then we can prolong calibration interval by tdiff < 100000
- */
-
- driftFreq = timeInfo.curCounterFreq.QuadPart +
- (driftFreq - timeInfo.curCounterFreq.QuadPart) / 2;
+ driftFreq = estFreq * 20000000 / (vt1 - vt0);
- /*
- * Average between estimated, 2 current and 5 drifted frequencies,
- * (do the soft drifting as possible)
- */
-
- estFreq = (estFreq + 2 * timeInfo.curCounterFreq.QuadPart +
- 5 * driftFreq) / 8;
- }
-
- /*
- * Avoid too large discrepancy from nominal frequency.
- */
-
- if (estFreq > 1003 * timeInfo.nominalFreq.QuadPart / 1000) {
- estFreq = 1003 * timeInfo.nominalFreq.QuadPart / 1000;
- vt0 = curFileTime.QuadPart;
- } else if (estFreq < 997 * timeInfo.nominalFreq.QuadPart / 1000) {
- estFreq = 997 * timeInfo.nominalFreq.QuadPart / 1000;
- vt0 = curFileTime.QuadPart;
- } else if (vt0 != curFileTime.QuadPart) {
- /*
- * Be sure the clock ticks never backwards (avoid it by negative
- * drifting). Just compare native time (in 100-ns) before and
- * hereafter using new calibrated values) and do a small adjustment
- * (short time freeze).
- */
-
- LARGE_INTEGER newPerfCounter;
- long long nt0, nt1;
-
- QueryPerformanceCounter(&newPerfCounter);
- nt0 = NativeCalc100NsTicks(timeInfo.fileTimeLastCall.QuadPart,
- timeInfo.perfCounterLastCall.QuadPart,
- timeInfo.curCounterFreq.QuadPart, newPerfCounter.QuadPart);
- nt1 = NativeCalc100NsTicks(vt0,
- curPerfCounter.QuadPart, estFreq, newPerfCounter.QuadPart);
- if (nt0 > nt1) {
- /*
- * Drifted backwards, try to compensate with new base.
- *
- * First adjust with a micro jump (short frozen time is
- * acceptable).
- */
- vt0 += nt0 - nt1;
-
- /*
- * If drift unavoidable (e. g. we had a time switch), then reset
- * it.
- */
-
- vt1 = vt0 - curFileTime.QuadPart;
- if (vt1 > 10000000 || vt1 < -10000000) {
- /*
- * Larger jump resp. shift relative new file-time.
- */
-
- vt0 = curFileTime.QuadPart;
- }
+ if (driftFreq > 1003*estFreq/1000) {
+ driftFreq = 1003*estFreq/1000;
+ } else if (driftFreq < 997*estFreq/1000) {
+ driftFreq = 997*estFreq/1000;
}
- }
-
- /*
- * In lock commit new values to timeInfo (hold lock as short as possible)
- */
- EnterCriticalSection(&timeInfo.cs);
-
- /*
- * Grow calibration interval up to 10 seconds (if still precise enough)
- */
-
- if (tdiff < -100000 || tdiff > 100000) {
- /*
- * Too long drift. Reset calibration interval to 1000 second.
- */
-
- timeInfo.calibrationInterv = 1;
- } else if (timeInfo.calibrationInterv < 10) {
- timeInfo.calibrationInterv++;
+ timeInfo.fileTimeLastCall.QuadPart = vt0;
+ timeInfo.curCounterFreq.QuadPart = driftFreq;
}
- timeInfo.fileTimeLastCall.QuadPart = vt0;
- timeInfo.curCounterFreq.QuadPart = estFreq;
timeInfo.perfCounterLastCall.QuadPart = curPerfCounter.QuadPart;
LeaveCriticalSection(&timeInfo.cs);
@@ -1319,13 +1049,12 @@ UpdateTimeEachSecond(void)
static void
ResetCounterSamples(
- unsigned long long fileTime,/* Current file time */
- long long perfCounter, /* Current performance counter */
- long long perfFreq) /* Target performance frequency */
+ 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;
@@ -1360,22 +1089,20 @@ ResetCounterSamples(
* case).
*/
-static long long
+static Tcl_WideInt
AccumulateSample(
- long long perfCounter,
- unsigned long long fileTime)
+ Tcl_WideInt perfCounter,
+ Tcl_WideUInt fileTime)
{
- unsigned long long workFTSample;
- /* File time sample being removed from or
+ Tcl_WideUInt workFTSample; /* File time sample being removed from or
* added to the circular buffer. */
- long long workPCSample; /* Performance counter sample being removed
+ Tcl_WideInt workPCSample; /* Performance counter sample being removed
* from or added to the circular buffer. */
- unsigned long long lastFTSample;
- /* Last file time sample recorded */
- long long lastPCSample; /* Last performance counter sample recorded */
- long long FTdiff; /* Difference between last FT and current */
- long long PCdiff; /* Difference between last PC and current */
- long long estFreq; /* Estimated performance counter frequency */
+ 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.
@@ -1409,7 +1136,7 @@ AccumulateSample(
estFreq = 10000000 * (perfCounter - workPCSample)
/ (fileTime - workFTSample);
timeInfo.perfCounterSample[timeInfo.sampleNo] = perfCounter;
- timeInfo.fileTimeSample[timeInfo.sampleNo] = (long long) fileTime;
+ timeInfo.fileTimeSample[timeInfo.sampleNo] = (Tcl_WideInt) fileTime;
/*
* Advance the sample number.
@@ -1439,10 +1166,9 @@ AccumulateSample(
*----------------------------------------------------------------------
*/
-#ifndef TCL_NO_DEPRECATED
struct tm *
TclpGmtime(
- const time_t *timePtr) /* Pointer to the number of seconds since the
+ CONST time_t *timePtr) /* Pointer to the number of seconds since the
* local system's epoch */
{
/*
@@ -1451,11 +1177,7 @@ TclpGmtime(
* Posix gmtime_r function.
*/
-#if defined(_WIN64) || defined(_USE_64BIT_TIME_T)
return gmtime(timePtr);
-#else
- return _gmtime32((const __time32_t *) timePtr);
-#endif /* _WIN64 || _USE_64BIT_TIME_T */
}
/*
@@ -1477,8 +1199,9 @@ TclpGmtime(
struct tm *
TclpLocaltime(
- const time_t *timePtr) /* Pointer to the number of seconds since the
+ 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
@@ -1486,13 +1209,8 @@ TclpLocaltime(
* provide a Posix localtime_r function.
*/
-#if defined(_WIN64) || defined(_USE_64BIT_TIME_T)
return localtime(timePtr);
-#else
- return _localtime32((const __time32_t *) timePtr);
-#endif /* _WIN64 || _USE_64BIT_TIME_T */
}
-#endif /* TCL_NO_DEPRECATED */
/*
*----------------------------------------------------------------------
@@ -1515,7 +1233,7 @@ void
Tcl_SetTimeProc(
Tcl_GetTimeProc *getProc,
Tcl_ScaleTimeProc *scaleProc,
- void *clientData)
+ ClientData clientData)
{
tclGetTimeProcPtr = getProc;
tclScaleTimeProcPtr = scaleProc;
@@ -1542,7 +1260,7 @@ void
Tcl_QueryTimeProc(
Tcl_GetTimeProc **getProc,
Tcl_ScaleTimeProc **scaleProc,
- void **clientData)
+ ClientData *clientData)
{
if (getProc) {
*getProc = tclGetTimeProcPtr;