<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>