[PATCH v2 1/3] ntdll: Implement NtQueryInformationThread(ThreadTimes) using procfs.
Rémi Bernon
rbernon at codeweavers.com
Mon Jun 29 01:32:57 CDT 2020
On 2020-06-29 03:43, Zebediah Figura wrote:
> 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 );
> }
>
Wouldn't it be possible (and portable) to track these times in wineserver?
Also FWIW these requests are used a lot by anti-debug checks, and
although they are apparently happy with the times not being reported,
I'm a little bit that reporting times could break some of them (although
I haven't checked yet if they did, I'll try a few ones).
--
Rémi Bernon <rbernon at codeweavers.com>
More information about the wine-devel
mailing list