jdk/src/java.management/windows/native/libmanagement/OperatingSystemImpl.c
changeset 30355 e37c7eba132f
parent 30354 ca83b4cae363
child 30356 a56e57aad51f
--- a/jdk/src/java.management/windows/native/libmanagement/OperatingSystemImpl.c	Wed Apr 15 13:27:39 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1363 +0,0 @@
-/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#include "jni.h"
-#include "jni_util.h"
-#include "jlong.h"
-#include "jvm.h"
-#include "management.h"
-#include "sun_management_OperatingSystemImpl.h"
-
-#include <psapi.h>
-#include <errno.h>
-#include <stdlib.h>
-
-#include <malloc.h>
-#pragma warning (push,0)
-#include <windows.h>
-#pragma warning (pop)
-#include <stdio.h>
-#include <time.h>
-#include <stdint.h>
-#include <assert.h>
-
-/* Disable warnings due to broken header files from Microsoft... */
-#pragma warning(push, 3)
-#include <pdh.h>
-#include <pdhmsg.h>
-#include <process.h>
-#pragma warning(pop)
-
-typedef unsigned __int32 juint;
-typedef unsigned __int64 julong;
-
-static void set_low(jlong* value, jint low) {
-    *value &= (jlong)0xffffffff << 32;
-    *value |= (jlong)(julong)(juint)low;
-}
-
-static void set_high(jlong* value, jint high) {
-    *value &= (jlong)(julong)(juint)0xffffffff;
-    *value |= (jlong)high       << 32;
-}
-
-static jlong jlong_from(jint h, jint l) {
-    jlong result = 0; // initialization to avoid warning
-    set_high(&result, h);
-    set_low(&result,  l);
-    return result;
-}
-
-static HANDLE main_process;
-
-static void perfInit(void);
-
-JNIEXPORT void JNICALL
-Java_sun_management_OperatingSystemImpl_initialize0
-  (JNIEnv *env, jclass cls)
-{
-    main_process = GetCurrentProcess();
-    perfInit();
-}
-
-JNIEXPORT jlong JNICALL
-Java_sun_management_OperatingSystemImpl_getCommittedVirtualMemorySize0
-  (JNIEnv *env, jobject mbean)
-{
-    PROCESS_MEMORY_COUNTERS pmc;
-    if (GetProcessMemoryInfo(main_process, &pmc, sizeof(PROCESS_MEMORY_COUNTERS)) == 0) {
-        return (jlong)-1L;
-    } else {
-        return (jlong) pmc.PagefileUsage;
-    }
-}
-
-JNIEXPORT jlong JNICALL
-Java_sun_management_OperatingSystemImpl_getTotalSwapSpaceSize0
-  (JNIEnv *env, jobject mbean)
-{
-    MEMORYSTATUSEX ms;
-    ms.dwLength = sizeof(ms);
-    GlobalMemoryStatusEx(&ms);
-    return (jlong) ms.ullTotalPageFile;
-}
-
-JNIEXPORT jlong JNICALL
-Java_sun_management_OperatingSystemImpl_getFreeSwapSpaceSize0
-  (JNIEnv *env, jobject mbean)
-{
-    MEMORYSTATUSEX ms;
-    ms.dwLength = sizeof(ms);
-    GlobalMemoryStatusEx(&ms);
-    return (jlong) ms.ullAvailPageFile;
-}
-
-JNIEXPORT jlong JNICALL
-Java_sun_management_OperatingSystemImpl_getProcessCpuTime0
-  (JNIEnv *env, jobject mbean)
-{
-
-    FILETIME process_creation_time, process_exit_time,
-             process_user_time, process_kernel_time;
-
-    // Using static variables declared above
-    // Units are 100-ns intervals.  Convert to ns.
-    GetProcessTimes(main_process, &process_creation_time,
-                    &process_exit_time,
-                    &process_kernel_time, &process_user_time);
-    return (jlong_from(process_user_time.dwHighDateTime,
-                        process_user_time.dwLowDateTime) +
-            jlong_from(process_kernel_time.dwHighDateTime,
-                        process_kernel_time.dwLowDateTime)) * 100;
-}
-
-JNIEXPORT jlong JNICALL
-Java_sun_management_OperatingSystemImpl_getFreePhysicalMemorySize0
-  (JNIEnv *env, jobject mbean)
-{
-    MEMORYSTATUSEX ms;
-    ms.dwLength = sizeof(ms);
-    GlobalMemoryStatusEx(&ms);
-    return (jlong) ms.ullAvailPhys;
-}
-
-JNIEXPORT jlong JNICALL
-Java_sun_management_OperatingSystemImpl_getTotalPhysicalMemorySize0
-  (JNIEnv *env, jobject mbean)
-{
-    MEMORYSTATUSEX ms;
-    ms.dwLength = sizeof(ms);
-    GlobalMemoryStatusEx(&ms);
-    return (jlong) ms.ullTotalPhys;
-}
-
-/* Performance Data Helper API (PDH) support */
-
-typedef PDH_STATUS (WINAPI *PdhAddCounterFunc)(
-                           HQUERY      hQuery,
-                           LPCSTR      szFullCounterPath,
-                           DWORD       dwUserData,
-                           HCOUNTER    *phCounter
-                           );
-typedef PDH_STATUS (WINAPI *PdhOpenQueryFunc)(
-                           LPCWSTR     szDataSource,
-                           DWORD       dwUserData,
-                           HQUERY      *phQuery
-                           );
-typedef PDH_STATUS (WINAPI *PdhCollectQueryDataFunc)(
-                           HQUERY      hQuery
-                           );
-
-typedef PDH_STATUS (WINAPI *PdhEnumObjectItemsFunc)(
-                           LPCTSTR     szDataSource,
-                           LPCTSTR     szMachineName,
-                           LPCTSTR     szObjectName,
-                           LPTSTR      mszCounterList,
-                           LPDWORD     pcchCounterListLength,
-                           LPTSTR      mszInstanceList,
-                           LPDWORD     pcchInstanceListLength,
-                           DWORD       dwDetailLevel,
-                           DWORD       dwFlags
-                           );
-typedef PDH_STATUS (WINAPI *PdhRemoveCounterFunc)(
-                           HCOUNTER   hCounter
-                           );
-typedef PDH_STATUS (WINAPI *PdhLookupPerfNameByIndexFunc)(
-                           LPCSTR     szMachineName,
-                           DWORD      dwNameIndex,
-                           LPSTR      szNameBuffer,
-                           LPDWORD    pcchNameBufferSize
-                           );
-typedef DWORD (WINAPI *PdhCloseQueryFunc)(
-                      HQUERY      hQuery
-                      );
-
-typedef DWORD (WINAPI *PdhGetFormattedCounterValueFunc)(
-                      HCOUNTER                hCounter,
-                      DWORD                   dwFormat,
-                      LPDWORD                 lpdwType,
-                      PPDH_FMT_COUNTERVALUE   pValue
-                      );
-
-static PdhAddCounterFunc PdhAddCounter_i;
-static PdhOpenQueryFunc PdhOpenQuery_i;
-static PdhCloseQueryFunc PdhCloseQuery_i;
-static PdhCollectQueryDataFunc PdhCollectQueryData_i;
-static PdhGetFormattedCounterValueFunc PdhGetFormattedCounterValue_i;
-static PdhEnumObjectItemsFunc PdhEnumObjectItems_i;
-static PdhRemoveCounterFunc PdhRemoveCounter_i;
-static PdhLookupPerfNameByIndexFunc PdhLookupPerfNameByIndex_i;
-
-/*
- * Struct for PDH queries.
- */
-typedef struct {
-    HQUERY      query;
-    uint64_t    lastUpdate; // Last time query was updated (ticks)
-} UpdateQueryS, *UpdateQueryP;
-
-// Min time between query updates (ticks)
-static const int MIN_UPDATE_INTERVAL = 500;
-
-/*
- * Struct for a PDH query with multiple counters.
- */
-typedef struct {
-    UpdateQueryS  query;
-    HCOUNTER*     counters;
-    int           noOfCounters;
-} MultipleCounterQueryS, *MultipleCounterQueryP;
-
-/*
- * Struct for a PDH query with a single counter.
- */
-typedef struct {
-    UpdateQueryS  query;
-    HCOUNTER      counter;
-} SingleCounterQueryS, *SingleCounterQueryP;
-
-
-typedef struct {
-    CRITICAL_SECTION cs;
-    DWORD owningThread;
-    DWORD recursionCount;
-} PdhCriticalSectionS, *PdhCriticalSectionP;
-
-static PdhCriticalSectionS initializationLock;
-
-static void InitializePdhCriticalSection(PdhCriticalSectionP criticalSection) {
-    assert(criticalSection);
-
-    InitializeCriticalSection(&criticalSection->cs);
-    criticalSection->owningThread = 0;
-    criticalSection->recursionCount = 0;
-}
-
-static void EnterPdhCriticalSection(PdhCriticalSectionP criticalSection) {
-    assert(criticalSection);
-
-    EnterCriticalSection(&criticalSection->cs);
-    criticalSection->recursionCount++;
-    if (!criticalSection->owningThread) {
-        criticalSection->owningThread = GetCurrentThreadId();
-    }
-}
-
-static void LeavePdhCriticalSection(PdhCriticalSectionP criticalSection) {
-    assert(criticalSection);
-    assert(GetCurrentThreadId() == criticalSection->owningThread);
-    assert(criticalSection->recursionCount >= 1);
-
-    criticalSection->recursionCount--;
-    if (!criticalSection->recursionCount) {
-        criticalSection->owningThread = 0;
-    }
-    LeaveCriticalSection(&criticalSection->cs);
-}
-
-/*
- * INFO: Using PDH APIs Correctly in a Localized Language (Q287159)
- *   http://support.microsoft.com/default.aspx?scid=kb;EN-US;q287159
- * The index value for the base system counters and objects like processor,
- * process, thread, memory, and so forth are always the same irrespective
- * of the localized version of the operating system or service pack installed.
- * To find the correct index for an object or counter, inspect the registry key/value:
- * [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009\Counter]
- */
-static const DWORD PDH_PROCESSOR_IDX = 238;
-static const DWORD PDH_PROCESSOR_TIME_IDX = 6;
-static const DWORD PDH_PROCESS_IDX = 230;
-static const DWORD PDH_ID_PROCESS_IDX = 784;
-
-/* useful pdh fmt's */
-static const char* const OBJECT_COUNTER_FMT = "\\%s\\%s";
-static const size_t OBJECT_COUNTER_FMT_LEN = 2;
-static const char* const OBJECT_WITH_INSTANCES_COUNTER_FMT = "\\%s(%s)\\%s";
-static const size_t OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN = 4;
-static const char* const PROCESS_OBJECT_INSTANCE_COUNTER_FMT = "\\%s(%s#%s)\\%s";
-static const size_t PROCESS_OBJECT_INSTANCE_COUNTER_FMT_LEN = 5;
-
-static const char* pdhProcessImageName = NULL; /* "java" */
-static char* pdhIDProcessCounterFmt = NULL;    /* "\Process(java#%d)\ID Process" */
-
-static int numberOfJavaProcessesAtInitialization = 0;
-
-/*
- * Currently used CPU queries/counters and variables
- */
-static SingleCounterQueryP processTotalCPULoad = NULL;
-static MultipleCounterQueryP multiCounterCPULoad = NULL;
-static double cpuFactor = .0;
-static DWORD  numCpus = 0;
-
-/*
- * Seems WinXP PDH returns PDH_MORE_DATA whenever we send in a NULL buffer.
- * Let's just ignore it, since we make sure we have enough buffer anyway.
- */
-static int
-pdhFail(PDH_STATUS pdhStat) {
-    return pdhStat != ERROR_SUCCESS && pdhStat != PDH_MORE_DATA;
-}
-
-static const char*
-allocateAndCopy(const char* const originalString) {
-    size_t len;
-    char* allocatedString;
-
-    assert(originalString);
-
-    len = strlen(originalString);
-
-    allocatedString = malloc(len + 1);
-
-    if (!allocatedString) {
-        return NULL;
-    }
-
-    strncpy(allocatedString, originalString, len);
-    allocatedString[len] = '\0';
-
-    return allocatedString;
-}
-
-/*
- * Allocates memory into the supplied pointer and
- * fills it with the localized PDH artifact description, if indexed correctly.
- * Caller owns the memory from the point of returning from this function.
- *
- * @param index    the PDH counter index as specified in the registry
- * @param ppBuffer pointer to a char*.
- * @return         0 if successful, negative on failure.
- */
-static int
-lookupNameByIndex(DWORD index, char** ppBuffer) {
-    DWORD size;
-
-    assert(ppBuffer);
-
-    /* determine size needed */
-    if (PdhLookupPerfNameByIndex_i(NULL, index, NULL, &size) != PDH_MORE_DATA) {
-      /* invalid index? */
-      return -1;
-    }
-
-    *ppBuffer = malloc((size_t)size);
-
-    if (!*ppBuffer) {
-        return -1;
-    }
-
-    if (PdhLookupPerfNameByIndex_i(NULL, index, *ppBuffer, &size) != ERROR_SUCCESS) {
-        free(*ppBuffer);
-        *ppBuffer = NULL;
-        return -1;
-    }
-
-    /* windows vista does not null-terminate the string
-     * (although the docs says it will) */
-    (*ppBuffer)[size - 1] = '\0';
-
-    return 0;
-}
-
-/*
-* Construct a fully qualified PDH path
-*
-* @param objectName   a PDH Object string representation (required)
-* @param counterName  a PDH Counter string representation (required)
-* @param imageName    a process image name string, ex. "java" (opt)
-* @param instance     an instance string, ex. "0", "1", ... (opt)
-* @return             the fully qualified PDH path.
-*
-* Caller will own the returned malloc:ed string
-*/
-static const char*
-makeFullCounterPath(const char* const objectName,
-                    const char* const counterName,
-                    const char* const imageName,
-                    const char* const instance) {
-
-    size_t fullCounterPathLen;
-    char* fullCounterPath;
-
-    assert(objectName);
-    assert(counterName);
-
-    fullCounterPathLen = strlen(objectName);
-    fullCounterPathLen += strlen(counterName);
-
-    if (imageName) {
-        /*
-         * For paths using the "Process" Object.
-         *
-         * Examples:
-         * abstract: "\Process(imageName#instance)\Counter"
-         * actual:   "\Process(java#2)\ID Process"
-         */
-        fullCounterPathLen += PROCESS_OBJECT_INSTANCE_COUNTER_FMT_LEN;
-        fullCounterPathLen += strlen(imageName);
-
-        /*
-         * imageName must be passed together with an associated
-         * instance "number" ("0", "1", "2", ...).
-         * This is required in order to create valid "Process" Object paths.
-         *
-         * Examples: "\Process(java#0)", \Process(java#1"), ...
-         */
-        assert(instance);
-
-        fullCounterPathLen += strlen(instance);
-
-        fullCounterPath = malloc(fullCounterPathLen + 1);
-
-        if (!fullCounterPath) {
-            return NULL;
-        }
-
-        _snprintf(fullCounterPath,
-                  fullCounterPathLen,
-                  PROCESS_OBJECT_INSTANCE_COUNTER_FMT,
-                  objectName,
-                  imageName,
-                  instance,
-                  counterName);
-    } else {
-        if (instance) {
-            /*
-             * For paths where the Object has multiple instances.
-             *
-             * Examples:
-             * abstract: "\Object(instance)\Counter"
-             * actual:   "\Processor(0)\% Privileged Time"
-             */
-            fullCounterPathLen += strlen(instance);
-            fullCounterPathLen += OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN;
-        } else {
-            /*
-             * For "normal" paths.
-             *
-             * Examples:
-             * abstract: "\Object\Counter"
-             * actual:   "\Memory\Available Mbytes"
-             */
-            fullCounterPathLen += OBJECT_COUNTER_FMT_LEN;
-        }
-
-        fullCounterPath = malloc(fullCounterPathLen + 1);
-
-        if (!fullCounterPath) {
-            return NULL;
-        }
-
-        if (instance) {
-            _snprintf(fullCounterPath,
-                      fullCounterPathLen,
-                      OBJECT_WITH_INSTANCES_COUNTER_FMT,
-                      objectName,
-                      instance,
-                      counterName);
-        } else {
-            _snprintf(fullCounterPath,
-                      fullCounterPathLen,
-                      OBJECT_COUNTER_FMT,
-                      objectName,
-                      counterName);
-        }
-    }
-
-    fullCounterPath[fullCounterPathLen] = '\0';
-
-    return fullCounterPath;
-}
-
-/*
- * Resolves an index for a PDH artifact to
- * a localized, malloc:ed string representation.
- * Caller will own the returned malloc:ed string.
- *
- * @param pdhArtifactIndex  PDH index
- * @return                  malloc:ed string representation
- *                          of the requested pdh artifact (localized).
- *                          NULL on failure.
- */
-static const char*
-getPdhLocalizedArtifact(DWORD pdhArtifactIndex) {
-    char* pdhLocalizedArtifactString;
-
-    if (lookupNameByIndex(pdhArtifactIndex,
-                          &pdhLocalizedArtifactString) != 0) {
-        return NULL;
-    }
-
-    return pdhLocalizedArtifactString;
-}
-
-static void
-pdhCleanup(HQUERY* const query, HCOUNTER* const counter) {
-    if (counter && *counter) {
-        PdhRemoveCounter_i(*counter);
-        *counter = NULL;
-    }
-    if (query && *query) {
-        PdhCloseQuery_i(*query);
-        *query = NULL;
-    }
-}
-
-static void
-destroySingleCounter(SingleCounterQueryP counterQuery) {
-    if (counterQuery) {
-        pdhCleanup(&counterQuery->query.query, &counterQuery->counter);
-    }
-}
-
-static void
-destroyMultiCounter(MultipleCounterQueryP multiCounterQuery) {
-    int i;
-    if (multiCounterQuery) {
-        if (multiCounterQuery->counters) {
-            for (i = 0; i < multiCounterQuery->noOfCounters; i++) {
-                pdhCleanup(NULL, &multiCounterQuery->counters[i]);
-            }
-            free(multiCounterQuery->counters);
-            multiCounterQuery->counters = NULL;
-        }
-        pdhCleanup(&multiCounterQuery->query.query, NULL);
-    }
-}
-
-static int
-openQuery(HQUERY* const query) {
-    assert(query);
-
-    if (PdhOpenQuery_i(NULL, 0, query) != ERROR_SUCCESS) {
-        return -1;
-    }
-
-    return 0;
-}
-
-static int
-addCounter(HQUERY query,
-           const char* const fullCounterPath,
-           HCOUNTER* const counter) {
-
-    assert(fullCounterPath);
-    assert(counter);
-
-    if (PdhAddCounter_i(query,
-                        fullCounterPath,
-                        0,
-                        counter) != ERROR_SUCCESS) {
-        return -1;
-    }
-
-    return 0;
-}
-
-/*
- * Sets up the supplied SingleCounterQuery to listen for the specified counter.
- *
- * @param counterQuery       the counter query to set up.
- * @param fullCounterPath    the string specifying the full path to the counter.
- * @returns                  0 if successful, negative on failure.
- */
-static int
-initializeSingleCounterQuery(SingleCounterQueryP counterQuery,
-                             const char* const fullCounterPath) {
-    assert(counterQuery);
-    assert(fullCounterPath);
-
-    if (openQuery(&counterQuery->query.query) == 0) {
-        if (addCounter(counterQuery->query.query,
-                       fullCounterPath,
-                       &counterQuery->counter) == 0) {
-            return 0;
-        }
-    }
-
-    return -1;
-}
-
-/*
- * Sets up a SingleCounterQuery
- *
- * param counter             the counter query to set up.
- * param localizedObject     string representing the PDH object to query
- * param localizedCounter    string representing the PDH counter to query
- * param processImageName    if the counter query needs the process image name ("java")
- * param instance            if the counter has instances, this is the instance ("\Processor(0)\")
-                                 where 0 is the instance
- * param firstSampleOnInit   for counters that need two queries to yield their values,
-                                 the first query can be issued just after initialization
- *
- * @returns                   0 if successful, negative on failure.
- */
-static int
-initializeSingleCounter(SingleCounterQueryP const counter,
-                        const char* const localizedObject,
-                        const char* const localizedCounter,
-                        const char* const processImageName,
-                        const char* const instance,
-                        BOOL firstSampleOnInit) {
-    int retValue = -1;
-
-    const char* fullCounterPath = makeFullCounterPath(localizedObject,
-                                                      localizedCounter,
-                                                      processImageName,
-                                                      instance);
-
-    if (fullCounterPath) {
-
-        assert(counter);
-
-        if (initializeSingleCounterQuery(counter, fullCounterPath) == 0) {
-            /*
-             * According to the MSDN documentation, rate counters must be read twice:
-             *
-             * "Obtaining the value of rate counters such as Page faults/sec requires that
-             *  PdhCollectQueryData be called twice, with a specific time interval between
-             *  the two calls, before calling PdhGetFormattedCounterValue. Call Sleep to
-             *  implement the waiting period between the two calls to PdhCollectQueryData."
-             *
-             *  Take the first sample here already to allow for the next (first) "real" sample
-             *  to succeed.
-             */
-            if (firstSampleOnInit) {
-                PdhCollectQueryData_i(counter->query.query);
-            }
-
-            retValue = 0;
-        }
-        free((char*)fullCounterPath);
-    }
-
-    return retValue;
-}
-
-static void
-perfInit(void) {
-    InitializePdhCriticalSection(&initializationLock);
-}
-
-static int
-getProcessID() {
-    static int myPid = 0;
-    if (0 == myPid) {
-        myPid = _getpid();
-    }
-    return myPid;
-}
-
-/*
- * Working against the Process object and it's related counters is inherently problematic
- * when using the PDH API:
- *
- * For PDH, a process is not primarily identified by it's process id,
- * but with a sequential number, for example \Process(java#0), \Process(java#1), ....
- * The really bad part is that this list is reset as soon as one process exits:
- * If \Process(java#1) exits, \Process(java#3) now becomes \Process(java#2) etc.
- *
- * The PDH query api requires a process identifier to be submitted when registering
- * a query, but as soon as the list resets, the query is invalidated (since the name
- * changed).
- *
- * Solution:
- * The #number identifier for a Process query can only decrease after process creation.
- *
- * Therefore we create an array of counter queries for all process object instances
- * up to and including ourselves:
- *
- * Ex. we come in as third process instance (java#2), we then create and register
- * queries for the following Process object instances:
- * java#0, java#1, java#2
- *
- * currentQueryIndexForProcess() keeps track of the current "correct" query
- * (in order to keep this index valid when the list resets from underneath,
- * ensure to call getCurrentQueryIndexForProcess() before every query involving
- * Process object instance data).
- */
-static int
-currentQueryIndexForProcess(void) {
-    HQUERY tmpQuery = NULL;
-    HCOUNTER handleCounter = NULL;
-    int retValue = -1;
-
-    assert(pdhProcessImageName);
-    assert(pdhIDProcessCounterFmt);
-
-    if (openQuery(&tmpQuery) == 0) {
-        int index;
-
-        /* iterate over all instance indexes and try to find our own pid */
-        for (index = 0; index < INT_MAX; ++index) {
-            char fullIDProcessCounterPath[MAX_PATH];
-            PDH_FMT_COUNTERVALUE counterValue;
-            PDH_STATUS res;
-
-            _snprintf(fullIDProcessCounterPath,
-                      MAX_PATH,
-                      pdhIDProcessCounterFmt,
-                      index);
-
-            if (addCounter(tmpQuery, fullIDProcessCounterPath, &handleCounter) != 0) {
-                break;
-            }
-
-            res = PdhCollectQueryData_i(tmpQuery);
-
-            if (PDH_INVALID_HANDLE == res || PDH_NO_DATA == res) {
-                break;
-            }
-
-            PdhGetFormattedCounterValue_i(handleCounter,
-                                          PDH_FMT_LONG,
-                                          NULL,
-                                          &counterValue);
-            /*
-             * This check seems to be needed for Win2k SMP boxes, since
-             * they for some reason don't return PDH_NO_DATA for non existing
-             * counters.
-             */
-            if (counterValue.CStatus != PDH_CSTATUS_VALID_DATA) {
-                break;
-            }
-
-            if ((LONG)getProcessID() == counterValue.longValue) {
-                retValue = index;
-                break;
-            }
-        }
-    }
-
-    pdhCleanup(&tmpQuery, &handleCounter);
-
-    return retValue;
-}
-
-/*
- * If successful, returns the #index corresponding to our PID
- * as resolved by the pdh query:
- * "\Process(java#index)\ID Process" (or localized equivalent)
- *
- * This function should be called before attempting to read
- * from any Process related counter(s), and the return value
- * is the index to be used for indexing an array of Process object query's:
- *
- * Example:
- * processTotalCPULoad[currentQueryIndex].query
- *
- * Returns -1 on failure.
- */
-static int
-getCurrentQueryIndexForProcess() {
-    int currentQueryIndex = currentQueryIndexForProcess();
-
-    assert(currentQueryIndex >= 0 &&
-           currentQueryIndex < numberOfJavaProcessesAtInitialization);
-
-    return currentQueryIndex;
-}
-
-/*
- * Returns the PDH string identifying the current process image name.
- * Use this name as a qualifier when getting counters from the PDH Process Object
- * representing your process.
-
- * Example:
- * "\Process(java#0)\Virtual Bytes" - where "java" is the PDH process
- * image name.
- *
- * Please note that the process image name is not necessarily "java",
- * hence the use of GetModuleFileName() to detect the process image name.
- *
- * @return   the process image name to be used when retrieving
- *           PDH counters from the current process. The caller will
-             own the returned malloc:ed string. NULL if failure.
- */
-static const char*
-getPdhProcessImageName() {
-    char moduleName[MAX_PATH];
-    char* processImageName;
-    char* dotPos;
-
-    // Find our module name and use it to extract the image name used by PDH
-    DWORD getmfnReturn = GetModuleFileName(NULL, moduleName, sizeof(moduleName));
-
-    if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
-        return NULL;
-    }
-
-    if (getmfnReturn >= MAX_PATH || 0 == getmfnReturn) {
-        return NULL;
-    }
-
-    processImageName = strrchr(moduleName, '\\'); //drop path
-    processImageName++;                           //skip slash
-    dotPos = strrchr(processImageName, '.');      //drop .exe
-    dotPos[0] = '\0';
-
-    return allocateAndCopy(processImageName);
-}
-
-/*
- * Sets up the supplied MultipleCounterQuery to check on the processors via PDH CPU counters.
- * TODO: Refactor and prettify as with the the SingleCounter queries
- * if more MultipleCounterQueries are discovered/needed.
- *
- * @param multiCounterCPULoad  a pointer to a MultipleCounterQueryS, will be filled in with
- *                             the necessary info to check the PDH processor counters.
- * @return                     0 if successful, negative on failure.
- */
-static int
-initializeMultipleCounterForCPUs(MultipleCounterQueryP multiCounterCPULoad) {
-    DWORD cSize = 0;
-    DWORD iSize = 0;
-    DWORD pCount;
-    DWORD index;
-    char* processor = NULL; //'Processor' == PDH_PROCESSOR_IDX
-    char* time = NULL;      //'Time' == PDH_PROCESSOR_TIME_IDX
-    char* instances = NULL;
-    char* tmp;
-    int   retValue = -1;
-    PDH_STATUS pdhStat;
-
-    if (lookupNameByIndex(PDH_PROCESSOR_IDX, &processor) != 0) {
-        goto end;
-    }
-
-    if (lookupNameByIndex(PDH_PROCESSOR_TIME_IDX, &time) != 0) {
-        goto end;
-    }
-
-    //ok, now we have enough to enumerate all processors.
-    pdhStat = PdhEnumObjectItems_i(
-                                   NULL, // reserved
-                                   NULL, // local machine
-                                   processor, // object to enumerate
-                                   NULL, // pass in NULL buffers
-                                   &cSize, // and 0 length to get
-                                   NULL, // required size
-                                   &iSize, // of the buffers in chars
-                                   PERF_DETAIL_WIZARD, // counter detail level
-                                   0);
-
-    if (pdhFail(pdhStat)) {
-        goto end;
-    }
-
-    instances = calloc(iSize, 1);
-
-    if (!instances) {
-        goto end;
-    }
-
-    cSize = 0;
-
-    pdhStat = PdhEnumObjectItems_i(
-                                   NULL, // reserved
-                                   NULL, // local machine
-                                   processor, // object to enumerate
-                                   NULL, // pass in NULL buffers
-                                   &cSize,
-                                   instances, // now allocated to be filled in
-                                   &iSize, // and size is known
-                                   PERF_DETAIL_WIZARD, // counter detail level
-                                   0);
-
-    if (pdhFail(pdhStat)) {
-        goto end;
-    }
-
-    // enumerate the Processor instances ("\Processor(0)", "\Processor(1)", ..., "\Processor(_Total)")
-    for (pCount = 0, tmp = instances; *tmp != '\0'; tmp = &tmp[strlen(tmp)+1], pCount++);
-
-    assert(pCount == numCpus+1);
-
-    //ok, we now have the number of Processor instances - allocate an HCOUNTER for each
-    multiCounterCPULoad->counters = (HCOUNTER*)malloc(pCount * sizeof(HCOUNTER));
-
-    if (!multiCounterCPULoad->counters) {
-        goto end;
-    }
-
-    multiCounterCPULoad->noOfCounters = pCount;
-
-    if (openQuery(&multiCounterCPULoad->query.query) != 0) {
-        goto end;
-    }
-
-    // fetch instance and register its corresponding HCOUNTER with the query
-    for (index = 0, tmp = instances; *tmp != '\0'; tmp = &tmp[strlen(tmp)+1], ++index) {
-        const char* const fullCounterPath = makeFullCounterPath(processor, time, NULL, tmp);
-
-        if (!fullCounterPath) {
-            goto end;
-        }
-
-        retValue = addCounter(multiCounterCPULoad->query.query,
-                              fullCounterPath,
-                              &multiCounterCPULoad->counters[index]);
-
-        free((char*)fullCounterPath);
-
-        if (retValue != 0) {
-            goto end;
-        }
-    }
-
-    // Query once to initialize the counters which require at least two samples
-    // (like the % CPU usage) to calculate correctly.
-    PdhCollectQueryData_i(multiCounterCPULoad->query.query);
-
-  end:
-    if (processor) {
-        free(processor);
-    }
-
-    if (time) {
-        free(time);
-    }
-
-    if (instances) {
-        free(instances);
-    }
-
-    return retValue;
-}
-
-/*
- * Dynamically sets up function pointers to the PDH library.
- *
- * @param h  HMODULE for the PDH library
- * @return   0 on success, negative on failure.
- */
-static int
-bindPdhFunctionPointers(HMODULE h) {
-    assert(h);
-    assert(GetCurrentThreadId() == initializationLock.owningThread);
-
-    /* The 'A' at the end means the ANSI (not the UNICODE) vesions of the methods */
-    PdhAddCounter_i         = (PdhAddCounterFunc)GetProcAddress(h, "PdhAddCounterA");
-    PdhOpenQuery_i         = (PdhOpenQueryFunc)GetProcAddress(h, "PdhOpenQueryA");
-    PdhCloseQuery_i         = (PdhCloseQueryFunc)GetProcAddress(h, "PdhCloseQuery");
-    PdhCollectQueryData_i     = (PdhCollectQueryDataFunc)GetProcAddress(h, "PdhCollectQueryData");
-    PdhGetFormattedCounterValue_i = (PdhGetFormattedCounterValueFunc)GetProcAddress(h, "PdhGetFormattedCounterValue");
-    PdhEnumObjectItems_i         = (PdhEnumObjectItemsFunc)GetProcAddress(h, "PdhEnumObjectItemsA");
-    PdhRemoveCounter_i         = (PdhRemoveCounterFunc)GetProcAddress(h, "PdhRemoveCounter");
-    PdhLookupPerfNameByIndex_i     = (PdhLookupPerfNameByIndexFunc)GetProcAddress(h, "PdhLookupPerfNameByIndexA");
-
-    if (!PdhAddCounter_i || !PdhOpenQuery_i ||
-        !PdhCloseQuery_i || !PdhCollectQueryData_i ||
-        !PdhGetFormattedCounterValue_i || !PdhEnumObjectItems_i ||
-        !PdhRemoveCounter_i || !PdhLookupPerfNameByIndex_i)
-    {
-        return -1;
-    }
-    return 0;
-}
-
-/*
- * Returns the counter value as a double for the specified query.
- * Will collect the query data and update the counter values as necessary.
- *
- * @param query       the query to update (if needed).
- * @param c           the counter to read.
- * @param value       where to store the formatted value.
- * @param format      the format to use (i.e. PDH_FMT_DOUBLE, PDH_FMT_LONG etc)
- * @return            0 if no error
- *                    -1 if PdhCollectQueryData fails
- *                    -2 if PdhGetFormattedCounterValue fails
- */
-static int
-getPerformanceData(UpdateQueryP query, HCOUNTER c, PDH_FMT_COUNTERVALUE* value, DWORD format) {
-    clock_t now = clock();
-
-    /*
-     * Need to limit how often we update the query
-     * to minimize the Heisenberg effect.
-     * (PDH behaves erratically if the counters are
-     * queried too often, especially counters that
-     * store and use values from two consecutive updates,
-     * like cpu load.)
-     */
-    if (now - query->lastUpdate > MIN_UPDATE_INTERVAL) {
-        if (PdhCollectQueryData_i(query->query) != ERROR_SUCCESS) {
-            return -1;
-        }
-        query->lastUpdate = now;
-    }
-
-    if (PdhGetFormattedCounterValue_i(c, format, NULL, value) != ERROR_SUCCESS) {
-        return -2;
-    }
-
-    return 0;
-}
-
-static int
-allocateAndInitializePdhConstants() {
-    const char* pdhLocalizedProcessObject = NULL;
-    const char* pdhLocalizedIDProcessCounter = NULL;
-    size_t pdhIDProcessCounterFmtLen;
-    int currentQueryIndex;
-    int retValue = -1;
-
-    assert(GetCurrentThreadId() == initializationLock.owningThread);
-
-    assert(!pdhProcessImageName);
-    pdhProcessImageName = getPdhProcessImageName();
-    if (!pdhProcessImageName) {
-        goto end;
-    }
-
-    pdhLocalizedProcessObject = getPdhLocalizedArtifact(PDH_PROCESS_IDX);
-    if (!pdhLocalizedProcessObject) {
-        goto end;
-    }
-
-    pdhLocalizedIDProcessCounter = getPdhLocalizedArtifact(PDH_ID_PROCESS_IDX);
-    if (!pdhLocalizedIDProcessCounter) {
-        goto end;
-    }
-
-    assert(!pdhIDProcessCounterFmt);
-
-    pdhIDProcessCounterFmtLen = strlen(pdhProcessImageName);
-    pdhIDProcessCounterFmtLen += strlen(pdhLocalizedProcessObject);
-    pdhIDProcessCounterFmtLen += strlen(pdhLocalizedIDProcessCounter);
-    pdhIDProcessCounterFmtLen += PROCESS_OBJECT_INSTANCE_COUNTER_FMT_LEN;
-    pdhIDProcessCounterFmtLen += 2; // "%d"
-
-    assert(pdhIDProcessCounterFmtLen < MAX_PATH);
-    pdhIDProcessCounterFmt = malloc(pdhIDProcessCounterFmtLen + 1);
-    if (!pdhIDProcessCounterFmt) {
-        goto end;
-    }
-
-    /* "\Process(java#%d)\ID Process" */
-    _snprintf(pdhIDProcessCounterFmt,
-              pdhIDProcessCounterFmtLen,
-              PROCESS_OBJECT_INSTANCE_COUNTER_FMT,
-              pdhLocalizedProcessObject,
-              pdhProcessImageName,
-              "%d",
-              pdhLocalizedIDProcessCounter);
-
-    pdhIDProcessCounterFmt[pdhIDProcessCounterFmtLen] = '\0';
-
-    assert(0 == numberOfJavaProcessesAtInitialization);
-    currentQueryIndex = currentQueryIndexForProcess();
-    if (-1 == currentQueryIndex) {
-        goto end;
-    }
-
-    numberOfJavaProcessesAtInitialization = currentQueryIndex + 1;
-    assert(numberOfJavaProcessesAtInitialization >= 1);
-
-    retValue = 0;
-
-  end:
-
-    if (pdhLocalizedProcessObject) {
-        free((char*)pdhLocalizedProcessObject);
-    }
-
-    if (pdhLocalizedIDProcessCounter) {
-        free((char*)pdhLocalizedIDProcessCounter);
-    }
-
-    return retValue;
-}
-
-static void
-deallocatePdhConstants() {
-    assert(GetCurrentThreadId() == initializationLock.owningThread);
-
-    if (pdhProcessImageName) {
-        free((char*)pdhProcessImageName);
-        pdhProcessImageName = NULL;
-    }
-
-    if (pdhIDProcessCounterFmt) {
-      free(pdhIDProcessCounterFmt);
-      pdhIDProcessCounterFmt = NULL;
-    }
-
-    numberOfJavaProcessesAtInitialization = 0;
-}
-
-static int
-initializeCPUCounters() {
-    SYSTEM_INFO si;
-    char* localizedProcessObject;
-    char* localizedProcessorTimeCounter;
-    int i;
-    int retValue = -1;
-
-    assert(GetCurrentThreadId() == initializationLock.owningThread);
-
-    assert(0 == numCpus);
-    GetSystemInfo(&si);
-    numCpus = si.dwNumberOfProcessors;
-    assert(numCpus >= 1);
-
-    /* Initialize the denominator for the jvm load calculations */
-    assert(.0 == cpuFactor);
-    cpuFactor = numCpus * 100;
-
-    if (lookupNameByIndex(PDH_PROCESS_IDX,
-                          &localizedProcessObject) == 0) {
-
-        if (lookupNameByIndex(PDH_PROCESSOR_TIME_IDX,
-                              &localizedProcessorTimeCounter) == 0) {
-
-            assert(processTotalCPULoad);
-            assert(pdhProcessImageName);
-
-            for (i = 0; i < numberOfJavaProcessesAtInitialization; ++i) {
-                char instanceIndexBuffer[32];
-                retValue = initializeSingleCounter(&processTotalCPULoad[i],
-                                                   localizedProcessObject,
-                                                   localizedProcessorTimeCounter,
-                                                   pdhProcessImageName,
-                                                   itoa(i, instanceIndexBuffer, 10),
-                                                   TRUE);
-                if (retValue != 0) {
-                    break;
-                }
-            }
-            free(localizedProcessorTimeCounter);
-        }
-        free(localizedProcessObject);
-    }
-
-    if (retValue != 0) {
-        return -1;
-    }
-
-    assert(multiCounterCPULoad);
-    return initializeMultipleCounterForCPUs(multiCounterCPULoad);
-}
-
-static void
-deallocateCPUCounters() {
-    int i;
-
-    assert(GetCurrentThreadId() == initializationLock.owningThread);
-
-    if (processTotalCPULoad) {
-        for (i = 0; i < numberOfJavaProcessesAtInitialization; ++i) {
-            destroySingleCounter(&processTotalCPULoad[i]);
-        }
-        free(processTotalCPULoad);
-        processTotalCPULoad = NULL;
-    }
-
-    if (multiCounterCPULoad) {
-        destroyMultiCounter(multiCounterCPULoad);
-        free(multiCounterCPULoad);
-        multiCounterCPULoad = NULL;
-    }
-
-    cpuFactor = .0;
-    numCpus = 0;
-}
-
-static void
-pdhInitErrorHandler(HMODULE h) {
-    assert(GetCurrentThreadId() == initializationLock.owningThread);
-
-    deallocatePdhConstants();
-
-    if (h) {
-        FreeLibrary(h);
-    }
-}
-
-/*
- * Helper to initialize the PDH library, function pointers and constants.
- *
- * @return  0 if successful, negative on failure.
- */
-static int
-pdhInit() {
-    static BOOL initialized = FALSE;
-    int retValue;
-
-    if (initialized) {
-        return 0;
-    }
-
-    retValue = 0;
-
-    EnterPdhCriticalSection(&initializationLock); {
-        if (!initialized) {
-            HMODULE h = NULL;
-            if ((h = LoadLibrary("pdh.dll")) == NULL) {
-                retValue = -1;
-            } else if (bindPdhFunctionPointers(h) < 0) {
-                retValue = -1;
-            } else if (allocateAndInitializePdhConstants() < 0) {
-                retValue = -1;
-            }
-
-            if (0 == retValue) {
-                initialized = TRUE;
-            } else {
-                pdhInitErrorHandler(h);
-            }
-        }
-    } LeavePdhCriticalSection(&initializationLock);
-
-    return retValue;
-}
-
-static int
-allocateCPUCounters() {
-    assert(GetCurrentThreadId() == initializationLock.owningThread);
-    assert(numberOfJavaProcessesAtInitialization >= 1);
-    assert(!processTotalCPULoad);
-    assert(!multiCounterCPULoad);
-
-    /*
-     * Create an array of Process object queries, for each instance
-     * up to and including our own (java#0, java#1, java#2, ...).
-     */
-    processTotalCPULoad = calloc(numberOfJavaProcessesAtInitialization,
-                                 sizeof(SingleCounterQueryS));
-
-    if (!processTotalCPULoad) {
-        return -1;
-    }
-
-    multiCounterCPULoad = calloc(1, sizeof(MultipleCounterQueryS));
-
-    if (!multiCounterCPULoad) {
-        return -1;
-    }
-
-    return 0;
-}
-
-static int
-initializePdhCPUCounters() {
-    static BOOL initialized = FALSE;
-    int retValue;
-
-    if (initialized) {
-        return 0;
-    }
-
-    retValue = 0;
-
-    EnterPdhCriticalSection(&initializationLock); {
-        if (!initialized) {
-            if (pdhInit() < 0) {
-                retValue = -1;
-            }  else if (allocateCPUCounters() < 0) {
-                retValue = -1;
-            } else if (initializeCPUCounters() < 0) {
-                retValue = -1;
-            }
-
-            if (0 == retValue) {
-                initialized = TRUE;
-            } else {
-              deallocateCPUCounters();
-            }
-        }
-    } LeavePdhCriticalSection(&initializationLock);
-
-    return retValue;
-}
-
-static int
-perfCPUInit() {
-    return initializePdhCPUCounters();
-}
-
-static double
-perfGetProcessCPULoad() {
-    PDH_FMT_COUNTERVALUE cv;
-    int currentQueryIndex;
-
-    if (perfCPUInit() < 0) {
-        // warn?
-        return -1.0;
-    }
-
-    currentQueryIndex = getCurrentQueryIndexForProcess();
-
-    if (getPerformanceData(&processTotalCPULoad[currentQueryIndex].query,
-                           processTotalCPULoad[currentQueryIndex].counter,
-                           &cv,
-                           PDH_FMT_DOUBLE | PDH_FMT_NOCAP100) == 0) {
-        double d = cv.doubleValue / cpuFactor;
-        d = min(1, d);
-        d = max(0, d);
-        return d;
-    }
-    return -1.0;
-}
-
-static double
-perfGetCPULoad(int which) {
-    PDH_FMT_COUNTERVALUE cv;
-    HCOUNTER c;
-
-    if (perfCPUInit() < 0) {
-        // warn?
-        return -1.0;
-    }
-
-    if (-1 == which) {
-        c = multiCounterCPULoad->counters[multiCounterCPULoad->noOfCounters - 1];
-    } else {
-        if (which < multiCounterCPULoad->noOfCounters) {
-            c = multiCounterCPULoad->counters[which];
-        } else {
-            return -1.0;
-        }
-    }
-    if (getPerformanceData(&multiCounterCPULoad->query, c, &cv, PDH_FMT_DOUBLE ) == 0) {
-        return cv.doubleValue / 100;
-    }
-    return -1.0;
-}
-
-JNIEXPORT jdouble JNICALL
-Java_sun_management_OperatingSystemImpl_getSystemCpuLoad0
-(JNIEnv *env, jobject dummy)
-{
-    return perfGetCPULoad(-1);
-}
-
-JNIEXPORT jdouble JNICALL
-Java_sun_management_OperatingSystemImpl_getProcessCpuLoad0
-(JNIEnv *env, jobject dummy)
-{
-    return perfGetProcessCPULoad();
-}