Author: dchagin
Date: Tue Feb  4 05:27:05 2020
New Revision: 357493
URL: https://svnweb.freebsd.org/changeset/base/357493

Log:
  Fix clock_gettime() and clock_getres() for cpu clocks:
  - handle the CLOCK_{PROCESS,THREAD}_CPUTIME_ID specified directly;
  - fix thread id calculation as in the Linuxulator we should
    convert the user supplied thread id to struct thread * by linux_tdfind();
  - fix CPUCLOCK_SCHED case by using kern_{process,thread}_cputime()
    directly as native get_cputime() used by kern_clock_gettime() uses
    native tdfind()/pfind() to find proccess/thread.
  
  PR:                   240990
  Reviewed by:          kib
  Differential Revision:        https://reviews.freebsd.org/D23341
  MFC after:            2 weeks

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

Modified: head/sys/compat/linux/linux_time.c
==============================================================================
--- head/sys/compat/linux/linux_time.c  Tue Feb  4 05:25:51 2020        
(r357492)
+++ head/sys/compat/linux/linux_time.c  Tue Feb  4 05:27:05 2020        
(r357493)
@@ -65,6 +65,7 @@ __KERNEL_RCSID(0, "$NetBSD: linux_time.c,v 1.14 2006/0
 #endif
 
 #include <compat/linux/linux_dtrace.h>
+#include <compat/linux/linux_misc.h>
 #include <compat/linux/linux_timer.h>
 
 /* DTrace init */
@@ -203,6 +204,12 @@ linux_to_native_clockid(clockid_t *n, clockid_t l)
        case LINUX_CLOCK_MONOTONIC:
                *n = CLOCK_MONOTONIC;
                break;
+       case LINUX_CLOCK_PROCESS_CPUTIME_ID:
+               *n = CLOCK_PROCESS_CPUTIME_ID;
+               break;
+       case LINUX_CLOCK_THREAD_CPUTIME_ID:
+               *n = CLOCK_THREAD_CPUTIME_ID;
+               break;
        case LINUX_CLOCK_REALTIME_COARSE:
                *n = CLOCK_REALTIME_FAST;
                break;
@@ -269,8 +276,13 @@ linux_clock_gettime(struct thread *td, struct linux_cl
 
        switch (nwhich) {
        case CLOCK_PROCESS_CPUTIME_ID:
-               clockwhich = LINUX_CPUCLOCK_WHICH(args->which);
-               pid = LINUX_CPUCLOCK_ID(args->which);
+               if (args->which < 0) {
+                       clockwhich = LINUX_CPUCLOCK_WHICH(args->which);
+                       pid = LINUX_CPUCLOCK_ID(args->which);
+               } else {
+                       clockwhich = LINUX_CPUCLOCK_SCHED;
+                       pid = 0;
+               }
                if (pid == 0) {
                        p = td->td_proc;
                        PROC_LOCK(p);
@@ -296,12 +308,8 @@ linux_clock_gettime(struct thread *td, struct linux_cl
                        TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &tp);
                        break;
                case LINUX_CPUCLOCK_SCHED:
+                       kern_process_cputime(p, &tp);
                        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);
@@ -311,14 +319,19 @@ linux_clock_gettime(struct thread *td, struct linux_cl
                break;
 
        case CLOCK_THREAD_CPUTIME_ID:
-               clockwhich = LINUX_CPUCLOCK_WHICH(args->which);
+               if (args->which < 0) {
+                       clockwhich = LINUX_CPUCLOCK_WHICH(args->which);
+                       tid = LINUX_CPUCLOCK_ID(args->which);
+               } else {
+                       clockwhich = LINUX_CPUCLOCK_SCHED;
+                       tid = 0;
+               }
                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);
+                       targettd = linux_tdfind(td, tid, p->p_pid);
                        if (targettd == NULL)
                                return (EINVAL);
                }
@@ -343,12 +356,10 @@ linux_clock_gettime(struct thread *td, struct linux_cl
                        TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &tp);
                        break;
                case LINUX_CPUCLOCK_SCHED:
-                       error = kern_clock_getcpuclockid2(td, tid,
-                           CPUCLOCK_WHICH_TID, &nwhich);
+                       if (td == targettd)
+                               targettd = NULL;
+                       kern_thread_cputime(targettd, &tp);
                        PROC_UNLOCK(p);
-                       if (error != 0)
-                               return (EINVAL);
-                       error = kern_clock_gettime(td, nwhich, &tp);
                        break;
                default:
                        PROC_UNLOCK(p);
@@ -440,25 +451,27 @@ linux_clock_getres(struct thread *td, struct linux_clo
         * 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);
+       if (args->which < 0) {
+               switch (nwhich) {
+               case CLOCK_THREAD_CPUTIME_ID:
+                       tid = LINUX_CPUCLOCK_ID(args->which);
+                       if (tid != 0) {
+                               p = td->td_proc;
+                               if (linux_tdfind(td, tid, p->p_pid) == NULL)
+                                       return (EINVAL);
+                               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;
                }
-               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) {
@@ -471,6 +484,20 @@ linux_clock_getres(struct thread *td, struct linux_clo
        case CLOCK_THREAD_CPUTIME_ID:
        case CLOCK_PROCESS_CPUTIME_ID:
                clockwhich = LINUX_CPUCLOCK_WHICH(args->which);
+               /*
+                * In both cases (when the clock id obtained by a call to
+                * clock_getcpuclockid() or using the clock
+                * ID CLOCK_PROCESS_CPUTIME_ID Linux hardcodes precision
+                * of clock. The same for the CLOCK_THREAD_CPUTIME_ID clock.
+                *
+                * See Linux posix_cpu_clock_getres() implementation.
+                */
+               if (args->which > 0 || clockwhich == LINUX_CPUCLOCK_SCHED) {
+                       ts.tv_sec = 0;
+                       ts.tv_nsec = 1;
+                       goto out;
+               }
+
                switch (clockwhich) {
                case LINUX_CPUCLOCK_PROF:
                        nwhich = CLOCK_PROF;
@@ -478,8 +505,6 @@ linux_clock_getres(struct thread *td, struct linux_clo
                case LINUX_CPUCLOCK_VIRT:
                        nwhich = CLOCK_VIRTUAL;
                        break;
-               case LINUX_CPUCLOCK_SCHED:
-                       break;
                default:
                        return (EINVAL);
                }
@@ -494,6 +519,8 @@ linux_clock_getres(struct thread *td, struct linux_clo
                LIN_SDT_PROBE1(time, linux_clock_getres, return, error);
                return (error);
        }
+
+out:
        error = native_to_linux_timespec(&lts, &ts);
        if (error != 0)
                return (error);
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to