}
-#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.
*-----------------------------------------------------------------------------
*/
-static VmTimeType
-HostinfoSystemTimerMach(void)
+static Bool
+HostinfoSystemTimerMach(VmTimeType *result) // OUT
{
+#if __APPLE__
+# define vmx86_apple 1
+
typedef struct {
double scalingFactor;
Bool unity;
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
+}
+
/*
*-----------------------------------------------------------------------------
* 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.
*
* while RANK_logLock is held. ***
*
* Results:
- * The time in nanoseconds is returned.
+ * The time in nanoseconds is returned. Zero upon error.
*
* Side effects:
* None.
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
/*