Module: wine Branch: master Commit: 847b93c7400f82225057e8b71938eb8ccd5d23be URL: https://source.winehq.org/git/wine.git/?a=commit;h=847b93c7400f82225057e8b71...
Author: Sebastian Lackner sebastian@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@pobox.co.uk.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=20230 Signed-off-by: Zebediah Figura z.figura12@gmail.com Signed-off-by: Alexandre Julliard julliard@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 )