[PATCH 1/3] ntdll: Return correct values in GetThreadTimes() for all threads.

Zebediah Figura z.figura12 at gmail.com
Tue Jun 2 20:01: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>
---
The only applications associated with this patch, and the others in the series,
are essentially system process monitors. Accordingly, it's not really providing
anything useful over host utilities such as ps(1).

This patch helps System Information Viewer, and the other two in the series help
Process Hacker.

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/thread.c | 84 ++++++++++++++++++++++++++++++++++++---------
 server/protocol.def |  2 ++
 server/thread.c     |  2 ++
 3 files changed, 71 insertions(+), 17 deletions(-)

diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c
index f9ea9203ed..7ec4a359ec 100644
--- a/dlls/ntdll/thread.c
+++ b/dlls/ntdll/thread.c
@@ -22,7 +22,10 @@
 #include "wine/port.h"
 
 #include <assert.h>
+#include <errno.h>
 #include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
 #include <limits.h>
 #include <sys/types.h>
 #ifdef HAVE_SYS_MMAN_H
@@ -764,6 +767,59 @@ NTSTATUS get_thread_context( HANDLE handle, context_t *context, unsigned int fla
     return ret;
 }
 
+#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
 
 /***********************************************************************
  *              NtSetContextThread  (NTDLL.@)
@@ -859,6 +915,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 )
             {
@@ -868,15 +925,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);
 
@@ -884,20 +947,7 @@ 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 632c996dc0..0e4c6e79bc 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -966,6 +966,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.26.2




More information about the wine-devel mailing list