Attachment "atip302.diff" to
ticket [3328635fff]
added by
chw
2016-09-25 18:59:51.
checkout: 572fd312681328ff1c2afc1f1e3e534dbbbcfb5f 2016-09-21 09:20:54 UTC
parent: 8924992522eb54095e55327fdbd5133cb226020f 2016-09-16 09:06:41 UTC
merged-from: a26067b252cb123a230c428635750001ab229eea 2016-09-21 09:15:34 UTC
merged-into: d22d2fc5be904fad860f188f05e2aa4135d2e1f5 2016-09-21 09:36:35 UTC
merged-into: 8ac9a69b51726f3e3f71d12d22dc4ee3ccbc4b9d 2016-09-21 09:28:39 UTC
leaf: open
tags: core-8-6-branch
comment: Make it more likely that compiles with VS2012/VS2013 actually
work on Windows XP. See:
[https://tedwvc.wordpress.com/2014/01/01/how-to-target-xp-with-
vc2012-or-vc2013-and-continue-to-use-the-windows-8-x-sdk/]
(user: jan.nijtmans)
Index: generic/tclCmdMZ.c
==================================================================
--- generic/tclCmdMZ.c
+++ generic/tclCmdMZ.c
@@ -4139,11 +4139,11 @@
}
objPtr = objv[1];
i = count;
#ifndef TCL_WIDE_CLICKS
- Tcl_GetTime(&start);
+ TclpGetMonotonicTime(&start);
#else
start = TclpGetWideClicks();
#endif
while (i-- > 0) {
result = Tcl_EvalObjEx(interp, objPtr, 0);
@@ -4150,11 +4150,11 @@
if (result != TCL_OK) {
return result;
}
}
#ifndef TCL_WIDE_CLICKS
- Tcl_GetTime(&stop);
+ TclpGetMonotonicTime(&stop);
totalMicroSec = ((double) (stop.sec - start.sec)) * 1.0e6
+ (stop.usec - start.usec);
#else
stop = TclpGetWideClicks();
totalMicroSec = ((double) TclpWideClicksToNanoseconds(stop - start))/1.0e3;
Index: generic/tclInt.h
==================================================================
--- generic/tclInt.h
+++ generic/tclInt.h
@@ -3159,10 +3159,11 @@
MODULE_SCOPE void TclpThreadDeleteKey(void *keyPtr);
MODULE_SCOPE void TclpThreadSetMasterTSD(void *tsdKeyPtr, void *ptr);
MODULE_SCOPE void * TclpThreadGetMasterTSD(void *tsdKeyPtr);
MODULE_SCOPE void TclErrorStackResetIf(Tcl_Interp *interp, const char *msg, int length);
+MODULE_SCOPE int TclpGetMonotonicTime(Tcl_Time *timePtr);
/*
*----------------------------------------------------------------
* Command procedures in the generic core:
*----------------------------------------------------------------
Index: generic/tclInterp.c
==================================================================
--- generic/tclInterp.c
+++ generic/tclInterp.c
@@ -3391,11 +3391,11 @@
if ((iPtr->limit.active & TCL_LIMIT_TIME) &&
((iPtr->limit.timeGranularity == 1) ||
(ticker % iPtr->limit.timeGranularity == 0))) {
Tcl_Time now;
- Tcl_GetTime(&now);
+ TclpGetMonotonicTime(&now);
if (iPtr->limit.time.sec < now.sec ||
(iPtr->limit.time.sec == now.sec &&
iPtr->limit.time.usec < now.usec)) {
iPtr->limit.exceeded |= TCL_LIMIT_TIME;
Tcl_Preserve(interp);
@@ -3946,11 +3946,29 @@
Tcl_LimitSetTime(
Tcl_Interp *interp,
Tcl_Time *timeLimitPtr)
{
Interp *iPtr = (Interp *) interp;
- Tcl_Time nextMoment;
+ Tcl_Time nextMoment, mono, real, limit;
+
+ if (TclpGetMonotonicTime(&mono)) {
+ Tcl_GetTime(&real);
+ limit = *timeLimitPtr;
+ limit.sec -= real.sec;
+ limit.usec -= real.usec;
+ if (limit.usec < 0) {
+ limit.sec -= 1;
+ limit.usec += 1000000;
+ }
+ limit.sec += mono.sec;
+ limit.usec += mono.usec;
+ if (limit.usec >= 1000000) {
+ limit.sec += 1;
+ limit.usec -= 1000000;
+ }
+ timeLimitPtr = &limit;
+ }
memcpy(&iPtr->limit.time, timeLimitPtr, sizeof(Tcl_Time));
if (iPtr->limit.timeEvent != NULL) {
Tcl_DeleteTimerHandler(iPtr->limit.timeEvent);
}
@@ -4031,11 +4049,30 @@
Tcl_LimitGetTime(
Tcl_Interp *interp,
Tcl_Time *timeLimitPtr)
{
Interp *iPtr = (Interp *) interp;
+ Tcl_Time mono, real, limit;
+ if (TclpGetMonotonicTime(&mono)) {
+ Tcl_GetTime(&real);
+ limit = iPtr->limit.time;
+ limit.sec -= mono.sec;
+ limit.usec -= mono.usec;
+ if (limit.usec < 0) {
+ limit.sec -= 1;
+ limit.usec += 1000000;
+ }
+ limit.sec += real.sec;
+ limit.usec += real.usec;
+ if (limit.usec >= 1000000) {
+ limit.sec += 1;
+ limit.usec -= 1000000;
+ }
+ memcpy(timeLimitPtr, &limit, sizeof(Tcl_Time));
+ return;
+ }
memcpy(timeLimitPtr, &iPtr->limit.time, sizeof(Tcl_Time));
}
/*
*----------------------------------------------------------------------
Index: generic/tclTimer.c
==================================================================
--- generic/tclTimer.c
+++ generic/tclTimer.c
@@ -257,11 +257,11 @@
/*
* Compute when the event should fire.
*/
- Tcl_GetTime(&time);
+ TclpGetMonotonicTime(&time);
time.sec += milliseconds/1000;
time.usec += (milliseconds%1000)*1000;
if (time.usec >= 1000000) {
time.usec -= 1000000;
time.sec += 1;
@@ -415,11 +415,11 @@
} else if ((flags & TCL_TIMER_EVENTS) && tsdPtr->firstTimerHandlerPtr) {
/*
* Compute the timeout for the next timer on the list.
*/
- Tcl_GetTime(&blockTime);
+ TclpGetMonotonicTime(&blockTime);
blockTime.sec = tsdPtr->firstTimerHandlerPtr->time.sec - blockTime.sec;
blockTime.usec = tsdPtr->firstTimerHandlerPtr->time.usec -
blockTime.usec;
if (blockTime.usec < 0) {
blockTime.sec -= 1;
@@ -466,11 +466,11 @@
if ((flags & TCL_TIMER_EVENTS) && tsdPtr->firstTimerHandlerPtr) {
/*
* Compute the timeout for the next timer on the list.
*/
- Tcl_GetTime(&blockTime);
+ TclpGetMonotonicTime(&blockTime);
blockTime.sec = tsdPtr->firstTimerHandlerPtr->time.sec - blockTime.sec;
blockTime.usec = tsdPtr->firstTimerHandlerPtr->time.usec -
blockTime.usec;
if (blockTime.usec < 0) {
blockTime.sec -= 1;
@@ -562,11 +562,11 @@
* timers appearing before later ones.
*/
tsdPtr->timerPending = 0;
currentTimerId = tsdPtr->lastTimerId;
- Tcl_GetTime(&time);
+ TclpGetMonotonicTime(&time);
while (1) {
nextPtrPtr = &tsdPtr->firstTimerHandlerPtr;
timerHandlerPtr = tsdPtr->firstTimerHandlerPtr;
if (timerHandlerPtr == NULL) {
break;
@@ -870,11 +870,11 @@
* around when wrap-around occurs.
*/
afterPtr->id = tsdPtr->afterId;
tsdPtr->afterId += 1;
- Tcl_GetTime(&wakeup);
+ TclpGetMonotonicTime(&wakeup);
wakeup.sec += (long)(ms / 1000);
wakeup.usec += ((long)(ms % 1000)) * 1000;
if (wakeup.usec > 1000000) {
wakeup.sec++;
wakeup.usec -= 1000000;
@@ -1015,11 +1015,11 @@
Interp *iPtr = (Interp *) interp;
Tcl_Time endTime, now;
Tcl_WideInt diff;
- Tcl_GetTime(&now);
+ TclpGetMonotonicTime(&now);
endTime = now;
endTime.sec += (long)(ms/1000);
endTime.usec += ((int)(ms%1000))*1000;
if (endTime.usec >= 1000000) {
endTime.sec++;
@@ -1081,11 +1081,11 @@
}
if (Tcl_LimitCheck(interp) != TCL_OK) {
return TCL_ERROR;
}
}
- Tcl_GetTime(&now);
+ TclpGetMonotonicTime(&now);
} while (TCL_TIME_BEFORE(now, endTime));
return TCL_OK;
}
/*
Index: unix/configure
==================================================================
--- unix/configure
+++ unix/configure
@@ -4674,11 +4674,12 @@
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=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
echo "$as_me:$LINENO: checking for $ac_func" >&5
echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
if eval "test \"\${$as_ac_var+set}\" = set"; then
@@ -5761,10 +5762,182 @@
LIBS="$LIBS -lnsl"
fi
fi
+
+ echo "$as_me:$LINENO: checking for clock_gettime in -lrt" >&5
+echo $ECHO_N "checking for clock_gettime in -lrt... $ECHO_C" >&6
+if test "${ac_cv_lib_rt_clock_gettime+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lrt $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char clock_gettime ();
+int
+main ()
+{
+clock_gettime ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_rt_clock_gettime=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_rt_clock_gettime=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_rt_clock_gettime" >&5
+echo "${ECHO_T}$ac_cv_lib_rt_clock_gettime" >&6
+if test $ac_cv_lib_rt_clock_gettime = yes; then
+ LIBS="$LIBS -lrt"
+fi
+
+
+
+for ac_func in clock_gettime clock_nanosleep
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
# Add the threads support libraries
LIBS="$LIBS$THREADS_LIBS"
Index: unix/tcl.m4
==================================================================
--- unix/tcl.m4
+++ unix/tcl.m4
@@ -676,11 +676,11 @@
# Does the pthread-implementation provide
# 'pthread_attr_setstacksize' ?
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
fi
# Do checking message here to not mess up interleaved configure output
@@ -2537,10 +2537,13 @@
LIBS="$LIBS -lsocket -lnsl"
AC_CHECK_FUNC(accept, tcl_checkNsl=0, [LIBS=$tk_oldLibs])
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)
])
#--------------------------------------------------------------------
# SC_TCL_EARLY_FLAGS
#
Index: unix/tclConfig.h.in
==================================================================
--- unix/tclConfig.h.in
+++ unix/tclConfig.h.in
@@ -16,10 +16,13 @@
/* Defined when compiler supports casting to union type. */
#undef HAVE_CAST_TO_UNION
/* 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
/* Define to 1 if you have the <copyfile.h> header file. */
@@ -166,10 +169,13 @@
/* Define to 1 if you have the `pthread_atfork' function. */
#undef HAVE_PTHREAD_ATFORK
/* 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
/* Are characters signed? */
Index: unix/tclUnixChan.c
==================================================================
--- unix/tclUnixChan.c
+++ unix/tclUnixChan.c
@@ -1785,11 +1785,11 @@
* If there is a non-zero finite timeout, compute the time when we give
* up.
*/
if (timeout > 0) {
- Tcl_GetTime(&now);
+ TclpGetMonotonicTime(&now);
abortTime.sec = now.sec + timeout/1000;
abortTime.usec = now.usec + (timeout%1000)*1000;
if (abortTime.usec >= 1000000) {
abortTime.usec -= 1000000;
abortTime.sec += 1;
@@ -1874,11 +1874,11 @@
/*
* The select returned early, so we need to recompute the timeout.
*/
- Tcl_GetTime(&now);
+ TclpGetMonotonicTime(&now);
if ((abortTime.sec < now.sec)
|| (abortTime.sec==now.sec && abortTime.usec<=now.usec)) {
break;
}
}
Index: unix/tclUnixEvent.c
==================================================================
--- unix/tclUnixEvent.c
+++ unix/tclUnixEvent.c
@@ -40,11 +40,11 @@
* The only trick here is that select appears to return early under some
* conditions, so we have to check to make sure that the right amount of
* time really has elapsed. If it's too early, go back to sleep again.
*/
- Tcl_GetTime(&before);
+ TclpGetMonotonicTime(&before);
after = before;
after.sec += ms/1000;
after.usec += (ms%1000)*1000;
if (after.usec > 1000000) {
after.usec -= 1000000;
@@ -79,11 +79,11 @@
|| ((delay.tv_usec == 0) && (delay.tv_sec == 0))) {
break;
}
(void) select(0, (SELECT_MASK *) 0, (SELECT_MASK *) 0,
(SELECT_MASK *) 0, &delay);
- Tcl_GetTime(&before);
+ TclpGetMonotonicTime(&before);
}
}
#endif /* HAVE_COREFOUNDATION */
/*
Index: unix/tclUnixNotfy.c
==================================================================
--- unix/tclUnixNotfy.c
+++ unix/tclUnixNotfy.c
@@ -100,10 +100,13 @@
void *hwnd; /* Messaging window. */
#else /* !__CYGWIN__ */
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 useMonoTime; /* 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.
* Used as condition flag together with waitCV
* above. */
@@ -354,12 +357,29 @@
tsdPtr->hwnd = CreateWindowExW(NULL, class.lpszClassName,
class.lpszClassName, 0, 0, 0, 0, 0, NULL, NULL,
TclWinGetTclInstance(), NULL);
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->useMonoTime =
+ pthread_condattr_setclock(&attr, CLOCK_MONOTONIC) == 0;
+ if (tsdPtr->useMonoTime) {
+ if (pthread_cond_init(&tsdPtr->waitCV, &attr)) {
+ tsdPtr->useMonoTime = 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;
}
pthread_mutex_lock(¬ifierInitMutex);
@@ -997,20 +1017,33 @@
MsgWaitForMultipleObjects(1, &tsdPtr->event, 0, timeout, 1279);
pthread_mutex_lock(¬ifierMutex);
}
#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->useMonoTime) {
+ 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, ¬ifierMutex, &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, ¬ifierMutex, &ptime);
} else {
- pthread_cond_wait(&tsdPtr->waitCV, ¬ifierMutex);
+ pthread_cond_wait(&tsdPtr->waitCV, ¬ifierMutex);
}
#endif /* __CYGWIN__ */
}
tsdPtr->eventReady = 0;
Index: unix/tclUnixPort.h
==================================================================
--- unix/tclUnixPort.h
+++ unix/tclUnixPort.h
@@ -635,10 +635,30 @@
(__GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ > 2 || \
(__GNUC_MINOR__ == 2 && __GNUC_PATCHLEVEL__ > 0))))
# undef USE_VFORK
# endif /* __llvm__ */
#endif /* __APPLE__ */
+
+/*
+ *---------------------------------------------------------------------------
+ * 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
Index: unix/tclUnixThrd.c
==================================================================
--- unix/tclUnixThrd.c
+++ unix/tclUnixThrd.c
@@ -525,10 +525,13 @@
const Tcl_Time *timePtr) /* Timeout on waiting period */
{
pthread_cond_t *pcondPtr;
pthread_mutex_t *pmutexPtr;
struct timespec ptime;
+#if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_PTHREAD_CONDATTR_SETCLOCK)
+ int *monoFlagPtr;
+#endif
if (*condPtr == NULL) {
MASTER_LOCK;
/*
@@ -535,12 +538,30 @@
* Double check inside mutex to avoid race, then initialize condition
* variable if necessary.
*/
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));
+ monoFlagPtr = (int *) (pcondPtr + 1);
+ pthread_condattr_init(&attr);
+ *monoFlagPtr = (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC) == 0);
+ if (*monoFlagPtr) {
+ if (pthread_cond_init(pcondPtr, &attr)) {
+ *monoFlagPtr = 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);
}
MASTER_UNLOCK;
}
@@ -547,10 +568,17 @@
pmutexPtr = *((pthread_mutex_t **)mutexPtr);
pcondPtr = *((pthread_cond_t **)condPtr);
if (timePtr == NULL) {
pthread_cond_wait(pcondPtr, pmutexPtr);
} else {
+#if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_PTHREAD_CONDATTR_SETCLOCK)
+ monoFlagPtr = (int *) (pcondPtr + 1);
+ clock_gettime(*monoFlagPtr ? CLOCK_MONOTONIC : 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;
/*
* Make sure to take into account the microsecond component of the
* current time, including possible overflow situations. [Bug #411603]
@@ -558,10 +586,11 @@
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(pcondPtr, pmutexPtr, &ptime);
}
}
/*
Index: unix/tclUnixTime.c
==================================================================
--- unix/tclUnixTime.c
+++ unix/tclUnixTime.c
@@ -103,10 +103,16 @@
unsigned long
TclpGetClicks(void)
{
unsigned long now;
+#ifdef HAVE_CLOCK_GETTIME
+ Tcl_Time time;
+
+ TclpGetMonotonicTime(&time);
+ now = time.sec*1000000 + time.usec;
+#else
#ifdef NO_GETTOD
if (tclGetTimeProcPtr != NativeGetTime) {
Tcl_Time time;
tclGetTimeProcPtr(&time, tclTimeClientData);
@@ -122,10 +128,11 @@
#else
Tcl_Time time;
tclGetTimeProcPtr(&time, tclTimeClientData);
now = time.sec*1000000 + time.usec;
+#endif
#endif
return now;
}
#ifdef TCL_WIDE_CLICKS
@@ -374,13 +381,15 @@
Tcl_SetTimeProc(
Tcl_GetTimeProc *getProc,
Tcl_ScaleTimeProc *scaleProc,
ClientData clientData)
{
+#ifndef HAVE_CLOCK_GETTIME
tclGetTimeProcPtr = getProc;
tclScaleTimeProcPtr = scaleProc;
tclTimeClientData = clientData;
+#endif
}
/*
*----------------------------------------------------------------------
*
@@ -529,13 +538,65 @@
CleanupMemory(
ClientData ignored)
{
ckfree(lastTZ);
}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclpGetMononoticTime --
+ *
+ * Like Tcl_GetTime() but return a monotonic clock source,
+ * if possible. Otherwise fall back to real (wall clock) time.
+ *
+ * Results:
+ * 1 if monotonic, 0 otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TclpGetMonotonicTime(Tcl_Time *timePtr)
+{
+#ifdef HAVE_CLOCK_GETTIME
+ int ret;
+ struct timespec ts;
+ static int useMonoClock = -1;
+
+ if (useMonoClock) {
+ ret = (clock_gettime(CLOCK_MONOTONIC, &ts) == 0);
+ if (useMonoClock < 0) {
+ useMonoClock = ret;
+ if (!ret) {
+ (void) clock_gettime(CLOCK_REALTIME, &ts);
+ }
+ } else if (!ret) {
+ Tcl_Panic("clock_gettime(CLOCK_MONOTONIC) failed");
+ }
+ } else {
+ (void) clock_gettime(CLOCK_REALTIME, &ts);
+ ret = 0;
+ }
+ timePtr->sec = ts.tv_sec;
+ timePtr->usec = ts.tv_nsec / 1000;
+ return ret;
+#else
+ struct timeval tv;
+
+ (void) gettimeofday(&tv, NULL);
+ timePtr->sec = tv.tv_sec;
+ timePtr->usec = tv.tv_usec;
+ return 0;
+#endif
+}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
Index: win/configure
==================================================================
--- win/configure
+++ win/configure
@@ -851,10 +851,11 @@
Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--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 TIP #233
Some influential environment variables:
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
@@ -4405,10 +4406,27 @@
cat >>confdefs.h <<\_ACEOF
#define HAVE_ZLIB 1
_ACEOF
+
+# 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
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
echo $ECHO_N "(cached) $ECHO_C" >&6
Index: win/configure.in
==================================================================
--- win/configure.in
+++ win/configure.in
@@ -139,10 +139,19 @@
])
], [
AC_SUBST(ZLIB_OBJS,[\${ZLIB_OBJS}])
])
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 TIP #233]),
+ [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, [
for tcl_cv_intptr_t in "int" "long" "long long" none; do
Index: win/tclWinInit.c
==================================================================
--- win/tclWinInit.c
+++ win/tclWinInit.c
@@ -105,10 +105,19 @@
static ProcessGlobalValue sourceLibraryDir =
{0, 0, NULL, NULL, InitializeSourceLibraryDir, NULL, NULL};
static void AppendEnvironment(Tcl_Obj *listPtr, const char *lib);
static int ToUtf(const WCHAR *wSrc, char *dst);
+
+#ifdef WIN32_USE_TICKCOUNT
+typedef ULONGLONG WINAPI (GetTickCount64Proc)(void);
+static GetTickCount64Proc *GetTickCount64ProcPtr = NULL;
+static CRITICAL_SECTION TickMutex;
+static DWORD TickOffset, LastTick;
+static ULONGLONG TickUpper;
+#endif
+
/*
*---------------------------------------------------------------------------
*
* TclpInitPlatform --
@@ -130,18 +139,44 @@
void
TclpInitPlatform(void)
{
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(2, 2);
+#ifdef WIN32_USE_TICKCOUNT
+ HMODULE handle;
+#endif
tclPlatform = TCL_PLATFORM_WINDOWS;
/*
* Initialize the winsock library. On Windows XP and higher this
* can never fail.
*/
WSAStartup(wVersionRequested, &wsaData);
+
+#ifdef WIN32_USE_TICKCOUNT
+ /*
+ * Check for availability of the GetTickCount64() API.
+ */
+
+ handle = GetModuleHandleA("KERNEL32");
+ if (handle != NULL) {
+ GetTickCount64ProcPtr = (GetTickCount64Proc *)
+ GetProcAddress(handle, "GetTickCount64");
+ }
+
+ InitializeCriticalSection(&TickMutex);
+
+ /*
+ * Force a wrap around within the first few seconds when
+ * we need to fall back to GetTickCount(), e.g. on XP.
+ */
+
+ TickOffset = 0xffffe000 - GetTickCount();
+ LastTick = TickOffset;
+ TickUpper = 0;
+#endif
#ifdef STATIC_BUILD
/*
* If we are in a statically linked executable, then we need to explicitly
* initialize the Windows function tables here since DllMain() will not be
@@ -709,13 +744,62 @@
done:
Tcl_DStringFree(&envString);
ckfree(nameUpper);
return result;
}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclpGetMononoticTime --
+ *
+ * Like Tcl_GetTime() but return a monotonic clock source,
+ * if possible. Otherwise fall back to real (wall clock) time.
+ *
+ * Results:
+ * 1 if monotonic, 0 otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TclpGetMonotonicTime(Tcl_Time *timePtr)
+{
+#ifdef WIN32_USE_TICKCOUNT
+ ULONGLONG ms;
+ DWORD tick;
+
+ if (GetTickCount64ProcPtr != NULL) {
+ ms = GetTickCount64ProcPtr();
+ } else {
+ /*
+ * Emulate 64 bit wide tick counter, e.g. on XP.
+ */
+
+ EnterCriticalSection(&TickMutex);
+ tick = GetTickCount() + TickOffset;
+ if ((LastTick & 0x80000000) && !(tick & 0x80000000)) {
+ TickUpper += 0x100000000ULL;
+ }
+ LastTick = tick;
+ ms = TickUpper | LastTick;
+ LeaveCriticalSection(&TickMutex);
+ }
+ timePtr->sec = (long)(ms/1000);
+ timePtr->usec = ((long)(ms%1000))*1000;
+ return 1;
+#else
+ Tcl_GetTime(timePtr);
+ return 0;
+#endif
+}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
Index: win/tclWinNotify.c
==================================================================
--- win/tclWinNotify.c
+++ win/tclWinNotify.c
@@ -443,10 +443,16 @@
/*
* Compute the timeout in milliseconds.
*/
if (timePtr) {
+#ifdef 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.
*/
@@ -458,10 +464,11 @@
if (myTime.sec != 0 || myTime.usec != 0) {
tclScaleTimeProcPtr(&myTime, tclTimeClientData);
}
timeout = myTime.sec * 1000 + myTime.usec / 1000;
+#endif
} else {
timeout = INFINITE;
}
/*
@@ -565,11 +572,11 @@
DWORD sleepTime; /* Time to sleep, real-time */
vdelay.sec = ms / 1000;
vdelay.usec = (ms % 1000) * 1000;
- Tcl_GetTime(&now);
+ TclpGetMonotonicTime(&now);
desired.sec = now.sec + vdelay.sec;
desired.usec = now.usec + vdelay.usec;
if (desired.usec > 1000000) {
++desired.sec;
desired.usec -= 1000000;
@@ -579,14 +586,17 @@
* TIP #233: Scale delay from virtual to real-time.
*/
tclScaleTimeProcPtr(&vdelay, tclTimeClientData);
sleepTime = vdelay.sec * 1000 + vdelay.usec / 1000;
+ if (sleepTime == INFINITE) {
+ --sleepTime;
+ }
for (;;) {
SleepEx(sleepTime, TRUE);
- Tcl_GetTime(&now);
+ TclpGetMonotonicTime(&now);
if (now.sec > desired.sec) {
break;
} else if ((now.sec == desired.sec) && (now.usec >= desired.usec)) {
break;
}
@@ -594,10 +604,13 @@
vdelay.sec = desired.sec - now.sec;
vdelay.usec = desired.usec - now.usec;
tclScaleTimeProcPtr(&vdelay, tclTimeClientData);
sleepTime = vdelay.sec * 1000 + vdelay.usec / 1000;
+ if (sleepTime == INFINITE) {
+ --sleepTime;
+ }
}
}
/*
* Local Variables:
Index: win/tclWinTime.c
==================================================================
--- win/tclWinTime.c
+++ win/tclWinTime.c
@@ -1116,13 +1116,15 @@
Tcl_SetTimeProc(
Tcl_GetTimeProc *getProc,
Tcl_ScaleTimeProc *scaleProc,
ClientData clientData)
{
+#ifndef WIN32_USE_TICKCOUNT
tclGetTimeProcPtr = getProc;
tclScaleTimeProcPtr = scaleProc;
tclTimeClientData = clientData;
+#endif
}
/*
*----------------------------------------------------------------------
*