jdk/src/jdk.management/windows/native/libmanagement_ext/OperatingSystemImpl.c
changeset 30355 e37c7eba132f
parent 27494 22353a4c3b4e
equal deleted inserted replaced
30354:ca83b4cae363 30355:e37c7eba132f
       
     1 /*
       
     2  * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 #include "jni.h"
       
    27 #include "jni_util.h"
       
    28 #include "jlong.h"
       
    29 #include "jvm.h"
       
    30 #include "management_ext.h"
       
    31 #include "com_sun_management_internal_OperatingSystemImpl.h"
       
    32 
       
    33 #include <psapi.h>
       
    34 #include <errno.h>
       
    35 #include <stdlib.h>
       
    36 
       
    37 #include <malloc.h>
       
    38 #pragma warning (push,0)
       
    39 #include <windows.h>
       
    40 #pragma warning (pop)
       
    41 #include <stdio.h>
       
    42 #include <time.h>
       
    43 #include <stdint.h>
       
    44 #include <assert.h>
       
    45 
       
    46 /* Disable warnings due to broken header files from Microsoft... */
       
    47 #pragma warning(push, 3)
       
    48 #include <pdh.h>
       
    49 #include <pdhmsg.h>
       
    50 #include <process.h>
       
    51 #pragma warning(pop)
       
    52 
       
    53 typedef unsigned __int32 juint;
       
    54 typedef unsigned __int64 julong;
       
    55 
       
    56 static void set_low(jlong* value, jint low) {
       
    57     *value &= (jlong)0xffffffff << 32;
       
    58     *value |= (jlong)(julong)(juint)low;
       
    59 }
       
    60 
       
    61 static void set_high(jlong* value, jint high) {
       
    62     *value &= (jlong)(julong)(juint)0xffffffff;
       
    63     *value |= (jlong)high       << 32;
       
    64 }
       
    65 
       
    66 static jlong jlong_from(jint h, jint l) {
       
    67     jlong result = 0; // initialization to avoid warning
       
    68     set_high(&result, h);
       
    69     set_low(&result,  l);
       
    70     return result;
       
    71 }
       
    72 
       
    73 static HANDLE main_process;
       
    74 
       
    75 static void perfInit(void);
       
    76 
       
    77 JNIEXPORT void JNICALL
       
    78 Java_com_sun_management_internal_OperatingSystemImpl_initialize0
       
    79   (JNIEnv *env, jclass cls)
       
    80 {
       
    81     main_process = GetCurrentProcess();
       
    82     perfInit();
       
    83 }
       
    84 
       
    85 JNIEXPORT jlong JNICALL
       
    86 Java_com_sun_management_internal_OperatingSystemImpl_getCommittedVirtualMemorySize0
       
    87   (JNIEnv *env, jobject mbean)
       
    88 {
       
    89     PROCESS_MEMORY_COUNTERS pmc;
       
    90     if (GetProcessMemoryInfo(main_process, &pmc, sizeof(PROCESS_MEMORY_COUNTERS)) == 0) {
       
    91         return (jlong)-1L;
       
    92     } else {
       
    93         return (jlong) pmc.PagefileUsage;
       
    94     }
       
    95 }
       
    96 
       
    97 JNIEXPORT jlong JNICALL
       
    98 Java_com_sun_management_internal_OperatingSystemImpl_getTotalSwapSpaceSize0
       
    99   (JNIEnv *env, jobject mbean)
       
   100 {
       
   101     MEMORYSTATUSEX ms;
       
   102     ms.dwLength = sizeof(ms);
       
   103     GlobalMemoryStatusEx(&ms);
       
   104     return (jlong) ms.ullTotalPageFile;
       
   105 }
       
   106 
       
   107 JNIEXPORT jlong JNICALL
       
   108 Java_com_sun_management_internal_OperatingSystemImpl_getFreeSwapSpaceSize0
       
   109   (JNIEnv *env, jobject mbean)
       
   110 {
       
   111     MEMORYSTATUSEX ms;
       
   112     ms.dwLength = sizeof(ms);
       
   113     GlobalMemoryStatusEx(&ms);
       
   114     return (jlong) ms.ullAvailPageFile;
       
   115 }
       
   116 
       
   117 JNIEXPORT jlong JNICALL
       
   118 Java_com_sun_management_internal_OperatingSystemImpl_getProcessCpuTime0
       
   119   (JNIEnv *env, jobject mbean)
       
   120 {
       
   121 
       
   122     FILETIME process_creation_time, process_exit_time,
       
   123              process_user_time, process_kernel_time;
       
   124 
       
   125     // Using static variables declared above
       
   126     // Units are 100-ns intervals.  Convert to ns.
       
   127     GetProcessTimes(main_process, &process_creation_time,
       
   128                     &process_exit_time,
       
   129                     &process_kernel_time, &process_user_time);
       
   130     return (jlong_from(process_user_time.dwHighDateTime,
       
   131                         process_user_time.dwLowDateTime) +
       
   132             jlong_from(process_kernel_time.dwHighDateTime,
       
   133                         process_kernel_time.dwLowDateTime)) * 100;
       
   134 }
       
   135 
       
   136 JNIEXPORT jlong JNICALL
       
   137 Java_com_sun_management_internal_OperatingSystemImpl_getFreePhysicalMemorySize0
       
   138   (JNIEnv *env, jobject mbean)
       
   139 {
       
   140     MEMORYSTATUSEX ms;
       
   141     ms.dwLength = sizeof(ms);
       
   142     GlobalMemoryStatusEx(&ms);
       
   143     return (jlong) ms.ullAvailPhys;
       
   144 }
       
   145 
       
   146 JNIEXPORT jlong JNICALL
       
   147 Java_com_sun_management_internal_OperatingSystemImpl_getTotalPhysicalMemorySize0
       
   148   (JNIEnv *env, jobject mbean)
       
   149 {
       
   150     MEMORYSTATUSEX ms;
       
   151     ms.dwLength = sizeof(ms);
       
   152     GlobalMemoryStatusEx(&ms);
       
   153     return (jlong) ms.ullTotalPhys;
       
   154 }
       
   155 
       
   156 /* Performance Data Helper API (PDH) support */
       
   157 
       
   158 typedef PDH_STATUS (WINAPI *PdhAddCounterFunc)(
       
   159                            HQUERY      hQuery,
       
   160                            LPCSTR      szFullCounterPath,
       
   161                            DWORD       dwUserData,
       
   162                            HCOUNTER    *phCounter
       
   163                            );
       
   164 typedef PDH_STATUS (WINAPI *PdhOpenQueryFunc)(
       
   165                            LPCWSTR     szDataSource,
       
   166                            DWORD       dwUserData,
       
   167                            HQUERY      *phQuery
       
   168                            );
       
   169 typedef PDH_STATUS (WINAPI *PdhCollectQueryDataFunc)(
       
   170                            HQUERY      hQuery
       
   171                            );
       
   172 
       
   173 typedef PDH_STATUS (WINAPI *PdhEnumObjectItemsFunc)(
       
   174                            LPCTSTR     szDataSource,
       
   175                            LPCTSTR     szMachineName,
       
   176                            LPCTSTR     szObjectName,
       
   177                            LPTSTR      mszCounterList,
       
   178                            LPDWORD     pcchCounterListLength,
       
   179                            LPTSTR      mszInstanceList,
       
   180                            LPDWORD     pcchInstanceListLength,
       
   181                            DWORD       dwDetailLevel,
       
   182                            DWORD       dwFlags
       
   183                            );
       
   184 typedef PDH_STATUS (WINAPI *PdhRemoveCounterFunc)(
       
   185                            HCOUNTER   hCounter
       
   186                            );
       
   187 typedef PDH_STATUS (WINAPI *PdhLookupPerfNameByIndexFunc)(
       
   188                            LPCSTR     szMachineName,
       
   189                            DWORD      dwNameIndex,
       
   190                            LPSTR      szNameBuffer,
       
   191                            LPDWORD    pcchNameBufferSize
       
   192                            );
       
   193 typedef DWORD (WINAPI *PdhCloseQueryFunc)(
       
   194                       HQUERY      hQuery
       
   195                       );
       
   196 
       
   197 typedef DWORD (WINAPI *PdhGetFormattedCounterValueFunc)(
       
   198                       HCOUNTER                hCounter,
       
   199                       DWORD                   dwFormat,
       
   200                       LPDWORD                 lpdwType,
       
   201                       PPDH_FMT_COUNTERVALUE   pValue
       
   202                       );
       
   203 
       
   204 static PdhAddCounterFunc PdhAddCounter_i;
       
   205 static PdhOpenQueryFunc PdhOpenQuery_i;
       
   206 static PdhCloseQueryFunc PdhCloseQuery_i;
       
   207 static PdhCollectQueryDataFunc PdhCollectQueryData_i;
       
   208 static PdhGetFormattedCounterValueFunc PdhGetFormattedCounterValue_i;
       
   209 static PdhEnumObjectItemsFunc PdhEnumObjectItems_i;
       
   210 static PdhRemoveCounterFunc PdhRemoveCounter_i;
       
   211 static PdhLookupPerfNameByIndexFunc PdhLookupPerfNameByIndex_i;
       
   212 
       
   213 /*
       
   214  * Struct for PDH queries.
       
   215  */
       
   216 typedef struct {
       
   217     HQUERY      query;
       
   218     uint64_t    lastUpdate; // Last time query was updated (ticks)
       
   219 } UpdateQueryS, *UpdateQueryP;
       
   220 
       
   221 // Min time between query updates (ticks)
       
   222 static const int MIN_UPDATE_INTERVAL = 500;
       
   223 
       
   224 /*
       
   225  * Struct for a PDH query with multiple counters.
       
   226  */
       
   227 typedef struct {
       
   228     UpdateQueryS  query;
       
   229     HCOUNTER*     counters;
       
   230     int           noOfCounters;
       
   231 } MultipleCounterQueryS, *MultipleCounterQueryP;
       
   232 
       
   233 /*
       
   234  * Struct for a PDH query with a single counter.
       
   235  */
       
   236 typedef struct {
       
   237     UpdateQueryS  query;
       
   238     HCOUNTER      counter;
       
   239 } SingleCounterQueryS, *SingleCounterQueryP;
       
   240 
       
   241 
       
   242 typedef struct {
       
   243     CRITICAL_SECTION cs;
       
   244     DWORD owningThread;
       
   245     DWORD recursionCount;
       
   246 } PdhCriticalSectionS, *PdhCriticalSectionP;
       
   247 
       
   248 static PdhCriticalSectionS initializationLock;
       
   249 
       
   250 static void InitializePdhCriticalSection(PdhCriticalSectionP criticalSection) {
       
   251     assert(criticalSection);
       
   252 
       
   253     InitializeCriticalSection(&criticalSection->cs);
       
   254     criticalSection->owningThread = 0;
       
   255     criticalSection->recursionCount = 0;
       
   256 }
       
   257 
       
   258 static void EnterPdhCriticalSection(PdhCriticalSectionP criticalSection) {
       
   259     assert(criticalSection);
       
   260 
       
   261     EnterCriticalSection(&criticalSection->cs);
       
   262     criticalSection->recursionCount++;
       
   263     if (!criticalSection->owningThread) {
       
   264         criticalSection->owningThread = GetCurrentThreadId();
       
   265     }
       
   266 }
       
   267 
       
   268 static void LeavePdhCriticalSection(PdhCriticalSectionP criticalSection) {
       
   269     assert(criticalSection);
       
   270     assert(GetCurrentThreadId() == criticalSection->owningThread);
       
   271     assert(criticalSection->recursionCount >= 1);
       
   272 
       
   273     criticalSection->recursionCount--;
       
   274     if (!criticalSection->recursionCount) {
       
   275         criticalSection->owningThread = 0;
       
   276     }
       
   277     LeaveCriticalSection(&criticalSection->cs);
       
   278 }
       
   279 
       
   280 /*
       
   281  * INFO: Using PDH APIs Correctly in a Localized Language (Q287159)
       
   282  *   http://support.microsoft.com/default.aspx?scid=kb;EN-US;q287159
       
   283  * The index value for the base system counters and objects like processor,
       
   284  * process, thread, memory, and so forth are always the same irrespective
       
   285  * of the localized version of the operating system or service pack installed.
       
   286  * To find the correct index for an object or counter, inspect the registry key/value:
       
   287  * [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009\Counter]
       
   288  */
       
   289 static const DWORD PDH_PROCESSOR_IDX = 238;
       
   290 static const DWORD PDH_PROCESSOR_TIME_IDX = 6;
       
   291 static const DWORD PDH_PROCESS_IDX = 230;
       
   292 static const DWORD PDH_ID_PROCESS_IDX = 784;
       
   293 
       
   294 /* useful pdh fmt's */
       
   295 static const char* const OBJECT_COUNTER_FMT = "\\%s\\%s";
       
   296 static const size_t OBJECT_COUNTER_FMT_LEN = 2;
       
   297 static const char* const OBJECT_WITH_INSTANCES_COUNTER_FMT = "\\%s(%s)\\%s";
       
   298 static const size_t OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN = 4;
       
   299 static const char* const PROCESS_OBJECT_INSTANCE_COUNTER_FMT = "\\%s(%s#%s)\\%s";
       
   300 static const size_t PROCESS_OBJECT_INSTANCE_COUNTER_FMT_LEN = 5;
       
   301 
       
   302 static const char* pdhProcessImageName = NULL; /* "java" */
       
   303 static char* pdhIDProcessCounterFmt = NULL;    /* "\Process(java#%d)\ID Process" */
       
   304 
       
   305 static int numberOfJavaProcessesAtInitialization = 0;
       
   306 
       
   307 /*
       
   308  * Currently used CPU queries/counters and variables
       
   309  */
       
   310 static SingleCounterQueryP processTotalCPULoad = NULL;
       
   311 static MultipleCounterQueryP multiCounterCPULoad = NULL;
       
   312 static double cpuFactor = .0;
       
   313 static DWORD  numCpus = 0;
       
   314 
       
   315 /*
       
   316  * Seems WinXP PDH returns PDH_MORE_DATA whenever we send in a NULL buffer.
       
   317  * Let's just ignore it, since we make sure we have enough buffer anyway.
       
   318  */
       
   319 static int
       
   320 pdhFail(PDH_STATUS pdhStat) {
       
   321     return pdhStat != ERROR_SUCCESS && pdhStat != PDH_MORE_DATA;
       
   322 }
       
   323 
       
   324 static const char*
       
   325 allocateAndCopy(const char* const originalString) {
       
   326     size_t len;
       
   327     char* allocatedString;
       
   328 
       
   329     assert(originalString);
       
   330 
       
   331     len = strlen(originalString);
       
   332 
       
   333     allocatedString = malloc(len + 1);
       
   334 
       
   335     if (!allocatedString) {
       
   336         return NULL;
       
   337     }
       
   338 
       
   339     strncpy(allocatedString, originalString, len);
       
   340     allocatedString[len] = '\0';
       
   341 
       
   342     return allocatedString;
       
   343 }
       
   344 
       
   345 /*
       
   346  * Allocates memory into the supplied pointer and
       
   347  * fills it with the localized PDH artifact description, if indexed correctly.
       
   348  * Caller owns the memory from the point of returning from this function.
       
   349  *
       
   350  * @param index    the PDH counter index as specified in the registry
       
   351  * @param ppBuffer pointer to a char*.
       
   352  * @return         0 if successful, negative on failure.
       
   353  */
       
   354 static int
       
   355 lookupNameByIndex(DWORD index, char** ppBuffer) {
       
   356     DWORD size;
       
   357 
       
   358     assert(ppBuffer);
       
   359 
       
   360     /* determine size needed */
       
   361     if (PdhLookupPerfNameByIndex_i(NULL, index, NULL, &size) != PDH_MORE_DATA) {
       
   362       /* invalid index? */
       
   363       return -1;
       
   364     }
       
   365 
       
   366     *ppBuffer = malloc((size_t)size);
       
   367 
       
   368     if (!*ppBuffer) {
       
   369         return -1;
       
   370     }
       
   371 
       
   372     if (PdhLookupPerfNameByIndex_i(NULL, index, *ppBuffer, &size) != ERROR_SUCCESS) {
       
   373         free(*ppBuffer);
       
   374         *ppBuffer = NULL;
       
   375         return -1;
       
   376     }
       
   377 
       
   378     /* windows vista does not null-terminate the string
       
   379      * (although the docs says it will) */
       
   380     (*ppBuffer)[size - 1] = '\0';
       
   381 
       
   382     return 0;
       
   383 }
       
   384 
       
   385 /*
       
   386 * Construct a fully qualified PDH path
       
   387 *
       
   388 * @param objectName   a PDH Object string representation (required)
       
   389 * @param counterName  a PDH Counter string representation (required)
       
   390 * @param imageName    a process image name string, ex. "java" (opt)
       
   391 * @param instance     an instance string, ex. "0", "1", ... (opt)
       
   392 * @return             the fully qualified PDH path.
       
   393 *
       
   394 * Caller will own the returned malloc:ed string
       
   395 */
       
   396 static const char*
       
   397 makeFullCounterPath(const char* const objectName,
       
   398                     const char* const counterName,
       
   399                     const char* const imageName,
       
   400                     const char* const instance) {
       
   401 
       
   402     size_t fullCounterPathLen;
       
   403     char* fullCounterPath;
       
   404 
       
   405     assert(objectName);
       
   406     assert(counterName);
       
   407 
       
   408     fullCounterPathLen = strlen(objectName);
       
   409     fullCounterPathLen += strlen(counterName);
       
   410 
       
   411     if (imageName) {
       
   412         /*
       
   413          * For paths using the "Process" Object.
       
   414          *
       
   415          * Examples:
       
   416          * abstract: "\Process(imageName#instance)\Counter"
       
   417          * actual:   "\Process(java#2)\ID Process"
       
   418          */
       
   419         fullCounterPathLen += PROCESS_OBJECT_INSTANCE_COUNTER_FMT_LEN;
       
   420         fullCounterPathLen += strlen(imageName);
       
   421 
       
   422         /*
       
   423          * imageName must be passed together with an associated
       
   424          * instance "number" ("0", "1", "2", ...).
       
   425          * This is required in order to create valid "Process" Object paths.
       
   426          *
       
   427          * Examples: "\Process(java#0)", \Process(java#1"), ...
       
   428          */
       
   429         assert(instance);
       
   430 
       
   431         fullCounterPathLen += strlen(instance);
       
   432 
       
   433         fullCounterPath = malloc(fullCounterPathLen + 1);
       
   434 
       
   435         if (!fullCounterPath) {
       
   436             return NULL;
       
   437         }
       
   438 
       
   439         _snprintf(fullCounterPath,
       
   440                   fullCounterPathLen,
       
   441                   PROCESS_OBJECT_INSTANCE_COUNTER_FMT,
       
   442                   objectName,
       
   443                   imageName,
       
   444                   instance,
       
   445                   counterName);
       
   446     } else {
       
   447         if (instance) {
       
   448             /*
       
   449              * For paths where the Object has multiple instances.
       
   450              *
       
   451              * Examples:
       
   452              * abstract: "\Object(instance)\Counter"
       
   453              * actual:   "\Processor(0)\% Privileged Time"
       
   454              */
       
   455             fullCounterPathLen += strlen(instance);
       
   456             fullCounterPathLen += OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN;
       
   457         } else {
       
   458             /*
       
   459              * For "normal" paths.
       
   460              *
       
   461              * Examples:
       
   462              * abstract: "\Object\Counter"
       
   463              * actual:   "\Memory\Available Mbytes"
       
   464              */
       
   465             fullCounterPathLen += OBJECT_COUNTER_FMT_LEN;
       
   466         }
       
   467 
       
   468         fullCounterPath = malloc(fullCounterPathLen + 1);
       
   469 
       
   470         if (!fullCounterPath) {
       
   471             return NULL;
       
   472         }
       
   473 
       
   474         if (instance) {
       
   475             _snprintf(fullCounterPath,
       
   476                       fullCounterPathLen,
       
   477                       OBJECT_WITH_INSTANCES_COUNTER_FMT,
       
   478                       objectName,
       
   479                       instance,
       
   480                       counterName);
       
   481         } else {
       
   482             _snprintf(fullCounterPath,
       
   483                       fullCounterPathLen,
       
   484                       OBJECT_COUNTER_FMT,
       
   485                       objectName,
       
   486                       counterName);
       
   487         }
       
   488     }
       
   489 
       
   490     fullCounterPath[fullCounterPathLen] = '\0';
       
   491 
       
   492     return fullCounterPath;
       
   493 }
       
   494 
       
   495 /*
       
   496  * Resolves an index for a PDH artifact to
       
   497  * a localized, malloc:ed string representation.
       
   498  * Caller will own the returned malloc:ed string.
       
   499  *
       
   500  * @param pdhArtifactIndex  PDH index
       
   501  * @return                  malloc:ed string representation
       
   502  *                          of the requested pdh artifact (localized).
       
   503  *                          NULL on failure.
       
   504  */
       
   505 static const char*
       
   506 getPdhLocalizedArtifact(DWORD pdhArtifactIndex) {
       
   507     char* pdhLocalizedArtifactString;
       
   508 
       
   509     if (lookupNameByIndex(pdhArtifactIndex,
       
   510                           &pdhLocalizedArtifactString) != 0) {
       
   511         return NULL;
       
   512     }
       
   513 
       
   514     return pdhLocalizedArtifactString;
       
   515 }
       
   516 
       
   517 static void
       
   518 pdhCleanup(HQUERY* const query, HCOUNTER* const counter) {
       
   519     if (counter && *counter) {
       
   520         PdhRemoveCounter_i(*counter);
       
   521         *counter = NULL;
       
   522     }
       
   523     if (query && *query) {
       
   524         PdhCloseQuery_i(*query);
       
   525         *query = NULL;
       
   526     }
       
   527 }
       
   528 
       
   529 static void
       
   530 destroySingleCounter(SingleCounterQueryP counterQuery) {
       
   531     if (counterQuery) {
       
   532         pdhCleanup(&counterQuery->query.query, &counterQuery->counter);
       
   533     }
       
   534 }
       
   535 
       
   536 static void
       
   537 destroyMultiCounter(MultipleCounterQueryP multiCounterQuery) {
       
   538     int i;
       
   539     if (multiCounterQuery) {
       
   540         if (multiCounterQuery->counters) {
       
   541             for (i = 0; i < multiCounterQuery->noOfCounters; i++) {
       
   542                 pdhCleanup(NULL, &multiCounterQuery->counters[i]);
       
   543             }
       
   544             free(multiCounterQuery->counters);
       
   545             multiCounterQuery->counters = NULL;
       
   546         }
       
   547         pdhCleanup(&multiCounterQuery->query.query, NULL);
       
   548     }
       
   549 }
       
   550 
       
   551 static int
       
   552 openQuery(HQUERY* const query) {
       
   553     assert(query);
       
   554 
       
   555     if (PdhOpenQuery_i(NULL, 0, query) != ERROR_SUCCESS) {
       
   556         return -1;
       
   557     }
       
   558 
       
   559     return 0;
       
   560 }
       
   561 
       
   562 static int
       
   563 addCounter(HQUERY query,
       
   564            const char* const fullCounterPath,
       
   565            HCOUNTER* const counter) {
       
   566 
       
   567     assert(fullCounterPath);
       
   568     assert(counter);
       
   569 
       
   570     if (PdhAddCounter_i(query,
       
   571                         fullCounterPath,
       
   572                         0,
       
   573                         counter) != ERROR_SUCCESS) {
       
   574         return -1;
       
   575     }
       
   576 
       
   577     return 0;
       
   578 }
       
   579 
       
   580 /*
       
   581  * Sets up the supplied SingleCounterQuery to listen for the specified counter.
       
   582  *
       
   583  * @param counterQuery       the counter query to set up.
       
   584  * @param fullCounterPath    the string specifying the full path to the counter.
       
   585  * @returns                  0 if successful, negative on failure.
       
   586  */
       
   587 static int
       
   588 initializeSingleCounterQuery(SingleCounterQueryP counterQuery,
       
   589                              const char* const fullCounterPath) {
       
   590     assert(counterQuery);
       
   591     assert(fullCounterPath);
       
   592 
       
   593     if (openQuery(&counterQuery->query.query) == 0) {
       
   594         if (addCounter(counterQuery->query.query,
       
   595                        fullCounterPath,
       
   596                        &counterQuery->counter) == 0) {
       
   597             return 0;
       
   598         }
       
   599     }
       
   600 
       
   601     return -1;
       
   602 }
       
   603 
       
   604 /*
       
   605  * Sets up a SingleCounterQuery
       
   606  *
       
   607  * param counter             the counter query to set up.
       
   608  * param localizedObject     string representing the PDH object to query
       
   609  * param localizedCounter    string representing the PDH counter to query
       
   610  * param processImageName    if the counter query needs the process image name ("java")
       
   611  * param instance            if the counter has instances, this is the instance ("\Processor(0)\")
       
   612                                  where 0 is the instance
       
   613  * param firstSampleOnInit   for counters that need two queries to yield their values,
       
   614                                  the first query can be issued just after initialization
       
   615  *
       
   616  * @returns                   0 if successful, negative on failure.
       
   617  */
       
   618 static int
       
   619 initializeSingleCounter(SingleCounterQueryP const counter,
       
   620                         const char* const localizedObject,
       
   621                         const char* const localizedCounter,
       
   622                         const char* const processImageName,
       
   623                         const char* const instance,
       
   624                         BOOL firstSampleOnInit) {
       
   625     int retValue = -1;
       
   626 
       
   627     const char* fullCounterPath = makeFullCounterPath(localizedObject,
       
   628                                                       localizedCounter,
       
   629                                                       processImageName,
       
   630                                                       instance);
       
   631 
       
   632     if (fullCounterPath) {
       
   633 
       
   634         assert(counter);
       
   635 
       
   636         if (initializeSingleCounterQuery(counter, fullCounterPath) == 0) {
       
   637             /*
       
   638              * According to the MSDN documentation, rate counters must be read twice:
       
   639              *
       
   640              * "Obtaining the value of rate counters such as Page faults/sec requires that
       
   641              *  PdhCollectQueryData be called twice, with a specific time interval between
       
   642              *  the two calls, before calling PdhGetFormattedCounterValue. Call Sleep to
       
   643              *  implement the waiting period between the two calls to PdhCollectQueryData."
       
   644              *
       
   645              *  Take the first sample here already to allow for the next (first) "real" sample
       
   646              *  to succeed.
       
   647              */
       
   648             if (firstSampleOnInit) {
       
   649                 PdhCollectQueryData_i(counter->query.query);
       
   650             }
       
   651 
       
   652             retValue = 0;
       
   653         }
       
   654         free((char*)fullCounterPath);
       
   655     }
       
   656 
       
   657     return retValue;
       
   658 }
       
   659 
       
   660 static void
       
   661 perfInit(void) {
       
   662     InitializePdhCriticalSection(&initializationLock);
       
   663 }
       
   664 
       
   665 static int
       
   666 getProcessID() {
       
   667     static int myPid = 0;
       
   668     if (0 == myPid) {
       
   669         myPid = _getpid();
       
   670     }
       
   671     return myPid;
       
   672 }
       
   673 
       
   674 /*
       
   675  * Working against the Process object and it's related counters is inherently problematic
       
   676  * when using the PDH API:
       
   677  *
       
   678  * For PDH, a process is not primarily identified by it's process id,
       
   679  * but with a sequential number, for example \Process(java#0), \Process(java#1), ....
       
   680  * The really bad part is that this list is reset as soon as one process exits:
       
   681  * If \Process(java#1) exits, \Process(java#3) now becomes \Process(java#2) etc.
       
   682  *
       
   683  * The PDH query api requires a process identifier to be submitted when registering
       
   684  * a query, but as soon as the list resets, the query is invalidated (since the name
       
   685  * changed).
       
   686  *
       
   687  * Solution:
       
   688  * The #number identifier for a Process query can only decrease after process creation.
       
   689  *
       
   690  * Therefore we create an array of counter queries for all process object instances
       
   691  * up to and including ourselves:
       
   692  *
       
   693  * Ex. we come in as third process instance (java#2), we then create and register
       
   694  * queries for the following Process object instances:
       
   695  * java#0, java#1, java#2
       
   696  *
       
   697  * currentQueryIndexForProcess() keeps track of the current "correct" query
       
   698  * (in order to keep this index valid when the list resets from underneath,
       
   699  * ensure to call getCurrentQueryIndexForProcess() before every query involving
       
   700  * Process object instance data).
       
   701  */
       
   702 static int
       
   703 currentQueryIndexForProcess(void) {
       
   704     HQUERY tmpQuery = NULL;
       
   705     HCOUNTER handleCounter = NULL;
       
   706     int retValue = -1;
       
   707 
       
   708     assert(pdhProcessImageName);
       
   709     assert(pdhIDProcessCounterFmt);
       
   710 
       
   711     if (openQuery(&tmpQuery) == 0) {
       
   712         int index;
       
   713 
       
   714         /* iterate over all instance indexes and try to find our own pid */
       
   715         for (index = 0; index < INT_MAX; ++index) {
       
   716             char fullIDProcessCounterPath[MAX_PATH];
       
   717             PDH_FMT_COUNTERVALUE counterValue;
       
   718             PDH_STATUS res;
       
   719 
       
   720             _snprintf(fullIDProcessCounterPath,
       
   721                       MAX_PATH,
       
   722                       pdhIDProcessCounterFmt,
       
   723                       index);
       
   724 
       
   725             if (addCounter(tmpQuery, fullIDProcessCounterPath, &handleCounter) != 0) {
       
   726                 break;
       
   727             }
       
   728 
       
   729             res = PdhCollectQueryData_i(tmpQuery);
       
   730 
       
   731             if (PDH_INVALID_HANDLE == res || PDH_NO_DATA == res) {
       
   732                 break;
       
   733             }
       
   734 
       
   735             PdhGetFormattedCounterValue_i(handleCounter,
       
   736                                           PDH_FMT_LONG,
       
   737                                           NULL,
       
   738                                           &counterValue);
       
   739             /*
       
   740              * This check seems to be needed for Win2k SMP boxes, since
       
   741              * they for some reason don't return PDH_NO_DATA for non existing
       
   742              * counters.
       
   743              */
       
   744             if (counterValue.CStatus != PDH_CSTATUS_VALID_DATA) {
       
   745                 break;
       
   746             }
       
   747 
       
   748             if ((LONG)getProcessID() == counterValue.longValue) {
       
   749                 retValue = index;
       
   750                 break;
       
   751             }
       
   752         }
       
   753     }
       
   754 
       
   755     pdhCleanup(&tmpQuery, &handleCounter);
       
   756 
       
   757     return retValue;
       
   758 }
       
   759 
       
   760 /*
       
   761  * If successful, returns the #index corresponding to our PID
       
   762  * as resolved by the pdh query:
       
   763  * "\Process(java#index)\ID Process" (or localized equivalent)
       
   764  *
       
   765  * This function should be called before attempting to read
       
   766  * from any Process related counter(s), and the return value
       
   767  * is the index to be used for indexing an array of Process object query's:
       
   768  *
       
   769  * Example:
       
   770  * processTotalCPULoad[currentQueryIndex].query
       
   771  *
       
   772  * Returns -1 on failure.
       
   773  */
       
   774 static int
       
   775 getCurrentQueryIndexForProcess() {
       
   776     int currentQueryIndex = currentQueryIndexForProcess();
       
   777 
       
   778     assert(currentQueryIndex >= 0 &&
       
   779            currentQueryIndex < numberOfJavaProcessesAtInitialization);
       
   780 
       
   781     return currentQueryIndex;
       
   782 }
       
   783 
       
   784 /*
       
   785  * Returns the PDH string identifying the current process image name.
       
   786  * Use this name as a qualifier when getting counters from the PDH Process Object
       
   787  * representing your process.
       
   788 
       
   789  * Example:
       
   790  * "\Process(java#0)\Virtual Bytes" - where "java" is the PDH process
       
   791  * image name.
       
   792  *
       
   793  * Please note that the process image name is not necessarily "java",
       
   794  * hence the use of GetModuleFileName() to detect the process image name.
       
   795  *
       
   796  * @return   the process image name to be used when retrieving
       
   797  *           PDH counters from the current process. The caller will
       
   798              own the returned malloc:ed string. NULL if failure.
       
   799  */
       
   800 static const char*
       
   801 getPdhProcessImageName() {
       
   802     char moduleName[MAX_PATH];
       
   803     char* processImageName;
       
   804     char* dotPos;
       
   805 
       
   806     // Find our module name and use it to extract the image name used by PDH
       
   807     DWORD getmfnReturn = GetModuleFileName(NULL, moduleName, sizeof(moduleName));
       
   808 
       
   809     if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
       
   810         return NULL;
       
   811     }
       
   812 
       
   813     if (getmfnReturn >= MAX_PATH || 0 == getmfnReturn) {
       
   814         return NULL;
       
   815     }
       
   816 
       
   817     processImageName = strrchr(moduleName, '\\'); //drop path
       
   818     processImageName++;                           //skip slash
       
   819     dotPos = strrchr(processImageName, '.');      //drop .exe
       
   820     dotPos[0] = '\0';
       
   821 
       
   822     return allocateAndCopy(processImageName);
       
   823 }
       
   824 
       
   825 /*
       
   826  * Sets up the supplied MultipleCounterQuery to check on the processors via PDH CPU counters.
       
   827  * TODO: Refactor and prettify as with the the SingleCounter queries
       
   828  * if more MultipleCounterQueries are discovered/needed.
       
   829  *
       
   830  * @param multiCounterCPULoad  a pointer to a MultipleCounterQueryS, will be filled in with
       
   831  *                             the necessary info to check the PDH processor counters.
       
   832  * @return                     0 if successful, negative on failure.
       
   833  */
       
   834 static int
       
   835 initializeMultipleCounterForCPUs(MultipleCounterQueryP multiCounterCPULoad) {
       
   836     DWORD cSize = 0;
       
   837     DWORD iSize = 0;
       
   838     DWORD pCount;
       
   839     DWORD index;
       
   840     char* processor = NULL; //'Processor' == PDH_PROCESSOR_IDX
       
   841     char* time = NULL;      //'Time' == PDH_PROCESSOR_TIME_IDX
       
   842     char* instances = NULL;
       
   843     char* tmp;
       
   844     int   retValue = -1;
       
   845     PDH_STATUS pdhStat;
       
   846 
       
   847     if (lookupNameByIndex(PDH_PROCESSOR_IDX, &processor) != 0) {
       
   848         goto end;
       
   849     }
       
   850 
       
   851     if (lookupNameByIndex(PDH_PROCESSOR_TIME_IDX, &time) != 0) {
       
   852         goto end;
       
   853     }
       
   854 
       
   855     //ok, now we have enough to enumerate all processors.
       
   856     pdhStat = PdhEnumObjectItems_i(
       
   857                                    NULL, // reserved
       
   858                                    NULL, // local machine
       
   859                                    processor, // object to enumerate
       
   860                                    NULL, // pass in NULL buffers
       
   861                                    &cSize, // and 0 length to get
       
   862                                    NULL, // required size
       
   863                                    &iSize, // of the buffers in chars
       
   864                                    PERF_DETAIL_WIZARD, // counter detail level
       
   865                                    0);
       
   866 
       
   867     if (pdhFail(pdhStat)) {
       
   868         goto end;
       
   869     }
       
   870 
       
   871     instances = calloc(iSize, 1);
       
   872 
       
   873     if (!instances) {
       
   874         goto end;
       
   875     }
       
   876 
       
   877     cSize = 0;
       
   878 
       
   879     pdhStat = PdhEnumObjectItems_i(
       
   880                                    NULL, // reserved
       
   881                                    NULL, // local machine
       
   882                                    processor, // object to enumerate
       
   883                                    NULL, // pass in NULL buffers
       
   884                                    &cSize,
       
   885                                    instances, // now allocated to be filled in
       
   886                                    &iSize, // and size is known
       
   887                                    PERF_DETAIL_WIZARD, // counter detail level
       
   888                                    0);
       
   889 
       
   890     if (pdhFail(pdhStat)) {
       
   891         goto end;
       
   892     }
       
   893 
       
   894     // enumerate the Processor instances ("\Processor(0)", "\Processor(1)", ..., "\Processor(_Total)")
       
   895     for (pCount = 0, tmp = instances; *tmp != '\0'; tmp = &tmp[strlen(tmp)+1], pCount++);
       
   896 
       
   897     assert(pCount == numCpus+1);
       
   898 
       
   899     //ok, we now have the number of Processor instances - allocate an HCOUNTER for each
       
   900     multiCounterCPULoad->counters = (HCOUNTER*)malloc(pCount * sizeof(HCOUNTER));
       
   901 
       
   902     if (!multiCounterCPULoad->counters) {
       
   903         goto end;
       
   904     }
       
   905 
       
   906     multiCounterCPULoad->noOfCounters = pCount;
       
   907 
       
   908     if (openQuery(&multiCounterCPULoad->query.query) != 0) {
       
   909         goto end;
       
   910     }
       
   911 
       
   912     // fetch instance and register its corresponding HCOUNTER with the query
       
   913     for (index = 0, tmp = instances; *tmp != '\0'; tmp = &tmp[strlen(tmp)+1], ++index) {
       
   914         const char* const fullCounterPath = makeFullCounterPath(processor, time, NULL, tmp);
       
   915 
       
   916         if (!fullCounterPath) {
       
   917             goto end;
       
   918         }
       
   919 
       
   920         retValue = addCounter(multiCounterCPULoad->query.query,
       
   921                               fullCounterPath,
       
   922                               &multiCounterCPULoad->counters[index]);
       
   923 
       
   924         free((char*)fullCounterPath);
       
   925 
       
   926         if (retValue != 0) {
       
   927             goto end;
       
   928         }
       
   929     }
       
   930 
       
   931     // Query once to initialize the counters which require at least two samples
       
   932     // (like the % CPU usage) to calculate correctly.
       
   933     PdhCollectQueryData_i(multiCounterCPULoad->query.query);
       
   934 
       
   935   end:
       
   936     if (processor) {
       
   937         free(processor);
       
   938     }
       
   939 
       
   940     if (time) {
       
   941         free(time);
       
   942     }
       
   943 
       
   944     if (instances) {
       
   945         free(instances);
       
   946     }
       
   947 
       
   948     return retValue;
       
   949 }
       
   950 
       
   951 /*
       
   952  * Dynamically sets up function pointers to the PDH library.
       
   953  *
       
   954  * @param h  HMODULE for the PDH library
       
   955  * @return   0 on success, negative on failure.
       
   956  */
       
   957 static int
       
   958 bindPdhFunctionPointers(HMODULE h) {
       
   959     assert(h);
       
   960     assert(GetCurrentThreadId() == initializationLock.owningThread);
       
   961 
       
   962     /* The 'A' at the end means the ANSI (not the UNICODE) vesions of the methods */
       
   963     PdhAddCounter_i         = (PdhAddCounterFunc)GetProcAddress(h, "PdhAddCounterA");
       
   964     PdhOpenQuery_i         = (PdhOpenQueryFunc)GetProcAddress(h, "PdhOpenQueryA");
       
   965     PdhCloseQuery_i         = (PdhCloseQueryFunc)GetProcAddress(h, "PdhCloseQuery");
       
   966     PdhCollectQueryData_i     = (PdhCollectQueryDataFunc)GetProcAddress(h, "PdhCollectQueryData");
       
   967     PdhGetFormattedCounterValue_i = (PdhGetFormattedCounterValueFunc)GetProcAddress(h, "PdhGetFormattedCounterValue");
       
   968     PdhEnumObjectItems_i         = (PdhEnumObjectItemsFunc)GetProcAddress(h, "PdhEnumObjectItemsA");
       
   969     PdhRemoveCounter_i         = (PdhRemoveCounterFunc)GetProcAddress(h, "PdhRemoveCounter");
       
   970     PdhLookupPerfNameByIndex_i     = (PdhLookupPerfNameByIndexFunc)GetProcAddress(h, "PdhLookupPerfNameByIndexA");
       
   971 
       
   972     if (!PdhAddCounter_i || !PdhOpenQuery_i ||
       
   973         !PdhCloseQuery_i || !PdhCollectQueryData_i ||
       
   974         !PdhGetFormattedCounterValue_i || !PdhEnumObjectItems_i ||
       
   975         !PdhRemoveCounter_i || !PdhLookupPerfNameByIndex_i)
       
   976     {
       
   977         return -1;
       
   978     }
       
   979     return 0;
       
   980 }
       
   981 
       
   982 /*
       
   983  * Returns the counter value as a double for the specified query.
       
   984  * Will collect the query data and update the counter values as necessary.
       
   985  *
       
   986  * @param query       the query to update (if needed).
       
   987  * @param c           the counter to read.
       
   988  * @param value       where to store the formatted value.
       
   989  * @param format      the format to use (i.e. PDH_FMT_DOUBLE, PDH_FMT_LONG etc)
       
   990  * @return            0 if no error
       
   991  *                    -1 if PdhCollectQueryData fails
       
   992  *                    -2 if PdhGetFormattedCounterValue fails
       
   993  */
       
   994 static int
       
   995 getPerformanceData(UpdateQueryP query, HCOUNTER c, PDH_FMT_COUNTERVALUE* value, DWORD format) {
       
   996     clock_t now = clock();
       
   997 
       
   998     /*
       
   999      * Need to limit how often we update the query
       
  1000      * to minimize the Heisenberg effect.
       
  1001      * (PDH behaves erratically if the counters are
       
  1002      * queried too often, especially counters that
       
  1003      * store and use values from two consecutive updates,
       
  1004      * like cpu load.)
       
  1005      */
       
  1006     if (now - query->lastUpdate > MIN_UPDATE_INTERVAL) {
       
  1007         if (PdhCollectQueryData_i(query->query) != ERROR_SUCCESS) {
       
  1008             return -1;
       
  1009         }
       
  1010         query->lastUpdate = now;
       
  1011     }
       
  1012 
       
  1013     if (PdhGetFormattedCounterValue_i(c, format, NULL, value) != ERROR_SUCCESS) {
       
  1014         return -2;
       
  1015     }
       
  1016 
       
  1017     return 0;
       
  1018 }
       
  1019 
       
  1020 static int
       
  1021 allocateAndInitializePdhConstants() {
       
  1022     const char* pdhLocalizedProcessObject = NULL;
       
  1023     const char* pdhLocalizedIDProcessCounter = NULL;
       
  1024     size_t pdhIDProcessCounterFmtLen;
       
  1025     int currentQueryIndex;
       
  1026     int retValue = -1;
       
  1027 
       
  1028     assert(GetCurrentThreadId() == initializationLock.owningThread);
       
  1029 
       
  1030     assert(!pdhProcessImageName);
       
  1031     pdhProcessImageName = getPdhProcessImageName();
       
  1032     if (!pdhProcessImageName) {
       
  1033         goto end;
       
  1034     }
       
  1035 
       
  1036     pdhLocalizedProcessObject = getPdhLocalizedArtifact(PDH_PROCESS_IDX);
       
  1037     if (!pdhLocalizedProcessObject) {
       
  1038         goto end;
       
  1039     }
       
  1040 
       
  1041     pdhLocalizedIDProcessCounter = getPdhLocalizedArtifact(PDH_ID_PROCESS_IDX);
       
  1042     if (!pdhLocalizedIDProcessCounter) {
       
  1043         goto end;
       
  1044     }
       
  1045 
       
  1046     assert(!pdhIDProcessCounterFmt);
       
  1047 
       
  1048     pdhIDProcessCounterFmtLen = strlen(pdhProcessImageName);
       
  1049     pdhIDProcessCounterFmtLen += strlen(pdhLocalizedProcessObject);
       
  1050     pdhIDProcessCounterFmtLen += strlen(pdhLocalizedIDProcessCounter);
       
  1051     pdhIDProcessCounterFmtLen += PROCESS_OBJECT_INSTANCE_COUNTER_FMT_LEN;
       
  1052     pdhIDProcessCounterFmtLen += 2; // "%d"
       
  1053 
       
  1054     assert(pdhIDProcessCounterFmtLen < MAX_PATH);
       
  1055     pdhIDProcessCounterFmt = malloc(pdhIDProcessCounterFmtLen + 1);
       
  1056     if (!pdhIDProcessCounterFmt) {
       
  1057         goto end;
       
  1058     }
       
  1059 
       
  1060     /* "\Process(java#%d)\ID Process" */
       
  1061     _snprintf(pdhIDProcessCounterFmt,
       
  1062               pdhIDProcessCounterFmtLen,
       
  1063               PROCESS_OBJECT_INSTANCE_COUNTER_FMT,
       
  1064               pdhLocalizedProcessObject,
       
  1065               pdhProcessImageName,
       
  1066               "%d",
       
  1067               pdhLocalizedIDProcessCounter);
       
  1068 
       
  1069     pdhIDProcessCounterFmt[pdhIDProcessCounterFmtLen] = '\0';
       
  1070 
       
  1071     assert(0 == numberOfJavaProcessesAtInitialization);
       
  1072     currentQueryIndex = currentQueryIndexForProcess();
       
  1073     if (-1 == currentQueryIndex) {
       
  1074         goto end;
       
  1075     }
       
  1076 
       
  1077     numberOfJavaProcessesAtInitialization = currentQueryIndex + 1;
       
  1078     assert(numberOfJavaProcessesAtInitialization >= 1);
       
  1079 
       
  1080     retValue = 0;
       
  1081 
       
  1082   end:
       
  1083 
       
  1084     if (pdhLocalizedProcessObject) {
       
  1085         free((char*)pdhLocalizedProcessObject);
       
  1086     }
       
  1087 
       
  1088     if (pdhLocalizedIDProcessCounter) {
       
  1089         free((char*)pdhLocalizedIDProcessCounter);
       
  1090     }
       
  1091 
       
  1092     return retValue;
       
  1093 }
       
  1094 
       
  1095 static void
       
  1096 deallocatePdhConstants() {
       
  1097     assert(GetCurrentThreadId() == initializationLock.owningThread);
       
  1098 
       
  1099     if (pdhProcessImageName) {
       
  1100         free((char*)pdhProcessImageName);
       
  1101         pdhProcessImageName = NULL;
       
  1102     }
       
  1103 
       
  1104     if (pdhIDProcessCounterFmt) {
       
  1105       free(pdhIDProcessCounterFmt);
       
  1106       pdhIDProcessCounterFmt = NULL;
       
  1107     }
       
  1108 
       
  1109     numberOfJavaProcessesAtInitialization = 0;
       
  1110 }
       
  1111 
       
  1112 static int
       
  1113 initializeCPUCounters() {
       
  1114     SYSTEM_INFO si;
       
  1115     char* localizedProcessObject;
       
  1116     char* localizedProcessorTimeCounter;
       
  1117     int i;
       
  1118     int retValue = -1;
       
  1119 
       
  1120     assert(GetCurrentThreadId() == initializationLock.owningThread);
       
  1121 
       
  1122     assert(0 == numCpus);
       
  1123     GetSystemInfo(&si);
       
  1124     numCpus = si.dwNumberOfProcessors;
       
  1125     assert(numCpus >= 1);
       
  1126 
       
  1127     /* Initialize the denominator for the jvm load calculations */
       
  1128     assert(.0 == cpuFactor);
       
  1129     cpuFactor = numCpus * 100;
       
  1130 
       
  1131     if (lookupNameByIndex(PDH_PROCESS_IDX,
       
  1132                           &localizedProcessObject) == 0) {
       
  1133 
       
  1134         if (lookupNameByIndex(PDH_PROCESSOR_TIME_IDX,
       
  1135                               &localizedProcessorTimeCounter) == 0) {
       
  1136 
       
  1137             assert(processTotalCPULoad);
       
  1138             assert(pdhProcessImageName);
       
  1139 
       
  1140             for (i = 0; i < numberOfJavaProcessesAtInitialization; ++i) {
       
  1141                 char instanceIndexBuffer[32];
       
  1142                 retValue = initializeSingleCounter(&processTotalCPULoad[i],
       
  1143                                                    localizedProcessObject,
       
  1144                                                    localizedProcessorTimeCounter,
       
  1145                                                    pdhProcessImageName,
       
  1146                                                    itoa(i, instanceIndexBuffer, 10),
       
  1147                                                    TRUE);
       
  1148                 if (retValue != 0) {
       
  1149                     break;
       
  1150                 }
       
  1151             }
       
  1152             free(localizedProcessorTimeCounter);
       
  1153         }
       
  1154         free(localizedProcessObject);
       
  1155     }
       
  1156 
       
  1157     if (retValue != 0) {
       
  1158         return -1;
       
  1159     }
       
  1160 
       
  1161     assert(multiCounterCPULoad);
       
  1162     return initializeMultipleCounterForCPUs(multiCounterCPULoad);
       
  1163 }
       
  1164 
       
  1165 static void
       
  1166 deallocateCPUCounters() {
       
  1167     int i;
       
  1168 
       
  1169     assert(GetCurrentThreadId() == initializationLock.owningThread);
       
  1170 
       
  1171     if (processTotalCPULoad) {
       
  1172         for (i = 0; i < numberOfJavaProcessesAtInitialization; ++i) {
       
  1173             destroySingleCounter(&processTotalCPULoad[i]);
       
  1174         }
       
  1175         free(processTotalCPULoad);
       
  1176         processTotalCPULoad = NULL;
       
  1177     }
       
  1178 
       
  1179     if (multiCounterCPULoad) {
       
  1180         destroyMultiCounter(multiCounterCPULoad);
       
  1181         free(multiCounterCPULoad);
       
  1182         multiCounterCPULoad = NULL;
       
  1183     }
       
  1184 
       
  1185     cpuFactor = .0;
       
  1186     numCpus = 0;
       
  1187 }
       
  1188 
       
  1189 static void
       
  1190 pdhInitErrorHandler(HMODULE h) {
       
  1191     assert(GetCurrentThreadId() == initializationLock.owningThread);
       
  1192 
       
  1193     deallocatePdhConstants();
       
  1194 
       
  1195     if (h) {
       
  1196         FreeLibrary(h);
       
  1197     }
       
  1198 }
       
  1199 
       
  1200 /*
       
  1201  * Helper to initialize the PDH library, function pointers and constants.
       
  1202  *
       
  1203  * @return  0 if successful, negative on failure.
       
  1204  */
       
  1205 static int
       
  1206 pdhInit() {
       
  1207     static BOOL initialized = FALSE;
       
  1208     int retValue;
       
  1209 
       
  1210     if (initialized) {
       
  1211         return 0;
       
  1212     }
       
  1213 
       
  1214     retValue = 0;
       
  1215 
       
  1216     EnterPdhCriticalSection(&initializationLock); {
       
  1217         if (!initialized) {
       
  1218             HMODULE h = NULL;
       
  1219             if ((h = LoadLibrary("pdh.dll")) == NULL) {
       
  1220                 retValue = -1;
       
  1221             } else if (bindPdhFunctionPointers(h) < 0) {
       
  1222                 retValue = -1;
       
  1223             } else if (allocateAndInitializePdhConstants() < 0) {
       
  1224                 retValue = -1;
       
  1225             }
       
  1226 
       
  1227             if (0 == retValue) {
       
  1228                 initialized = TRUE;
       
  1229             } else {
       
  1230                 pdhInitErrorHandler(h);
       
  1231             }
       
  1232         }
       
  1233     } LeavePdhCriticalSection(&initializationLock);
       
  1234 
       
  1235     return retValue;
       
  1236 }
       
  1237 
       
  1238 static int
       
  1239 allocateCPUCounters() {
       
  1240     assert(GetCurrentThreadId() == initializationLock.owningThread);
       
  1241     assert(numberOfJavaProcessesAtInitialization >= 1);
       
  1242     assert(!processTotalCPULoad);
       
  1243     assert(!multiCounterCPULoad);
       
  1244 
       
  1245     /*
       
  1246      * Create an array of Process object queries, for each instance
       
  1247      * up to and including our own (java#0, java#1, java#2, ...).
       
  1248      */
       
  1249     processTotalCPULoad = calloc(numberOfJavaProcessesAtInitialization,
       
  1250                                  sizeof(SingleCounterQueryS));
       
  1251 
       
  1252     if (!processTotalCPULoad) {
       
  1253         return -1;
       
  1254     }
       
  1255 
       
  1256     multiCounterCPULoad = calloc(1, sizeof(MultipleCounterQueryS));
       
  1257 
       
  1258     if (!multiCounterCPULoad) {
       
  1259         return -1;
       
  1260     }
       
  1261 
       
  1262     return 0;
       
  1263 }
       
  1264 
       
  1265 static int
       
  1266 initializePdhCPUCounters() {
       
  1267     static BOOL initialized = FALSE;
       
  1268     int retValue;
       
  1269 
       
  1270     if (initialized) {
       
  1271         return 0;
       
  1272     }
       
  1273 
       
  1274     retValue = 0;
       
  1275 
       
  1276     EnterPdhCriticalSection(&initializationLock); {
       
  1277         if (!initialized) {
       
  1278             if (pdhInit() < 0) {
       
  1279                 retValue = -1;
       
  1280             }  else if (allocateCPUCounters() < 0) {
       
  1281                 retValue = -1;
       
  1282             } else if (initializeCPUCounters() < 0) {
       
  1283                 retValue = -1;
       
  1284             }
       
  1285 
       
  1286             if (0 == retValue) {
       
  1287                 initialized = TRUE;
       
  1288             } else {
       
  1289               deallocateCPUCounters();
       
  1290             }
       
  1291         }
       
  1292     } LeavePdhCriticalSection(&initializationLock);
       
  1293 
       
  1294     return retValue;
       
  1295 }
       
  1296 
       
  1297 static int
       
  1298 perfCPUInit() {
       
  1299     return initializePdhCPUCounters();
       
  1300 }
       
  1301 
       
  1302 static double
       
  1303 perfGetProcessCPULoad() {
       
  1304     PDH_FMT_COUNTERVALUE cv;
       
  1305     int currentQueryIndex;
       
  1306 
       
  1307     if (perfCPUInit() < 0) {
       
  1308         // warn?
       
  1309         return -1.0;
       
  1310     }
       
  1311 
       
  1312     currentQueryIndex = getCurrentQueryIndexForProcess();
       
  1313 
       
  1314     if (getPerformanceData(&processTotalCPULoad[currentQueryIndex].query,
       
  1315                            processTotalCPULoad[currentQueryIndex].counter,
       
  1316                            &cv,
       
  1317                            PDH_FMT_DOUBLE | PDH_FMT_NOCAP100) == 0) {
       
  1318         double d = cv.doubleValue / cpuFactor;
       
  1319         d = min(1, d);
       
  1320         d = max(0, d);
       
  1321         return d;
       
  1322     }
       
  1323     return -1.0;
       
  1324 }
       
  1325 
       
  1326 static double
       
  1327 perfGetCPULoad(int which) {
       
  1328     PDH_FMT_COUNTERVALUE cv;
       
  1329     HCOUNTER c;
       
  1330 
       
  1331     if (perfCPUInit() < 0) {
       
  1332         // warn?
       
  1333         return -1.0;
       
  1334     }
       
  1335 
       
  1336     if (-1 == which) {
       
  1337         c = multiCounterCPULoad->counters[multiCounterCPULoad->noOfCounters - 1];
       
  1338     } else {
       
  1339         if (which < multiCounterCPULoad->noOfCounters) {
       
  1340             c = multiCounterCPULoad->counters[which];
       
  1341         } else {
       
  1342             return -1.0;
       
  1343         }
       
  1344     }
       
  1345     if (getPerformanceData(&multiCounterCPULoad->query, c, &cv, PDH_FMT_DOUBLE ) == 0) {
       
  1346         return cv.doubleValue / 100;
       
  1347     }
       
  1348     return -1.0;
       
  1349 }
       
  1350 
       
  1351 JNIEXPORT jdouble JNICALL
       
  1352 Java_com_sun_management_internal_OperatingSystemImpl_getSystemCpuLoad0
       
  1353 (JNIEnv *env, jobject dummy)
       
  1354 {
       
  1355     return perfGetCPULoad(-1);
       
  1356 }
       
  1357 
       
  1358 JNIEXPORT jdouble JNICALL
       
  1359 Java_com_sun_management_internal_OperatingSystemImpl_getProcessCpuLoad0
       
  1360 (JNIEnv *env, jobject dummy)
       
  1361 {
       
  1362     return perfGetProcessCPULoad();
       
  1363 }