From: Brock York twunknown@gmail.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 the kernel and user mode. Reads from /proc/[pid]/stat the utime and stime fields --- 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. --- 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))