summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoroehhar <harald.oehlmann@elmicron.de>2016-03-30 20:03:21 (GMT)
committeroehhar <harald.oehlmann@elmicron.de>2016-03-30 20:03:21 (GMT)
commitd54d3f124b4a7f2e781821ab9dfc3a7a9e7e299e (patch)
tree4670cd37f5937aaed3fdab8fecdc7d3fe1cb2ffd
parent77ccaefbb1482145de9b9276979318e88b9e542e (diff)
downloadtcl-d54d3f124b4a7f2e781821ab9dfc3a7a9e7e299e.zip
tcl-d54d3f124b4a7f2e781821ab9dfc3a7a9e7e299e.tar.gz
tcl-d54d3f124b4a7f2e781821ab9dfc3a7a9e7e299e.tar.bz2
The following patch against a stock tcl 8.6.5 source tree tries to
implement most of TIP #302 for UN*X and WIN32/64: * use clock_gettime(CLOCK_MONOTONIC) for relative timing (UN*X) when available (tested at runtime) * use PTHREAD_CONDATTR_SETCLOCK et.al. for pthread_cond (UN*X) when available (tested at runtime) * use GetTickCount64() for relative timing (WIN64) * use GetTickCount() for relative timing (WIN32 for WINNT<6.0) * configure (UN*X) detects availabilty of clock_gettime() and pthread_condattr_setclock() plus adds optional -lrt to LIBS * configure (WIN32) adds command line option --with-tickcount to turn on GetTickCount*() usage Trade-off: implementation eliminates virtualized time, unfortunately. Best regards, Christian Werner --- missing merge --- diff -ur tcl8.6.5-orig/win/configure.in tcl8.6.5/win/configure.in --- tcl8.6.5-orig/win/configure.in 2016-02-29 20:13:09.000000000 +0100 +++ tcl8.6.5/win/configure.in 2016-03-25 06:47:47.712516747 +0100 @@ -142,6 +142,15 @@ ]) AC_DEFINE(HAVE_ZLIB, 1, [Is there an installed zlib?]) +AC_ARG_WITH(tickcount, + AC_HELP_STRING([--with-tickcount], + [use GetTickCount for timers, turns off interp time limits]), + [tcl_ok=$withval], [tcl_ok=no]) +AC_MSG_RESULT([$tcl_ok]) +if test $tcl_ok = yes; then + AC_DEFINE(WIN32_USE_TICKCOUNT, 1, [Use GetTickCount for timers?]) +fi + AC_CHECK_TYPE([intptr_t], [ AC_DEFINE([HAVE_INTPTR_T], 1, [Do we have the intptr_t type?])], [ AC_CACHE_CHECK([for pointer-size signed integer type], tcl_cv_intptr_t, [
-rwxr-xr-x[-rw-r--r--]generic/tclCmdMZ.c43
-rwxr-xr-x[-rw-r--r--]generic/tclInterp.c26
-rwxr-xr-x[-rw-r--r--]generic/tclTimer.c251
-rwxr-xr-xunix/configure55
-rwxr-xr-x[-rw-r--r--]unix/tcl.m44
-rwxr-xr-x[-rw-r--r--]unix/tclConfig.h.in6
-rwxr-xr-x[-rw-r--r--]unix/tclUnixChan.c21
-rwxr-xr-x[-rw-r--r--]unix/tclUnixEvent.c18
-rwxr-xr-x[-rw-r--r--]unix/tclUnixNotfy.c47
-rwxr-xr-x[-rw-r--r--]unix/tclUnixPort.h19
-rwxr-xr-x[-rw-r--r--]unix/tclUnixThrd.c33
-rwxr-xr-x[-rw-r--r--]unix/tclUnixTime.c11
-rwxr-xr-xwin/configure28
-rwxr-xr-x[-rw-r--r--]win/tclWinNotify.c48
-rwxr-xr-x[-rw-r--r--]win/tclWinTime.c13
15 files changed, 610 insertions, 13 deletions
diff --git a/generic/tclCmdMZ.c b/generic/tclCmdMZ.c
index 13f9e7d..4c83b80 100644..100755
--- a/generic/tclCmdMZ.c
+++ b/generic/tclCmdMZ.c
@@ -4124,11 +4124,24 @@ Tcl_TimeObjCmd(
register int i, result;
int count;
double totalMicroSec;
+#ifdef WIN32_USE_TICKCOUNT
+#if (_WIN32_WINNT >= 0x0600)
+ ULONGLONG start, stop;
+#else
+ DWORD start, stop;
+#endif
+#else
+#ifdef HAVE_CLOCK_GETTIME
+ int monoClock = 1;
+ struct timespec start, stop;
+#else
#ifndef TCL_WIDE_CLICKS
Tcl_Time start, stop;
#else
Tcl_WideInt start, stop;
#endif
+#endif
+#endif
if (objc == 2) {
count = 1;
@@ -4144,17 +4157,45 @@ Tcl_TimeObjCmd(
objPtr = objv[1];
i = count;
+#ifdef WIN32_USE_TICKCOUNT
+#if (_WIN32_WINNT >= 0x0600)
+ start = GetTickCount64();
+#else
+ start = GetTickCount();
+#endif
+#else
+#ifdef HAVE_CLOCK_GETTIME
+ if (clock_gettime(CLOCK_MONOTONIC, &start) == -1) {
+ clock_gettime(CLOCK_REALTIME, &start);
+ monoClock = 0;
+ }
+#else
#ifndef TCL_WIDE_CLICKS
Tcl_GetTime(&start);
#else
start = TclpGetWideClicks();
#endif
+#endif
+#endif
while (i-- > 0) {
result = Tcl_EvalObjEx(interp, objPtr, 0);
if (result != TCL_OK) {
return result;
}
}
+#ifdef WIN32_USE_TICKCOUNT
+#if (_WIN32_WINNT >= 0x0600)
+ stop = GetTickCount64();
+#else
+ stop = GetTickCount();
+#endif
+ totalMicroSec = (stop - start) * 1000.0;
+#else
+#ifdef HAVE_CLOCK_GETTIME
+ clock_gettime(monoClock ? CLOCK_MONOTONIC : CLOCK_REALTIME, &stop);
+ totalMicroSec = ((double) (stop.tv_sec - start.tv_sec)) * 1.0e6
+ + (stop.tv_nsec - start.tv_nsec) / 1000.0;
+#else
#ifndef TCL_WIDE_CLICKS
Tcl_GetTime(&stop);
totalMicroSec = ((double) (stop.sec - start.sec)) * 1.0e6
@@ -4163,6 +4204,8 @@ Tcl_TimeObjCmd(
stop = TclpGetWideClicks();
totalMicroSec = ((double) TclpWideClicksToNanoseconds(stop - start))/1.0e3;
#endif
+#endif
+#endif
if (count <= 1) {
/*
diff --git a/generic/tclInterp.c b/generic/tclInterp.c
index cd0dc18..f7dfa3a 100644..100755
--- a/generic/tclInterp.c
+++ b/generic/tclInterp.c
@@ -3416,8 +3416,24 @@ Tcl_LimitCheck(
((iPtr->limit.timeGranularity == 1) ||
(ticker % iPtr->limit.timeGranularity == 0))) {
Tcl_Time now;
+#if (_WIN32_WINNT >= 0x0600) && defined(WIN32_USE_TICKCOUNT)
+ ULONGLONG ticks = GetTickCount64();
+ now.sec = ticks / 1000;
+ now.usec = (ticks % 1000) * 1000;
+#else
+#ifdef HAVE_CLOCK_GETTIME
+ struct timespec ts;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) {
+ clock_gettime(CLOCK_REALTIME, &ts);
+ }
+ now.sec = ts.tv_sec;
+ now.usec = ts.tv_nsec * 1000;
+#else
Tcl_GetTime(&now);
+#endif
+#endif
if (iPtr->limit.time.sec < now.sec ||
(iPtr->limit.time.sec == now.sec &&
iPtr->limit.time.usec < now.usec)) {
@@ -3858,6 +3874,12 @@ Tcl_LimitTypeSet(
int type)
{
Interp *iPtr = (Interp *) interp;
+#if (_WIN32_WINNT < 0x0600) && defined(WIN32_USE_TICKCOUNT)
+ if (type == TCL_LIMIT_TIME) {
+ /* not implemented for _WIN32 */
+ return;
+ }
+#endif
iPtr->limit.active |= type;
}
@@ -4382,12 +4404,16 @@ InheritLimitsFromMaster(
slavePtr->limit.cmdCount = 0;
slavePtr->limit.cmdGranularity = masterPtr->limit.cmdGranularity;
}
+#if (_WIN32_WINNT < 0x0600) && defined(WIN32_USE_TICKCOUNT)
+ /* not implemented for _WIN32 */
+#else
if (masterPtr->limit.active & TCL_LIMIT_TIME) {
slavePtr->limit.active |= TCL_LIMIT_TIME;
memcpy(&slavePtr->limit.time, &masterPtr->limit.time,
sizeof(Tcl_Time));
slavePtr->limit.timeGranularity = masterPtr->limit.timeGranularity;
}
+#endif
}
/*
diff --git a/generic/tclTimer.c b/generic/tclTimer.c
index c10986a..9fa013f 100644..100755
--- a/generic/tclTimer.c
+++ b/generic/tclTimer.c
@@ -259,7 +259,33 @@ Tcl_CreateTimerHandler(
* Compute when the event should fire.
*/
+#ifdef WIN32_USE_TICKCOUNT
+#if (_WIN32_WINNT >= 0x0600)
+ ULONGLONG ticks = GetTickCount64();
+
+ time.sec = (long) ((ticks+milliseconds)/1000);
+ time.usec = (long) (((ticks+milliseconds)%1000)*1000);
+#else
+ if (milliseconds > 0x7FFFFFFF) {
+ milliseconds = 0x7FFFFFFF;
+ } else if (milliseconds < 0) {
+ milliseconds = 0;
+ }
+ time.sec = milliseconds + GetTickCount();
+ time.usec = 0;
+#endif
+#else
+#ifdef HAVE_CLOCK_GETTIME
+ struct timespec ts;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) {
+ clock_gettime(CLOCK_REALTIME, &ts);
+ }
+ time.sec = ts.tv_sec;
+ time.usec = ts.tv_nsec / 1000;
+#else
Tcl_GetTime(&time);
+#endif
time.sec += milliseconds/1000;
time.usec += (milliseconds%1000)*1000;
if (time.usec >= 1000000) {
@@ -316,9 +342,15 @@ TclCreateAbsoluteTimerHandler(
for (tPtr2 = tsdPtr->firstTimerHandlerPtr, prevPtr = NULL; tPtr2 != NULL;
prevPtr = tPtr2, tPtr2 = tPtr2->nextPtr) {
+#if (_WIN32_WINNT < 0x0600) && defined(WIN32_USE_TICKCOUNT)
+ if (timerHandlerPtr->time.sec - tPtr2->time.sec < 0) {
+ break;
+ }
+#else
if (TCL_TIME_BEFORE(timerHandlerPtr->time, tPtr2->time)) {
break;
}
+#endif
}
timerHandlerPtr->nextPtr = tPtr2;
if (prevPtr == NULL) {
@@ -417,7 +449,46 @@ TimerSetupProc(
* Compute the timeout for the next timer on the list.
*/
+#ifdef WIN32_USE_TICKCOUNT
+#if (_WIN32_WINNT >= 0x0600)
+ ULONGLONG ticks = GetTickCount64();
+
+ blockTime.sec = (long)
+ ((ULONGLONG) tsdPtr->firstTimerHandlerPtr->time.sec -
+ (ticks / 1000));
+ blockTime.usec = (long)
+ ((ULONGLONG) tsdPtr->firstTimerHandlerPtr->time.usec -
+ (ticks % 1000) * 1000);
+ if (blockTime.usec < 0) {
+ blockTime.sec -= 1;
+ blockTime.usec += 1000000;
+ }
+ if (blockTime.sec < 0) {
+ blockTime.sec = 0;
+ blockTime.usec = 0;
+ }
+#else
+ blockTime.sec = tsdPtr->firstTimerHandlerPtr->time.sec - GetTickCount();
+ if (blockTime.sec <= 0) {
+ blockTime.sec = 0;
+ blockTime.usec = 0;
+ } else {
+ blockTime.usec = (blockTime.sec % 1000) * 1000;
+ blockTime.sec /= 1000;
+ }
+#endif
+#else
+#ifdef HAVE_CLOCK_GETTIME
+ struct timespec ts;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) {
+ clock_gettime(CLOCK_REALTIME, &ts);
+ }
+ blockTime.sec = ts.tv_sec;
+ blockTime.usec = ts.tv_nsec / 1000;
+#else
Tcl_GetTime(&blockTime);
+#endif
blockTime.sec = tsdPtr->firstTimerHandlerPtr->time.sec - blockTime.sec;
blockTime.usec = tsdPtr->firstTimerHandlerPtr->time.usec -
blockTime.usec;
@@ -429,6 +500,7 @@ TimerSetupProc(
blockTime.sec = 0;
blockTime.usec = 0;
}
+#endif
} else {
return;
}
@@ -468,7 +540,46 @@ TimerCheckProc(
* Compute the timeout for the next timer on the list.
*/
+#ifdef WIN32_USE_TICKCOUNT
+#if (_WIN32_WINNT >= 0x0600)
+ ULONGLONG ticks = GetTickCount64();
+
+ blockTime.sec = (long)
+ ((ULONGLONG) tsdPtr->firstTimerHandlerPtr->time.sec -
+ (ticks / 1000));
+ blockTime.usec = (long)
+ ((ULONGLONG) tsdPtr->firstTimerHandlerPtr->time.usec -
+ (ticks % 1000) * 1000);
+ if (blockTime.usec < 0) {
+ blockTime.sec -= 1;
+ blockTime.usec += 1000000;
+ }
+ if (blockTime.sec < 0) {
+ blockTime.sec = 0;
+ blockTime.usec = 0;
+ }
+#else
+ blockTime.sec = tsdPtr->firstTimerHandlerPtr->time.sec - GetTickCount();
+ if (blockTime.sec <= 0) {
+ blockTime.sec = 0;
+ blockTime.usec = 0;
+ } else {
+ blockTime.usec = (blockTime.sec % 1000) * 1000;
+ blockTime.sec /= 1000;
+ }
+#endif
+#else
+#ifdef HAVE_CLOCK_GETTIME
+ struct timespec ts;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) {
+ clock_gettime(CLOCK_REALTIME, &ts);
+ }
+ blockTime.sec = ts.tv_sec;
+ blockTime.usec = ts.tv_nsec / 1000;
+#else
Tcl_GetTime(&blockTime);
+#endif
blockTime.sec = tsdPtr->firstTimerHandlerPtr->time.sec - blockTime.sec;
blockTime.usec = tsdPtr->firstTimerHandlerPtr->time.usec -
blockTime.usec;
@@ -480,6 +591,7 @@ TimerCheckProc(
blockTime.sec = 0;
blockTime.usec = 0;
}
+#endif
/*
* If the first timer has expired, stick an event on the queue.
@@ -526,6 +638,12 @@ TimerHandlerEventProc(
Tcl_Time time;
int currentTimerId;
ThreadSpecificData *tsdPtr = InitTimer();
+#ifdef HAVE_CLOCK_GETTIME
+ struct timespec ts;
+#endif
+#if (_WIN32_WINNT >= 0x0600) && defined(WIN32_USE_TICKCOUNT)
+ ULONGLONG ticks;
+#endif
/*
* Do nothing if timers aren't enabled. This leaves the event on the
@@ -564,7 +682,26 @@ TimerHandlerEventProc(
tsdPtr->timerPending = 0;
currentTimerId = tsdPtr->lastTimerId;
+#ifdef WIN32_USE_TICKCOUNT
+#if (_WIN32_WINNT >= 0x0600)
+ ticks = GetTickCount64();
+ time.sec = ticks / 1000;
+ time.usec = (ticks % 1000) * 1000;
+#else
+ time.sec = GetTickCount();
+ time.usec = 0;
+#endif
+#else
+#ifdef HAVE_CLOCK_GETTIME
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) {
+ clock_gettime(CLOCK_REALTIME, &ts);
+ }
+ time.sec = ts.tv_sec;
+ time.usec = ts.tv_nsec / 1000;
+#else
Tcl_GetTime(&time);
+#endif
+#endif
while (1) {
nextPtrPtr = &tsdPtr->firstTimerHandlerPtr;
timerHandlerPtr = tsdPtr->firstTimerHandlerPtr;
@@ -572,10 +709,16 @@ TimerHandlerEventProc(
break;
}
+#if (_WIN32_WINNT < 0x0600) && defined(WIN32_USE_TICKCOUNT)
+ if (time.sec - timerHandlerPtr->time.sec < 0) {
+ break;
+ }
+#else
if (TCL_TIME_BEFORE(time, timerHandlerPtr->time)) {
break;
}
+#endif
/*
* Bail out if the next timer is of a newer generation.
*/
@@ -845,6 +988,13 @@ Tcl_AfterObjCmd(
switch (index) {
case -1: {
+#ifdef HAVE_CLOCK_GETTIME
+ struct timespec ts;
+#endif
+#if (_WIN32_WINNT >= 0x0600) && defined(WIN32_USE_TICKCOUNT)
+ ULONGLONG ticks;
+#endif
+
if (ms < 0) {
ms = 0;
}
@@ -872,13 +1022,43 @@ Tcl_AfterObjCmd(
afterPtr->id = tsdPtr->afterId;
tsdPtr->afterId += 1;
++#ifdef WIN32_USE_TICKCOUNT
++#if (_WIN32_WINNT >= 0x0600)
++ ticks = GetTickCount64();
++ wakeup.sec = ticks / 1000;
++ wakeup.usec = (ticks % 1000) * 1000;
++ wakeup.sec += (long)(ms / 1000);
++ wakeup.usec += ((long)(ms % 1000)) * 1000;
++ if (wakeup.usec > 1000000) {
++ wakeup.sec++;
++ wakeup.usec -= 1000000;
++ }
+#else
+ if (ms > 0x7FFFFFFF) {
+ ms = 0x7FFFFFFF;
+ } else if (ms < 0) {
+ ms = 0;
+ }
+ wakeup.sec = ms + GetTickCount();
+ wakeup.usec = 0;
+#endif
+#else
+#ifdef HAVE_CLOCK_GETTIME
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) {
+ clock_gettime(CLOCK_REALTIME, &ts);
+ }
+ wakeup.sec = ts.tv_sec;
+ wakeup.usec = ts.tv_nsec / 1000;
+#else
Tcl_GetTime(&wakeup);
+#endif
wakeup.sec += (long)(ms / 1000);
wakeup.usec += ((long)(ms % 1000)) * 1000;
if (wakeup.usec > 1000000) {
wakeup.sec++;
wakeup.usec -= 1000000;
}
+#endif
afterPtr->token = TclCreateAbsoluteTimerHandler(&wakeup,
AfterProc, afterPtr);
afterPtr->nextPtr = assocPtr->firstAfterPtr;
@@ -1012,12 +1192,49 @@ AfterDelay(
Tcl_Interp *interp,
Tcl_WideInt ms)
{
+ Tcl_Time endTime, now;
+#ifdef WIN32_USE_TICKCOUNT
+#if (_WIN32_WINNT >= 0x0600)
Interp *iPtr = (Interp *) interp;
+ ULONGLONG ticks = GetTickCount64();
+ Tcl_WideInt diff;
- Tcl_Time endTime, now;
+ now.sec = ticks/1000;
+ now.usec = (ticks%1000)*1000;
+ endTime = now;
+ endTime.sec += (long)(ms/1000);
+ endTime.usec += ((int)(ms%1000))*1000;
+ if (endTime.usec >= 1000000) {
+ endTime.sec++;
+ endTime.usec -= 1000000;
+ }
+#else
+ int diff;
+
+ now.sec = GetTickCount();
+ now.usec = 0;
+ if (ms > 0x7FFFFFFF) {
+ ms = 0x7FFFFFFF;
+ } else if (ms < 0) {
+ ms = 0;
+ }
+ endTime.sec = now.sec + ms;
+ endTime.usec = 0;
+#endif
+#else
+ Interp *iPtr = (Interp *) interp;
Tcl_WideInt diff;
+#ifdef HAVE_CLOCK_GETTIME
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) {
+ clock_gettime(CLOCK_REALTIME, &ts);
+ }
+ now.sec = ts.tv_sec;
+ now.usec = ts.tv_nsec/1000;
+#else
Tcl_GetTime(&now);
+#endif
endTime = now;
endTime.sec += (long)(ms/1000);
endTime.usec += ((int)(ms%1000))*1000;
@@ -1025,6 +1242,7 @@ AfterDelay(
endTime.sec++;
endTime.usec -= 1000000;
}
+#endif
do {
if (Tcl_AsyncReady()) {
@@ -1035,6 +1253,15 @@ AfterDelay(
if (Tcl_Canceled(interp, TCL_LEAVE_ERR_MSG) == TCL_ERROR) {
return TCL_ERROR;
}
+#if (_WIN32_WINNT < 0x0600) && defined(WIN32_USE_TICKCOUNT)
+ diff = endTime.sec - now.sec;
+ if (diff > 0) {
+ Tcl_Sleep((long) diff);
+ } else {
+ break;
+ }
+ now.sec = GetTickCount();
+#else
if (iPtr->limit.timeEvent != NULL
&& TCL_TIME_BEFORE(iPtr->limit.time, now)) {
iPtr->limit.granularityTicker = 0;
@@ -1083,8 +1310,28 @@ AfterDelay(
return TCL_ERROR;
}
}
+#if (_WIN32_WINNT >= 0x0600) && defined(WIN32_USE_TICKCOUNT)
+ ticks = GetTickCount64();
+ now.sec = ticks / 1000;
+ now.usec = (ticks % 1000) * 1000;
+#else
+#ifdef HAVE_CLOCK_GETTIME
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) {
+ clock_gettime(CLOCK_REALTIME, &ts);
+ }
+ now.sec = ts.tv_sec;
+ now.usec = ts.tv_nsec / 1000;
+#else
Tcl_GetTime(&now);
- } while (TCL_TIME_BEFORE(now, endTime));
+#endif
+#endif
+#endif
+ }
+#if (_WIN32_WINNT < 0x0600) && defined(WIN32_USE_TICKCOUNT)
+ while (now.sec - endTime.sec < 0);
+#else
+ while (TCL_TIME_BEFORE(now, endTime));
+#endif
return TCL_OK;
}
diff --git a/unix/configure b/unix/configure
index e999455..068503c 100755
--- a/unix/configure
+++ b/unix/configure
@@ -4209,7 +4209,7 @@ $as_echo "$as_me: WARNING: Don't know how to find pthread lib on your system - y
ac_saved_libs=$LIBS
LIBS="$LIBS $THREADS_LIBS"
- for ac_func in pthread_attr_setstacksize pthread_atfork
+ for ac_func in pthread_attr_setstacksize pthread_atfork pthread_condattr_setclock
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
@@ -4509,6 +4509,59 @@ fi
fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5
+$as_echo_n "checking for clock_gettime in -lrt... " >&6; }
+if ${ac_cv_lib_rt_clock_gettime+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lrt $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char clock_gettime ();
+int
+main ()
+{
+return clock_gettime ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_rt_clock_gettime=yes
+else
+ ac_cv_lib_rt_clock_gettime=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5
+$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; }
+if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then :
+ LIBS="$LIBS -lrt"
+fi
+
+ for ac_func in clock_gettime clock_nanosleep
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
# Add the threads support libraries
LIBS="$LIBS$THREADS_LIBS"
diff --git a/unix/tcl.m4 b/unix/tcl.m4
index f5aa84e..ff0237c 100644..100755
--- a/unix/tcl.m4
+++ b/unix/tcl.m4
@@ -678,7 +678,7 @@ AC_DEFUN([SC_ENABLE_THREADS], [
ac_saved_libs=$LIBS
LIBS="$LIBS $THREADS_LIBS"
- AC_CHECK_FUNCS(pthread_attr_setstacksize pthread_atfork)
+ AC_CHECK_FUNCS(pthread_attr_setstacksize pthread_atfork pthread_condattr_setclock)
LIBS=$ac_saved_libs
else
TCL_THREADS=0
@@ -2539,6 +2539,8 @@ AC_DEFUN([SC_TCL_LINK_LIBS], [
fi
AC_CHECK_FUNC(gethostbyname, , [AC_CHECK_LIB(nsl, gethostbyname,
[LIBS="$LIBS -lnsl"])])
+ AC_CHECK_LIB(rt, clock_gettime, [LIBS="$LIBS -lrt"])
+ AC_CHECK_FUNCS(clock_gettime clock_nanosleep)
])
#--------------------------------------------------------------------
diff --git a/unix/tclConfig.h.in b/unix/tclConfig.h.in
index a4ab3e5..6c2f47d 100644..100755
--- a/unix/tclConfig.h.in
+++ b/unix/tclConfig.h.in
@@ -19,6 +19,9 @@
/* Define to 1 if you have the `chflags' function. */
#undef HAVE_CHFLAGS
+/* Define to 1 if you have the `clock_gettime' function. */
+#undef HAVE_CLOCK_GETTIME
+
/* Define to 1 if you have the `copyfile' function. */
#undef HAVE_COPYFILE
@@ -169,6 +172,9 @@
/* Define to 1 if you have the `pthread_attr_setstacksize' function. */
#undef HAVE_PTHREAD_ATTR_SETSTACKSIZE
+/* Define to 1 if you have the `pthread_condattr_setclock' function. */
+#undef HAVE_PTHREAD_CONDATTR_SETCLOCK
+
/* Does putenv() copy strings or incorporate them by reference? */
#undef HAVE_PUTENV_THAT_COPIES
diff --git a/unix/tclUnixChan.c b/unix/tclUnixChan.c
index b4b2739..b253c16 100644..100755
--- a/unix/tclUnixChan.c
+++ b/unix/tclUnixChan.c
@@ -1763,12 +1763,16 @@ TclUnixWaitForFile(
* at all, and a value of -1 means wait
* forever. */
{
- Tcl_Time abortTime = {0, 0}, now; /* silence gcc 4 warning */
+ Tcl_Time abortTime = {0, 0}, now = { 0, 0 }; /* silence gcc 4 warning */
struct timeval blockTime, *timeoutPtr;
int numFound, result = 0;
fd_set readableMask;
fd_set writableMask;
fd_set exceptionMask;
+#ifdef HAVE_CLOCK_GETTIME
+ int monoClock = 1;
+ struct timespec ts;
+#endif
#ifndef _DARWIN_C_SOURCE
/*
@@ -1787,7 +1791,16 @@ TclUnixWaitForFile(
*/
if (timeout > 0) {
+#ifdef HAVE_CLOCK_GETTIME
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) {
+ clock_gettime(CLOCK_REALTIME, &ts);
+ monoClock = 0;
+ }
+ now.sec = ts.tv_sec;
+ now.usec = ts.tv_nsec / 1000;
+#else
Tcl_GetTime(&now);
+#endif
abortTime.sec = now.sec + timeout/1000;
abortTime.usec = now.usec + (timeout%1000)*1000;
if (abortTime.usec >= 1000000) {
@@ -1876,7 +1889,13 @@ TclUnixWaitForFile(
* The select returned early, so we need to recompute the timeout.
*/
+#ifdef HAVE_CLOCK_GETTIME
+ clock_gettime(monoClock ? CLOCK_MONOTONIC : CLOCK_REALTIME, &ts);
+ now.sec = ts.tv_sec;
+ now.usec = ts.tv_nsec / 1000;
+#else
Tcl_GetTime(&now);
+#endif
if ((abortTime.sec < now.sec)
|| (abortTime.sec==now.sec && abortTime.usec<=now.usec)) {
break;
diff --git a/unix/tclUnixEvent.c b/unix/tclUnixEvent.c
index 40aac6f..e31aef2 100644..100755
--- a/unix/tclUnixEvent.c
+++ b/unix/tclUnixEvent.c
@@ -42,7 +42,19 @@ Tcl_Sleep(
* time really has elapsed. If it's too early, go back to sleep again.
*/
+#ifdef HAVE_CLOCK_GETTIME
+ int monoClock = 1;
+ struct timespec ts;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) {
+ clock_gettime(CLOCK_REALTIME, &ts);
+ monoClock = 0;
+ }
+ before.sec = ts.tv_sec;
+ before.usec = ts.tv_nsec / 1000;
+#else
Tcl_GetTime(&before);
+#endif
after = before;
after.sec += ms/1000;
after.usec += (ms%1000)*1000;
@@ -81,7 +93,13 @@ Tcl_Sleep(
}
(void) select(0, (SELECT_MASK *) 0, (SELECT_MASK *) 0,
(SELECT_MASK *) 0, &delay);
+#ifdef HAVE_CLOCK_GETTIME
+ clock_gettime(monoClock ? CLOCK_MONOTONIC : CLOCK_REALTIME, &ts);
+ before.sec = ts.tv_sec;
+ before.usec = ts.tv_nsec / 1000;
+#else
Tcl_GetTime(&before);
+#endif
}
}
diff --git a/unix/tclUnixNotfy.c b/unix/tclUnixNotfy.c
index 3422089..4fbad85 100644..100755
--- a/unix/tclUnixNotfy.c
+++ b/unix/tclUnixNotfy.c
@@ -100,6 +100,9 @@ typedef struct ThreadSpecificData {
pthread_cond_t waitCV; /* Any other thread alerts a notifier that an
* event is ready to be processed by signaling
* this condition variable. */
+#if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_PTHREAD_CONDATTR_SETCLOCK)
+ int monoClock; /* When true use CLOCK_MONOTONIC */
+#endif
#endif /* __CYGWIN__ */
int waitCVinitialized; /* Variable to flag initialization of the structure */
int eventReady; /* True if an event is ready to be processed.
@@ -353,7 +356,24 @@ Tcl_InitNotifier(void)
tsdPtr->event = CreateEventW(NULL, 1 /* manual */,
0 /* !signaled */, NULL);
#else
+#if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_PTHREAD_CONDATTR_SETCLOCK)
+ pthread_condattr_t attr;
+
+ pthread_condattr_init(&attr);
+ tsdPtr->monoClock =
+ pthread_condattr_setclock(&attr, CLOCK_MONOTONIC) == 0;
+ if (tsdPtr->monoClock) {
+ if (pthread_cond_init(&tsdPtr->waitCV, &attr)) {
+ tsdPtr->monoClock = 0;
+ pthread_cond_init(&tsdPtr->waitCV, NULL);
+ }
+ } else {
+ pthread_cond_init(&tsdPtr->waitCV, NULL);
+ }
+ pthread_condattr_destroy(&attr);
+#else
pthread_cond_init(&tsdPtr->waitCV, NULL);
+#endif
#endif /* __CYGWIN__ */
tsdPtr->waitCVinitialized = 1;
}
@@ -995,16 +1015,29 @@ Tcl_WaitForEvent(
}
#else
if (timePtr != NULL) {
- Tcl_Time now;
- struct timespec ptime;
+ struct timespec ptime;
- Tcl_GetTime(&now);
- ptime.tv_sec = timePtr->sec + now.sec + (timePtr->usec + now.usec) / 1000000;
- ptime.tv_nsec = 1000 * ((timePtr->usec + now.usec) % 1000000);
+#if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_PTHREAD_CONDATTR_SETCLOCK)
+ if (tsdPtr->monoClock) {
+ clock_gettime(CLOCK_MONOTONIC, &ptime);
+ } else {
+ clock_gettime(CLOCK_REALTIME, &ptime);
+ }
+ ptime.tv_sec += timePtr->sec +
+ (timePtr->usec * 1000 + ptime.tv_nsec) / 1000000000;
+ ptime.tv_nsec = (timePtr->usec * 1000 + ptime.tv_nsec) %
+ 1000000000;
+#else
+ Tcl_Time now;
- pthread_cond_timedwait(&tsdPtr->waitCV, &notifierMutex, &ptime);
+ Tcl_GetTime(&now);
+ ptime.tv_sec = timePtr->sec + now.sec +
+ (timePtr->usec + now.usec) / 1000000;
+ ptime.tv_nsec = 1000 * ((timePtr->usec + now.usec) % 1000000);
+#endif
+ pthread_cond_timedwait(&tsdPtr->waitCV, &notifierMutex, &ptime);
} else {
- pthread_cond_wait(&tsdPtr->waitCV, &notifierMutex);
+ pthread_cond_wait(&tsdPtr->waitCV, &notifierMutex);
}
#endif /* __CYGWIN__ */
}
diff --git a/unix/tclUnixPort.h b/unix/tclUnixPort.h
index 2728957..8429690 100644..100755
--- a/unix/tclUnixPort.h
+++ b/unix/tclUnixPort.h
@@ -640,6 +640,25 @@ extern char ** environ;
/*
*---------------------------------------------------------------------------
+ * Use clock_gettime() only if _POSIX_MONOTONIC_CLOCK present.
+ *---------------------------------------------------------------------------
+ */
+
+#if defined(HAVE_CLOCK_GETTIME) && !defined(_POSIX_MONOTONIC_CLOCK)
+# undef HAVE_CLOCK_GETTIME
+#endif
+
+#ifdef TCL_THREADS
+# ifndef HAVE_CLOCK_GETTIME
+# undef HAVE_PTHREAD_CONDATTR_SETCLOCK
+# endif
+# ifndef HAVE_PTHREAD_CONDATTR_SETCLOCK
+# undef HAVE_CLOCK_GETTIME
+# endif
+#endif
+
+/*
+ *---------------------------------------------------------------------------
* The following macros and declarations represent the interface between
* generic and unix-specific parts of Tcl. Some of the macros may override
* functions declared in tclInt.h.
diff --git a/unix/tclUnixThrd.c b/unix/tclUnixThrd.c
index 554a2dc..90ac379 100644..100755
--- a/unix/tclUnixThrd.c
+++ b/unix/tclUnixThrd.c
@@ -520,6 +520,9 @@ Tcl_ConditionWait(
pthread_cond_t *pcondPtr;
pthread_mutex_t *pmutexPtr;
struct timespec ptime;
+#if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_PTHREAD_CONDATTR_SETCLOCK)
+ int *flagPtr;
+#endif
if (*condPtr == NULL) {
pthread_mutex_lock(&masterLock);
@@ -530,8 +533,26 @@ Tcl_ConditionWait(
*/
if (*condPtr == NULL) {
+#if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_PTHREAD_CONDATTR_SETCLOCK)
+ pthread_condattr_t attr;
+
+ pcondPtr = ckalloc(sizeof(pthread_cond_t) + sizeof(int));
+ flagPtr = (int *) (pcondPtr + 1);
+ pthread_condattr_init(&attr);
+ *flagPtr = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC) == 0;
+ if (*flagPtr) {
+ if (pthread_cond_init(pcondPtr, &attr)) {
+ *flagPtr = 0;
+ pthread_cond_init(pcondPtr, NULL);
+ }
+ } else {
+ pthread_cond_init(pcondPtr, NULL);
+ }
+ pthread_condattr_destroy(&attr);
+#else
pcondPtr = ckalloc(sizeof(pthread_cond_t));
pthread_cond_init(pcondPtr, NULL);
+#endif
*condPtr = (Tcl_Condition) pcondPtr;
TclRememberCondition(condPtr);
}
@@ -542,6 +563,17 @@ Tcl_ConditionWait(
if (timePtr == NULL) {
pthread_cond_wait(pcondPtr, pmutexPtr);
} else {
+#if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_PTHREAD_CONDATTR_SETCLOCK)
+ flagPtr = (int *) (pcondPtr + 1);
+ if (*flagPtr) {
+ clock_gettime(CLOCK_MONOTONIC, &ptime);
+ } else {
+ clock_gettime(CLOCK_REALTIME, &ptime);
+ }
+ ptime.tv_sec += timePtr->sec +
+ (timePtr->usec * 1000 + ptime.tv_nsec) / 1000000000;
+ ptime.tv_nsec = (timePtr->usec * 1000 + ptime.tv_nsec) % 1000000000;
+#else
Tcl_Time now;
/*
@@ -553,6 +585,7 @@ Tcl_ConditionWait(
ptime.tv_sec = timePtr->sec + now.sec +
(timePtr->usec + now.usec) / 1000000;
ptime.tv_nsec = 1000 * ((timePtr->usec + now.usec) % 1000000);
+#endif
pthread_cond_timedwait(pcondPtr, pmutexPtr, &ptime);
}
}
diff --git a/unix/tclUnixTime.c b/unix/tclUnixTime.c
index 315bcf9..a98856d 100644..100755
--- a/unix/tclUnixTime.c
+++ b/unix/tclUnixTime.c
@@ -105,6 +105,14 @@ TclpGetClicks(void)
{
unsigned long now;
+#ifdef HAVE_CLOCK_GETTIME
+ struct timespec ts;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) {
+ clock_gettime(CLOCK_REALTIME, &ts);
+ }
+ now = ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
+#else
#ifdef NO_GETTOD
if (tclGetTimeProcPtr != NativeGetTime) {
Tcl_Time time;
@@ -125,6 +133,7 @@ TclpGetClicks(void)
tclGetTimeProcPtr(&time, tclTimeClientData);
now = time.sec*1000000 + time.usec;
#endif
+#endif
return now;
}
@@ -376,9 +385,11 @@ Tcl_SetTimeProc(
Tcl_ScaleTimeProc *scaleProc,
ClientData clientData)
{
+#ifndef HAVE_CLOCK_GETTIME
tclGetTimeProcPtr = getProc;
tclScaleTimeProcPtr = scaleProc;
tclTimeClientData = clientData;
+#endif
}
/*
diff --git a/win/configure b/win/configure
index 73d6d9f..bc14c2a 100755
--- a/win/configure
+++ b/win/configure
@@ -1401,6 +1401,8 @@ Optional Packages:
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--with-encoding encoding for configuration values
--with-celib=DIR use Windows/CE support library from DIR
+ --with-tickcount use GetTickCount for timers, turns off interp time
+ limits
Some influential environment variables:
CC C compiler command
@@ -4673,6 +4675,32 @@ case ${host_alias} in
;;
esac
+# *** HaO 2016-03-30 this may be at the wrong place.
+# *** should be in Line 4410 betwen
+# _ACEOF
+# and
+# echo "$as_me:$LINENO: checking for intptr_t" >&5
+# echo $ECHO_N "checking for intptr_t... $ECHO_C" >&6
+# if test "${ac_cv_type_intptr_t+set}" = set; then
+
+# Check whether --with-tickcount or --without-tickcount was given.
+if test "${with_tickcount+set}" = set; then
+ withval="$with_tickcount"
+ tcl_ok=$withval
+else
+ tcl_ok=no
+fi;
+echo "$as_me:$LINENO: result: $tcl_ok" >&5
+echo "${ECHO_T}$tcl_ok" >&6
+if test $tcl_ok = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define WIN32_USE_TICKCOUNT 1
+_ACEOF
+
+fi
+
+
#------------------------------------------------------------------------
# Add stuff for zlib; note that this is mostly done in the makefile now
# as we just assume that the platform hasn't got a usable z.lib
diff --git a/win/tclWinNotify.c b/win/tclWinNotify.c
index ea4035b..209d8a6 100644..100755
--- a/win/tclWinNotify.c
+++ b/win/tclWinNotify.c
@@ -445,6 +445,12 @@ Tcl_WaitForEvent(
*/
if (timePtr) {
+#if (_WIN32_WINNT < 0x0600) && defined(WIN32_USE_TICKCOUNT)
+ timeout = timePtr->sec * 1000 + timePtr->usec / 1000;
+ if (timeout == INFINITE) {
+ timeout--;
+ }
+#else
/*
* TIP #233 (Virtualized Time). Convert virtual domain delay to
* real-time.
@@ -460,6 +466,7 @@ Tcl_WaitForEvent(
}
timeout = myTime.sec * 1000 + myTime.usec / 1000;
+#endif
} else {
timeout = INFINITE;
}
@@ -548,6 +555,46 @@ void
Tcl_Sleep(
int ms) /* Number of milliseconds to sleep. */
{
+#ifdef WIN32_USE_TICKCOUNT
+#if (_WIN32_WINNT >= 0x0600)
+ ULONGLONG now; /* Current wall clock time. */
+ ULONGLONG desired; /* Desired wakeup time. */
+ ULONGLONG sleepTime;
+
+ now = GetTickCount64();
+#else
+ DWORD now; /* Current wall clock time. */
+ DWORD desired; /* Desired wakeup time. */
+ DWORD sleepTime;
+
+ now = GetTickCount();
+#endif
+
+ if (ms < 0) {
+ ms = 0;
+#if (_WIN32_WINNT < 0x0600)
+ } else if (ms > 0x7FFFFFFF) {
+ ms = 0x7FFFFFFF;
+#endif
+ }
+ desired = now + ms;
+ sleepTime = ms;
+ for (;;) {
+ SleepEx(sleepTime, TRUE);
+#if (_WIN32_WINNT >= 0x0600)
+ now = GetTickCount64();
+ if (now - desired >= 0) {
+ break;
+ }
+#else
+ now = GetTickCount();
+ if ((long) now - (long) desired >= 0) {
+ break;
+ }
+#endif
+ sleepTime = desired - now;
+ }
+#else
/*
* Simply calling 'Sleep' for the requisite number of milliseconds can
* make the process appear to wake up early because it isn't synchronized
@@ -597,6 +644,7 @@ Tcl_Sleep(
tclScaleTimeProcPtr(&vdelay, tclTimeClientData);
sleepTime = vdelay.sec * 1000 + vdelay.usec / 1000;
}
+#endif
}
/*
diff --git a/win/tclWinTime.c b/win/tclWinTime.c
index 7045c72..74d1770 100644..100755
--- a/win/tclWinTime.c
+++ b/win/tclWinTime.c
@@ -113,7 +113,7 @@ static TimeInfo timeInfo = {
* Declarations for functions defined later in this file.
*/
-static struct tm * ComputeGMT(const time_t *tp);
+#ifndef WIN32_USE_TICKCOUNT
static void StopCalibration(ClientData clientData);
static DWORD WINAPI CalibrationThread(LPVOID arg);
static void UpdateTimeEachSecond(void);
@@ -121,6 +121,7 @@ static void ResetCounterSamples(Tcl_WideUInt fileTime,
Tcl_WideInt perfCounter, Tcl_WideInt perfFreq);
static Tcl_WideInt AccumulateSample(Tcl_WideInt perfCounter,
Tcl_WideUInt fileTime);
+#endif
static void NativeScaleTime(Tcl_Time* timebuf,
ClientData clientData);
static void NativeGetTime(Tcl_Time* timebuf,
@@ -294,6 +295,9 @@ NativeGetTime(
if (!timeInfo.initialized) {
TclpInitLock();
if (!timeInfo.initialized) {
+#ifdef WIN32_USE_TICKCOUNT
+ timeInfo.perfCounterAvailable = 0;
+#else
timeInfo.perfCounterAvailable =
QueryPerformanceFrequency(&timeInfo.nominalFreq);
@@ -387,6 +391,7 @@ NativeGetTime(
CloseHandle(timeInfo.readyEvent);
Tcl_CreateExitHandler(StopCalibration, NULL);
}
+#endif /* !WIN32_USE_TICKCOUNT */
timeInfo.initialized = TRUE;
}
TclpInitUnlock();
@@ -452,6 +457,7 @@ NativeGetTime(
}
}
+#ifndef WIN32_USE_TICKCOUNT
/*
*----------------------------------------------------------------------
*
@@ -485,6 +491,7 @@ StopCalibration(
CloseHandle(timeInfo.exitEvent);
CloseHandle(timeInfo.calibrationThread);
}
+#endif /* !WIN32_USE_TICKCOUNT */
/*
*----------------------------------------------------------------------
@@ -707,6 +714,7 @@ ComputeGMT(
return tmPtr;
}
+#ifndef WIN32_USE_TICKCOUNT
/*
*----------------------------------------------------------------------
*
@@ -1033,6 +1041,7 @@ AccumulateSample(
return estFreq;
}
}
+#endif /* !WIN32_USE_TICKCOUNT */
/*
*----------------------------------------------------------------------
@@ -1118,9 +1127,11 @@ Tcl_SetTimeProc(
Tcl_ScaleTimeProc *scaleProc,
ClientData clientData)
{
+#if !defined(WIN32_USE_TICKCOUNT) || (_WIN32_WINNT >= 0x0600)
tclGetTimeProcPtr = getProc;
tclScaleTimeProcPtr = scaleProc;
tclTimeClientData = clientData;
+#endif
}
/*