diff options
author | sebres <sebres@users.sourceforge.net> | 2017-01-02 14:31:22 (GMT) |
---|---|---|
committer | sebres <sebres@users.sourceforge.net> | 2017-01-02 14:31:22 (GMT) |
commit | b901129d9617508943f0a9e70ae6de14b10c8fec (patch) | |
tree | 8dd5d50d589afd40c0d90b93df4dae5c46d09ab0 | |
parent | be0289c6ab1c90cdc651dd4219d6566e68ff5d3e (diff) | |
download | tcl-b901129d9617508943f0a9e70ae6de14b10c8fec.zip tcl-b901129d9617508943f0a9e70ae6de14b10c8fec.tar.gz tcl-b901129d9617508943f0a9e70ae6de14b10c8fec.tar.bz2 |
[win] bug fix in NativeGetTime: each call of it blurs current performance counters actualized in calibration thread in UpdateTimeEachSecond;
This entails that sometimes sporadically time-drifts resp. jump-esque time-shifts occurred, what for example produces very confusing results during time measurement.
[unix] wrong cast fixed in TclpGetWideClicks: multiplication with 1000000 in long int may cause overflow
See ticket b87ad7e9146832d505f9a430d779c5313c440256
-rw-r--r-- | unix/tclUnixTime.c | 2 | ||||
-rw-r--r-- | win/tclWinTime.c | 54 |
2 files changed, 38 insertions, 18 deletions
diff --git a/unix/tclUnixTime.c b/unix/tclUnixTime.c index df759d8..d634449 100644 --- a/unix/tclUnixTime.c +++ b/unix/tclUnixTime.c @@ -158,7 +158,7 @@ TclpGetWideClicks(void) Tcl_Time time; tclGetTimeProcPtr(&time, tclTimeClientData); - now = (Tcl_WideInt) (time.sec*1000000 + time.usec); + now = ((Tcl_WideInt)time.sec)*1000000 + time.usec; } else { #ifdef MAC_OSX_TCL now = (Tcl_WideInt) (mach_absolute_time() & INT64_MAX); diff --git a/win/tclWinTime.c b/win/tclWinTime.c index 71a0366..8546c68 100644 --- a/win/tclWinTime.c +++ b/win/tclWinTime.c @@ -280,10 +280,6 @@ 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. */ - /* * Initialize static storage on the first trip through. * @@ -398,6 +394,10 @@ NativeGetTime( * time. */ + ULARGE_INTEGER fileTimeLastCall; + LARGE_INTEGER 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 @@ -411,9 +411,29 @@ NativeGetTime( posixEpoch.LowPart = 0xD53E8000; posixEpoch.HighPart = 0x019DB1DE; + QueryPerformanceCounter(&curCounter); + + /* + * Hold time section locked as short as possible + */ EnterCriticalSection(&timeInfo.cs); - QueryPerformanceCounter(&curCounter); + fileTimeLastCall.QuadPart = timeInfo.fileTimeLastCall.QuadPart; + perfCounterLastCall.QuadPart = timeInfo.perfCounterLastCall.QuadPart; + curCounterFreq.QuadPart = timeInfo.curCounterFreq.QuadPart; + + LeaveCriticalSection(&timeInfo.cs); + + /* + * If calibration cycle occurred after we get curCounter + */ + if (curCounter.QuadPart <= perfCounterLastCall.QuadPart) { + usecSincePosixEpoch = + (fileTimeLastCall.QuadPart - posixEpoch.QuadPart) / 10; + timePtr->sec = (long) (usecSincePosixEpoch / 1000000); + timePtr->usec = (unsigned long) (usecSincePosixEpoch % 1000000); + return; + } /* * If it appears to be more than 1.1 seconds since the last trip @@ -425,31 +445,31 @@ NativeGetTime( * 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); - timeInfo.fileTimeLastCall.QuadPart = curFileTime; - timeInfo.perfCounterLastCall.QuadPart = curCounter.QuadPart; + if (curCounter.QuadPart - perfCounterLastCall.QuadPart < + 11 * curCounterFreq.QuadPart / 10 + ) { + curFileTime = fileTimeLastCall.QuadPart + + ((curCounter.QuadPart - perfCounterLastCall.QuadPart) + * 10000000 / curCounterFreq.QuadPart); + usecSincePosixEpoch = (curFileTime - posixEpoch.QuadPart) / 10; timePtr->sec = (long) (usecSincePosixEpoch / 1000000); timePtr->usec = (unsigned long) (usecSincePosixEpoch % 1000000); - useFtime = 0; + return; } - - LeaveCriticalSection(&timeInfo.cs); } - if (useFtime) { + do { /* * High resolution timer is not available. Just use ftime. */ + struct _timeb t; _ftime(&t); timePtr->sec = (long)t.time; timePtr->usec = t.millitm * 1000; - } + + } while(0); } /* |