Tcl Source Code

Artifact [7d7e13e353]
Login

Artifact 7d7e13e3535b098d0fcb7dbc555f31ea2b426fc0:

Attachment "atip302.diff" to ticket [3328635fff] added by chw 2016-09-25 18:59:51. (unpublished)
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(&notifierInitMutex);
@@ -997,20 +1017,33 @@
 		MsgWaitForMultipleObjects(1, &tsdPtr->event, 0, timeout, 1279);
 		pthread_mutex_lock(&notifierMutex);
 	    }
 #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, &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__ */
 	}
 	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
 }
 
 /*
  *----------------------------------------------------------------------
  *