Skip to content
This repository has been archived by the owner on May 4, 2018. It is now read-only.

Commit

Permalink
Browse files Browse the repository at this point in the history
Windows: make uv_uptime() more robust
  • Loading branch information
piscisaureus committed Apr 12, 2012
1 parent f3e3e5b commit 9984d15
Showing 1 changed file with 84 additions and 50 deletions.
134 changes: 84 additions & 50 deletions src/win/util.c
Expand Up @@ -25,6 +25,7 @@
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <wchar.h>

#include "uv.h"
#include "internal.h"
Expand Down Expand Up @@ -385,70 +386,103 @@ uv_err_t uv_resident_set_memory(size_t* rss) {


uv_err_t uv_uptime(double* uptime) {
uv_err_t err;
PERF_DATA_BLOCK *dataBlock = NULL;
PERF_OBJECT_TYPE *objType;
PERF_COUNTER_DEFINITION *counterDef;
PERF_COUNTER_DEFINITION *counterDefUptime = NULL;
DWORD dataSize = 4096;
DWORD getSize;
LONG lError = ERROR_MORE_DATA;
uint64_t upsec;
unsigned int i;
BYTE *counterData;

*uptime = 0;

while (lError == ERROR_MORE_DATA) {
if (dataBlock) {
free(dataBlock);
}
dataBlock = (PERF_DATA_BLOCK*)malloc(dataSize);
if (!dataBlock) {
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
BYTE stack_buffer[4096];
BYTE* malloced_buffer = NULL;
BYTE* buffer = (BYTE*) stack_buffer;
size_t buffer_size = sizeof(stack_buffer);
DWORD data_size;

PERF_DATA_BLOCK* data_block;
PERF_OBJECT_TYPE* object_type;
PERF_COUNTER_DEFINITION* counter_definition;

DWORD i;

for (;;) {
LONG result;

data_size = (DWORD) buffer_size;
result = RegQueryValueExW(HKEY_PERFORMANCE_DATA,
L"2",
NULL,
NULL,
buffer,
&data_size);
if (result == ERROR_SUCCESS) {
break;
} else if (result != ERROR_MORE_DATA) {
*uptime = 0;
return uv__new_sys_error(result);
}
getSize = dataSize;

lError = RegQueryValueExW(HKEY_PERFORMANCE_DATA, "2", NULL, NULL,
(BYTE*)dataBlock, &getSize);
if (lError != ERROR_SUCCESS && getSize > 0) {
if (wcsncmp(dataBlock->Signature, "PERF", 4) == 0) {
break;
}
} else if (lError != ERROR_SUCCESS && lError != ERROR_MORE_DATA) {
err = uv__new_sys_error(GetLastError());
goto done;
free(malloced_buffer);

buffer_size *= 2;
/* Don't let the buffer grow infinitely. */
if (buffer_size > 1 << 20) {
goto internalError;
}

dataSize += 1024;
buffer = malloced_buffer = (BYTE*) malloc(buffer_size);
if (malloced_buffer == NULL) {
*uptime = 0;
return uv__new_artificial_error(UV_ENOMEM);
}
}

RegCloseKey(HKEY_PERFORMANCE_DATA);
if (data_size < sizeof(*data_block))
goto internalError;

data_block = (PERF_DATA_BLOCK*) buffer;

if (wmemcmp(data_block->Signature, L"PERF", 4) != 0)
goto internalError;

objType = (PERF_OBJECT_TYPE*)((BYTE*)dataBlock + dataBlock->HeaderLength);
counterDef = (PERF_COUNTER_DEFINITION*)((BYTE*)objType + objType->HeaderLength);
if (data_size < data_block->HeaderLength + sizeof(*object_type))
goto internalError;

for (i = 0; i < objType->NumCounters; ++i) {
if (counterDef->CounterNameTitleIndex == 674) {
counterDefUptime = counterDef;
object_type = (PERF_OBJECT_TYPE*) (buffer + data_block->HeaderLength);

if (object_type->NumInstances != PERF_NO_INSTANCES)
goto internalError;

counter_definition = (PERF_COUNTER_DEFINITION*) (buffer +
data_block->HeaderLength + object_type->HeaderLength);
for (i = 0; i < object_type->NumCounters; i++) {
if ((BYTE*) counter_definition + sizeof(*counter_definition) >
buffer + data_size) {
break;
}
counterDef = (PERF_COUNTER_DEFINITION*)((BYTE*)counterDef + counterDef->ByteLength);
}

counterData = (BYTE*)objType + objType->DefinitionLength;
counterData += counterDefUptime->CounterOffset;

upsec = *((uint64_t*)counterData);
*uptime = ((objType->PerfTime.QuadPart - upsec) / objType->PerfFreq.QuadPart);
err = uv_ok_;
if (counter_definition->CounterNameTitleIndex == 674 &&
counter_definition->CounterSize == sizeof(uint64_t)) {
if (counter_definition->CounterOffset + sizeof(uint64_t) > data_size ||
!(counter_definition->CounterType & PERF_OBJECT_TIMER)) {
goto internalError;
} else {
BYTE* address = (BYTE*) object_type + object_type->DefinitionLength +
counter_definition->CounterOffset;
uint64_t value = *((uint64_t*) address);
*uptime = (double) (object_type->PerfTime.QuadPart - value) /
(double) object_type->PerfFreq.QuadPart;
free(malloced_buffer);
return uv_ok_;
}
}

done:
if (dataBlock) {
free(dataBlock);
counter_definition = (PERF_COUNTER_DEFINITION*)
((BYTE*) counter_definition + counter_definition->ByteLength);
}

return err;
/* If we get here, the uptime value was not found. */
free(malloced_buffer);
*uptime = 0;
return uv__new_artificial_error(UV_ENOSYS);

internalError:
free(malloced_buffer);
*uptime = 0;
return uv__new_artificial_error(UV_EIO);
}


Expand Down

0 comments on commit 9984d15

Please sign in to comment.