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>
This commit is contained in:
parent
045455bfe4
commit
847b93c740
|
@ -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) );
|
||||
}
|
||||
|
|
|
@ -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 ### */
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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 )
|
||||
|
|
Loading…
Reference in New Issue