Commit 847b93c7 authored by Sebastian Lackner's avatar Sebastian Lackner Committed by Alexandre Julliard

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=20230Signed-off-by: 's avatarZebediah Figura <z.figura12@gmail.com> Signed-off-by: 's avatarAlexandre Julliard <julliard@winehq.org>
parent 045455bf
...@@ -29,6 +29,8 @@ ...@@ -29,6 +29,8 @@
#include <errno.h> #include <errno.h>
#include <limits.h> #include <limits.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h> #include <pthread.h>
#include <signal.h> #include <signal.h>
#include <sys/types.h> #include <sys/types.h>
...@@ -821,6 +823,59 @@ static void wow64_context_to_server( context_t *to, const WOW64_CONTEXT *from ) ...@@ -821,6 +823,59 @@ static void wow64_context_to_server( context_t *to, const WOW64_CONTEXT *from )
#endif /* __x86_64__ */ #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.@) * NtQueryInformationThread (NTDLL.@)
...@@ -886,6 +941,7 @@ NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class, ...@@ -886,6 +941,7 @@ NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class,
case ThreadTimes: case ThreadTimes:
{ {
KERNEL_USER_TIMES kusrt; KERNEL_USER_TIMES kusrt;
int unix_pid, unix_tid;
SERVER_START_REQ( get_thread_times ) SERVER_START_REQ( get_thread_times )
{ {
...@@ -895,15 +951,21 @@ NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class, ...@@ -895,15 +951,21 @@ NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class,
{ {
kusrt.CreateTime.QuadPart = reply->creation_time; kusrt.CreateTime.QuadPart = reply->creation_time;
kusrt.ExitTime.QuadPart = reply->exit_time; kusrt.ExitTime.QuadPart = reply->exit_time;
unix_pid = reply->unix_pid;
unix_tid = reply->unix_tid;
} }
} }
SERVER_END_REQ; SERVER_END_REQ;
if (status == STATUS_SUCCESS) if (status == STATUS_SUCCESS)
{ {
/* We call times(2) for kernel time or user time */ BOOL ret = FALSE;
/* We can only (portably) do this for the current thread */
if (handle == GetCurrentThread()) 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; struct tms time_buf;
long clocks_per_sec = sysconf(_SC_CLK_TCK); long clocks_per_sec = sysconf(_SC_CLK_TCK);
...@@ -911,20 +973,6 @@ NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class, ...@@ -911,20 +973,6 @@ NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class,
kusrt.KernelTime.QuadPart = (ULONGLONG)time_buf.tms_stime * 10000000 / clocks_per_sec; kusrt.KernelTime.QuadPart = (ULONGLONG)time_buf.tms_stime * 10000000 / clocks_per_sec;
kusrt.UserTime.QuadPart = (ULONGLONG)time_buf.tms_utime * 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 (data) memcpy( data, &kusrt, min( length, sizeof(kusrt) ));
if (ret_len) *ret_len = min( length, sizeof(kusrt) ); if (ret_len) *ret_len = min( length, sizeof(kusrt) );
} }
......
...@@ -1037,6 +1037,8 @@ struct get_thread_times_reply ...@@ -1037,6 +1037,8 @@ struct get_thread_times_reply
struct reply_header __header; struct reply_header __header;
timeout_t creation_time; timeout_t creation_time;
timeout_t exit_time; timeout_t exit_time;
int unix_pid;
int unix_tid;
}; };
...@@ -6700,7 +6702,7 @@ union generic_reply ...@@ -6700,7 +6702,7 @@ union generic_reply
/* ### protocol_version begin ### */ /* ### protocol_version begin ### */
#define SERVER_PROTOCOL_VERSION 609 #define SERVER_PROTOCOL_VERSION 610
/* ### protocol_version end ### */ /* ### protocol_version end ### */
......
...@@ -967,6 +967,8 @@ struct rawinput_device ...@@ -967,6 +967,8 @@ struct rawinput_device
@REPLY @REPLY
timeout_t creation_time; /* thread creation time */ timeout_t creation_time; /* thread creation time */
timeout_t exit_time; /* thread exit time */ timeout_t exit_time; /* thread exit time */
int unix_pid; /* thread native pid */
int unix_tid; /* thread native pid */
@END @END
......
...@@ -862,7 +862,9 @@ C_ASSERT( FIELD_OFFSET(struct get_thread_times_request, handle) == 12 ); ...@@ -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( 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, creation_time) == 8 );
C_ASSERT( FIELD_OFFSET(struct get_thread_times_reply, exit_time) == 16 ); 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, handle) == 12 );
C_ASSERT( FIELD_OFFSET(struct set_thread_info_request, mask) == 16 ); C_ASSERT( FIELD_OFFSET(struct set_thread_info_request, mask) == 16 );
C_ASSERT( FIELD_OFFSET(struct set_thread_info_request, priority) == 20 ); C_ASSERT( FIELD_OFFSET(struct set_thread_info_request, priority) == 20 );
......
...@@ -1554,6 +1554,8 @@ DECL_HANDLER(get_thread_times) ...@@ -1554,6 +1554,8 @@ DECL_HANDLER(get_thread_times)
{ {
reply->creation_time = thread->creation_time; reply->creation_time = thread->creation_time;
reply->exit_time = thread->exit_time; reply->exit_time = thread->exit_time;
reply->unix_pid = thread->unix_pid;
reply->unix_tid = thread->unix_tid;
release_object( thread ); release_object( thread );
} }
......
...@@ -1442,6 +1442,8 @@ static void dump_get_thread_times_reply( const struct get_thread_times_reply *re ...@@ -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( " creation_time=", &req->creation_time );
dump_timeout( ", exit_time=", &req->exit_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 ) static void dump_set_thread_info_request( const struct set_thread_info_request *req )
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment