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
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to