[PATCH v2 1/3] ntdll: Implement NtQueryInformationThread(ThreadTimes) using procfs.

Zebediah Figura z.figura12 at gmail.com
Sun Jun 28 20:43:17 CDT 2020


From: Sebastian Lackner <sebastian at fds-team.de>

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>
---
v2: Rebase onto current git (i.e. onto ntdll.so).

This patch lets System Information Viewer, Ollydbg 1.x/2.x, and x64dbg display
accurate values.

While these values are available through host utilities such as ps(1), it is
sometimes more useful to access them from within debuggers and utilities running
under Wine.

I have omitted NtQueryInformationProcess(ProcessTimes), since the obvious
solution needs the server to pass back more data than it currently can, and I
don't know what the preferred way to handle that is.

 dlls/ntdll/unix/thread.c | 82 +++++++++++++++++++++++++++++++---------
 server/protocol.def      |  2 +
 server/thread.c          |  2 +
 3 files changed, 69 insertions(+), 17 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/server/protocol.def b/server/protocol.def
index c3442c06e9..54668a8cdc 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/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 );
     }
-- 
2.27.0




More information about the wine-devel mailing list