os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/win/tclWinTime.c
Update contrib.
4 * Contains Windows specific versions of Tcl functions that
5 * obtain time values from the operating system.
7 * Copyright 1995-1998 by Sun Microsystems, Inc.
9 * See the file "license.terms" for information on usage and redistribution
10 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12 * RCS: @(#) $Id: tclWinTime.c,v 1.14.2.11 2007/04/21 19:52:15 kennykb Exp $
15 #include "tclWinInt.h"
17 #define SECSPERDAY (60L * 60L * 24L)
18 #define SECSPERYEAR (SECSPERDAY * 365L)
19 #define SECSPER4YEAR (SECSPERYEAR * 4L + SECSPERDAY)
22 * Number of samples over which to estimate the performance counter
27 * The following arrays contain the day of year for the last day of
28 * each month, where index 1 is January.
31 static int normalDays[] = {
32 -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364
35 static int leapDays[] = {
36 -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
39 typedef struct ThreadSpecificData {
40 char tzName[64]; /* Time zone name */
41 struct tm tm; /* time information */
43 static Tcl_ThreadDataKey dataKey;
46 * Data for managing high-resolution timers.
49 typedef struct TimeInfo {
51 CRITICAL_SECTION cs; /* Mutex guarding this structure */
53 int initialized; /* Flag == 1 if this structure is
56 int perfCounterAvailable; /* Flag == 1 if the hardware has a
57 * performance counter */
59 HANDLE calibrationThread; /* Handle to the thread that keeps the
60 * virtual clock calibrated. */
62 HANDLE readyEvent; /* System event used to
63 * trigger the requesting thread
64 * when the clock calibration procedure
65 * is initialized for the first time */
67 HANDLE exitEvent; /* Event to signal out of an exit handler
68 * to tell the calibration loop to
71 LARGE_INTEGER nominalFreq; /* Nominal frequency of the system
72 * performance counter, that is, the value
73 * returned from QueryPerformanceFrequency. */
76 * The following values are used for calculating virtual time.
77 * Virtual time is always equal to:
78 * lastFileTime + (current perf counter - lastCounter)
79 * * 10000000 / curCounterFreq
80 * and lastFileTime and lastCounter are updated any time that
81 * virtual time is returned to a caller.
84 ULARGE_INTEGER fileTimeLastCall;
85 LARGE_INTEGER perfCounterLastCall;
86 LARGE_INTEGER curCounterFreq;
89 * Data used in developing the estimate of performance counter
92 Tcl_WideUInt fileTimeSample[SAMPLES];
93 /* Last 64 samples of system time */
94 Tcl_WideInt perfCounterSample[SAMPLES];
95 /* Last 64 samples of performance counter */
96 int sampleNo; /* Current sample number */
101 static TimeInfo timeInfo = {
108 #ifdef HAVE_CAST_TO_UNION
109 (LARGE_INTEGER) (Tcl_WideInt) 0,
110 (ULARGE_INTEGER) (DWORDLONG) 0,
111 (LARGE_INTEGER) (Tcl_WideInt) 0,
112 (LARGE_INTEGER) (Tcl_WideInt) 0,
124 CONST static FILETIME posixEpoch = { 0xD53E8000, 0x019DB1DE };
127 * Declarations for functions defined later in this file.
130 static struct tm * ComputeGMT _ANSI_ARGS_((const time_t *tp));
131 static void StopCalibration _ANSI_ARGS_(( ClientData ));
132 static DWORD WINAPI CalibrationThread _ANSI_ARGS_(( LPVOID arg ));
133 static void UpdateTimeEachSecond _ANSI_ARGS_(( void ));
134 static void ResetCounterSamples _ANSI_ARGS_((
135 Tcl_WideUInt fileTime,
136 Tcl_WideInt perfCounter,
139 static Tcl_WideInt AccumulateSample _ANSI_ARGS_((
140 Tcl_WideInt perfCounter,
141 Tcl_WideUInt fileTime
145 *----------------------------------------------------------------------
149 * This procedure returns the number of seconds from the epoch.
150 * On most Unix systems the epoch is Midnight Jan 1, 1970 GMT.
153 * Number of seconds from the epoch.
158 *----------------------------------------------------------------------
170 *----------------------------------------------------------------------
174 * This procedure returns a value that represents the highest
175 * resolution clock available on the system. There are no
176 * guarantees on what the resolution will be. In Tcl we will
177 * call this value a "click". The start time is also system
181 * Number of clicks from some start time.
186 *----------------------------------------------------------------------
193 * Use the Tcl_GetTime abstraction to get the time in microseconds,
194 * as nearly as we can, and return it.
197 Tcl_Time now; /* Current Tcl time */
198 unsigned long retval; /* Value to return */
201 retval = ( now.sec * 1000000 ) + now.usec;
207 *----------------------------------------------------------------------
211 * Determines the current timezone. The method varies wildly
212 * between different Platform implementations, so its hidden in
216 * Minutes west of GMT.
221 *----------------------------------------------------------------------
225 TclpGetTimeZone (currentTime)
226 Tcl_WideInt currentTime;
231 timeZone = _timezone / 60;
237 *----------------------------------------------------------------------
241 * Gets the current system time in seconds and microseconds
242 * since the beginning of the epoch: 00:00 UCT, January 1, 1970.
245 * Returns the current time in timePtr.
248 * On the first call, initializes a set of static variables to
249 * keep track of the base value of the performance counter, the
250 * corresponding wall clock (obtained through ftime) and the
251 * frequency of the performance counter. Also spins a thread
252 * whose function is to wake up periodically and monitor these
253 * values, adjusting them as necessary to correct for drift
254 * in the performance counter's oscillator.
256 *----------------------------------------------------------------------
261 Tcl_Time *timePtr; /* Location to store time information. */
265 int useFtime = 1; /* Flag == TRUE if we need to fall back
266 * on ftime rather than using the perf
269 /* Initialize static storage on the first trip through. */
272 * Note: Outer check for 'initialized' is a performance win
273 * since it avoids an extra mutex lock in the common case.
276 if ( !timeInfo.initialized ) {
278 if ( !timeInfo.initialized ) {
279 timeInfo.perfCounterAvailable
280 = QueryPerformanceFrequency( &timeInfo.nominalFreq );
283 * Some hardware abstraction layers use the CPU clock
284 * in place of the real-time clock as a performance counter
285 * reference. This results in:
286 * - inconsistent results among the processors on
287 * multi-processor systems.
288 * - unpredictable changes in performance counter frequency
289 * on "gearshift" processors such as Transmeta and
292 * There seems to be no way to test whether the performance
293 * counter is reliable, but a useful heuristic is that
294 * if its frequency is 1.193182 MHz or 3.579545 MHz, it's
295 * derived from a colorburst crystal and is therefore
296 * the RTC rather than the TSC.
298 * A sloppier but serviceable heuristic is that the RTC crystal
299 * is normally less than 15 MHz while the TSC crystal is
300 * virtually assured to be greater than 100 MHz. Since Win98SE
301 * appears to fiddle with the definition of the perf counter
302 * frequency (perhaps in an attempt to calibrate the clock?)
303 * we use the latter rule rather than an exact match.
306 if ( timeInfo.perfCounterAvailable
307 /* The following lines would do an exact match on
309 * && timeInfo.nominalFreq.QuadPart != (Tcl_WideInt) 1193182
310 * && timeInfo.nominalFreq.QuadPart != (Tcl_WideInt) 3579545
312 && timeInfo.nominalFreq.QuadPart > (Tcl_WideInt) 15000000 ) {
315 * As an exception, if every logical processor on the system
316 * is on the same chip, we use the performance counter anyway,
317 * presuming that everyone's TSC is locked to the same
321 SYSTEM_INFO systemInfo;
322 unsigned int regs[4];
323 GetSystemInfo( &systemInfo );
324 if ( TclWinCPUID( 0, regs ) == TCL_OK
326 && regs[1] == 0x756e6547 /* "Genu" */
327 && regs[3] == 0x49656e69 /* "ineI" */
328 && regs[2] == 0x6c65746e /* "ntel" */
330 && TclWinCPUID( 1, regs ) == TCL_OK
332 && ( (regs[0] & 0x00000F00) == 0x00000F00 /* Pentium 4 */
333 || ( (regs[0] & 0x00F00000) /* Extended family */
334 && (regs[3] & 0x10000000) ) ) /* Hyperthread */
335 && ( ( ( regs[1] & 0x00FF0000 ) >> 16 ) /* CPU count */
336 == systemInfo.dwNumberOfProcessors )
339 timeInfo.perfCounterAvailable = TRUE;
341 timeInfo.perfCounterAvailable = FALSE;
347 * If the performance counter is available, start a thread to
351 if ( timeInfo.perfCounterAvailable ) {
353 InitializeCriticalSection( &timeInfo.cs );
354 timeInfo.readyEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
355 timeInfo.exitEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
356 timeInfo.calibrationThread = CreateThread( NULL,
362 SetThreadPriority( timeInfo.calibrationThread,
363 THREAD_PRIORITY_HIGHEST );
366 * Wait for the thread just launched to start running,
367 * and create an exit handler that kills it so that it
368 * doesn't outlive unloading tclXX.dll
371 WaitForSingleObject( timeInfo.readyEvent, INFINITE );
372 CloseHandle( timeInfo.readyEvent );
373 Tcl_CreateExitHandler( StopCalibration, (ClientData) NULL );
375 timeInfo.initialized = TRUE;
380 if ( timeInfo.perfCounterAvailable ) {
382 * Query the performance counter and use it to calculate the
386 LARGE_INTEGER curCounter;
387 /* Current performance counter */
389 Tcl_WideInt curFileTime;
390 /* Current estimated time, expressed
391 * as 100-ns ticks since the Windows epoch */
393 static LARGE_INTEGER posixEpoch;
394 /* Posix epoch expressed as 100-ns ticks
395 * since the windows epoch */
397 Tcl_WideInt usecSincePosixEpoch;
398 /* Current microseconds since Posix epoch */
400 posixEpoch.LowPart = 0xD53E8000;
401 posixEpoch.HighPart = 0x019DB1DE;
403 EnterCriticalSection( &timeInfo.cs );
405 QueryPerformanceCounter( &curCounter );
408 * If it appears to be more than 1.1 seconds since the last trip
409 * through the calibration loop, the performance counter may
410 * have jumped forward. (See MSDN Knowledge Base article
411 * Q274323 for a description of the hardware problem that makes
412 * this test necessary.) If the counter jumps, we don't want
413 * to use it directly. Instead, we must return system time.
414 * Eventually, the calibration loop should recover.
416 if ( curCounter.QuadPart - timeInfo.perfCounterLastCall.QuadPart
417 < 11 * timeInfo.curCounterFreq.QuadPart / 10 ) {
419 curFileTime = timeInfo.fileTimeLastCall.QuadPart
420 + ( ( curCounter.QuadPart - timeInfo.perfCounterLastCall.QuadPart )
421 * 10000000 / timeInfo.curCounterFreq.QuadPart );
422 timeInfo.fileTimeLastCall.QuadPart = curFileTime;
423 timeInfo.perfCounterLastCall.QuadPart = curCounter.QuadPart;
424 usecSincePosixEpoch = ( curFileTime - posixEpoch.QuadPart ) / 10;
425 timePtr->sec = (long) ( usecSincePosixEpoch / 1000000 );
426 timePtr->usec = (unsigned long ) ( usecSincePosixEpoch % 1000000 );
430 LeaveCriticalSection( &timeInfo.cs );
434 /* High resolution timer is not available. Just use ftime */
437 timePtr->sec = (long)t.time;
438 timePtr->usec = t.millitm * 1000;
443 *----------------------------------------------------------------------
447 * Turns off the calibration thread in preparation for exiting the
454 * Sets the 'exitEvent' event in the 'timeInfo' structure to ask
455 * the thread in question to exit, and waits for it to do so.
457 *----------------------------------------------------------------------
461 StopCalibration( ClientData unused )
462 /* Client data is unused */
464 SetEvent( timeInfo.exitEvent );
465 WaitForSingleObject( timeInfo.calibrationThread, INFINITE );
466 CloseHandle( timeInfo.exitEvent );
467 CloseHandle( timeInfo.calibrationThread );
471 *----------------------------------------------------------------------
475 * Gets the current timezone string.
478 * Returns a pointer to a static string, or NULL on failure.
483 *----------------------------------------------------------------------
487 TclpGetTZName(int dst)
491 TIME_ZONE_INFORMATION tz;
492 Tcl_Encoding encoding;
493 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
494 char *name = tsdPtr->tzName;
497 * tzset() under Borland doesn't seem to set up tzname[] at all.
498 * tzset() under MSVC has the following weird observed behavior:
499 * First time we call "clock format [clock seconds] -format %Z -gmt 1"
500 * we get "GMT", but on all subsequent calls we get the current time
501 * zone string, even though env(TZ) is GMT and the variable _timezone
510 * TZ is of form "NST-4:30NDT", where "NST" would be the
511 * name of the standard time zone for this area, "-4:30" is
512 * the offset from GMT in hours, and "NDT is the name of
513 * the daylight savings time zone in this area. The offset
514 * and DST strings are optional.
523 * Skip the offset string and get the DST string.
527 p += strspn(p, "+-:0123456789");
536 Tcl_ExternalToUtf(NULL, NULL, zone, (int)len, 0, NULL, name,
537 sizeof(tsdPtr->tzName), NULL, NULL, NULL);
539 if (name[0] == '\0') {
540 if (GetTimeZoneInformation(&tz) == TIME_ZONE_ID_UNKNOWN) {
542 * MSDN: On NT this is returned if DST is not used in
547 encoding = Tcl_GetEncoding(NULL, "unicode");
548 Tcl_ExternalToUtf(NULL, encoding,
549 (char *) ((dst) ? tz.DaylightName : tz.StandardName), -1,
550 0, NULL, name, sizeof(tsdPtr->tzName), NULL, NULL, NULL);
551 Tcl_FreeEncoding(encoding);
557 *----------------------------------------------------------------------
561 * This function converts between seconds and struct tm. If
562 * useGMT is true, then the returned date will be in Greenwich
563 * Mean Time (GMT). Otherwise, it will be in the local time zone.
566 * Returns a static tm structure.
571 *----------------------------------------------------------------------
575 TclpGetDate(t, useGMT)
579 const time_t *tp = (const time_t *) t;
587 * If we are in the valid range, let the C run-time library
588 * handle it. Otherwise we need to fake it. Note that this
589 * algorithm ignores daylight savings time before the epoch.
593 return localtime(tp);
596 time = *tp - _timezone;
599 * If we aren't near to overflowing the long, just add the bias and
600 * use the normal calculation. Otherwise we will need to adjust
601 * the result at the end.
604 if (*tp < (LONG_MAX - 2 * SECSPERDAY)
605 && *tp > (LONG_MIN + 2 * SECSPERDAY)) {
606 tmPtr = ComputeGMT(&time);
608 tmPtr = ComputeGMT(tp);
613 * Add the bias directly to the tm structure to avoid overflow.
614 * Propagate seconds overflow into minutes, hours and days.
617 time = tmPtr->tm_sec - _timezone;
618 tmPtr->tm_sec = (int)(time % 60);
619 if (tmPtr->tm_sec < 0) {
624 time = tmPtr->tm_min + time/60;
625 tmPtr->tm_min = (int)(time % 60);
626 if (tmPtr->tm_min < 0) {
631 time = tmPtr->tm_hour + time/60;
632 tmPtr->tm_hour = (int)(time % 24);
633 if (tmPtr->tm_hour < 0) {
634 tmPtr->tm_hour += 24;
639 tmPtr->tm_mday += (int)time;
640 tmPtr->tm_yday += (int)time;
641 tmPtr->tm_wday = (tmPtr->tm_wday + (int)time) % 7;
644 tmPtr = ComputeGMT(tp);
650 *----------------------------------------------------------------------
654 * This function computes GMT given the number of seconds since
655 * the epoch (midnight Jan 1 1970).
658 * Returns a (per thread) statically allocated struct tm.
661 * Updates the values of the static struct tm.
663 *----------------------------------------------------------------------
674 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
679 * Compute the 4 year span containing the specified time.
682 tmp = (long)(*tp / SECSPER4YEAR);
683 rem = (LONG)(*tp % SECSPER4YEAR);
686 * Correct for weird mod semantics so the remainder is always positive.
695 * Compute the year after 1900 by taking the 4 year span and adjusting
696 * for the remainder. This works because 2000 is a leap year, and
697 * 1900/2100 are out of the range.
700 tmp = (tmp * 4) + 70;
702 if (rem >= SECSPERYEAR) { /* 1971, etc. */
705 if (rem >= SECSPERYEAR) { /* 1972, etc. */
708 if (rem >= SECSPERYEAR + SECSPERDAY) { /* 1973, etc. */
710 rem -= SECSPERYEAR + SECSPERDAY;
716 tmPtr->tm_year = tmp;
719 * Compute the day of year and leave the seconds in the current day in
723 tmPtr->tm_yday = rem / SECSPERDAY;
727 * Compute the time of day.
730 tmPtr->tm_hour = rem / 3600;
732 tmPtr->tm_min = rem / 60;
733 tmPtr->tm_sec = rem % 60;
736 * Compute the month and day of month.
739 days = (isLeap) ? leapDays : normalDays;
740 for (tmp = 1; days[tmp] < tmPtr->tm_yday; tmp++) {
742 tmPtr->tm_mon = --tmp;
743 tmPtr->tm_mday = tmPtr->tm_yday - days[tmp];
746 * Compute day of week. Epoch started on a Thursday.
749 tmPtr->tm_wday = (long)(*tp / SECSPERDAY) + 4;
750 if ((*tp % SECSPERDAY) < 0) {
754 if (tmPtr->tm_wday < 0) {
762 *----------------------------------------------------------------------
764 * CalibrationThread --
766 * Thread that manages calibration of the hi-resolution time
767 * derived from the performance counter, to keep it synchronized
768 * with the system clock.
771 * arg -- Client data from the CreateThread call. This parameter
772 * points to the static TimeInfo structure.
775 * None. This thread embeds an infinite loop.
778 * At an interval of 1 s, this thread performs virtual time discipline.
780 * Note: When this thread is entered, TclpInitLock has been called
781 * to safeguard the static storage. There is therefore no synchronization
782 * in the body of this procedure.
784 *----------------------------------------------------------------------
788 CalibrationThread( LPVOID arg )
790 FILETIME curFileTime;
793 /* Get initial system time and performance counter */
795 GetSystemTimeAsFileTime( &curFileTime );
796 QueryPerformanceCounter( &timeInfo.perfCounterLastCall );
797 QueryPerformanceFrequency( &timeInfo.curCounterFreq );
798 timeInfo.fileTimeLastCall.LowPart = curFileTime.dwLowDateTime;
799 timeInfo.fileTimeLastCall.HighPart = curFileTime.dwHighDateTime;
801 ResetCounterSamples( timeInfo.fileTimeLastCall.QuadPart,
802 timeInfo.perfCounterLastCall.QuadPart,
803 timeInfo.curCounterFreq.QuadPart );
806 * Wake up the calling thread. When it wakes up, it will release the
807 * initialization lock.
810 SetEvent( timeInfo.readyEvent );
812 /* Run the calibration once a second */
816 /* If the exitEvent is set, break out of the loop. */
818 waitResult = WaitForSingleObjectEx(timeInfo.exitEvent, 1000, FALSE);
819 if ( waitResult == WAIT_OBJECT_0 ) {
822 UpdateTimeEachSecond();
830 *----------------------------------------------------------------------
832 * UpdateTimeEachSecond --
834 * Callback from the waitable timer in the clock calibration thread
835 * that updates system time.
838 * info -- Pointer to the static TimeInfo structure
844 * Performs virtual time calibration discipline.
846 *----------------------------------------------------------------------
850 UpdateTimeEachSecond()
853 LARGE_INTEGER curPerfCounter;
854 /* Current value returned from
855 * QueryPerformanceCounter */
857 FILETIME curSysTime; /* Current system time */
859 LARGE_INTEGER curFileTime; /* File time at the time this callback
862 Tcl_WideInt estFreq; /* Estimated perf counter frequency */
864 Tcl_WideInt vt0; /* Tcl time right now */
865 Tcl_WideInt vt1; /* Tcl time one second from now */
867 Tcl_WideInt tdiff; /* Difference between system clock and
870 Tcl_WideInt driftFreq; /* Frequency needed to drift virtual time
871 * into step over 1 second */
874 * Sample performance counter and system time.
877 QueryPerformanceCounter( &curPerfCounter );
878 GetSystemTimeAsFileTime( &curSysTime );
879 curFileTime.LowPart = curSysTime.dwLowDateTime;
880 curFileTime.HighPart = curSysTime.dwHighDateTime;
882 EnterCriticalSection( &timeInfo.cs );
885 * Several things may have gone wrong here that have to
887 * (1) The performance counter may have jumped.
888 * (2) The system clock may have been reset.
890 * In either case, we'll need to reinitialize the circular buffer
891 * with samples relative to the current system time and the NOMINAL
892 * performance frequency (not the actual, because the actual has
893 * probably run slow in the first case). Our estimated frequency
894 * will be the nominal frequency.
898 * Store the current sample into the circular buffer of samples,
899 * and estimate the performance counter frequency.
902 estFreq = AccumulateSample( curPerfCounter.QuadPart,
903 (Tcl_WideUInt) curFileTime.QuadPart );
906 * We want to adjust things so that time appears to be continuous.
907 * Virtual file time, right now, is
909 * vt0 = 10000000 * ( curPerfCounter - perfCounterLastCall )
913 * Ideally, we would like to drift the clock into place over a
914 * period of 2 sec, so that virtual time 2 sec from now will be
916 * vt1 = 20000000 + curFileTime
918 * The frequency that we need to use to drift the counter back into
919 * place is estFreq * 20000000 / ( vt1 - vt0 )
922 vt0 = 10000000 * ( curPerfCounter.QuadPart
923 - timeInfo.perfCounterLastCall.QuadPart )
924 / timeInfo.curCounterFreq.QuadPart
925 + timeInfo.fileTimeLastCall.QuadPart;
926 vt1 = 20000000 + curFileTime.QuadPart;
929 * If we've gotten more than a second away from system time,
930 * then drifting the clock is going to be pretty hopeless.
931 * Just let it jump. Otherwise, compute the drift frequency and
932 * fill in everything.
935 tdiff = vt0 - curFileTime.QuadPart;
936 if ( tdiff > 10000000 || tdiff < -10000000 ) {
937 timeInfo.fileTimeLastCall.QuadPart = curFileTime.QuadPart;
938 timeInfo.curCounterFreq.QuadPart = estFreq;
940 driftFreq = estFreq * 20000000 / ( vt1 - vt0 );
941 if ( driftFreq > 1003 * estFreq / 1000 ) {
942 driftFreq = 1003 * estFreq / 1000;
944 if ( driftFreq < 997 * estFreq / 1000 ) {
945 driftFreq = 997 * estFreq / 1000;
947 timeInfo.fileTimeLastCall.QuadPart = vt0;
948 timeInfo.curCounterFreq.QuadPart = driftFreq;
951 timeInfo.perfCounterLastCall.QuadPart = curPerfCounter.QuadPart;
953 LeaveCriticalSection( &timeInfo.cs );
958 *----------------------------------------------------------------------
960 * ResetCounterSamples --
962 * Fills the sample arrays in 'timeInfo' with dummy values that will
963 * yield the current performance counter and frequency.
969 * The array of samples is filled in so that it appears that there
970 * are SAMPLES samples at one-second intervals, separated by precisely
971 * the given frequency.
973 *----------------------------------------------------------------------
977 ResetCounterSamples( Tcl_WideUInt fileTime,
978 /* Current file time */
979 Tcl_WideInt perfCounter,
980 /* Current performance counter */
981 Tcl_WideInt perfFreq )
982 /* Target performance frequency */
985 for ( i = SAMPLES-1; i >= 0; --i ) {
986 timeInfo.perfCounterSample[i] = perfCounter;
987 timeInfo.fileTimeSample[i] = fileTime;
988 perfCounter -= perfFreq;
989 fileTime -= 10000000;
991 timeInfo.sampleNo = 0;
995 *----------------------------------------------------------------------
997 * AccumulateSample --
999 * Updates the circular buffer of performance counter and system
1000 * time samples with a new data point.
1006 * The new data point replaces the oldest point in the circular
1007 * buffer, and the descriptive statistics are updated to accumulate
1010 * Several things may have gone wrong here that have to
1012 * (1) The performance counter may have jumped.
1013 * (2) The system clock may have been reset.
1015 * In either case, we'll need to reinitialize the circular buffer
1016 * with samples relative to the current system time and the NOMINAL
1017 * performance frequency (not the actual, because the actual has
1018 * probably run slow in the first case).
1022 AccumulateSample( Tcl_WideInt perfCounter,
1023 Tcl_WideUInt fileTime )
1025 Tcl_WideUInt workFTSample; /* File time sample being removed
1026 * from or added to the circular buffer */
1028 Tcl_WideInt workPCSample; /* Performance counter sample being
1029 * removed from or added to the circular
1032 Tcl_WideUInt lastFTSample; /* Last file time sample recorded */
1034 Tcl_WideInt lastPCSample; /* Last performance counter sample recorded */
1036 Tcl_WideInt FTdiff; /* Difference between last FT and current */
1038 Tcl_WideInt PCdiff; /* Difference between last PC and current */
1040 Tcl_WideInt estFreq; /* Estimated performance counter frequency */
1042 /* Test for jumps and reset the samples if we have one. */
1044 if ( timeInfo.sampleNo == 0 ) {
1045 lastPCSample = timeInfo.perfCounterSample[ timeInfo.sampleNo
1047 lastFTSample = timeInfo.fileTimeSample[ timeInfo.sampleNo
1050 lastPCSample = timeInfo.perfCounterSample[ timeInfo.sampleNo - 1 ];
1051 lastFTSample = timeInfo.fileTimeSample[ timeInfo.sampleNo - 1 ];
1053 PCdiff = perfCounter - lastPCSample;
1054 FTdiff = fileTime - lastFTSample;
1055 if ( PCdiff < timeInfo.nominalFreq.QuadPart * 9 / 10
1056 || PCdiff > timeInfo.nominalFreq.QuadPart * 11 / 10
1058 || FTdiff > 11000000 ) {
1059 ResetCounterSamples( fileTime, perfCounter,
1060 timeInfo.nominalFreq.QuadPart );
1061 return timeInfo.nominalFreq.QuadPart;
1065 /* Estimate the frequency */
1067 workPCSample = timeInfo.perfCounterSample[ timeInfo.sampleNo ];
1068 workFTSample = timeInfo.fileTimeSample[ timeInfo.sampleNo ];
1069 estFreq = 10000000 * ( perfCounter - workPCSample )
1070 / ( fileTime - workFTSample );
1071 timeInfo.perfCounterSample[ timeInfo.sampleNo ] = perfCounter;
1072 timeInfo.fileTimeSample[ timeInfo.sampleNo ] = (Tcl_WideInt) fileTime;
1074 /* Advance the sample number */
1076 if ( ++timeInfo.sampleNo >= SAMPLES ) {
1077 timeInfo.sampleNo = 0;
1085 *----------------------------------------------------------------------
1089 * Wrapper around the 'gmtime' library function to make it thread
1093 * Returns a pointer to a 'struct tm' in thread-specific data.
1096 * Invokes gmtime or gmtime_r as appropriate.
1098 *----------------------------------------------------------------------
1103 TclpTime_t_CONST tt;
1105 CONST time_t *timePtr = (CONST time_t *) tt;
1106 /* Pointer to the number of seconds
1107 * since the local system's epoch */
1109 * The MS implementation of gmtime is thread safe because
1110 * it returns the time in a block of thread-local storage,
1111 * and Windows does not provide a Posix gmtime_r function.
1113 return gmtime( timePtr );
1117 *----------------------------------------------------------------------
1121 * Wrapper around the 'localtime' library function to make it thread
1125 * Returns a pointer to a 'struct tm' in thread-specific data.
1128 * Invokes localtime or localtime_r as appropriate.
1130 *----------------------------------------------------------------------
1135 TclpTime_t_CONST tt;
1137 CONST time_t *timePtr = (CONST time_t *) tt;
1138 /* Pointer to the number of seconds
1139 * since the local system's epoch */
1142 * The MS implementation of localtime is thread safe because
1143 * it returns the time in a block of thread-local storage,
1144 * and Windows does not provide a Posix localtime_r function.
1146 return localtime( timePtr );