diff options
author | jan.nijtmans <nijtmans@users.sourceforge.net> | 2016-09-26 15:38:23 (GMT) |
---|---|---|
committer | jan.nijtmans <nijtmans@users.sourceforge.net> | 2016-09-26 15:38:23 (GMT) |
commit | 4be64948c96e8b037c13a0b2166ba37572ab6a2a (patch) | |
tree | 44b289ba647c1797b19ba9faef5d103df37d4a7c /unix | |
parent | 848a94dd3acbd7420103354f2d6773e8e7f077a7 (diff) | |
parent | 2a21b737eaf5db0eb26712dae12203c3c75fbd42 (diff) | |
download | tcl-4be64948c96e8b037c13a0b2166ba37572ab6a2a.zip tcl-4be64948c96e8b037c13a0b2166ba37572ab6a2a.tar.gz tcl-4be64948c96e8b037c13a0b2166ba37572ab6a2a.tar.bz2 |
Merge core-8-6-branch. upstream androwish modifications.
Diffstat (limited to 'unix')
-rwxr-xr-x | unix/configure | 175 | ||||
-rw-r--r-- | unix/tcl.m4 | 5 | ||||
-rw-r--r-- | unix/tclConfig.h.in | 6 | ||||
-rw-r--r-- | unix/tclUnixChan.c | 4 | ||||
-rw-r--r-- | unix/tclUnixEvent.c | 4 | ||||
-rw-r--r-- | unix/tclUnixNotfy.c | 47 | ||||
-rw-r--r-- | unix/tclUnixPort.h | 35 | ||||
-rw-r--r-- | unix/tclUnixThrd.c | 119 | ||||
-rw-r--r-- | unix/tclUnixTime.c | 61 |
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, ¬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__ */ } 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 |