Add some clock mappings used in glibc 2.20.

Differential Revision:	https://reviews.freebsd.org/D1465
Reviewd by:	trasz
This commit is contained in:
Dmitry Chagin 2015-05-24 17:23:08 +00:00
parent 7d96520b25
commit 2711aba97e
2 changed files with 205 additions and 17 deletions

View File

@ -39,8 +39,11 @@ __KERNEL_RCSID(0, "$NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp
#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,v 1.14 2006/05/14 03:40:54 christos Exp
#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, clockid_t l)
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, clockid_t l)
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, struct linux_clock_gettime_args *args)
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, struct linux_clock_settime_args *args)
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, struct linux_clock_getres_args *args)
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);

View File

@ -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