<pre style='margin:0'>
Christopher Nielsen (mascguy) pushed a commit to branch master
in repository macports-legacy-support.

</pre>
<p><a href="https://github.com/macports/macports-legacy-support/commit/a52954537c923ed120c585bcc26aefc9423a6c00">https://github.com/macports/macports-legacy-support/commit/a52954537c923ed120c585bcc26aefc9423a6c00</a></p>
<pre style="white-space: pre; background: #F8F8F8"><span style='display:block; white-space:pre;color:#808000;'>commit a52954537c923ed120c585bcc26aefc9423a6c00
</span>Author: Fred Wright <fw@fwright.net>
AuthorDate: Tue May 27 16:00:48 2025 -0700

<span style='display:block; white-space:pre;color:#404040;'>    time.c: Implement sleep offset.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    This provides the sleep offset for the "continuous" time functions
</span><span style='display:block; white-space:pre;color:#404040;'>    and derivatives.  This only accounts for "static" sleep offsets,
</span><span style='display:block; white-space:pre;color:#404040;'>    not "dynamic" sleep offsets.  See the comments for more details.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    Closes: https://trac.macports.org/ticket/68007
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    TESTED:
</span><span style='display:block; white-space:pre;color:#404040;'>    Gives plausible no-sleep results on all platforms.  Sleeps aren't
</span><span style='display:block; white-space:pre;color:#404040;'>    available in VMs, limiting the test cases for actual sleeps.
</span><span style='display:block; white-space:pre;color:#404040;'>    Tested with sleeps on 10.4-10.5 ppc and 10.7-10.11 x86_64.
</span>---
 src/time.c | 243 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 236 insertions(+), 7 deletions(-)

<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/time.c b/src/time.c
</span><span style='display:block; white-space:pre;color:#808080;'>index e0b928a..4e768b2 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/time.c
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/time.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -39,24 +39,230 @@ uint64_t mach_approximate_time(void)
</span> 
 #if __MPLS_LIB_SUPPORT_CONTINUOUS_TIME__
 
<span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <pthread.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> #include <mach/mach_time.h>
 
<span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/sysctl.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/time.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> /*
<span style='display:block; white-space:pre;background:#ffe0e0;'>- * Here we provide versions of mach_continuous_time() which are just wrappers
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- * around the non-continuous versions.  This isn't strictly functionally
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- * correct, but permits programs to build and run (correctly if they don't
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- * care about sleep time).  A later version may add proper accounting for
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- * sleep time, if some means can be found to obtain it.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Continuous time.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Unlike mach_absolute_time, mach_continuous_time includes time spent
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * sleeping.  Since pre-10.12 kernels don't directly provide accounting
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * for this, we need to deduce the sleep-time offset from other clock
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * values.  The clocks used for this are:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *   1) Boottime.  The date/time when the system was first booted.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *   2) Timeofday.  The current date/time.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *   3) Mach Absolute Time.  The system "running" time, in mach units.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Subtracting #1 from #2 gives us the total time since boot.  Subtracting
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * #3 from that gives us the sleep-time offset (in principle).
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * However, there are a number of issues affecting the accuracy of this
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * approach:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *   1) The timeofday clock may be adjusted for synchronization purposes,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *  while the mach time is not.  Assuming the synchronization is to a
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *  correct source, the two will diverge based on the error in the frequency
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *  of the timebase reference clock.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *   2) Systems prior to 10.12 only track boottime with one-second precision,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *  leading to an error of up to one second in the #2 - #1 difference.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *   3) The OS doesn't set boottime as early as it starts counting mach time,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *  so in the absence of sleeping, the computed sleep offset will typically
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *  be negative.  On x86 systems, this is usually no more than a few seconds,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *  but on PowerPC systems it's been observed to approach a minute.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Since there's not a lot we can do about these issues, at present we simply
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * tolerate #2, and for #3, treat negative sleep offsets as zero.  For #1, we
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * calculate a maximum false offset due to MAX_DRIFT_PPM, and disallow
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * adjustments of less than that.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Note that issue #1 represents an ongoing change in the apparent sleep
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * offset.  And since we can only compute the offset local to one program,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * different programs may disagree as to the sleep offset, and hence on
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * values of the synthesized mach_continuous_time.  There's not much we
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * can do about that.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Also note that, since the subsecond portions of timeofday and mach time
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * are the same, they cancel out in the final sleep offset, so that the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * up to one-second error in the result is the same for all parties.  Hence,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * although the calculated sleep time may differ from the true value by
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * up to one second (from this source), all programs will agree on that
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * error, and it will not cause a discrepancy across programs.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * The present implementation only accounts for the "static" sleep offset,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * i.e. sleeps occuring before the program was launched.  There is no
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * provision for tracking "dynamic" sleep offsets, i.e. sleeps occurring
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * while the program is running.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * In spite of the above, the code is written to allow for the possibility
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * of recomputing the sleep offset later.  To avoid excessive "churn", it
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * does not update the actual offset unless it's been increased by at least
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * MIN_SLEEP_OFFSET_ADVANCE seconds, or the drift-based limit if larger.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Since the initial offset is zero, this also has the effect of excluding
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * negative offsets as noted above.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * If the first "raw" offset is negative, it's retained to use as a baseline
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * for any subsequent adjustments (not currently implemented), thereby removing
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * the "boottime delay" from any subsequent adjustments.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Unlike the mach scale factor setup, attempting to set up the sleep offset
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * simultaneously from multiple threads can cause trouble, so we protect
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * the setup code with a mutex.
</span>  */
 
