#include <mach/mach_types.h>
#include <kern/clock.h>
#include <kern/thread.h>
#include <kern/macro_help.h>
#include <kern/spl.h>
#include <kern/host_notify.h>
#include <machine/commpage.h>
#include <machine/machine_routines.h>
#include <ppc/exception.h>
#include <ppc/proc_reg.h>
#include <IOKit/IOPlatformExpert.h>
#include <sys/kdebug.h>
int sysclk_config(void);
int sysclk_init(void);
void treqs(uint32_t dec);
kern_return_t sysclk_gettime(
mach_timespec_t *cur_time);
kern_return_t sysclk_getattr(
clock_flavor_t flavor,
clock_attr_t attr,
mach_msg_type_number_t *count);
void sysclk_setalarm(
mach_timespec_t *deadline);
struct clock_ops sysclk_ops = {
sysclk_config, sysclk_init,
sysclk_gettime, 0,
sysclk_getattr, 0,
sysclk_setalarm,
};
int calend_config(void);
kern_return_t calend_gettime(
mach_timespec_t *cur_time);
kern_return_t calend_getattr(
clock_flavor_t flavor,
clock_attr_t attr,
mach_msg_type_number_t *count);
struct clock_ops calend_ops = {
calend_config, 0,
calend_gettime, 0,
calend_getattr, 0,
0,
};
static struct rtclock_calend {
uint32_t epoch;
uint32_t microepoch;
uint64_t epoch1;
int64_t adjtotal;
int32_t adjdelta;
} rtclock_calend;
static uint32_t rtclock_boottime;
#define TIME_ADD(rsecs, secs, rfrac, frac, unit) \
MACRO_BEGIN \
if (((rfrac) += (frac)) >= (unit)) { \
(rfrac) -= (unit); \
(rsecs) += 1; \
} \
(rsecs) += (secs); \
MACRO_END
#define TIME_SUB(rsecs, secs, rfrac, frac, unit) \
MACRO_BEGIN \
if ((int32_t)((rfrac) -= (frac)) < 0) { \
(rfrac) += (unit); \
(rsecs) -= 1; \
} \
(rsecs) -= (secs); \
MACRO_END
#define NSEC_PER_HZ (NSEC_PER_SEC / 100)
static uint32_t rtclock_tick_interval;
static uint32_t rtclock_sec_divisor;
static mach_timebase_info_data_t rtclock_timebase_const;
static boolean_t rtclock_timebase_initialized;
static clock_timer_func_t rtclock_timer_expire;
static timer_call_data_t rtclock_alarm_timer;
static void nanotime_to_absolutetime(
uint32_t secs,
uint32_t nanosecs,
uint64_t *result);
static int deadline_to_decrementer(
uint64_t deadline,
uint64_t now);
static void rtclock_alarm_expire(
timer_call_param_t p0,
timer_call_param_t p1);
#define DECREMENTER_MAX 0x7FFFFFFFUL
#define DECREMENTER_MIN 0xAUL
natural_t rtclock_decrementer_min;
decl_simple_lock_data(static,rtclock_lock)
#define LOCK_RTC(s) \
MACRO_BEGIN \
(s) = splclock(); \
simple_lock(&rtclock_lock); \
MACRO_END
#define UNLOCK_RTC(s) \
MACRO_BEGIN \
simple_unlock(&rtclock_lock); \
splx(s); \
MACRO_END
static void
timebase_callback(
struct timebase_freq_t *freq)
{
uint32_t numer, denom;
uint64_t abstime;
spl_t s;
if ( freq->timebase_den < 1 || freq->timebase_den > 4 ||
freq->timebase_num < freq->timebase_den )
panic("rtclock timebase_callback: invalid constant %d / %d",
freq->timebase_num, freq->timebase_den);
denom = freq->timebase_num;
numer = freq->timebase_den * NSEC_PER_SEC;
LOCK_RTC(s);
if (!rtclock_timebase_initialized) {
commpage_set_timestamp(0,0,0,0);
rtclock_timebase_const.numer = numer;
rtclock_timebase_const.denom = denom;
rtclock_sec_divisor = freq->timebase_num / freq->timebase_den;
nanoseconds_to_absolutetime(NSEC_PER_HZ, &abstime);
rtclock_tick_interval = abstime;
ml_init_lock_timeout();
}
else {
UNLOCK_RTC(s);
printf("rtclock timebase_callback: late old %d / %d new %d / %d\n",
rtclock_timebase_const.numer, rtclock_timebase_const.denom,
numer, denom);
return;
}
UNLOCK_RTC(s);
clock_timebase_init();
}
int
sysclk_config(void)
{
timer_call_setup(&rtclock_alarm_timer, rtclock_alarm_expire, NULL);
simple_lock_init(&rtclock_lock, 0);
PE_register_timebase_callback(timebase_callback);
return (1);
}
int
sysclk_init(void)
{
uint64_t abstime, nexttick;
int decr1, decr2;
struct rtclock_timer *mytimer;
struct per_proc_info *pp;
decr1 = decr2 = DECREMENTER_MAX;
pp = getPerProc();
mytimer = &pp->rtclock_timer;
abstime = mach_absolute_time();
nexttick = abstime + rtclock_tick_interval;
pp->rtclock_tick_deadline = nexttick;
decr1 = deadline_to_decrementer(nexttick, abstime);
if (mytimer->is_set)
decr2 = deadline_to_decrementer(mytimer->deadline, abstime);
if (decr1 > decr2)
decr1 = decr2;
treqs(decr1);
return (1);
}
kern_return_t
sysclk_gettime(
mach_timespec_t *time)
{
uint64_t now, t64;
uint32_t divisor;
now = mach_absolute_time();
time->tv_sec = t64 = now / (divisor = rtclock_sec_divisor);
now -= (t64 * divisor);
time->tv_nsec = (now * NSEC_PER_SEC) / divisor;
return (KERN_SUCCESS);
}
void
clock_get_system_microtime(
uint32_t *secs,
uint32_t *microsecs)
{
uint64_t now, t64;
uint32_t divisor;
now = mach_absolute_time();
*secs = t64 = now / (divisor = rtclock_sec_divisor);
now -= (t64 * divisor);
*microsecs = (now * USEC_PER_SEC) / divisor;
}
void
clock_get_system_nanotime(
uint32_t *secs,
uint32_t *nanosecs)
{
uint64_t now, t64;
uint32_t divisor;
now = mach_absolute_time();
*secs = t64 = now / (divisor = rtclock_sec_divisor);
now -= (t64 * divisor);
*nanosecs = (now * NSEC_PER_SEC) / divisor;
}
kern_return_t
sysclk_getattr(
clock_flavor_t flavor,
clock_attr_t attr,
mach_msg_type_number_t *count)
{
spl_t s;
if (*count != 1)
return (KERN_FAILURE);
switch (flavor) {
case CLOCK_GET_TIME_RES:
case CLOCK_ALARM_CURRES:
case CLOCK_ALARM_MINRES:
case CLOCK_ALARM_MAXRES:
LOCK_RTC(s);
*(clock_res_t *) attr = NSEC_PER_HZ;
UNLOCK_RTC(s);
break;
default:
return (KERN_INVALID_VALUE);
}
return (KERN_SUCCESS);
}
void
sysclk_setalarm(
mach_timespec_t *deadline)
{
uint64_t abstime;
nanotime_to_absolutetime(deadline->tv_sec, deadline->tv_nsec, &abstime);
timer_call_enter(&rtclock_alarm_timer, abstime);
}
int
calend_config(void)
{
return (1);
}
kern_return_t
calend_gettime(
mach_timespec_t *time)
{
clock_get_calendar_nanotime(
&time->tv_sec, &time->tv_nsec);
return (KERN_SUCCESS);
}
kern_return_t
calend_getattr(
clock_flavor_t flavor,
clock_attr_t attr,
mach_msg_type_number_t *count)
{
spl_t s;
if (*count != 1)
return (KERN_FAILURE);
switch (flavor) {
case CLOCK_GET_TIME_RES:
LOCK_RTC(s);
*(clock_res_t *) attr = NSEC_PER_HZ;
UNLOCK_RTC(s);
break;
case CLOCK_ALARM_CURRES:
case CLOCK_ALARM_MINRES:
case CLOCK_ALARM_MAXRES:
*(clock_res_t *) attr = 0;
break;
default:
return (KERN_INVALID_VALUE);
}
return (KERN_SUCCESS);
}
void
clock_get_calendar_microtime(
uint32_t *secs,
uint32_t *microsecs)
{
uint32_t epoch, microepoch;
uint64_t now, t64;
spl_t s = splclock();
simple_lock(&rtclock_lock);
if (rtclock_calend.adjdelta >= 0) {
uint32_t divisor;
now = mach_absolute_time();
epoch = rtclock_calend.epoch;
microepoch = rtclock_calend.microepoch;
simple_unlock(&rtclock_lock);
*secs = t64 = now / (divisor = rtclock_sec_divisor);
now -= (t64 * divisor);
*microsecs = (now * USEC_PER_SEC) / divisor;
TIME_ADD(*secs, epoch, *microsecs, microepoch, USEC_PER_SEC);
}
else {
uint32_t delta, t32;
delta = -rtclock_calend.adjdelta;
now = mach_absolute_time();
*secs = rtclock_calend.epoch;
*microsecs = rtclock_calend.microepoch;
if (now > rtclock_calend.epoch1) {
t64 = now - rtclock_calend.epoch1;
t32 = (t64 * USEC_PER_SEC) / rtclock_sec_divisor;
if (t32 > delta)
TIME_ADD(*secs, 0, *microsecs, (t32 - delta), USEC_PER_SEC);
}
simple_unlock(&rtclock_lock);
}
splx(s);
}
void
clock_gettimeofday(
uint32_t *secs_p,
uint32_t *microsecs_p)
{
uint32_t epoch, microepoch;
uint32_t secs, microsecs;
uint64_t now, t64, secs_64, usec_64;
spl_t s = splclock();
simple_lock(&rtclock_lock);
if (rtclock_calend.adjdelta >= 0) {
now = mach_absolute_time();
epoch = rtclock_calend.epoch;
microepoch = rtclock_calend.microepoch;
secs = secs_64 = now / rtclock_sec_divisor;
t64 = now - (secs_64 * rtclock_sec_divisor);
microsecs = usec_64 = (t64 * USEC_PER_SEC) / rtclock_sec_divisor;
TIME_ADD(secs, epoch, microsecs, microepoch, USEC_PER_SEC);
now -= t64 - ((usec_64 * rtclock_sec_divisor) / USEC_PER_SEC);
commpage_set_timestamp(now,secs,microsecs,rtclock_sec_divisor);
}
else {
uint32_t delta, t32;
delta = -rtclock_calend.adjdelta;
now = mach_absolute_time();
secs = rtclock_calend.epoch;
microsecs = rtclock_calend.microepoch;
if (now > rtclock_calend.epoch1) {
t64 = now - rtclock_calend.epoch1;
t32 = (t64 * USEC_PER_SEC) / rtclock_sec_divisor;
if (t32 > delta)
TIME_ADD(secs, 0, microsecs, (t32 - delta), USEC_PER_SEC);
}
}
simple_unlock(&rtclock_lock);
splx(s);
*secs_p = secs;
*microsecs_p = microsecs;
}
void
clock_get_calendar_nanotime(
uint32_t *secs,
uint32_t *nanosecs)
{
uint32_t epoch, nanoepoch;
uint64_t now, t64;
spl_t s = splclock();
simple_lock(&rtclock_lock);
if (rtclock_calend.adjdelta >= 0) {
uint32_t divisor;
now = mach_absolute_time();
epoch = rtclock_calend.epoch;
nanoepoch = rtclock_calend.microepoch * NSEC_PER_USEC;
simple_unlock(&rtclock_lock);
*secs = t64 = now / (divisor = rtclock_sec_divisor);
now -= (t64 * divisor);
*nanosecs = ((now * USEC_PER_SEC) / divisor) * NSEC_PER_USEC;
TIME_ADD(*secs, epoch, *nanosecs, nanoepoch, NSEC_PER_SEC);
}
else {
uint32_t delta, t32;
delta = -rtclock_calend.adjdelta;
now = mach_absolute_time();
*secs = rtclock_calend.epoch;
*nanosecs = rtclock_calend.microepoch * NSEC_PER_USEC;
if (now > rtclock_calend.epoch1) {
t64 = now - rtclock_calend.epoch1;
t32 = (t64 * USEC_PER_SEC) / rtclock_sec_divisor;
if (t32 > delta)
TIME_ADD(*secs, 0, *nanosecs, ((t32 - delta) * NSEC_PER_USEC), NSEC_PER_SEC);
}
simple_unlock(&rtclock_lock);
}
splx(s);
}
void
clock_set_calendar_microtime(
uint32_t secs,
uint32_t microsecs)
{
uint32_t sys, microsys;
uint32_t newsecs;
spl_t s;
newsecs = (microsecs < 500*USEC_PER_SEC)?
secs: secs + 1;
s = splclock();
simple_lock(&rtclock_lock);
commpage_set_timestamp(0,0,0,0);
clock_get_system_microtime(&sys, µsys);
TIME_SUB(secs, sys, microsecs, microsys, USEC_PER_SEC);
rtclock_boottime += secs - rtclock_calend.epoch;
rtclock_calend.epoch = secs;
rtclock_calend.microepoch = microsecs;
rtclock_calend.epoch1 = 0;
rtclock_calend.adjdelta = rtclock_calend.adjtotal = 0;
simple_unlock(&rtclock_lock);
PESetGMTTimeOfDay(newsecs);
splx(s);
host_notify_calendar_change();
}
#define tickadj (40)
#define bigadj (USEC_PER_SEC)
uint32_t
clock_set_calendar_adjtime(
int32_t *secs,
int32_t *microsecs)
{
int64_t total, ototal;
uint32_t interval = 0;
spl_t s;
total = (int64_t)*secs * USEC_PER_SEC + *microsecs;
LOCK_RTC(s);
commpage_set_timestamp(0,0,0,0);
ototal = rtclock_calend.adjtotal;
if (rtclock_calend.adjdelta < 0) {
uint64_t now, t64;
uint32_t delta, t32;
uint32_t sys, microsys;
delta = -rtclock_calend.adjdelta;
sys = rtclock_calend.epoch;
microsys = rtclock_calend.microepoch;
now = mach_absolute_time();
if (now > rtclock_calend.epoch1)
t64 = now - rtclock_calend.epoch1;
else
t64 = 0;
t32 = (t64 * USEC_PER_SEC) / rtclock_sec_divisor;
if (t32 > delta)
TIME_ADD(sys, 0, microsys, (t32 - delta), USEC_PER_SEC);
rtclock_calend.epoch = sys;
rtclock_calend.microepoch = microsys;
sys = t64 = now / rtclock_sec_divisor;
now -= (t64 * rtclock_sec_divisor);
microsys = (now * USEC_PER_SEC) / rtclock_sec_divisor;
TIME_SUB(rtclock_calend.epoch, sys, rtclock_calend.microepoch, microsys, USEC_PER_SEC);
}
if (total != 0) {
int32_t delta = tickadj;
if (total > 0) {
if (total > bigadj)
delta *= 10;
if (delta > total)
delta = total;
rtclock_calend.epoch1 = 0;
}
else {
uint64_t now, t64;
uint32_t sys, microsys;
if (total < -bigadj)
delta *= 10;
delta = -delta;
if (delta < total)
delta = total;
rtclock_calend.epoch1 = now = mach_absolute_time();
sys = t64 = now / rtclock_sec_divisor;
now -= (t64 * rtclock_sec_divisor);
microsys = (now * USEC_PER_SEC) / rtclock_sec_divisor;
TIME_ADD(rtclock_calend.epoch, sys, rtclock_calend.microepoch, microsys, USEC_PER_SEC);
}
rtclock_calend.adjtotal = total;
rtclock_calend.adjdelta = delta;
interval = rtclock_tick_interval;
}
else {
rtclock_calend.epoch1 = 0;
rtclock_calend.adjdelta = rtclock_calend.adjtotal = 0;
}
UNLOCK_RTC(s);
if (ototal == 0)
*secs = *microsecs = 0;
else {
*secs = ototal / USEC_PER_SEC;
*microsecs = ototal % USEC_PER_SEC;
}
return (interval);
}
uint32_t
clock_adjust_calendar(void)
{
uint32_t interval = 0;
int32_t delta;
spl_t s;
LOCK_RTC(s);
commpage_set_timestamp(0,0,0,0);
delta = rtclock_calend.adjdelta;
if (delta > 0) {
TIME_ADD(rtclock_calend.epoch, 0, rtclock_calend.microepoch, delta, USEC_PER_SEC);
rtclock_calend.adjtotal -= delta;
if (delta > rtclock_calend.adjtotal)
rtclock_calend.adjdelta = rtclock_calend.adjtotal;
}
else
if (delta < 0) {
uint64_t now, t64;
uint32_t t32;
now = mach_absolute_time();
if (now > rtclock_calend.epoch1)
t64 = now - rtclock_calend.epoch1;
else
t64 = 0;
rtclock_calend.epoch1 = now;
t32 = (t64 * USEC_PER_SEC) / rtclock_sec_divisor;
TIME_ADD(rtclock_calend.epoch, 0, rtclock_calend.microepoch, (t32 + delta), USEC_PER_SEC);
rtclock_calend.adjtotal -= delta;
if (delta < rtclock_calend.adjtotal)
rtclock_calend.adjdelta = rtclock_calend.adjtotal;
if (rtclock_calend.adjdelta == 0) {
uint32_t sys, microsys;
sys = t64 = now / rtclock_sec_divisor;
now -= (t64 * rtclock_sec_divisor);
microsys = (now * USEC_PER_SEC) / rtclock_sec_divisor;
TIME_SUB(rtclock_calend.epoch, sys, rtclock_calend.microepoch, microsys, USEC_PER_SEC);
rtclock_calend.epoch1 = 0;
}
}
if (rtclock_calend.adjdelta != 0)
interval = rtclock_tick_interval;
UNLOCK_RTC(s);
return (interval);
}
void
clock_initialize_calendar(void)
{
uint32_t sys, microsys;
uint32_t microsecs = 0, secs = PEGetGMTTimeOfDay();
spl_t s;
LOCK_RTC(s);
commpage_set_timestamp(0,0,0,0);
if ((int32_t)secs >= (int32_t)rtclock_boottime) {
if (rtclock_boottime == 0)
rtclock_boottime = secs;
clock_get_system_microtime(&sys, µsys);
TIME_SUB(secs, sys, microsecs, microsys, USEC_PER_SEC);
rtclock_calend.epoch = secs;
rtclock_calend.microepoch = microsecs;
rtclock_calend.epoch1 = 0;
rtclock_calend.adjdelta = rtclock_calend.adjtotal = 0;
}
UNLOCK_RTC(s);
host_notify_calendar_change();
}
void
clock_get_boottime_nanotime(
uint32_t *secs,
uint32_t *nanosecs)
{
*secs = rtclock_boottime;
*nanosecs = 0;
}
void
clock_timebase_info(
mach_timebase_info_t info)
{
spl_t s;
LOCK_RTC(s);
rtclock_timebase_initialized = TRUE;
*info = rtclock_timebase_const;
UNLOCK_RTC(s);
}
void
clock_set_timer_deadline(
uint64_t deadline)
{
uint64_t abstime;
int decr;
struct rtclock_timer *mytimer;
struct per_proc_info *pp;
spl_t s;
s = splclock();
pp = getPerProc();
mytimer = &pp->rtclock_timer;
mytimer->deadline = deadline;
mytimer->is_set = TRUE;
if (!mytimer->has_expired) {
abstime = mach_absolute_time();
if ( mytimer->deadline < pp->rtclock_tick_deadline ) {
decr = deadline_to_decrementer(mytimer->deadline, abstime);
if ( rtclock_decrementer_min != 0 &&
rtclock_decrementer_min < (natural_t)decr )
decr = rtclock_decrementer_min;
treqs(decr);
KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_DECI, 1)
| DBG_FUNC_NONE, decr, 2, 0, 0, 0);
}
}
splx(s);
}
void
clock_set_timer_func(
clock_timer_func_t func)
{
spl_t s;
LOCK_RTC(s);
if (rtclock_timer_expire == NULL)
rtclock_timer_expire = func;
UNLOCK_RTC(s);
}
void
rtclock_intr(
int device,
struct savearea *ssp,
spl_t old);
void
rtclock_intr(
__unused int device,
struct savearea *ssp,
__unused spl_t old_spl)
{
uint64_t abstime;
int decr1, decr2;
struct rtclock_timer *mytimer;
struct per_proc_info *pp;
decr1 = decr2 = DECREMENTER_MAX;
pp = getPerProc();
abstime = mach_absolute_time();
if ( pp->rtclock_tick_deadline <= abstime ) {
clock_deadline_for_periodic_event(rtclock_tick_interval, abstime,
&pp->rtclock_tick_deadline);
hertz_tick(USER_MODE(ssp->save_srr1), ssp->save_srr0);
}
mytimer = &pp->rtclock_timer;
abstime = mach_absolute_time();
if ( mytimer->is_set &&
mytimer->deadline <= abstime ) {
mytimer->has_expired = TRUE; mytimer->is_set = FALSE;
(*rtclock_timer_expire)(abstime);
mytimer->has_expired = FALSE;
}
abstime = mach_absolute_time();
decr1 = deadline_to_decrementer(pp->rtclock_tick_deadline, abstime);
if (mytimer->is_set)
decr2 = deadline_to_decrementer(mytimer->deadline, abstime);
if (decr1 > decr2)
decr1 = decr2;
if ( rtclock_decrementer_min != 0 &&
rtclock_decrementer_min < (natural_t)decr1 )
decr1 = rtclock_decrementer_min;
treqs(decr1);
KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_DECI, 1)
| DBG_FUNC_NONE, decr1, 3, 0, 0, 0);
}
static void
rtclock_alarm_expire(
__unused void *p0,
__unused void *p1)
{
mach_timespec_t timestamp;
(void) sysclk_gettime(×tamp);
clock_alarm_intr(SYSTEM_CLOCK, ×tamp);
}
static int
deadline_to_decrementer(
uint64_t deadline,
uint64_t now)
{
uint64_t delt;
if (deadline <= now)
return DECREMENTER_MIN;
else {
delt = deadline - now;
return (delt >= (DECREMENTER_MAX + 1))? DECREMENTER_MAX:
((delt >= (DECREMENTER_MIN + 1))? (delt - 1): DECREMENTER_MIN);
}
}
static void
nanotime_to_absolutetime(
uint32_t secs,
uint32_t nanosecs,
uint64_t *result)
{
uint32_t divisor = rtclock_sec_divisor;
*result = ((uint64_t)secs * divisor) +
((uint64_t)nanosecs * divisor) / NSEC_PER_SEC;
}
void
absolutetime_to_microtime(
uint64_t abstime,
uint32_t *secs,
uint32_t *microsecs)
{
uint64_t t64;
uint32_t divisor;
*secs = t64 = abstime / (divisor = rtclock_sec_divisor);
abstime -= (t64 * divisor);
*microsecs = (abstime * USEC_PER_SEC) / divisor;
}
void
clock_interval_to_deadline(
uint32_t interval,
uint32_t scale_factor,
uint64_t *result)
{
uint64_t abstime;
clock_get_uptime(result);
clock_interval_to_absolutetime_interval(interval, scale_factor, &abstime);
*result += abstime;
}
void
clock_interval_to_absolutetime_interval(
uint32_t interval,
uint32_t scale_factor,
uint64_t *result)
{
uint64_t nanosecs = (uint64_t)interval * scale_factor;
uint64_t t64;
uint32_t divisor;
*result = (t64 = nanosecs / NSEC_PER_SEC) *
(divisor = rtclock_sec_divisor);
nanosecs -= (t64 * NSEC_PER_SEC);
*result += (nanosecs * divisor) / NSEC_PER_SEC;
}
void
clock_absolutetime_interval_to_deadline(
uint64_t abstime,
uint64_t *result)
{
clock_get_uptime(result);
*result += abstime;
}
void
absolutetime_to_nanoseconds(
uint64_t abstime,
uint64_t *result)
{
uint64_t t64;
uint32_t divisor;
*result = (t64 = abstime / (divisor = rtclock_sec_divisor)) * NSEC_PER_SEC;
abstime -= (t64 * divisor);
*result += (abstime * NSEC_PER_SEC) / divisor;
}
void
nanoseconds_to_absolutetime(
uint64_t nanosecs,
uint64_t *result)
{
uint64_t t64;
uint32_t divisor;
*result = (t64 = nanosecs / NSEC_PER_SEC) *
(divisor = rtclock_sec_divisor);
nanosecs -= (t64 * NSEC_PER_SEC);
*result += (nanosecs * divisor) / NSEC_PER_SEC;
}
void
machine_delay_until(
uint64_t deadline)
{
uint64_t now;
do {
now = mach_absolute_time();
} while (now < deadline);
}
void treqs(uint32_t dec) {
struct per_proc_info *pp;
uint64_t nowtime, newtime;
nowtime = mach_absolute_time();
pp = getPerProc();
newtime = nowtime + (uint64_t)dec;
pp->rtcPop = newtime;
mtdec((uint32_t)(newtime - nowtime));
return;
}