]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
Revert previous change.
authorOliver Kurth <okurth@vmware.com>
Fri, 15 Sep 2017 18:23:08 +0000 (11:23 -0700)
committerOliver Kurth <okurth@vmware.com>
Fri, 15 Sep 2017 18:23:08 +0000 (11:23 -0700)
open-vm-tools/lib/misc/hostinfoPosix.c

index f4ac6c0f98b840fb6d33076c6de3cf7ce443f8a0..cb275d9afbd5eb866d40898e604d01837d0b07ba 100644 (file)
@@ -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
 
 
 /*