+ clock_sec_t sys;
+ clock_sec_t secs;
+ clock_usec_t microsys;
+ clock_usec_t microsecs;
+ spl_t s;
+ struct bintime bt, last_sleep_bt;
+ clock_sec_t basesleep_s, last_sleep_sec;
+ clock_usec_t basesleep_us, last_sleep_usec;
+ struct latched_time monotonic_time;
+ uint64_t monotonic_usec_total;
+ size_t size;
+ clock_sec_t secs_copy;
+ clock_usec_t microsecs_copy;
+#if DEVELOPMENT || DEBUG
+ clock_sec_t utc_sec;
+ clock_usec_t utc_usec;
+ PEGetUTCTimeOfDay(&utc_sec, &utc_usec);
+#endif
+
+ /*
+ * If the platform has the monotonic clock use that to
+ * compute the sleep time. The monotonic clock does not have an offset
+ * that can be modified, so nor kernel or userspace can change the time
+ * of this clock, it can only monotonically increase over time.
+ * During sleep mach_absolute_time does not tick,
+ * so the sleep time is the difference betwen the current monotonic time
+ * less the absolute time and the previous difference stored at wake time.
+ *
+ * basesleep = monotonic - sys ---> computed at last wake
+ * sleep_time = (monotonic - sys) - basesleep
+ *
+ * If the platform does not support monotonic time we use the PMU time
+ * to compute the last sleep.
+ * The PMU time is the monotonic clock + an offset that can be set
+ * by kernel.
+ *
+ * IMPORTANT:
+ * We assume that only the kernel is setting the offset of the PMU and that
+ * it is doing it only througth the settimeofday interface.
+ *
+ * basesleep is the different between the PMU time and the mach_absolute_time
+ * at wake.
+ * During awake time settimeofday can change the PMU offset by a delta,
+ * and basesleep is shifted by the same delta applyed to the PMU. So the sleep
+ * time computation becomes:
+ *
+ * PMU = monotonic + PMU_offset
+ * basesleep = PMU - sys ---> computed at last wake
+ * basesleep += settimeofday_delta
+ * PMU_offset += settimeofday_delta
+ * sleep_time = (PMU - sys) - basesleep
+ */
+ if (has_monotonic_clock) {
+ //Get monotonic time with corresponding sys time
+ size = sizeof(monotonic_time);
+ if (kernel_sysctlbyname("kern.monotonicclock_usecs", &monotonic_time, &size, NULL, 0) != 0) {
+ panic("%s: could not call kern.monotonicclock_usecs", __func__);
+ }
+ monotonic_usec_total = monotonic_time.monotonic_time_usec;
+ absolutetime_to_microtime(monotonic_time.mach_time, &sys, µsys);
+
+ secs = monotonic_usec_total / (clock_sec_t)USEC_PER_SEC;
+ microsecs = monotonic_usec_total % (clock_usec_t)USEC_PER_SEC;
+ } else {
+ //Get PMU time with offset and corresponding sys time
+ PEGetUTCTimeOfDay(&secs, µsecs);
+ clock_get_system_microtime(&sys, µsys);
+
+ }