<span style='display:block; white-space:pre;background:#e0ffe0;'>+#define MIN_SLEEP_OFFSET_ADVANCE 5
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define MAX_DRIFT_PPM 100
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef struct sleepofs_info_s {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  struct timeval boottime;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  struct timeval timeofday;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  uint64_t mach_before;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  uint64_t mach_after;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  uint64_t mach_diff;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+} sleepofs_info_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int sleep_offset_valid = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static uint64_t sleep_offset = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int64_t raw_offset = 0, first_offset = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static sleepofs_info_t sleep_info_raw, sleep_info = {.mach_before = 0};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static pthread_mutex_t sleepofs_lock = PTHREAD_MUTEX_INITIALIZER;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Get the system boot time, via sysctl.  The comm-page method of obtaining
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * this faster and with better resolution didn't appear until 10.12, where
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * this code is no longer relevant.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+get_boottime(struct timeval *bt)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  size_t bt_len = sizeof(*bt);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  int bt_mib[] = {CTL_KERN, KERN_BOOTTIME};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  size_t bt_miblen = sizeof(bt_mib) / sizeof(bt_mib[0]);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  bt->tv_usec = 0;  /* In case OS doesn't store it */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  return sysctl(bt_mib, bt_miblen, bt, &bt_len, NULL, 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Get timeofday/mach_time pair.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * This obtains the timeofday at its next change, sandwiched by a pair
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * of mach_absolute_time reads.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+get_todmach(sleepofs_info_t *si)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  struct timeval tv1, tv2;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  uint64_t mt1, mt2;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (gettimeofday(&tv1, NULL)) return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  mt2 = mach_absolute_time();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  do {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    mt1 = mt2;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (gettimeofday(&tv2, NULL)) return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    mt2 = mach_absolute_time();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  } while (tv2.tv_usec == tv1.tv_usec);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  si->timeofday = tv2;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  si->mach_before = mt1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  si->mach_after = mt2;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  /* Round up and add one unit to mach diff */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  si->mach_diff = (mt2 - mt1 + 1 + 2) / 2;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Get the parameters for calculating the sleep offset.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Although boottime should be constant in all pre-10.12 systems, we still
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * verify that it doesn't change during the collection of the tod/mach pair.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Within that, we obtain the "tightest" of five tod/mach samples.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+get_sleepofs_info(sleepofs_info_t *si)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  int tries;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  sleepofs_info_t si2;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (get_boottime(&si->boottime)) return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  si2.boottime = si->boottime;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  while(1) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (get_todmach(si)) return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    tries = 5;  /* Get best of 5 samples */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    while (--tries) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      if (get_todmach(&si2)) return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      if (si2.mach_diff < si->mach_diff) *si = si2;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (get_boottime(&si2.boottime)) return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (si2.boottime.tv_sec == si->boottime.tv_sec
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        && si2.boottime.tv_usec == si->boottime.tv_usec) break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    *si = si2;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Compute the sleep offset.  Do nothing on failure, leaving the offset as is.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int get_mach_scale(void);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int64_t tvdiff2mach(const struct timeval *tv1,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           const struct timeval *tv2);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static void get_sleep_offset(void)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  int64_t toddiff, offset, minsleepadj, maxdrift;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  sleepofs_info_t si;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  static const struct timeval tv5a = {MIN_SLEEP_OFFSET_ADVANCE, 0},
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                              tv5b = {0, 0};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (get_mach_scale()) return;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (get_sleepofs_info(&si)) return;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  toddiff = tvdiff2mach(&si.timeofday, &si.boottime);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  offset = toddiff - (si.mach_before + si.mach_after) / 2;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  minsleepadj = tvdiff2mach(&tv5a, &tv5b);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  maxdrift = (si.mach_before - sleep_info.mach_before)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+             / (1000000 / MAX_DRIFT_PPM);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (maxdrift > minsleepadj) minsleepadj = maxdrift;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (pthread_mutex_lock(&sleepofs_lock)) return;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  raw_offset = offset;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (!first_offset && offset < 0) first_offset = offset;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  sleep_info_raw = si;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (offset - first_offset > sleep_offset + minsleepadj) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    sleep_offset = offset - first_offset;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    sleep_offset_valid = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    sleep_info = si;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  (void) pthread_mutex_unlock(&sleepofs_lock);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> uint64_t mach_continuous_time(void)
 {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-  return mach_absolute_time();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  uint64_t mach_time;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (!sleep_offset_valid) get_sleep_offset();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  mach_time = mach_absolute_time();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  return mach_time + sleep_offset;
</span> }
 
 uint64_t mach_continuous_approximate_time(void)
 {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-  return mach_approximate_time();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  uint64_t mach_time;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (!sleep_offset_valid) get_sleep_offset();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  mach_time = mach_approximate_time();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  return mach_time + sleep_offset;
</span> }
 
 #endif /* __MPLS_LIB_SUPPORT_CONTINUOUS_TIME__ */
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -346,6 +552,29 @@ mach2timespec(uint64_t mach_time, struct timespec *ts)
</span>   nanos2timespec(mach2nanos(mach_time), ts);
 }
 
<span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Convert timeval diff to mach units.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Since this is only used for the sleep offset setup, we do it the easy
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * way and use floating-point.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * If the tv_sec fields are 32-bit, we force unsigned interpretation
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * to get around a possible Y2038 isue.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int64_t
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+tvdiff2mach(const struct timeval *tv1, const struct timeval *tv2)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  double tvdiff;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (sizeof(tv1->tv_sec) == sizeof(int32_t)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    tvdiff = ((uint32_t) tv1->tv_sec - (uint32_t) tv2->tv_sec) * 1E9;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    tvdiff = (tv1->tv_sec - tv2->tv_sec) * 1E9;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  tvdiff += (tv1->tv_usec - tv2->tv_usec) * 1000.0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  return tvdiff * mach_scale.denom / mach_scale.numer;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> /*
  * Get the best available thread time, using the syscall on 10.10+,
  * but falling back to thread_info() on <10.10.
</pre><pre style='margin:0'>

</pre>