From 1d64a36caa04f47f9ee34c06e2602d3a5c0f7d31 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Sat, 2 Jun 2012 20:01:33 +0200 Subject: [PATCH] windows: add support for cpu times to uv_cpu_info() * Also cleans up the code and makes it use unicode APIs consistently. * Credits go to Brian White for creating an earlier version of this patch. Closes #327 --- src/win/util.c | 154 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 110 insertions(+), 44 deletions(-) diff --git a/src/win/util.c b/src/win/util.c index 10c22712..d79388af 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -47,7 +47,6 @@ */ #define MAX_TITLE_LENGTH 8192 - static char *process_title; static uv_once_t uv_process_title_init_guard_ = UV_ONCE_INIT; static CRITICAL_SECTION process_title_lock; @@ -488,81 +487,148 @@ uv_err_t uv_uptime(double* uptime) { uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { - uv_err_t err; - char key[128]; - HKEY processor_key = NULL; - DWORD cpu_speed = 0; - DWORD cpu_speed_length = sizeof(cpu_speed); - char cpu_brand[256]; - DWORD cpu_brand_length = sizeof(cpu_brand); + SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* sppi; + DWORD sppi_size; SYSTEM_INFO system_info; + DWORD cpu_count, i, r; + ULONG result_size; + size_t size; + uv_err_t err; uv_cpu_info_t* cpu_info; - unsigned int i; + + *cpu_infos = NULL; + *count = 0; + + uv__once_init(); GetSystemInfo(&system_info); + cpu_count = system_info.dwNumberOfProcessors; - *cpu_infos = (uv_cpu_info_t*)malloc(system_info.dwNumberOfProcessors * - sizeof(uv_cpu_info_t)); - if (!(*cpu_infos)) { + size = cpu_count * sizeof(uv_cpu_info_t); + *cpu_infos = (uv_cpu_info_t*) malloc(size); + if (*cpu_infos == NULL) { + err = uv__new_artificial_error(UV_ENOMEM); + goto out; + } + memset(*cpu_infos, 0, size); + + sppi_size = sizeof(*sppi) * cpu_count; + sppi = (SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION*) malloc(sppi_size); + if (!sppi) { uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); } - *count = 0; + r = pNtQuerySystemInformation(SystemProcessorPerformanceInformation, + sppi, + sppi_size, + &result_size); + if (r != ERROR_SUCCESS || result_size != sppi_size) { + err = uv__new_sys_error(GetLastError()); + goto out; + } - for (i = 0; i < system_info.dwNumberOfProcessors; i++) { - _snprintf(key, sizeof(key), "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d", i); + for (i = 0; i < cpu_count; i++) { + WCHAR key_name[128]; + HKEY processor_key; + DWORD cpu_speed; + DWORD cpu_speed_size = sizeof(cpu_speed); + WCHAR cpu_brand[256]; + DWORD cpu_brand_size = sizeof(cpu_brand); - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, key, 0, KEY_QUERY_VALUE, - &processor_key) != ERROR_SUCCESS) { - if (i == 0) { - err = uv__new_sys_error(GetLastError()); - goto done; - } + _snwprintf(key_name, + ARRAY_SIZE(key_name), + L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d", + i); - continue; + r = RegOpenKeyExW(HKEY_LOCAL_MACHINE, + key_name, + 0, + KEY_QUERY_VALUE, + &processor_key); + if (r != ERROR_SUCCESS) { + err = uv__new_sys_error(GetLastError()); + goto out; } - if (RegQueryValueEx(processor_key, "~MHz", NULL, NULL, - (LPBYTE)&cpu_speed, &cpu_speed_length) - != ERROR_SUCCESS) { + if (RegQueryValueExW(processor_key, + L"~MHz", + NULL, NULL, + (BYTE*) &cpu_speed, + &cpu_speed_size) != ERROR_SUCCESS) { err = uv__new_sys_error(GetLastError()); - goto done; + RegCloseKey(processor_key); + goto out; } - if (RegQueryValueEx(processor_key, "ProcessorNameString", NULL, NULL, - (LPBYTE)&cpu_brand, &cpu_brand_length) - != ERROR_SUCCESS) { + if (RegQueryValueExW(processor_key, + L"ProcessorNameString", + NULL, NULL, + (BYTE*) &cpu_brand, + &cpu_brand_size) != ERROR_SUCCESS) { err = uv__new_sys_error(GetLastError()); - goto done; + RegCloseKey(processor_key); + goto out; } RegCloseKey(processor_key); - processor_key = NULL; cpu_info = &(*cpu_infos)[i]; - - /* $TODO: find times on windows */ - cpu_info->cpu_times.user = 0; - cpu_info->cpu_times.nice = 0; - cpu_info->cpu_times.sys = 0; - cpu_info->cpu_times.idle = 0; - cpu_info->cpu_times.irq = 0; - - cpu_info->model = strdup(cpu_brand); cpu_info->speed = cpu_speed; + cpu_info->cpu_times.user = sppi[i].UserTime.QuadPart / 10000; + cpu_info->cpu_times.sys = (sppi[i].KernelTime.QuadPart - + sppi[i].IdleTime.QuadPart) / 10000; + cpu_info->cpu_times.idle = sppi[i].IdleTime.QuadPart / 10000; + cpu_info->cpu_times.irq = sppi[i].InterruptTime.QuadPart / 10000; + cpu_info->cpu_times.nice = 0; + + size = uv_utf16_to_utf8(cpu_brand, + cpu_brand_size / sizeof(WCHAR), + NULL, + 0); + if (size == 0) { + err = uv__new_sys_error(GetLastError()); + goto out; + } + + /* Allocate 1 extra byte for the null terminator. */ + cpu_info->model = (char*) malloc(size + 1); + if (cpu_info->model == NULL) { + err = uv__new_artificial_error(UV_ENOMEM); + goto out; + } + + if (uv_utf16_to_utf8(cpu_brand, + cpu_brand_size / sizeof(WCHAR), + cpu_info->model, + size) == 0) { + err = uv__new_sys_error(GetLastError()); + goto out; + } + + /* Ensure that cpu_info->model is null terminated. */ + cpu_info->model[size] = '\0'; (*count)++; } err = uv_ok_; -done: - if (processor_key) { - RegCloseKey(processor_key); + out: + if (sppi) { + free(sppi); } - if (err.code != UV_OK) { + if (err.code != UV_OK && + *cpu_infos != NULL) { + int i; + + for (i = 0; i < *count; i++) { + /* This is safe because the cpu_infos memory area is zeroed out */ + /* immediately after allocating it. */ + free((*cpu_infos)[i].model); + } free(*cpu_infos); + *cpu_infos = NULL; *count = 0; }