From: Bernard Ladenthin Subject: kernel32/time: Implement GetSystemTimes using /proc/stat. Message-Id: <52F9075B.4000601@gmail.com> Date: Mon, 10 Feb 2014 18:07:39 +0100 --- dlls/kernel32/time.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 147 insertions(+), 2 deletions(-) diff --git a/dlls/kernel32/time.c b/dlls/kernel32/time.c index 77c71cb..1e2468d 100644 --- a/dlls/kernel32/time.c +++ b/dlls/kernel32/time.c @@ -20,6 +20,7 @@ #include "config.h" +#include #include #ifdef HAVE_UNISTD_H # include @@ -1077,9 +1078,153 @@ BOOL WINAPI FileTimeToDosDateTime( const FILETIME *ft, LPWORD fatdate, */ BOOL WINAPI GetSystemTimes(LPFILETIME lpIdleTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime) { - FIXME("(%p,%p,%p): Stub!\n", lpIdleTime, lpKernelTime, lpUserTime); + FILE *procfile; + int successfulValues; + unsigned int numCPUs = 0; + const char proc_stat[] = "/proc/stat"; + float idleTime, kernelTime, userTime; + float divisor; + + /* Enough for each of the /proc/stat cpu lines. */ + char line[512]; + + /* Description from PROC(5): proc - process information pseudo-filesystem + * All the fields don't necessarily exist, depending on the kernel version used. + * Therefore, all values are initialized. + */ + + /* Time spent in user mode. */ + unsigned long long cpu_user = 0; + + /* Time spent in user mode with low priority (nice). */ + unsigned long long cpu_nice = 0; + + /* Time spent in system mode. */ + unsigned long long cpu_sys = 0; + + /* Time spent in the idle task. This value should be USER_HZ times the second entry in the + * /proc/uptime pseudo-file. + */ + unsigned long long cpu_idle = 0; + + /* Time waiting for I/O to complete. (since Linux 2.5.41) */ + unsigned long long cpu_iowait = 0; + + /* Time servicing interrupts. (since Linux 2.6.0-test4) */ + unsigned long long cpu_hardirq = 0; + + /* Time servicing softirqs. (since Linux 2.6.0-test4) */ + unsigned long long cpu_softirq = 0; + + /* Stolen time, which is the time spent in other operating systems when running in a + * virtualized environment. (since Linux 2.6.11) + */ + unsigned long long cpu_steal = 0; + + /* Time spent running a virtual CPU for guest operating systems under the control of the + * Linux kernel. (since Linux 2.6.24) + */ + unsigned long long cpu_guest = 0; + + /* Time spent running a niced guest (virtual CPU for guest operating systems under the + * control of the Linux kernel). (since Linux 2.6.33) + */ + unsigned long long cpu_guest_nice = 0; + + procfile = fopen(proc_stat, "r"); + if (!procfile) + { + FIXME("(%p,%p,%p): Not implemented for this platform!\n", lpIdleTime, lpKernelTime, + lpUserTime); + return FALSE; + } + + /* Read the cpu summary line. */ + if (!fgets(line, sizeof(line), procfile)) + { + fclose(procfile); + TRACE("Could not read the cpu summary line from %s\n", proc_stat); + SetLastError(ERROR_BAD_FORMAT); + return FALSE; + } + + if (strncmp(line, "cpu ", 4) != 0) + { + fclose(procfile); + TRACE("Cpu summary line starts invalid in %s\n", proc_stat); + return FALSE; + } + + successfulValues = sscanf( + line + 5, + "%llu %llu %llu %llu %llu %llu %llu %llu %llu %llu", + + &cpu_user, + &cpu_nice, + &cpu_sys, + &cpu_idle, + &cpu_iowait, + &cpu_hardirq, + &cpu_softirq, + &cpu_steal, + &cpu_guest, + &cpu_guest_nice + ); + + /* cpu_user, cpu_nice, cpu_sys, cpu_idle, cpu_iowait, cpu_hardirq, cpu_softirq and cpu_steal + * must be at least read correctly. cpu_guest and cpu_guest_nice is insignificant. + * cpu_user/cpu_nice already include cpu_guest/cpu_guest_nice. + */ + if (successfulValues < 8) + { + fclose(procfile); + TRACE("Could not read the cpu summary line properly from %s\n", proc_stat); + SetLastError(ERROR_BAD_FORMAT); + return FALSE; + } + + for (;;) + { + if (!fgets(line, sizeof(line), procfile)) + { + fclose(procfile); + TRACE("Could not read the cpu line from %s\n", proc_stat); + SetLastError(ERROR_BAD_FORMAT); + return FALSE; + } + + if (strncmp(line, "cpu", 3) != 0) break; + else ++numCPUs; + } + + fclose(procfile); + + /* Times are multiplied by the number of processors. */ + divisor = 10000 * numCPUs; + + idleTime = cpu_idle / divisor; - return FALSE; + kernelTime = idleTime; + kernelTime += cpu_sys / divisor; + kernelTime += cpu_iowait / divisor; + kernelTime += cpu_hardirq / divisor; + kernelTime += cpu_softirq / divisor; + kernelTime += cpu_steal / divisor; + + /* cpu_user/cpu_nice already include cpu_guest/cpu_guest_nice. */ + userTime = cpu_user / divisor; + userTime += cpu_nice / divisor; + + lpIdleTime->dwHighDateTime = idleTime; + lpIdleTime->dwLowDateTime = MAXDWORD * (idleTime-lpIdleTime->dwHighDateTime); + + lpKernelTime->dwHighDateTime = kernelTime; + lpKernelTime->dwLowDateTime = MAXDWORD * (kernelTime-lpKernelTime->dwHighDateTime); + + lpUserTime->dwHighDateTime = userTime; + lpUserTime->dwLowDateTime = MAXDWORD * (userTime-lpUserTime->dwHighDateTime); + + return TRUE; } /***********************************************************************