diff options
author | dchagin <dchagin@FreeBSD.org> | 2016-01-09 17:06:21 +0000 |
---|---|---|
committer | dchagin <dchagin@FreeBSD.org> | 2016-01-09 17:06:21 +0000 |
commit | a72b15cf79b4aeaaf7b46ed0e689a5170d7c0538 (patch) | |
tree | e850abd6788fcb8cb7f1f67f72118bdca92768f9 /sys/compat | |
parent | 102940f6d345b6c91c252cd047d127f4c146fb74 (diff) | |
download | FreeBSD-src-a72b15cf79b4aeaaf7b46ed0e689a5170d7c0538.zip FreeBSD-src-a72b15cf79b4aeaaf7b46ed0e689a5170d7c0538.tar.gz |
MFC r283459:
Add some clock mappings used in glibc 2.20.
Diffstat (limited to 'sys/compat')
-rw-r--r-- | sys/compat/linux/linux_time.c | 205 | ||||
-rw-r--r-- | sys/compat/linux/linux_timer.h | 17 |
2 files changed, 205 insertions, 17 deletions
diff --git a/sys/compat/linux/linux_time.c b/sys/compat/linux/linux_time.c index e03af00..f658f8e 100644 --- a/sys/compat/linux/linux_time.c +++ b/sys/compat/linux/linux_time.c @@ -40,8 +40,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> @@ -60,7 +63,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); @@ -158,6 +161,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; @@ -165,21 +182,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); @@ -190,9 +213,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); @@ -203,7 +231,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); @@ -261,19 +382,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, @@ -281,6 +399,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); diff --git a/sys/compat/linux/linux_timer.h b/sys/compat/linux/linux_timer.h index 4f64ee5..6067fc8 100644 --- a/sys/compat/linux/linux_timer.h +++ b/sys/compat/linux/linux_timer.h @@ -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 |