summaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
authorcheloha <cheloha@cvs.openbsd.org>2019-10-26 21:16:39 +0000
committercheloha <cheloha@cvs.openbsd.org>2019-10-26 21:16:39 +0000
commit00d2d25764dcd4eb1fbe19182d6bf34c546fe306 (patch)
tree50827026722331193ef848f46e8ac280e72f879d /sys/kern
parent49a30ec569d6a50a04865947ad5b87bcb4cf0d1a (diff)
clock_getres(2): actually return the resolution of the given clock
Currently we return (1000000000 / hz) from clock_getres(2) as the resolution for every clock. This is often untrue. For CPUTIME clocks, if we have a separate statclock interrupt the resolution is (1000000000 / stathz). Otherwise it is as we currently claim: (1000000000 / hz). For the REALTIME/MONOTONIC/UPTIME/BOOTTIME clocks the resolution is that of the active timecounter. During tc_init() we can compute the precision of a timecounter by examining its tc_counter_mask and store it for lookup later in a new member, tc_precision. The resolution of a clock backed by a timecounter "tc" is then tc.tc_precision * (2^64 / tc.tc_frequency) fractional seconds. While here we can clean up sys_clock_getres() a bit. Standards input from guenther@. Lots of input, feedback from kettenis@. ok kettenis@
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/kern_tc.c16
-rw-r--r--sys/kern/kern_time.c27
2 files changed, 32 insertions, 11 deletions
diff --git a/sys/kern/kern_tc.c b/sys/kern/kern_tc.c
index d72f305a0bb..7f427e44667 100644
--- a/sys/kern/kern_tc.c
+++ b/sys/kern/kern_tc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_tc.c,v 1.49 2019/10/22 20:19:41 cheloha Exp $ */
+/* $OpenBSD: kern_tc.c,v 1.50 2019/10/26 21:16:38 cheloha Exp $ */
/*
* Copyright (c) 2000 Poul-Henning Kamp <phk@FreeBSD.org>
@@ -310,6 +310,7 @@ getmicrotime(struct timeval *tvp)
void
tc_init(struct timecounter *tc)
{
+ u_int64_t tmp;
u_int u;
u = tc->tc_frequency / tc->tc_counter_mask;
@@ -325,6 +326,11 @@ tc_init(struct timecounter *tc)
}
}
+ /* Determine the counter's precision. */
+ for (tmp = 1; (tmp & tc->tc_counter_mask) == 0; tmp <<= 1)
+ continue;
+ tc->tc_precision = tmp;
+
SLIST_INSERT_HEAD(&tc_list, tc, tc_next);
/*
@@ -349,10 +355,16 @@ tc_init(struct timecounter *tc)
u_int64_t
tc_getfrequency(void)
{
-
return (timehands->th_counter->tc_frequency);
}
+/* Report the precision of the current timecounter. */
+u_int64_t
+tc_getprecision(void)
+{
+ return (timehands->th_counter->tc_precision);
+}
+
/*
* Step our concept of UTC, aka the realtime clock.
* This is done by modifying our estimate of when we booted.
diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c
index 31934323f71..b1d421684df 100644
--- a/sys/kern/kern_time.c
+++ b/sys/kern/kern_time.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_time.c,v 1.124 2019/09/04 14:27:55 cheloha Exp $ */
+/* $OpenBSD: kern_time.c,v 1.125 2019/10/26 21:16:38 cheloha Exp $ */
/* $NetBSD: kern_time.c,v 1.20 1996/02/18 11:57:06 fvdl Exp $ */
/*
@@ -214,21 +214,31 @@ sys_clock_getres(struct proc *p, void *v, register_t *retval)
syscallarg(struct timespec *) tp;
} */ *uap = v;
clockid_t clock_id;
+ struct bintime bt;
struct timespec ts;
struct proc *q;
- int error = 0;
+ u_int64_t scale;
+ int error = 0, realstathz;
memset(&ts, 0, sizeof(ts));
+ realstathz = (stathz == 0) ? hz : stathz;
clock_id = SCARG(uap, clock_id);
+
switch (clock_id) {
case CLOCK_REALTIME:
case CLOCK_MONOTONIC:
case CLOCK_BOOTTIME:
case CLOCK_UPTIME:
+ memset(&bt, 0, sizeof(bt));
+ rw_enter_read(&tc_lock);
+ scale = ((1ULL << 63) / tc_getfrequency()) * 2;
+ bt.frac = tc_getprecision() * scale;
+ rw_exit_read(&tc_lock);
+ BINTIME_TO_TIMESPEC(&bt, &ts);
+ break;
case CLOCK_PROCESS_CPUTIME_ID:
case CLOCK_THREAD_CPUTIME_ID:
- ts.tv_sec = 0;
- ts.tv_nsec = 1000000000 / hz;
+ ts.tv_nsec = 1000000000 / realstathz;
break;
default:
/* check for clock from pthread_getcpuclockid() */
@@ -237,10 +247,8 @@ sys_clock_getres(struct proc *p, void *v, register_t *retval)
q = tfind(__CLOCK_PTID(clock_id) - THREAD_PID_OFFSET);
if (q == NULL || q->p_p != p->p_p)
error = ESRCH;
- else {
- ts.tv_sec = 0;
- ts.tv_nsec = 1000000000 / hz;
- }
+ else
+ ts.tv_nsec = 1000000000 / realstathz;
KERNEL_UNLOCK();
} else
error = EINVAL;
@@ -248,7 +256,8 @@ sys_clock_getres(struct proc *p, void *v, register_t *retval)
}
if (error == 0 && SCARG(uap, tp)) {
- error = copyout(&ts, SCARG(uap, tp), sizeof (ts));
+ ts.tv_nsec = MAX(ts.tv_nsec, 1);
+ error = copyout(&ts, SCARG(uap, tp), sizeof(ts));
#ifdef KTRACE
if (error == 0 && KTRPOINT(p, KTR_STRUCT))
ktrreltimespec(p, &ts);