Sebastian Lackner : ntdll: Implement NtQueryInformationThread(ThreadTimes) using procfs.

Alexandre Julliard julliard at winehq.org
Mon Jun 29 14:59:20 CDT 2020


Module: wine
Branch: master
Commit: 847b93c7400f82225057e8b71938eb8ccd5d23be
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=847b93c7400f82225057e8b71938eb8ccd5d23be

Author: Sebastian Lackner <sebastian at fds-team.de>
Date:   Sun Jun 28 20:43:17 2020 -0500

ntdll: Implement NtQueryInformationThread(ThreadTimes) using procfs.

Based on a patch by Ray Hinchliffe <ray at pobox.co.uk>.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=20230
Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/ntdll/unix/thread.c       | 82 +++++++++++++++++++++++++++++++++---------
 include/wine/server_protocol.h |  4 ++-
 server/protocol.def            |  2 ++
 server/request.h               |  4 ++-
 server/thread.c                |  2 ++
 server/trace.c                 |  2 ++
 6 files changed, 77 insertions(+), 19 deletions(-)

diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c
index f3dddd2b02..54483e1f99 100644
--- a/dlls/ntdll/unix/thread.c
+++ b/dlls/ntdll/unix/thread.c
@@ -29,6 +29,8 @@
 #include <errno.h>
 #include <limits.h>
 #include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
 #include <pthread.h>
 #include <signal.h>
 #include <sys/types.h>
@@ -821,6 +823,59 @@ static void wow64_context_to_server( context_t *to, const WOW64_CONTEXT *from )
 
 #endif /* __x86_64__ */
 
+#ifdef linux
+static BOOL get_thread_times(int unix_pid, int unix_tid, LARGE_INTEGER *kernel_time, LARGE_INTEGER *user_time)
+{
+    unsigned long clocks_per_sec = sysconf( _SC_CLK_TCK );
+    unsigned long usr, sys;
+    const char *pos;
+    char buf[512];
+    FILE *f;
+    int i;
+
+    sprintf( buf, "/proc/%u/task/%u/stat", unix_pid, unix_tid );
+    if (!(f = fopen( buf, "r" )))
+    {
+        ERR("Failed to open %s: %s\n", buf, strerror(errno));
+        return FALSE;
+    }
+
+    pos = fgets( buf, sizeof(buf), f );
+    fclose( f );
+
+    /* the process name is printed unescaped, so we have to skip to the last ')'
+     * to avoid misinterpreting the string */
+    if (pos) pos = strrchr( pos, ')' );
+    if (pos) pos = strchr( pos + 1, ' ' );
+    if (pos) pos++;
+
+    /* skip over the following fields: state, ppid, pgid, sid, tty_nr, tty_pgrp,
+     * task->flags, min_flt, cmin_flt, maj_flt, cmaj_flt */
+    for (i = 0; i < 11 && pos; i++)
+    {
+        pos = strchr( pos + 1, ' ' );
+        if (pos) pos++;
+    }
+
+    /* the next two values are user and system time */
+    if (pos && (sscanf( pos, "%lu %lu", &usr, &sys ) == 2))
+    {
+        kernel_time->QuadPart = (ULONGLONG)sys * 10000000 / clocks_per_sec;
+        user_time->QuadPart = (ULONGLONG)usr * 10000000 / clocks_per_sec;
+        return TRUE;
+    }
+
+    ERR("Failed to parse %s\n", debugstr_a(buf));
+    return FALSE;
+}
+#else
+static BOOL get_thread_times(int unix_pid, int unix_tid, LARGE_INTEGER *kernel_time, LARGE_INTEGER *user_time)
+{
+    static int once;
+    if (!once++) FIXME("not implemented on this platform\n");
+    return FALSE;
+}
+#endif
 
 /******************************************************************************
  *              NtQueryInformationThread  (NTDLL.@)
@@ -886,6 +941,7 @@ NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class,
     case ThreadTimes:
     {
         KERNEL_USER_TIMES kusrt;
+        int unix_pid, unix_tid;
 
         SERVER_START_REQ( get_thread_times )
         {
@@ -895,15 +951,21 @@ NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class,
             {
                 kusrt.CreateTime.QuadPart = reply->creation_time;
                 kusrt.ExitTime.QuadPart = reply->exit_time;
+                unix_pid = reply->unix_pid;
+                unix_tid = reply->unix_tid;
             }
         }
         SERVER_END_REQ;
         if (status == STATUS_SUCCESS)
         {
-            /* We call times(2) for kernel time or user time */
-            /* We can only (portably) do this for the current thread */
-            if (handle == GetCurrentThread())
+            BOOL ret = FALSE;
+
+            kusrt.KernelTime.QuadPart = kusrt.UserTime.QuadPart = 0;
+            if (unix_pid != -1 && unix_tid != -1)
+                ret = get_thread_times( unix_pid, unix_tid, &kusrt.KernelTime, &kusrt.UserTime );
+            if (!ret && handle == GetCurrentThread())
             {
+                /* fall back to process times */
                 struct tms time_buf;
                 long clocks_per_sec = sysconf(_SC_CLK_TCK);
 
@@ -911,20 +973,6 @@ NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class,
                 kusrt.KernelTime.QuadPart = (ULONGLONG)time_buf.tms_stime * 10000000 / clocks_per_sec;
                 kusrt.UserTime.QuadPart = (ULONGLONG)time_buf.tms_utime * 10000000 / clocks_per_sec;
             }
