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