summaryrefslogtreecommitdiffstats
path: root/unix
diff options
context:
space:
mode:
authorjan.nijtmans <nijtmans@users.sourceforge.net>2016-09-26 15:38:23 (GMT)
committerjan.nijtmans <nijtmans@users.sourceforge.net>2016-09-26 15:38:23 (GMT)
commit4be64948c96e8b037c13a0b2166ba37572ab6a2a (patch)
tree44b289ba647c1797b19ba9faef5d103df37d4a7c /unix
parent848a94dd3acbd7420103354f2d6773e8e7f077a7 (diff)
parent2a21b737eaf5db0eb26712dae12203c3c75fbd42 (diff)
downloadtcl-4be64948c96e8b037c13a0b2166ba37572ab6a2a.zip
tcl-4be64948c96e8b037c13a0b2166ba37572ab6a2a.tar.gz
tcl-4be64948c96e8b037c13a0b2166ba37572ab6a2a.tar.bz2
Merge core-8-6-branch. upstream androwish modifications.
Diffstat (limited to 'unix')
-rwxr-xr-xunix/configure175
-rw-r--r--unix/tcl.m45
-rw-r--r--unix/tclConfig.h.in6
-rw-r--r--unix/tclUnixChan.c4
-rw-r--r--unix/tclUnixEvent.c4
-rw-r--r--unix/tclUnixNotfy.c47
-rw-r--r--unix/tclUnixPort.h35
-rw-r--r--unix/tclUnixThrd.c119
-rw-r--r--unix/tclUnixTime.c61
9 files changed, 443 insertions, 13 deletions
diff --git a/unix/configure b/unix/configure
index 835988e..d3bdfbc 100755
--- a/unix/configure
+++ b/unix/configure
@@ -5327,7 +5327,8 @@ $as_echo "$as_me: WARNING: Don't know how to find pthread lib on your system - y
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`
{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5
@@ -6383,6 +6384,178 @@ fi
fi
+ { $as_echo "$as_me:$LINENO: checking for clock_gettime in -lrt" >&5
+$as_echo_n "checking for clock_gettime in -lrt... " >&6; }
+if test "${ac_cv_lib_rt_clock_gettime+set}" = set; then
+ $as_echo_n "(cached) " >&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 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
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_test_x conftest$ac_exeext
+ }; then
+ ac_cv_lib_rt_clock_gettime=yes
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_lib_rt_clock_gettime=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$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" = x""yes; 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`
+{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5
+$as_echo_n "checking for $ac_func... " >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+ $as_echo_n "(cached) " >&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 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 $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
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_test_x conftest$ac_exeext
+ }; then
+ eval "$as_ac_var=yes"
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ eval "$as_ac_var=no"
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval 'as_val=${'$as_ac_var'}
+ $as_echo "$as_val"'`
+ { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+as_val=`eval 'as_val=${'$as_ac_var'}
+ $as_echo "$as_val"'`
+ if test "x$as_val" = 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 57d8ff0..f27bc92 100644
--- 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,9 @@ 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
--- 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..f0320be 100644
--- a/unix/tclUnixChan.c
+++ b/unix/tclUnixChan.c
@@ -1787,7 +1787,7 @@ TclUnixWaitForFile(
*/
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) {
@@ -1876,7 +1876,7 @@ TclUnixWaitForFile(
* 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;
diff --git a/unix/tclUnixEvent.c b/unix/tclUnixEvent.c
index 40aac6f..f7b675b 100644
--- a/unix/tclUnixEvent.c
+++ b/unix/tclUnixEvent.c
@@ -42,7 +42,7 @@ Tcl_Sleep(
* 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;
@@ -81,7 +81,7 @@ Tcl_Sleep(
}
(void) select(0, (SELECT_MASK *) 0, (SELECT_MASK *) 0,
(SELECT_MASK *) 0, &delay);
- Tcl_GetTime(&before);
+ TclpGetMonotonicTime(&before);
}
}
diff --git a/unix/tclUnixNotfy.c b/unix/tclUnixNotfy.c
index 21706bf..1211440 100644
--- 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 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.
@@ -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->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;
}
@@ -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->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__ */
}
diff --git a/unix/tclUnixPort.h b/unix/tclUnixPort.h
index 2728957..995280f 100644
--- a/unix/tclUnixPort.h
+++ b/unix/tclUnixPort.h
@@ -640,6 +640,26 @@ 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.
@@ -713,6 +733,21 @@ extern struct hostent * TclpGetHostByAddr(const char *addr,
int length, int type);
extern void *TclpMakeTcpClientChannelMode(
void *tcpSocket, int mode);
+
+#ifdef ANDROID
+/*
+ *---------------------------------------------------------------------------
+ * Working around varying Android API levels.
+ *---------------------------------------------------------------------------
+ */
+
+#define pthread_condattr_setclock TclpCondattrSetclock
+#define pthread_cond_timedwait TclpCondTimedwait
+
+extern int TclpCondattrSetclock(const pthread_condattr_t *, clockid_t);
+extern int TclpCondTimedwait(pthread_cond_t *, pthread_mutex_t *,
+ struct timespec *);
+#endif
#endif /* _TCLUNIXPORT */
diff --git a/unix/tclUnixThrd.c b/unix/tclUnixThrd.c
index 9074a3a..e873cd2 100644
--- a/unix/tclUnixThrd.c
+++ b/unix/tclUnixThrd.c
@@ -527,6 +527,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 *monoFlagPtr;
+#endif
if (*condPtr == NULL) {
MASTER_LOCK;
@@ -537,8 +540,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));
+ 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);
}
@@ -549,6 +570,13 @@ Tcl_ConditionWait(
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;
/*
@@ -560,6 +588,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);
}
}
@@ -813,6 +842,96 @@ TclpThreadGetMasterTSD(
}
#endif /* TCL_THREADS */
+
+
+#ifdef ANDROID
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclpCondattrSetClock, TclpCondTimedwait --
+ *
+ * Replacements for pthread_condattr_setclock() and
+ * pthread_cond_timedwait() on Android due to varying support
+ * depending on API level. Deals with the cases:
+ *
+ * - API<21 has no pthread_condattr_setclock() but could have support
+ * for pthread_cond_timedwait_monotonic_np().
+ *
+ * - API>=21 has pthread_condattr_setclock() and doesn't require to
+ * use pthread_cond_timedwait_monotonic_np() since
+ * pthread_cond_timedwait() should deal with CLOCK_MONOTONIC cleanly.
+ *
+ * This can be resolved only by runtime linking libc.so and
+ * using dlsym() to find out which pthread functions are available.
+ *
+ *----------------------------------------------------------------------
+ */
+
+#include <dlfcn.h>
+
+typedef int (CondattrSetclockProc)(
+ const pthread_condattr_t *attrPtr,
+ clockid_t clkid);
+
+typedef int (CondTimedwaitProc)(
+ pthread_cond_t *condPtr,
+ pthread_mutex_t *mutexPtr,
+ struct timespec *tsPtr);
+
+static CondattrSetclockProc *condattrSetclockProc = NULL;
+static CondTimedwaitProc *condTimedwaitMonotonicNpProc = NULL;
+static CondTimedwaitProc *condTimedwaitProc = NULL;
+
+int TclpCondattrSetclock(
+ const pthread_condattr_t *attrPtr,
+ clockid_t clkid)
+{
+ if (condattrSetclockProc == NULL) {
+ void *libc = dlopen("libc.so", RTLD_NOW | RTLD_GLOBAL);
+
+ if (libc == NULL) {
+ /* no way to continue, thus ... */
+ Tcl_Panic("could not dlopen libc.so");
+ }
+ condTimedwaitProc = (CondTimedwaitProc *)
+ dlsym(libc, "pthread_cond_timedwait");
+ condattrSetclockProc = (CondattrSetclockProc *)
+ dlsym(libc, "pthread_condattr_setclock");
+ if (condattrSetclockProc != NULL) {
+ condTimedwaitMonotonicNpProc = (CondTimedwaitProc *) -1;
+ } else {
+ condTimedwaitMonotonicNpProc = (CondTimedwaitProc *)
+ dlsym(libc, "pthread_cond_timedwait_monotonic_np");
+ if (condTimedwaitMonotonicNpProc == NULL) {
+ condTimedwaitMonotonicNpProc = (CondTimedwaitProc *) -1;
+ }
+ condattrSetclockProc = (CondattrSetclockProc *) -1;
+ }
+ dlclose(libc);
+ }
+ if (condattrSetclockProc != (CondattrSetclockProc *) -1) {
+ return condattrSetclockProc(attrPtr, clkid);
+ }
+ if (condTimedwaitMonotonicNpProc != (CondTimedwaitProc *) -1) {
+ return 0;
+ }
+ return EINVAL;
+}
+
+int TclpCondTimedwait(
+ pthread_cond_t *condPtr,
+ pthread_mutex_t *mutexPtr,
+ struct timespec *tsPtr)
+{
+ if ((condTimedwaitMonotonicNpProc != NULL) &&
+ (condTimedwaitMonotonicNpProc != (CondTimedwaitProc *) -1)) {
+ return condTimedwaitMonotonicNpProc(condPtr, mutexPtr, tsPtr);
+ }
+ return condTimedwaitProc(condPtr, mutexPtr, tsPtr);
+}
+
+#endif
+
/*
* Local Variables:
diff --git a/unix/tclUnixTime.c b/unix/tclUnixTime.c
index 315bcf9..a983ea2 100644
--- a/unix/tclUnixTime.c
+++ b/unix/tclUnixTime.c
@@ -105,6 +105,12 @@ 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;
@@ -125,6 +131,7 @@ TclpGetClicks(void)
tclGetTimeProcPtr(&time, tclTimeClientData);
now = time.sec*1000000 + time.usec;
#endif
+#endif
return now;
}
@@ -376,9 +383,11 @@ Tcl_SetTimeProc(
Tcl_ScaleTimeProc *scaleProc,
ClientData clientData)
{
+#ifndef HAVE_CLOCK_GETTIME
tclGetTimeProcPtr = getProc;
tclScaleTimeProcPtr = scaleProc;
tclTimeClientData = clientData;
+#endif
}
/*
@@ -533,6 +542,58 @@ CleanupMemory(
}
/*
+ *----------------------------------------------------------------------
+ *
+ * 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