-            else
-            {
-                static BOOL reported = FALSE;
-
-                kusrt.KernelTime.QuadPart = 0;
-                kusrt.UserTime.QuadPart = 0;
-                if (reported)
-                    TRACE("Cannot get kerneltime or usertime of other threads\n");
-                else
-                {
-                    FIXME("Cannot get kerneltime or usertime of other threads\n");
-                    reported = TRUE;
-                }
-            }
             if (data) memcpy( data, &kusrt, min( length, sizeof(kusrt) ));
             if (ret_len) *ret_len = min( length, sizeof(kusrt) );
         }
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 1acaded199..0473c6a64a 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -1037,6 +1037,8 @@ struct get_thread_times_reply
     struct reply_header __header;
     timeout_t    creation_time;
     timeout_t    exit_time;
+    int          unix_pid;
+    int          unix_tid;
 };
 
 
@@ -6700,7 +6702,7 @@ union generic_reply
 
 /* ### protocol_version begin ### */
 
-#define SERVER_PROTOCOL_VERSION 609
+#define SERVER_PROTOCOL_VERSION 610
 
 /* ### protocol_version end ### */
 
diff --git a/server/protocol.def b/server/protocol.def
index d412889518..ed8ca3c478 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -967,6 +967,8 @@ struct rawinput_device
 @REPLY
     timeout_t    creation_time; /* thread creation time */
     timeout_t    exit_time;     /* thread exit time */
+    int          unix_pid;      /* thread native pid */
+    int          unix_tid;      /* thread native pid */
 @END
 
 
diff --git a/server/request.h b/server/request.h
index 7c7c0fd92f..2a64643848 100644
--- a/server/request.h
+++ b/server/request.h
@@ -862,7 +862,9 @@ C_ASSERT( FIELD_OFFSET(struct get_thread_times_request, handle) == 12 );
 C_ASSERT( sizeof(struct get_thread_times_request) == 16 );
 C_ASSERT( FIELD_OFFSET(struct get_thread_times_reply, creation_time) == 8 );
 C_ASSERT( FIELD_OFFSET(struct get_thread_times_reply, exit_time) == 16 );
-C_ASSERT( sizeof(struct get_thread_times_reply) == 24 );
+C_ASSERT( FIELD_OFFSET(struct get_thread_times_reply, unix_pid) == 24 );
+C_ASSERT( FIELD_OFFSET(struct get_thread_times_reply, unix_tid) == 28 );
+C_ASSERT( sizeof(struct get_thread_times_reply) == 32 );
 C_ASSERT( FIELD_OFFSET(struct set_thread_info_request, handle) == 12 );
 C_ASSERT( FIELD_OFFSET(struct set_thread_info_request, mask) == 16 );
 C_ASSERT( FIELD_OFFSET(struct set_thread_info_request, priority) == 20 );
diff --git a/server/thread.c b/server/thread.c
index e2bfa50c7b..3cf447b1a0 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -1554,6 +1554,8 @@ DECL_HANDLER(get_thread_times)
     {
         reply->creation_time  = thread->creation_time;
         reply->exit_time      = thread->exit_time;
+        reply->unix_pid       = thread->unix_pid;
+        reply->unix_tid       = thread->unix_tid;
 
         release_object( thread );
     }
diff --git a/server/trace.c b/server/trace.c
index 6c7f3251db..2b22dc5207 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -1442,6 +1442,8 @@ static void dump_get_thread_times_reply( const struct get_thread_times_reply *re
 {
     dump_timeout( " creation_time=", &req->creation_time );
     dump_timeout( ", exit_time=", &req->exit_time );
+    fprintf( stderr, ", unix_pid=%d", req->unix_pid );
+    fprintf( stderr, ", unix_tid=%d", req->unix_tid );
 }
 
 static void dump_set_thread_info_request( const struct set_thread_info_request *req )




More information about the wine-cvs mailing list