From c1b9c0932e482bb6a37eb190a5b504b270d2166d Mon Sep 17 00:00:00 2001 From: Sascha Wildner Date: Mon, 26 Sep 2016 00:36:03 +0200 Subject: [PATCH] kernel/clock_gettime: Various fixes. * Fix CLOCK_PROF and CLOCK_VIRTUAL to behave like FreeBSD's. They are not meant to return the values of ITIMER_PROF and ITIMER_VIRTUAL (which are decreasing, see getitimer(2)), like they were implemented by 91810a6f0686477493e9915e98cfc5adcbe91363. This also fixes CLOCK_PROCESS_CPUTIME_ID. * Fix CLOCK_PROCESS_THREAD_ID. It was adding the values wrongly in a way that could cause tv_nsec to overflow (i.e. become >= 1000000000). * Fix clock_getres() for CLOCK_{PROCESS,THREAD}_CPUTIME_ID. * Mention CLOCK_{PROCESS,THREAD}_CPUTIME_ID in clock_gettime()'s manual page. * Bring in some minor manual page fixes from FreeBSD. Reported-by: zhtw Dragonfly-bug: --- lib/libc/sys/clock_gettime.2 | 40 +++++++++++-------- sys/kern/kern_time.c | 75 +++++++++++++++++++----------------- 2 files changed, 63 insertions(+), 52 deletions(-) diff --git a/lib/libc/sys/clock_gettime.2 b/lib/libc/sys/clock_gettime.2 index 63bde7d856..dcab0f09e4 100644 --- a/lib/libc/sys/clock_gettime.2 +++ b/lib/libc/sys/clock_gettime.2 @@ -1,5 +1,4 @@ .\" $OpenBSD: clock_gettime.2,v 1.4 1997/05/08 20:21:16 kstailey Exp $ -.\" $FreeBSD: src/lib/libc/sys/clock_gettime.2,v 1.3.2.8 2001/12/14 18:34:00 ru Exp $ .\" .\" Copyright (c) 1980, 1991, 1993 .\" The Regents of the University of California. All rights reserved. @@ -28,7 +27,9 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd March 17, 2015 +.\" $FreeBSD: head/lib/libc/sys/clock_gettime.2 292777 2015-12-27 15:37:07Z dchagin $ +.\" +.Dd September 26, 2016 .Dt CLOCK_GETTIME 2 .Os .Sh NAME @@ -51,11 +52,13 @@ The .Fn clock_gettime and .Fn clock_settime -allow the calling process to retrieve or set the value used by a clock -which is specified by +system calls allow the calling process to retrieve or set the value +used by a clock which is specified by .Fa clock_id . .Pp +The .Fa clock_id +argument can be one of the following values: .Dv CLOCK_REALTIME , .Dv CLOCK_REALTIME_PRECISE , @@ -78,10 +81,14 @@ for time that increments only when the CPU is running in user mode on behalf of the calling process; .Dv CLOCK_PROF for time that increments when the CPU is running in user or -kernel mode; or +kernel mode; .Dv CLOCK_SECOND which returns the current second without performing a full time counter -query, using in-kernel cached value of current second. +query, using in-kernel cached value of current second; +.Dv CLOCK_PROCESS_CPUTIME_ID +which returns the CPU-time clock of the calling process; or +.Dv CLOCK_THREAD_CPUTIME_ID +which returns the CPU-time clock of the calling thread. .Pp The clock IDs .Dv CLOCK_REALTIME_FAST , @@ -111,7 +118,7 @@ and do not incur any system call overhead after a certain amount of calls. The structure pointed to by .Fa tp is defined in -.In sys/time.h +.In sys/_timespec.h as: .Bd -literal struct timespec { @@ -120,7 +127,8 @@ struct timespec { }; .Ed .Pp -Only the super-user may set the time of day. +Only the super-user may set the time of day, using only +.Dv CLOCK_REALTIME . If the system securelevel is greater than 1 (see .Xr init 8 ) , the time may only be advanced. @@ -132,7 +140,7 @@ system call even when the system is secure. .Pp The resolution (granularity) of a clock is returned by the .Fn clock_getres -call. +system call. This value is placed in a (non-NULL) .Fa *tp . .Sh RETURN VALUES @@ -144,11 +152,9 @@ The following error codes may be set in .It Bq Er EINVAL The .Fa clock_id -was not a valid value. -.It Bq Er EFAULT -The -.Fa *tp -argument address referenced invalid memory. +or +.Fa tp +argument was not a valid value. .It Bq Er EPERM A user other than the super-user attempted to set the time. .El @@ -160,8 +166,10 @@ A user other than the super-user attempted to set the time. .Sh STANDARDS The .Fn clock_gettime , -etc.\& -functions conform to +.Fn clock_settime , +and +.Fn clock_getres +system calls conform to .St -p1003.1b-93 . The clock IDs .Dv CLOCK_REALTIME_FAST , diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c index 41527c7ac5..cd03e87ec4 100644 --- a/sys/kern/kern_time.c +++ b/sys/kern/kern_time.c @@ -151,23 +151,38 @@ settime(struct timeval *tv) return (0); } +static void +get_process_cputime(struct proc *p, struct timespec *ats) +{ + struct rusage ru; + + lwkt_gettoken(&p->p_token); + calcru_proc(p, &ru); + lwkt_reltoken(&p->p_token); + timevaladd(&ru.ru_utime, &ru.ru_stime); + TIMEVAL_TO_TIMESPEC(&ru.ru_utime, ats); +} + +static void +get_process_usertime(struct proc *p, struct timespec *ats) +{ + struct rusage ru; + + lwkt_gettoken(&p->p_token); + calcru_proc(p, &ru); + lwkt_reltoken(&p->p_token); + TIMEVAL_TO_TIMESPEC(&ru.ru_utime, ats); +} + static void get_curthread_cputime(struct timespec *ats) { struct thread *td = curthread; + struct timeval sys, user; - crit_enter(); - /* - * These are 64-bit fields but the actual values should never reach - * the limit. We don't care about overflows. - */ - ats->tv_sec = td->td_uticks / 1000000; - ats->tv_sec += td->td_sticks / 1000000; - ats->tv_sec += td->td_iticks / 1000000; - ats->tv_nsec = (td->td_uticks % 1000000) * 1000; - ats->tv_nsec += (td->td_sticks % 1000000) * 1000; - ats->tv_nsec += (td->td_iticks % 1000000) * 1000; - crit_exit(); + calcru(td->td_lwp, &user, &sys); + timevaladd(&user, &sys); + TIMEVAL_TO_TIMESPEC(&user, ats); } /* @@ -176,9 +191,9 @@ get_curthread_cputime(struct timespec *ats) int kern_clock_gettime(clockid_t clock_id, struct timespec *ats) { - int error = 0; struct proc *p; + p = curproc; switch(clock_id) { case CLOCK_REALTIME: case CLOCK_REALTIME_PRECISE: @@ -198,17 +213,11 @@ kern_clock_gettime(clockid_t clock_id, struct timespec *ats) getnanouptime(ats); break; case CLOCK_VIRTUAL: - p = curproc; - ats->tv_sec = p->p_timer[ITIMER_VIRTUAL].it_value.tv_sec; - ats->tv_nsec = p->p_timer[ITIMER_VIRTUAL].it_value.tv_usec * - 1000; + get_process_usertime(p, ats); break; case CLOCK_PROF: case CLOCK_PROCESS_CPUTIME_ID: - p = curproc; - ats->tv_sec = p->p_timer[ITIMER_PROF].it_value.tv_sec; - ats->tv_nsec = p->p_timer[ITIMER_PROF].it_value.tv_usec * - 1000; + get_process_cputime(p, ats); break; case CLOCK_SECOND: ats->tv_sec = time_second; @@ -218,10 +227,9 @@ kern_clock_gettime(clockid_t clock_id, struct timespec *ats) get_curthread_cputime(ats); break; default: - error = EINVAL; - break; + return (EINVAL); } - return (error); + return (0); } /* @@ -283,8 +291,7 @@ sys_clock_settime(struct clock_settime_args *uap) int kern_clock_getres(clockid_t clock_id, struct timespec *ts) { - int error; - + ts->tv_sec = 0; switch(clock_id) { case CLOCK_REALTIME: case CLOCK_REALTIME_FAST: @@ -295,36 +302,32 @@ kern_clock_getres(clockid_t clock_id, struct timespec *ts) case CLOCK_UPTIME: case CLOCK_UPTIME_FAST: case CLOCK_UPTIME_PRECISE: - case CLOCK_THREAD_CPUTIME_ID: - case CLOCK_PROCESS_CPUTIME_ID: /* * Round up the result of the division cheaply * by adding 1. Rounding up is especially important * if rounding down would give 0. Perfect rounding * is unimportant. */ - ts->tv_sec = 0; ts->tv_nsec = 1000000000 / sys_cputimer->freq + 1; - error = 0; break; case CLOCK_VIRTUAL: case CLOCK_PROF: /* Accurately round up here because we can do so cheaply. */ - ts->tv_sec = 0; ts->tv_nsec = (1000000000 + hz - 1) / hz; - error = 0; break; case CLOCK_SECOND: ts->tv_sec = 1; ts->tv_nsec = 0; - error = 0; break; - default: - error = EINVAL; + case CLOCK_THREAD_CPUTIME_ID: + case CLOCK_PROCESS_CPUTIME_ID: + ts->tv_nsec = 1000; break; + default: + return (EINVAL); } - return(error); + return (0); } /* -- 2.41.0