Sebastian Lackner : ntdll: Implement NtQueryInformationThread(ThreadTimes) using procfs.
Alexandre Julliard
julliard at winehq.org
Mon Jun 29 14:59:20 CDT 2020
Module: wine
Branch: master
Commit: 847b93c7400f82225057e8b71938eb8ccd5d23be
URL: https://source.winehq.org/git/wine.git/?a=commit;h=847b93c7400f82225057e8b71938eb8ccd5d23be
Author: Sebastian Lackner <sebastian at 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 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>
Signed-off-by: Alexandre Julliard <julliard at 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 )
More information about the wine-cvs
mailing list