From: Sebastian Lackner sebastian@fds-team.de
Based on a patch by Ray Hinchliffe ray@pobox.co.uk.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=20230 Signed-off-by: Zebediah Figura z.figura12@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 ); }