Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 24 May 2015 17:23:08 +0000 (UTC)
From:      Dmitry Chagin <dchagin@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r283459 - head/sys/compat/linux
Message-ID:  <201505241723.t4OHN8BB018745@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: dchagin
Date: Sun May 24 17:23:08 2015
New Revision: 283459
URL: https://svnweb.freebsd.org/changeset/base/283459

Log:
  Add some clock mappings used in glibc 2.20.
  
  Differential Revision:	https://reviews.freebsd.org/D1465
  Reviewd by:	trasz

Modified:
  head/sys/compat/linux/linux_time.c
  head/sys/compat/linux/linux_timer.h

Modified: head/sys/compat/linux/linux_time.c
==============================================================================
--- head/sys/compat/linux/linux_time.c	Sun May 24 17:16:55 2015	(r283458)
+++ head/sys/compat/linux/linux_time.c	Sun May 24 17:23:08 2015	(r283459)
@@ -39,8 +39,11 @@ __KERNEL_RCSID(0, "$NetBSD: linux_time.c
 
 #include <sys/param.h>
 #include <sys/kernel.h>
+#include <sys/lock.h>
 #include <sys/ucred.h>
 #include <sys/mount.h>
+#include <sys/mutex.h>
+#include <sys/resourcevar.h>
 #include <sys/sdt.h>
 #include <sys/signal.h>
 #include <sys/stdint.h>
@@ -59,7 +62,7 @@ __KERNEL_RCSID(0, "$NetBSD: linux_time.c
 #endif
 
 #include <compat/linux/linux_dtrace.h>
-#include <compat/linux/linux_misc.h>
+#include <compat/linux/linux_timer.h>
 
 /* DTrace init */
 LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE);
@@ -157,6 +160,20 @@ linux_to_native_clockid(clockid_t *n, cl
 
 	LIN_SDT_PROBE2(time, linux_to_native_clockid, entry, n, l);
 
+	if (l < 0) {
+		/* cpu-clock */
+		if ((l & LINUX_CLOCKFD_MASK) == LINUX_CLOCKFD)
+			return (EINVAL);
+		if (LINUX_CPUCLOCK_WHICH(l) >= LINUX_CPUCLOCK_MAX)
+			return (EINVAL);
+
+		if (LINUX_CPUCLOCK_PERTHREAD(l))
+			*n = CLOCK_THREAD_CPUTIME_ID;
+		else
+			*n = CLOCK_PROCESS_CPUTIME_ID;
+		return (0);
+	}
+
 	switch (l) {
 	case LINUX_CLOCK_REALTIME:
 		*n = CLOCK_REALTIME;
@@ -164,21 +181,27 @@ linux_to_native_clockid(clockid_t *n, cl
 	case LINUX_CLOCK_MONOTONIC:
 		*n = CLOCK_MONOTONIC;
 		break;
-	case LINUX_CLOCK_PROCESS_CPUTIME_ID:
-	case LINUX_CLOCK_THREAD_CPUTIME_ID:
-	case LINUX_CLOCK_REALTIME_HR:
-	case LINUX_CLOCK_MONOTONIC_HR:
+	case LINUX_CLOCK_REALTIME_COARSE:
+		*n = CLOCK_REALTIME_FAST;
+		break;
+	case LINUX_CLOCK_MONOTONIC_COARSE:
+		*n = CLOCK_MONOTONIC_FAST;
+		break;
+	case LINUX_CLOCK_MONOTONIC_RAW:
+	case LINUX_CLOCK_BOOTTIME:
+	case LINUX_CLOCK_REALTIME_ALARM:
+	case LINUX_CLOCK_BOOTTIME_ALARM:
+	case LINUX_CLOCK_SGI_CYCLE:
+	case LINUX_CLOCK_TAI:
 		LIN_SDT_PROBE1(time, linux_to_native_clockid,
 		    unsupported_clockid, l);
 		LIN_SDT_PROBE1(time, linux_to_native_clockid, return, EINVAL);
 		return (EINVAL);
-		break;
 	default:
 		LIN_SDT_PROBE1(time, linux_to_native_clockid,
 		    unknown_clockid, l);
 		LIN_SDT_PROBE1(time, linux_to_native_clockid, return, EINVAL);
 		return (EINVAL);
-		break;
 	}
 
 	LIN_SDT_PROBE1(time, linux_to_native_clockid, return, 0);
@@ -189,9 +212,14 @@ int
 linux_clock_gettime(struct thread *td, struct linux_clock_gettime_args *args)
 {
 	struct l_timespec lts;
-	int error;
-	clockid_t nwhich = 0;	/* XXX: GCC */
 	struct timespec tp;
+	struct rusage ru;
+	struct thread *targettd;
+	struct proc *p;
+	int error, clockwhich;
+	clockid_t nwhich = 0;	/* XXX: GCC */
+	pid_t pid;
+	lwpid_t tid;
 
 	LIN_SDT_PROBE2(time, linux_clock_gettime, entry, args->which, args->tp);
 
@@ -202,7 +230,100 @@ linux_clock_gettime(struct thread *td, s
 		LIN_SDT_PROBE1(time, linux_clock_gettime, return, error);
 		return (error);
 	}
-	error = kern_clock_gettime(td, nwhich, &tp);
+
+	switch (nwhich) {
+	case CLOCK_PROCESS_CPUTIME_ID:
+		clockwhich = LINUX_CPUCLOCK_WHICH(args->which);
+		pid = LINUX_CPUCLOCK_ID(args->which);
+		if (pid == 0) {
+			p = td->td_proc;
+			PROC_LOCK(p);
+		} else {
+			error = pget(pid, PGET_CANSEE, &p);
+			if (error != 0)
+				return (EINVAL);
+		}
+		switch (clockwhich) {
+		case LINUX_CPUCLOCK_PROF:
+			PROC_STATLOCK(p);
+			calcru(p, &ru.ru_utime, &ru.ru_stime);
+			PROC_STATUNLOCK(p);
+			PROC_UNLOCK(p);
+			timevaladd(&ru.ru_utime, &ru.ru_stime);
+			TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &tp);
+			break;
+		case LINUX_CPUCLOCK_VIRT:
+			PROC_STATLOCK(p);
+			calcru(p, &ru.ru_utime, &ru.ru_stime);
+			PROC_STATUNLOCK(p);
+			PROC_UNLOCK(p);
+			TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &tp);
+			break;
+		case LINUX_CPUCLOCK_SCHED:
+			PROC_UNLOCK(p);
+			error = kern_clock_getcpuclockid2(td, pid,
+			    CPUCLOCK_WHICH_PID, &nwhich);
+			if (error != 0)
+				return (EINVAL);
+			error = kern_clock_gettime(td, nwhich, &tp);
+			break;
+		default:
+			PROC_UNLOCK(p);
+			return (EINVAL);
+		}
+
+		break;
+
+	case CLOCK_THREAD_CPUTIME_ID:
+		clockwhich = LINUX_CPUCLOCK_WHICH(args->which);
+		p = td->td_proc;
+		tid = LINUX_CPUCLOCK_ID(args->which);
+		if (tid == 0) {
+			targettd = td;
+			PROC_LOCK(p);
+		} else {
+			targettd = tdfind(tid, p->p_pid);
+			if (targettd == NULL)
+				return (EINVAL);
+		}
+		switch (clockwhich) {
+		case LINUX_CPUCLOCK_PROF:
+			PROC_STATLOCK(p);
+			thread_lock(targettd);
+			rufetchtd(targettd, &ru);
+			thread_unlock(targettd);
+			PROC_STATUNLOCK(p);
+			PROC_UNLOCK(p);
+			timevaladd(&ru.ru_utime, &ru.ru_stime);
+			TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &tp);
+			break;
+		case LINUX_CPUCLOCK_VIRT:
+			PROC_STATLOCK(p);
+			thread_lock(targettd);
+			rufetchtd(targettd, &ru);
+			thread_unlock(targettd);
+			PROC_STATUNLOCK(p);
+			PROC_UNLOCK(p);
+			TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &tp);
+			break;
+		case LINUX_CPUCLOCK_SCHED:
+			error = kern_clock_getcpuclockid2(td, tid,
+			    CPUCLOCK_WHICH_TID, &nwhich);
+			PROC_UNLOCK(p);
+			if (error != 0)
+				return (EINVAL);
+			error = kern_clock_gettime(td, nwhich, &tp);
+			break;
+		default:
+			PROC_UNLOCK(p);
+			return (EINVAL);
+		}
+		break;
+
+	default:
+		error = kern_clock_gettime(td, nwhich, &tp);
+		break;
+	}
 	if (error != 0) {
 		LIN_SDT_PROBE1(time, linux_clock_gettime, gettime_error, error);
 		LIN_SDT_PROBE1(time, linux_clock_gettime, return, error);
@@ -260,19 +381,16 @@ linux_clock_settime(struct thread *td, s
 int
 linux_clock_getres(struct thread *td, struct linux_clock_getres_args *args)
 {
+	struct proc *p;
 	struct timespec ts;
 	struct l_timespec lts;
-	int error;
+	int error, clockwhich;
 	clockid_t nwhich = 0;	/* XXX: GCC */
+	pid_t pid;
+	lwpid_t tid;
 
 	LIN_SDT_PROBE2(time, linux_clock_getres, entry, args->which, args->tp);
 
-	if (args->tp == NULL) {
-		LIN_SDT_PROBE0(time, linux_clock_getres, nullcall);
-		LIN_SDT_PROBE1(time, linux_clock_getres, return, 0);
-	  	return (0);
-	}
-
 	error = linux_to_native_clockid(&nwhich, args->which);
 	if (error != 0) {
 		LIN_SDT_PROBE1(time, linux_clock_getres, conversion_error,
@@ -280,6 +398,59 @@ linux_clock_getres(struct thread *td, st
 		LIN_SDT_PROBE1(time, linux_clock_getres, return, error);
 		return (error);
 	}
+
+	/*
+	 * Check user supplied clock id in case of per-process 
+	 * or thread-specific cpu-time clock.
+	 */
+	switch (nwhich) {
+	case CLOCK_THREAD_CPUTIME_ID:
+		tid = LINUX_CPUCLOCK_ID(args->which);
+		if (tid != 0) {
+			p = td->td_proc;
+			if (tdfind(tid, p->p_pid) == NULL)
+				return (ESRCH);
+			PROC_UNLOCK(p);
+		}
+		break;
+	case CLOCK_PROCESS_CPUTIME_ID:
+		pid = LINUX_CPUCLOCK_ID(args->which);
+		if (pid != 0) {
+			error = pget(pid, PGET_CANSEE, &p);
+			if (error != 0)
+				return (EINVAL);
+			PROC_UNLOCK(p);
+		}
+		break;
+	}
+
+	if (args->tp == NULL) {
+		LIN_SDT_PROBE0(time, linux_clock_getres, nullcall);
+		LIN_SDT_PROBE1(time, linux_clock_getres, return, 0);
+	  	return (0);
+	}
+
+	switch (nwhich) {
+	case CLOCK_THREAD_CPUTIME_ID:
+	case CLOCK_PROCESS_CPUTIME_ID:
+		clockwhich = LINUX_CPUCLOCK_WHICH(args->which);
+		switch (clockwhich) {
+		case LINUX_CPUCLOCK_PROF:
+			nwhich = CLOCK_PROF;
+			break;
+		case LINUX_CPUCLOCK_VIRT:
+			nwhich = CLOCK_VIRTUAL;
+			break;
+		case LINUX_CPUCLOCK_SCHED:
+			break;
+		default:
+			return (EINVAL);
+		}
+		break;
+
+	default:
+		break;
+	}
 	error = kern_clock_getres(td, nwhich, &ts);
 	if (error != 0) {
 		LIN_SDT_PROBE1(time, linux_clock_getres, getres_error, error);

Modified: head/sys/compat/linux/linux_timer.h
==============================================================================
--- head/sys/compat/linux/linux_timer.h	Sun May 24 17:16:55 2015	(r283458)
+++ head/sys/compat/linux/linux_timer.h	Sun May 24 17:23:08 2015	(r283459)
@@ -56,6 +56,23 @@
 #define	LINUX_CLOCK_SGI_CYCLE			10
 #define	LINUX_CLOCK_TAI				11
 
+#define	LINUX_CPUCLOCK_PERTHREAD_MASK		4
+#define	LINUX_CPUCLOCK_MASK			3
+#define	LINUX_CPUCLOCK_WHICH(clock)		\
+	((clock) & (clockid_t) LINUX_CPUCLOCK_MASK)
+#define	LINUX_CPUCLOCK_PROF			0
+#define	LINUX_CPUCLOCK_VIRT			1
+#define	LINUX_CPUCLOCK_SCHED			2
+#define	LINUX_CPUCLOCK_MAX			3
+#define	LINUX_CLOCKFD				LINUX_CPUCLOCK_MAX
+#define	LINUX_CLOCKFD_MASK			\
+	(LINUX_CPUCLOCK_PERTHREAD_MASK|LINUX_CPUCLOCK_MASK)
+
+#define	LINUX_CPUCLOCK_ID(clock)		((pid_t) ~((clock) >> 3))
+#define	LINUX_CPUCLOCK_PERTHREAD(clock)		\
+	(((clock) & (clockid_t) LINUX_CPUCLOCK_PERTHREAD_MASK) != 0)
+
+
 #define	L_SIGEV_SIGNAL				0
 #define	L_SIGEV_NONE				1
 #define	L_SIGEV_THREAD				2



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201505241723.t4OHN8BB018745>