From 4c69b0e70d6c4f90a14042f756a14f70d968a528 Mon Sep 17 00:00:00 2001
From: Sascha Wildner <saw@online.de>
Date: Sat, 24 Sep 2016 11:37:58 +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: <https://bugs.dragonflybsd.org/issues/2951>
---
 lib/libc/sys/clock_gettime.2 | 40 +++++++++++++----------
 sys/kern/kern_time.c         | 75 ++++++++++++++++++++++++--------------------
 2 files changed, 65 insertions(+), 50 deletions(-)

diff --git a/lib/libc/sys/clock_gettime.2 b/lib/libc/sys/clock_gettime.2
index 63bde7d..14ea412 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 24, 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 41527c7..b45e8e9 100644
--- a/sys/kern/kern_time.c
+++ b/sys/kern/kern_time.c
@@ -152,22 +152,36 @@ settime(struct timeval *tv)
 }
 
 static void
-get_curthread_cputime(struct timespec *ats)
+get_process_cputime(struct proc *p, struct timespec *ats)
 {
-	struct thread *td = curthread;
+	struct rusage ru;
 
-	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();
+	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_thread_cputime(struct thread *td, struct timespec *ats)
+{
+	struct timeval sys, user;
+
+	calcru(td->td_lwp, &user, &sys);
+	timevaladd(&user, &sys);
+	TIMEVAL_TO_TIMESPEC(&user, ats);
 }
 
 /*
@@ -178,7 +192,10 @@ kern_clock_gettime(clockid_t clock_id, struct timespec *ats)
 {
 	int error = 0;
 	struct proc *p;
+	struct thread *td;
 
+	p = curproc;
+	td = curthread;
 	switch(clock_id) {
 	case CLOCK_REALTIME:
 	case CLOCK_REALTIME_PRECISE:
@@ -198,24 +215,18 @@ 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;
 		ats->tv_nsec = 0;
 		break;
 	case CLOCK_THREAD_CPUTIME_ID:
-		get_curthread_cputime(ats);
+		get_thread_cputime(td, ats);
 		break;
 	default:
 		error = EINVAL;
@@ -283,8 +294,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 +305,33 @@ 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;
+	case CLOCK_THREAD_CPUTIME_ID:
+	case CLOCK_PROCESS_CPUTIME_ID:
+		ts->tv_nsec = 1000;
 		break;
 	default:
-		error = EINVAL;
+		return (EINVAL);
 		break;
 	}
 
-	return(error);
+	return (0);
 }
 
 /*
-- 
2.9.2

