From b901129d9617508943f0a9e70ae6de14b10c8fec Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 2 Jan 2017 14:31:22 +0000 Subject: [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 --- unix/tclUnixTime.c | 2 +- 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); } /* -- cgit v0.12