#include <os/log.h>
uint32_t hz_tick_interval = 1;
+#if !HAS_CONTINUOUS_HWCLOCK
static uint64_t has_monotonic_clock = 0;
+#endif
decl_simple_lock_data(, clock_lock);
lck_grp_attr_t * settime_lock_grp_attr;
*nanosecs = ((uint64_t)NSEC_PER_SEC * (uint32_t)(_bt->frac >> 32)) >> 32;
}
+#if !defined(HAS_CONTINUOUS_HWCLOCK)
static __inline void
bintime2absolutetime(const struct bintime *_bt, uint64_t *abs)
{
extern int
kernel_sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen);
+#endif
/*
* Time of day (calendar) variables.
*
struct bintime offset; /* cumulative offset expressed in (sec, 64 bits frac of a second) */
struct bintime bintime; /* cumulative offset (it includes bootime) expressed in (sec, 64 bits frac of a second) */
struct bintime boottime; /* boot time expressed in (sec, 64 bits frac of a second) */
+#if !HAS_CONTINUOUS_HWCLOCK
struct bintime basesleep;
+#endif
} clock_calend;
static uint64_t ticks_per_sec; /* ticks in a second (expressed in abs time) */
func, clock_calend_cp->boottime.sec, clock_calend_cp->boottime.frac,
(unsigned long)bootime_secs, bootime_microsecs);
+#if !HAS_CONTINUOUS_HWCLOCK
clock_sec_t basesleep_secs;
clock_usec_t basesleep_microsecs;
os_log(OS_LOG_DEFAULT, "%s basesleep.sec %ld basesleep.frac %llu basesleep_secs %lu basesleep_microsecs %d\n",
func, clock_calend_cp->basesleep.sec, clock_calend_cp->basesleep.frac,
(unsigned long)basesleep_secs, basesleep_microsecs);
+#endif
}
clock_usec_t utc_offset_microsecs;
spl_t s;
struct bintime bt;
+#if !HAS_CONTINUOUS_HWCLOCK
struct bintime monotonic_bt;
struct latched_time monotonic_time;
uint64_t monotonic_usec_total;
clock_usec_t microsys2, monotonic_usec;
size_t size;
+#endif
//Get the UTC time and corresponding sys time
PEGetUTCTimeOfDay(&secs, µsecs);
clock_get_system_microtime(&sys, µsys);
+#if !HAS_CONTINUOUS_HWCLOCK
/*
* If the platform has a monotonic clock, use kern.monotonicclock_usecs
* to estimate the sleep/wake time, otherwise use the UTC time to estimate
absolutetime_to_microtime(monotonic_time.mach_time, &sys2, µsys2);
os_log(OS_LOG_DEFAULT, "%s system has monotonic clock\n", __func__);
}
+#endif
s = splclock();
clock_lock();
clock_calend.s_scale_ns = NSEC_PER_SEC;
clock_calend.s_adj_nsx = 0;
+#if !HAS_CONTINUOUS_HWCLOCK
if (has_monotonic_clock) {
monotonic_sec = monotonic_usec_total / (clock_sec_t)USEC_PER_SEC;
monotonic_usec = monotonic_usec_total % (clock_usec_t)USEC_PER_SEC;
// set the baseleep as the difference between monotonic clock - sys
clock_calend.basesleep = monotonic_bt;
}
+#endif
commpage_update_mach_continuous_time(mach_absolutetime_asleep);
#if DEVELOPMENT || DEBUG
#endif
}
+#if HAS_CONTINUOUS_HWCLOCK
+
+static void
+scale_sleep_time(void)
+{
+ /* Apply the current NTP frequency adjustment to the time slept.
+ * The frequency adjustment remains stable between calls to ntp_adjtime(),
+ * and should thus provide a reasonable approximation of the total adjustment
+ * required for the time slept. */
+ struct bintime sleep_time;
+ uint64_t tick_scale_x, s_scale_ns;
+ int64_t s_adj_nsx;
+ int64_t sleep_adj = ntp_get_freq();
+ if (sleep_adj) {
+ get_scale_factors_from_adj(sleep_adj, &tick_scale_x, &s_scale_ns, &s_adj_nsx);
+ sleep_time = scale_delta(mach_absolutetime_last_sleep, tick_scale_x, s_scale_ns, s_adj_nsx);
+ } else {
+ tick_scale_x = (uint64_t)1 << 63;
+ tick_scale_x /= ticks_per_sec;
+ tick_scale_x *= 2;
+ sleep_time.sec = mach_absolutetime_last_sleep / ticks_per_sec;
+ sleep_time.frac = (mach_absolutetime_last_sleep % ticks_per_sec) * tick_scale_x;
+ }
+ bintime_add(&clock_calend.offset, &sleep_time);
+ bintime_add(&clock_calend.bintime, &sleep_time);
+}
+
+void
+clock_wakeup_calendar(void)
+{
+ spl_t s;
+
+ s = splclock();
+ clock_lock();
+
+ commpage_disable_timestamp();
+
+ uint64_t abstime = mach_absolute_time();
+ uint64_t total_sleep_time = ml_get_hwclock() - abstime;
+
+ mach_absolutetime_last_sleep = total_sleep_time - mach_absolutetime_asleep;
+ mach_absolutetime_asleep = total_sleep_time;
+
+ scale_sleep_time();
+
+ KERNEL_DEBUG_CONSTANT(
+ MACHDBG_CODE(DBG_MACH_CLOCK, MACH_EPOCH_CHANGE) | DBG_FUNC_NONE,
+ (uintptr_t) mach_absolutetime_last_sleep,
+ (uintptr_t) mach_absolutetime_asleep,
+ (uintptr_t) (mach_absolutetime_last_sleep >> 32),
+ (uintptr_t) (mach_absolutetime_asleep >> 32),
+ 0);
+
+ commpage_update_mach_continuous_time(mach_absolutetime_asleep);
+ adjust_cont_time_thread_calls();
+
+ clock_unlock();
+ splx(s);
+
+ host_notify_calendar_change();
+
+#if CONFIG_DTRACE
+ clock_track_calend_nowait();
+#endif
+}
+
+#else /* HAS_CONTINUOUS_HWCLOCK */
void
clock_wakeup_calendar(void)
#endif
}
+#endif /* !HAS_CONTINUOUS_HWCLOCK */
/*
* clock_get_boottime_nanotime:
clock_interval_to_absolutetime_interval(interval, scale_factor, &abstime);
- *result = mach_absolute_time() + abstime;
+ if (os_add_overflow(mach_absolute_time(), abstime, result)) {
+ *result = UINT64_MAX;
+ }
}
void
uint64_t abstime,
uint64_t *result)
{
- *result = mach_absolute_time() + abstime;
+ if (os_add_overflow(mach_absolute_time(), abstime, result)) {
+ *result = UINT64_MAX;
+ }
}
void
uint64_t conttime,
uint64_t *result)
{
- *result = mach_continuous_time() + conttime;
+ if (os_add_overflow(mach_continuous_time(), conttime, result)) {
+ *result = UINT64_MAX;
+ }
}
void
{
assert(interval != 0);
- *deadline += interval;
+ // *deadline += interval;
+ if (os_add_overflow(*deadline, interval, deadline)) {
+ *deadline = UINT64_MAX;
+ }
if (*deadline <= abstime) {
- *deadline = abstime + interval;
- abstime = mach_absolute_time();
+ // *deadline = abstime + interval;
+ if (os_add_overflow(abstime, interval, deadline)) {
+ *deadline = UINT64_MAX;
+ }
+ abstime = mach_absolute_time();
if (*deadline <= abstime) {
- *deadline = abstime + interval;
+ // *deadline = abstime + interval;
+ if (os_add_overflow(abstime, interval, deadline)) {
+ *deadline = UINT64_MAX;
+ }
}
}
}
uint64_t
mach_continuous_time(void)
{
+#if HAS_CONTINUOUS_HWCLOCK
+ return ml_get_hwclock();
+#else
while (1) {
uint64_t read1 = mach_absolutetime_asleep;
uint64_t absolute = mach_absolute_time();
return absolute + read1;
}
}
+#endif
}
uint64_t
mach_continuous_approximate_time(void)
{
+#if HAS_CONTINUOUS_HWCLOCK
+ return ml_get_hwclock();
+#else
while (1) {
uint64_t read1 = mach_absolutetime_asleep;
uint64_t absolute = mach_approximate_time();
return absolute + read1;
}
}
+#endif
}
/*