diff options
author | cheloha <cheloha@cvs.openbsd.org> | 2019-10-26 21:16:39 +0000 |
---|---|---|
committer | cheloha <cheloha@cvs.openbsd.org> | 2019-10-26 21:16:39 +0000 |
commit | 00d2d25764dcd4eb1fbe19182d6bf34c546fe306 (patch) | |
tree | 50827026722331193ef848f46e8ac280e72f879d /sys/kern | |
parent | 49a30ec569d6a50a04865947ad5b87bcb4cf0d1a (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.c | 16 | ||||
-rw-r--r-- | sys/kern/kern_time.c | 27 |
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); |