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 },