From: Brock York twunknown@gmail.com
Signed-off-by: Brock York brock@polynubstudios.com --- tools/make_requests | 1 + 1 file changed, 1 insertion(+)
diff --git a/tools/make_requests b/tools/make_requests index 4e39bb65a9..77353b4e7d 100755 --- a/tools/make_requests +++ b/tools/make_requests @@ -53,6 +53,7 @@ my %formats = "ioctl_code_t" => [ 4, 4, "&dump_ioctl_code" ], "client_cpu_t" => [ 4, 4, "&dump_client_cpu" ], "hw_input_t" => [ 32, 8, "&dump_hw_input" ], + "unsigned __int64" => [ 8, 8, "&dump_uint64" ], );
my @requests = ();
From: Brock York twunknown@gmail.com
get_process_time returns the amount of time a given process has spent in kernel and user mode. Reads from /proc/[pid]/stat the utime and stime fields
Signed-off-by: Brock York brock@polynubstudios.com --- include/wine/server_protocol.h | 18 ++++++++++++++++- server/process.c | 35 ++++++++++++++++++++++++++++++++++ server/protocol.def | 8 ++++++++ server/request.h | 8 ++++++++ server/trace.c | 15 +++++++++++++++ 5 files changed, 83 insertions(+), 1 deletion(-)
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 3b457df8b0..58a6af779b 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -5797,6 +5797,19 @@ struct resume_process_reply };
+struct get_process_time_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct get_process_time_reply +{ + struct reply_header __header; + unsigned __int64 utime; + unsigned __int64 stime; +}; + + enum request { REQ_new_process, @@ -6096,6 +6109,7 @@ enum request REQ_terminate_job, REQ_suspend_process, REQ_resume_process, + REQ_get_process_time, REQ_NB_REQUESTS };
@@ -6400,6 +6414,7 @@ union generic_request struct terminate_job_request terminate_job_request; struct suspend_process_request suspend_process_request; struct resume_process_request resume_process_request; + struct get_process_time_request get_process_time_request; }; union generic_reply { @@ -6702,8 +6717,9 @@ union generic_reply struct terminate_job_reply terminate_job_reply; struct suspend_process_reply suspend_process_reply; struct resume_process_reply resume_process_reply; + struct get_process_time_reply get_process_time_reply; };
-#define SERVER_PROTOCOL_VERSION 595 +#define SERVER_PROTOCOL_VERSION 596
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/process.c b/server/process.c index 73984f363f..112006b02e 100644 --- a/server/process.c +++ b/server/process.c @@ -1792,3 +1792,38 @@ DECL_HANDLER(resume_process) release_object( process ); } } + +/* Get kernel and user time for a process */ +DECL_HANDLER(get_process_time) +{ + char procPath[32]; + char line[1024]; + FILE *procPidStat = NULL; + //See man (5) proc for format of /proc/[pid]/stat file + const char *procPidStatFmt = "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*lu %*lu %*lu %*lu %lu %lu"; + unsigned __int64 utime = 0; + unsigned __int64 stime = 0; + struct process *process = get_process_from_handle( req->handle, PROCESS_QUERY_LIMITED_INFORMATION ); + + if (!process) return; +#ifdef linux + if (process->unix_pid != -1) + { + sprintf( procPath, "/proc/%u/stat", process->unix_pid ); + if ((procPidStat = fopen( procPath, "r" ))) + { + fgets( line, sizeof(line), procPidStat ); + if (sscanf( line, procPidStatFmt, &utime, &stime ) == 2) + { + reply->utime = utime; + reply->stime = stime; + } + else set_error(STATUS_SEVERITY_ERROR); + fclose(procPidStat); + } + else set_error( STATUS_ACCESS_DENIED ); + } + else set_error( STATUS_ACCESS_DENIED ); +#endif + release_object( process ); +} diff --git a/server/protocol.def b/server/protocol.def index 6c44b2b43f..5cc568a5bb 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3956,3 +3956,11 @@ struct handle_info @REQ(resume_process) obj_handle_t handle; /* process handle */ @END + +/* Get kernel and user time for a process */ +@REQ(get_process_time) + obj_handle_t handle; /* process handle */ +@REPLY + unsigned __int64 utime; /* time process has spent in user mode */ + unsigned __int64 stime; /* time process has spent in kernel mode */ +@END diff --git a/server/request.h b/server/request.h index 15fcb671bb..b38a9f0b5a 100644 --- a/server/request.h +++ b/server/request.h @@ -410,6 +410,7 @@ DECL_HANDLER(set_job_completion_port); DECL_HANDLER(terminate_job); DECL_HANDLER(suspend_process); DECL_HANDLER(resume_process); +DECL_HANDLER(get_process_time);
#ifdef WANT_REQUEST_HANDLERS
@@ -713,6 +714,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_terminate_job, (req_handler)req_suspend_process, (req_handler)req_resume_process, + (req_handler)req_get_process_time, };
C_ASSERT( sizeof(affinity_t) == 8 ); @@ -741,6 +743,7 @@ C_ASSERT( sizeof(rectangle_t) == 16 ); C_ASSERT( sizeof(short int) == 2 ); C_ASSERT( sizeof(thread_id_t) == 4 ); C_ASSERT( sizeof(timeout_t) == 8 ); +C_ASSERT( sizeof(unsigned __int64) == 8 ); C_ASSERT( sizeof(unsigned char) == 1 ); C_ASSERT( sizeof(unsigned int) == 4 ); C_ASSERT( sizeof(unsigned short) == 2 ); @@ -2445,6 +2448,11 @@ C_ASSERT( FIELD_OFFSET(struct suspend_process_request, handle) == 12 ); C_ASSERT( sizeof(struct suspend_process_request) == 16 ); C_ASSERT( FIELD_OFFSET(struct resume_process_request, handle) == 12 ); C_ASSERT( sizeof(struct resume_process_request) == 16 ); +C_ASSERT( FIELD_OFFSET(struct get_process_time_request, handle) == 12 ); +C_ASSERT( sizeof(struct get_process_time_request) == 16 ); +C_ASSERT( FIELD_OFFSET(struct get_process_time_reply, utime) == 8 ); +C_ASSERT( FIELD_OFFSET(struct get_process_time_reply, stime) == 16 ); +C_ASSERT( sizeof(struct get_process_time_reply) == 24 );
#endif /* WANT_REQUEST_HANDLERS */
diff --git a/server/trace.c b/server/trace.c index 79e3f22ee5..c69531c9de 100644 --- a/server/trace.c +++ b/server/trace.c @@ -4608,6 +4608,17 @@ static void dump_resume_process_request( const struct resume_process_request *re fprintf( stderr, " handle=%04x", req->handle ); }
+static void dump_get_process_time_request( const struct get_process_time_request *req ) +{ + fprintf( stderr, " handle=%04x", req->handle ); +} + +static void dump_get_process_time_reply( const struct get_process_time_reply *req ) +{ + dump_uint64( " utime=", &req->utime ); + dump_uint64( ", stime=", &req->stime ); +} + static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_new_process_request, (dump_func)dump_exec_process_request, @@ -4906,6 +4917,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_terminate_job_request, (dump_func)dump_suspend_process_request, (dump_func)dump_resume_process_request, + (dump_func)dump_get_process_time_request, };
static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { @@ -5206,6 +5218,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { NULL, NULL, NULL, + (dump_func)dump_get_process_time_reply, };
static const char * const req_names[REQ_NB_REQUESTS] = { @@ -5506,6 +5519,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "terminate_job", "suspend_process", "resume_process", + "get_process_time", };
static const struct @@ -5625,6 +5639,7 @@ static const struct { "REPARSE_POINT_NOT_RESOLVED", STATUS_REPARSE_POINT_NOT_RESOLVED }, { "SECTION_TOO_BIG", STATUS_SECTION_TOO_BIG }, { "SEMAPHORE_LIMIT_EXCEEDED", STATUS_SEMAPHORE_LIMIT_EXCEEDED }, + { "SEVERITY_ERROR", STATUS_SEVERITY_ERROR }, { "SHARING_VIOLATION", STATUS_SHARING_VIOLATION }, { "SHUTDOWN_IN_PROGRESS", STATUS_SHUTDOWN_IN_PROGRESS }, { "SUSPEND_COUNT_EXCEEDED", STATUS_SUSPEND_COUNT_EXCEEDED },
From: Brock York twunknown@gmail.com
-GetProcessTimes would return the current processes cpu and kernel times even if the handle was for a different remote process. -Read the user and kernel times using get_process_times from wineserver if the requested process to read from is not the current process. If the requested process is the current process then the times(7) syscall is used instead as it was before.
Signed-off-by: Brock York brock@polynubstudios.com --- dlls/kernel32/time.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-)
diff --git a/dlls/kernel32/time.c b/dlls/kernel32/time.c index 4ebdabf18c..050c8b6b5c 100644 --- a/dlls/kernel32/time.c +++ b/dlls/kernel32/time.c @@ -180,7 +180,8 @@ static void TIME_ClockTimeToFileTime(clock_t unix_time, LPFILETIME filetime) * Also, there is a need to separate times used by different applications. * * BUGS - * KernelTime and UserTime are always for the current process + * twunknown@gmail.com: + * Cannot get process time if hprocess handle is for another process and not on Linux */ BOOL WINAPI GetProcessTimes( HANDLE hprocess, LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime ) @@ -188,7 +189,34 @@ BOOL WINAPI GetProcessTimes( HANDLE hprocess, LPFILETIME lpCreationTime, struct tms tms; KERNEL_USER_TIMES pti;
- times(&tms); + //CompareObjectHandles is a Window 10 thing so this should suffice + //If process is current process then just use times syscall + if (hprocess == GetCurrentProcess()) + times(&tms); +#ifdef linux + else + { + SERVER_START_REQ( get_process_time ) + { + req->handle = wine_server_obj_handle( hprocess ); + if (wine_server_call( req ) == STATUS_SUCCESS) + { + tms.tms_utime = reply->utime; + tms.tms_stime = reply->stime; + } + else + return FALSE; + } + SERVER_END_REQ; + } +#else //If not on linux we can't get another processes time, so return failure + else + { + FIXME("Cannot get process time for another process on non linux OS\n"); + return FALSE; + } +#endif + TIME_ClockTimeToFileTime(tms.tms_utime,lpUserTime); TIME_ClockTimeToFileTime(tms.tms_stime,lpKernelTime); if (NtQueryInformationProcess( hprocess, ProcessTimes, &pti, sizeof(pti), NULL))