Fix user/kernel times of GetProcessTimes()
Sidney Fong
wine at sidney.hk
Sun Oct 22 03:10:28 CDT 2006
From 487243c1040f7ed17bd9241fc0f63f3f4774d76d Mon Sep 17 00:00:00 2001
From: FONG Sidney Hok Nang <wine at sidney.hk>
Date: Sun, 22 Oct 2006 15:36:38 +0800
Subject: Fix user/kernel times of GetProcessTimes()
Changes:
Fix the known bug[1] of GetProcessTimes() where it originally returned
the user/kernel times of the current process instead of the designated
one
[1]: See bottom of http://source.winehq.org/WineAPI/GetProcessTimes.html
Notes:
POSIX does not seem to have a good way to get the rusage of a running
process. Therefore a not-so-clean workaround is implemented as
get_process_rusage(), using ptrace to stop the designated process so we
can wait4() it.
---
dlls/kernel32/time.c | 30 ++--------------------------
dlls/ntdll/process.c | 2 ++
include/wine/server_protocol.h | 2 ++
server/process.c | 29 +++++++++++++++++++++++++++
server/process.h | 5 +++++
server/ptrace.c | 43
+++++++++++++++++++++++++++++++++++++---
6 files changed, 80 insertions(+), 31 deletions(-)
diff --git a/dlls/kernel32/time.c b/dlls/kernel32/time.c
index 5dd5592..a48f92d 100644
--- a/dlls/kernel32/time.c
+++ b/dlls/kernel32/time.c
@@ -30,9 +30,6 @@ #include <time.h>
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
-#ifdef HAVE_SYS_TIMES_H
-# include <sys/times.h>
-#endif
#ifdef HAVE_SYS_LIMITS_H
#include <sys/limits.h>
#elif defined(HAVE_MACHINE_LIMITS_H)
@@ -533,27 +530,6 @@ VOID WINAPI GetSystemTimeAsFileTime(
/*********************************************************************
- * TIME_ClockTimeToFileTime (olorin at fandra.org, 20-Sep-1998)
- *
- * Used by GetProcessTimes to convert clock_t into FILETIME.
- *
- * Differences to UnixTimeToFileTime:
- * 1) Divided by CLK_TCK
- * 2) Time is relative. There is no 'starting date', so there is
- * no need for offset correction, like in UnixTimeToFileTime
- */
-#ifndef CLK_TCK
-# define CLK_TCK CLOCKS_PER_SEC
-#endif
-static void TIME_ClockTimeToFileTime(clock_t unix_time, LPFILETIME
filetime)
-{
- ULONGLONG secs = RtlEnlargedUnsignedMultiply( unix_time, 10000000 );
- secs = RtlExtendedLargeIntegerDivide( secs, CLK_TCK, NULL );
- filetime->dwLowDateTime = (DWORD)secs;
- filetime->dwHighDateTime = (DWORD)(secs >> 32);
-}
-
-/*********************************************************************
* GetProcessTimes (KERNEL32.@)
*
* Get the user and kernel execution times of a process,
@@ -580,16 +556,14 @@ static void TIME_ClockTimeToFileTime(clo
BOOL WINAPI GetProcessTimes( HANDLE hprocess, LPFILETIME lpCreationTime,
LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime )
{
- struct tms tms;
KERNEL_USER_TIMES pti;
- times(&tms);
- TIME_ClockTimeToFileTime(tms.tms_utime,lpUserTime);
- TIME_ClockTimeToFileTime(tms.tms_stime,lpKernelTime);
if (NtQueryInformationProcess( hprocess, ProcessTimes, &pti,
sizeof(pti), NULL))
return FALSE;
LL2FILETIME( pti.CreateTime.QuadPart, lpCreationTime);
LL2FILETIME( pti.ExitTime.QuadPart, lpExitTime);
+ LL2FILETIME( pti.UserTime.QuadPart, lpUserTime);
+ LL2FILETIME( pti.KernelTime.QuadPart, lpKernelTime);
return TRUE;
}
diff --git a/dlls/ntdll/process.c b/dlls/ntdll/process.c
index 5af750d..fd4bf36 100644
--- a/dlls/ntdll/process.c
+++ b/dlls/ntdll/process.c
@@ -238,6 +238,8 @@ NTSTATUS WINAPI NtQueryInformationProces
{
NTDLL_from_server_abstime(&pti.CreateTime,
&reply->start_time);
NTDLL_from_server_abstime(&pti.ExitTime,
&reply->end_time);
+ NTDLL_from_server_abstime(&pti.UserTime,
&reply->user_time);
+ NTDLL_from_server_abstime(&pti.KernelTime,
&reply->kernel_time);
}
}
SERVER_END_REQ;
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 894d5f3..fe94dbd 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -374,6 +374,8 @@ struct get_process_info_reply
void* peb;
abs_time_t start_time;
abs_time_t end_time;
+ abs_time_t user_time;
+ abs_time_t kernel_time;
};
diff --git a/server/process.c b/server/process.c
index cc4fd6f..b8ac2f8 100644
--- a/server/process.c
+++ b/server/process.c
@@ -284,6 +284,7 @@ struct thread *create_process( int fd, s
process->winstation = 0;
process->desktop = 0;
process->token = token_create_admin();
+ process->rusage_times_set= 0;
list_init( &process->thread_list );
list_init( &process->locks );
list_init( &process->classes );
@@ -291,6 +292,8 @@ struct thread *create_process( int fd, s
process->start_time = current_time;
process->end_time.tv_sec = process->end_time.tv_usec = 0;
+ process->user_time.tv_sec = process->user_time.tv_usec = 0;
+ process->kernel_time.tv_sec = process->kernel_time.tv_usec = 0;
list_add_head( &process_list, &process->entry );
if (!(process->id = process->group_id = alloc_ptid( process )))
@@ -972,9 +975,15 @@ DECL_HANDLER(open_process)
DECL_HANDLER(terminate_process)
{
struct process *process;
+ struct rusage r;
if ((process = get_process_from_handle( req->handle,
PROCESS_TERMINATE )))
{
+ if (get_process_rusage(process, &r)) {
+ process->rusage_times_set = 1;
+ process->user_time = r.ru_utime;
+ process->kernel_time = r.ru_stime;
+ }
reply->self = (current->process == process);
terminate_process( process, current, req->exit_code );
release_object( process );
@@ -985,6 +994,7 @@ DECL_HANDLER(terminate_process)
DECL_HANDLER(get_process_info)
{
struct process *process;
+ struct rusage r;
if ((process = get_process_from_handle( req->handle,
PROCESS_QUERY_INFORMATION )))
{
@@ -998,6 +1008,25 @@ DECL_HANDLER(get_process_info)
reply->start_time.usec = process->start_time.tv_usec;
reply->end_time.sec = process->end_time.tv_sec;
reply->end_time.usec = process->end_time.tv_usec;
+
+ if (process->rusage_times_set)
+ {
+ reply->user_time.sec = process->user_time.tv_sec;
+ reply->user_time.usec = process->user_time.tv_usec;
+
+ reply->kernel_time.sec = process->kernel_time.tv_sec;
+ reply->kernel_time.usec = process->kernel_time.tv_usec;
+
+ }
+ else if (get_process_rusage(process, &r))
+ {
+ reply->user_time.sec = r.ru_utime.tv_sec;
+ reply->user_time.usec = r.ru_utime.tv_usec;
+
+ reply->kernel_time.sec = r.ru_stime.tv_sec;
+ reply->kernel_time.usec = r.ru_stime.tv_usec;
+ }
+
release_object( process );
}
}
diff --git a/server/process.h b/server/process.h
index af84719..37f9c51 100644
--- a/server/process.h
+++ b/server/process.h
@@ -21,6 +21,7 @@
#ifndef __WINE_SERVER_PROCESS_H
#define __WINE_SERVER_PROCESS_H
+#include <sys/resource.h>
#include "object.h"
struct msg_queue;
@@ -63,6 +64,9 @@ struct process
int running_threads; /* number of threads running
in this process */
struct timeval start_time; /* absolute time at process
start */
struct timeval end_time; /* absolute time at process
end */
+ struct timeval user_time; /* absolute user time */
+ struct timeval kernel_time; /* absolute kernel time */
+ int rusage_times_set;/* whether the user/kernel
time is set */
int priority; /* priority class */
int affinity; /* process affinity mask */
int suspend; /* global process suspend
count */
@@ -130,6 +134,7 @@ extern struct module_snapshot *module_sn
extern void enum_processes( int (*cb)(struct process*, void*), void *user);
extern int read_process_memory( struct process *process, const void
*ptr, data_size_t size, char *dest );
extern int write_process_memory( struct process *process, void *ptr,
data_size_t size, const char *src );
+extern int get_process_rusage(struct process *process, struct rusage
*rusage);
inline static process_id_t get_process_id( struct process *process ) {
return process->id; }
diff --git a/server/ptrace.c b/server/ptrace.c
index ef72713..ffc012b 100644
--- a/server/ptrace.c
+++ b/server/ptrace.c
@@ -157,14 +157,14 @@ static int get_ptrace_pid( struct thread
}
/* wait for a ptraced child to get a certain signal */
-static int wait4_thread( struct thread *thread, int signal )
+static int wait4_thread( struct thread *thread, int signal, struct
rusage *rusage )
{
int res, status;
start_watchdog();
for (;;)
{
- if ((res = wait4_wrapper( get_ptrace_pid(thread), &status,
WUNTRACED, NULL )) == -1)
+ if ((res = wait4_wrapper( get_ptrace_pid(thread), &status,
WUNTRACED, rusage )) == -1)
{
if (errno == EINTR)
{
@@ -264,7 +264,7 @@ static int suspend_for_ptrace( struct th
if (errno == ESRCH) thread->unix_pid = thread->unix_tid = -1;
/* thread got killed */
goto error;
}
- if (wait4_thread( thread, SIGSTOP )) return 1;
+ if (wait4_thread( thread, SIGSTOP, NULL )) return 1;
resume_after_ptrace( thread );
error:
set_error( STATUS_ACCESS_DENIED );
@@ -311,6 +311,43 @@ static struct thread *get_ptrace_thread(
return NULL;
}
+int get_process_rusage(struct process *process, struct rusage *rusage)
+{
+ struct thread *t;
+
+ t = get_ptrace_thread(process);
+ if (t == NULL)
+ {
+ fprintf(stderr, "get_process_rusage: thread not found\n");
+ return 0;
+ }
+
+ /*** The following chunk is taken from suspend_for_ptrace() ***/
+
+ /* can't stop a thread while initialisation is in progress */
+ if (t->unix_pid == -1 || !is_process_init_done(t->process)) goto error;
+
+ /* this may fail if the client is already being debugged */
+ if (ptrace( PTRACE_ATTACH, get_ptrace_pid(t), 0, 0 ) == -1)
+ {
+ if (errno == ESRCH) t->unix_pid = t->unix_tid = -1; /* thread
got killed */
+ goto error;
+ }
+
+ /*** end chunk ***/
+
+ if (!wait4_thread(t, SIGSTOP, rusage)) goto error;
+
+success:
+ resume_after_ptrace(t);
+ return 1;
+
+error:
+ fprintf(stderr, "get_process_rusage: error\n");
+ resume_after_ptrace(t);
+ return 0;
+}
+
/* read data from a process memory space */
int read_process_memory( struct process *process, const void *ptr,
data_size_t size, char *dest )
{
--
1.4.1.1
More information about the wine-patches
mailing list