From: Oliver Kurth Date: Fri, 15 Sep 2017 18:23:08 +0000 (-0700) Subject: Revert previous change. X-Git-Tag: stable-10.2.0~490 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=50a89b5ff8e3787f77f1c6122099d2eac89bbfde;p=thirdparty%2Fopen-vm-tools.git Revert previous change. --- diff --git a/open-vm-tools/lib/misc/hostinfoPosix.c b/open-vm-tools/lib/misc/hostinfoPosix.c index f4ac6c0f9..cb275d9af 100644 --- a/open-vm-tools/lib/misc/hostinfoPosix.c +++ b/open-vm-tools/lib/misc/hostinfoPosix.c @@ -1540,30 +1540,85 @@ Hostinfo_LogLoadAverage(void) } -#if __APPLE__ /* *----------------------------------------------------------------------------- * - * HostinfoSystemTimerMach -- + * HostinfoGetTimeOfDayMonotonic -- * - * Returns system time based on a monotonic, nanosecond-resolution, - * fast timer provided by the Mach kernel. Requires speed conversion - * so is non-trivial (but lockless). + * Return the system time as indicated by Hostinfo_GetTimeOfDay(), with + * locking to ensure monotonicity. + * + * Uses OS native locks as lib/lock is not available in lib/misc. This + * is safe because nothing occurs while locked that can be reentrant. + * + * Results: + * The time in microseconds is returned. Zero upon error. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +static VmTimeType +HostinfoGetTimeOfDayMonotonic(void) +{ + VmTimeType newTime; + VmTimeType curTime; + + static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + + static VmTimeType lastTimeBase; + static VmTimeType lastTimeRead; + static VmTimeType lastTimeReset; + + pthread_mutex_lock(&mutex); // Use native mechanism, just like Windows + + Hostinfo_GetTimeOfDay(&curTime); + + if (curTime == 0) { + newTime = 0; + goto exit; + } + + /* + * Don't let time be negative or go backward. We do this by tracking a + * base and moving forward from there. + */ + + newTime = lastTimeBase + (curTime - lastTimeReset); + + if (newTime < lastTimeRead) { + lastTimeReset = curTime; + lastTimeBase = lastTimeRead + 1; + newTime = lastTimeBase + (curTime - lastTimeReset); + } + + lastTimeRead = newTime; + +exit: + pthread_mutex_unlock(&mutex); + + return newTime; +} + + +/* + *----------------------------------------------------------------------------- * - * See also Apple TechNote QA1398. + * HostinfoSystemTimerMach -- + * HostinfoSystemTimerPosix -- * - * NOTE: on x86, macOS does TSC->ns conversion in the commpage - * for mach_absolute_time() to correct for speed-stepping, so x86 - * should always be 1:1 a.k.a. 'unity'. But as Apple has never - * documented this as a promise, retain the fallback... it is - * possible that when Apple drops support for processors where - * speed-stepping can vary TSC frequency, Apple may adjust the mapping. + * Returns system time based on a monotonic, nanosecond-resolution, + * fast timer provided by the (relevant) operating system. * - * On iOS, mach_absolute_time() uses an ARM register and always - * needs conversion. + * Caller should check return value, as some variants may not be known + * to be absent until runtime. Where possible, these functions collapse + * into constants at compile-time. * * Results: - * Current value of timer + * TRUE if timer is available; FALSE to indicate unavailability. + * If available, the current time is returned via 'result'. * * Side effects: * None. @@ -1571,9 +1626,12 @@ Hostinfo_LogLoadAverage(void) *----------------------------------------------------------------------------- */ -static VmTimeType -HostinfoSystemTimerMach(void) +static Bool +HostinfoSystemTimerMach(VmTimeType *result) // OUT { +#if __APPLE__ +# define vmx86_apple 1 + typedef struct { double scalingFactor; Bool unity; @@ -1612,13 +1670,74 @@ HostinfoSystemTimerMach(void) raw = mach_absolute_time(); if (LIKELY(ptr->unity)) { - return raw; + *result = raw; } else { - /* Could use fixed-point, but 'unity' is the common case already. */ - return ((double) raw) * ptr->scalingFactor; + *result = ((double) raw) * ptr->scalingFactor; } + + return TRUE; +#else +# define vmx86_apple 0 + return FALSE; +#endif } + +static Bool +HostinfoSystemTimerPosix(VmTimeType *result) // OUT +{ +#if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 && defined(_POSIX_MONOTONIC_CLOCK) +# define vmx86_posix 1 + /* Weak declaration to avoid librt.so dependency */ + extern int clock_gettime(clockid_t clk_id, struct timespec *tp) __attribute__ ((weak)); + + /* Assignment is idempotent (expected to always be same answer). */ + static volatile enum { UNKNOWN, PRESENT, FAILED } hasGetTime = UNKNOWN; + + struct timespec ts; + int ret; + + switch (hasGetTime) { + case FAILED: + break; + case UNKNOWN: + if (clock_gettime == NULL) { + /* librt.so is not present. No clock_gettime() */ + hasGetTime = FAILED; + break; + } + ret = clock_gettime(CLOCK_MONOTONIC, &ts); + if (ret != 0) { + hasGetTime = FAILED; + /* + * Well-understood error codes: + * ENOSYS, OS does not implement syscall + * EINVAL, OS implements syscall but not CLOCK_MONOTONIC + */ + if (errno != ENOSYS && errno != EINVAL) { + Log("%s: failure, err %d!\n", __FUNCTION__, errno); + } + break; + } + hasGetTime = PRESENT; + /* Fall through to 'case PRESENT' */ + + case PRESENT: + ret = clock_gettime(CLOCK_MONOTONIC, &ts); + ASSERT(ret == 0); + *result = (VmTimeType)ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec; + return TRUE; + } + return FALSE; +#else +#if vmx86_server +# error Posix clock_gettime support required on ESX +#endif +# define vmx86_posix 0 + /* No Posix support for clock_gettime() */ + return FALSE; #endif +} + /* *----------------------------------------------------------------------------- @@ -1626,12 +1745,17 @@ HostinfoSystemTimerMach(void) * Hostinfo_SystemTimerNS -- * * Return the time. - * - These timers are documented to be non-decreasing - * - These timers never take locks + * - These timers are documented to never go backwards. + * - These timers may take locks * * NOTES: * These are the routines to use when performing timing measurements. * + * The value returned is valid (finish-time - start-time) only within a + * single process. Don't send a time measurement obtained with these + * routines to another process and expect a relative time measurement + * to be correct. + * * The actual resolution of these "clocks" are undefined - it varies * depending on hardware, OSen and OS versions. * @@ -1639,7 +1763,7 @@ HostinfoSystemTimerMach(void) * while RANK_logLock is held. *** * * Results: - * The time in nanoseconds is returned. + * The time in nanoseconds is returned. Zero upon error. * * Side effects: * None. @@ -1650,25 +1774,19 @@ HostinfoSystemTimerMach(void) VmTimeType Hostinfo_SystemTimerNS(void) { -#ifdef __APPLE__ - return HostinfoSystemTimerMach(); -#else - struct timespec ts; - int ret; - - /* - * clock_gettime() is implemented on Linux as a commpage routine that - * adds a known offset to TSC, which makes it very fast. Other OSes... - * are at worst a single syscall (see: vmkernel PR820064), which still - * makes this the best time API. Also, clock_gettime() allows nanosecond - * resolution and any alternative is worse: gettimeofday() is microsecond. - */ - ret = clock_gettime(CLOCK_MONOTONIC, &ts); - ASSERT(ret == 0); + VmTimeType result = 0; // = 0 silence compiler warning - return (VmTimeType)ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec; -#endif + if ((vmx86_apple && HostinfoSystemTimerMach(&result)) || + (vmx86_posix && HostinfoSystemTimerPosix(&result))) { + /* Host provides monotonic clock source. */ + return result; + } else { + /* GetTimeOfDay is microseconds. */ + return HostinfoGetTimeOfDayMonotonic() * 1000; + } } +#undef vmx86_apple +#undef vmx86_posix /*