Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

676 lines
19 KiB

/*++
Copyright (C) 1995 Microsoft Corporation
Module Name:
query.c
Abstract:
Query management functions exposed in pdh.dll
--*/
#include <windows.h>
#include <winperf.h>
#include <pdh.h>
#include <stdlib.h>
#include <math.h>
#include "pdhitype.h"
#include "pdhidef.h"
// query link list head pointer
static PPDHI_QUERY DllHeadQueryPtr = NULL;
static
BOOL
PdhiFreeQuery (
IN PPDHI_QUERY pThisQuery
)
/*++
Routine Description:
removes the query from the list of queries and updates the list
linkages
Arguments:
IN PPDHI_QUERY pThisQuery
pointer to the query to remove. No testing is performed on
this pointer so it's assumed to be a valid query pointer.
The pointer is invalid when this function returns.
Return Value:
TRUE
--*/
{
PPDHI_QUERY pPrevQuery;
PPDHI_QUERY pNextQuery;
PPDHI_COUNTER pThisCounter;
PPDHI_QUERY_MACHINE pQMachine;
PPDHI_QUERY_MACHINE pNextQMachine;
WAIT_FOR_AND_LOCK_MUTEX(pThisQuery->hMutex);
// define pointers
pPrevQuery = pThisQuery->next.blink;
pNextQuery = pThisQuery->next.flink;
// free any counters in counter list
if ((pThisCounter = pThisQuery->pCounterListHead) != NULL) {
while (pThisCounter->next.blink != pThisCounter->next.flink) {
// delete from list
// the deletion routine updates the blink pointer as it
// removes the specified entry.
FreeCounter (pThisCounter->next.blink);
}
// remove last counter
FreeCounter (pThisCounter);
pThisQuery->pCounterListHead = NULL;
}
// free allocated memory in the query
if ((pQMachine = pThisQuery->pFirstQMachine) != NULL) {
// Free list of machine pointers
do {
pNextQMachine = pQMachine->pNext;
if (pQMachine->pPerfData != NULL) {
G_FREE (pQMachine->pPerfData);
}
G_FREE (pQMachine);
pQMachine = pNextQMachine;
} while (pQMachine != NULL);
pThisQuery->pFirstQMachine = NULL;
}
// update pointers
if ((pPrevQuery == pThisQuery) && (pNextQuery == pThisQuery)) {
// then this query is the only (i.e. last) one in the list
DllHeadQueryPtr = NULL;
} else {
// update query list pointers
pPrevQuery->next.flink = pNextQuery;
pNextQuery->next.blink = pPrevQuery;
if (DllHeadQueryPtr == pThisQuery) {
// then this is the first entry in the list so point to the
// next one in line
DllHeadQueryPtr = pNextQuery;
}
}
// release and free the query mutex
RELEASE_MUTEX(pThisQuery->hMutex);
if (pThisQuery->hMutex != NULL) CloseHandle(pThisQuery->hMutex);
// clear the query structure
memset (pThisQuery, 0, sizeof(PDHI_QUERY));
// delete this query
G_FREE (pThisQuery);
return TRUE;
}
PDH_FUNCTION
PdhOpenQuery (
IN LPVOID pReserved,
IN DWORD dwUserData,
IN HQUERY *phQuery
)
/*++
Routine Description:
allocates a new query structure and inserts it at the end of the
query list.
Arguments:
IN DWORD dwUserData
the user defined data field for this query,
Return Value:
Returns ERROR_SUCCESS if a new query was created and initialized,
and a PDH_ error value if not.
PDH_INVALID_ARGUMENT is returned when one or more of the arguements
is invalid or incorrect.
PDH_MEMORY_ALLOCATION_FAILURE is returned when a memory buffer could
not be allocated.
--*/
{
PPDHI_QUERY pNewQuery;
PPDHI_QUERY pLastQuery;
PDH_STATUS ReturnStatus = ERROR_SUCCESS;
// try writing to return pointer
__try {
*phQuery = NULL;
} __except (EXCEPTION_EXECUTE_HANDLER) {
return PDH_INVALID_ARGUMENT;
}
if (pReserved != NULL) {
return PDH_INVALID_ARGUMENT;
}
// allocate new memory
pNewQuery = G_ALLOC (GPTR, sizeof (PDHI_QUERY));
if (pNewQuery == NULL) {
ReturnStatus = PDH_MEMORY_ALLOCATION_FAILURE;
} else {
// create and capture the mutex for this query.
pNewQuery->hMutex = CreateMutex (NULL, TRUE, NULL);
//initialize structures & list pointers
// assign signature
*(DWORD *)(&pNewQuery->signature[0]) = SigQuery;
WAIT_FOR_AND_LOCK_MUTEX (hPdhDataMutex);
// update list pointers
// test to see if this is the first query in the list
if (DllHeadQueryPtr == NULL) {
// then this is the first so fill in the static link pointers
DllHeadQueryPtr =
pNewQuery->next.flink =
pNewQuery->next.blink = pNewQuery;
} else {
// get pointer to "last" entry in list
pLastQuery = DllHeadQueryPtr->next.blink;
// update new query pointers
pNewQuery->next.flink = DllHeadQueryPtr;
pNewQuery->next.blink = pLastQuery;
// update existing pointers
DllHeadQueryPtr->next.blink = pNewQuery;
pLastQuery->next.flink = pNewQuery;
}
RELEASE_MUTEX (hPdhDataMutex);
// initialize the counter linked list pointer
pNewQuery->pCounterListHead = NULL;
// initialize the machine list pointer
pNewQuery->pFirstQMachine = NULL;
// set length & user data
pNewQuery->dwLength = sizeof (PDHI_QUERY);
pNewQuery->dwUserData = dwUserData;
// initialize remaining data fields
pNewQuery->dwNotifyFlags = 0;
// release the mutex for this query
RELEASE_MUTEX(pNewQuery->hMutex);
// return new query pointer as a handle.
*phQuery = (HQUERY)pNewQuery;
ReturnStatus = ERROR_SUCCESS;
}
return ReturnStatus;
}
PDH_FUNCTION
PdhAddCounterW (
IN HQUERY hQuery,
IN LPCWSTR szFullCounterPath,
IN DWORD dwUserData,
IN HCOUNTER *phCounter
)
/*++
Routine Description:
Creates and initializes a counter structure and attaches it to the
specified query.
Arguments:
IN HQUERY hQuery
handle of the query to attach this counter to once the counter
entry has been successfully created.
IN LPCWSTR szFullCounterPath
pointer to the path string that describes the counter to add to
the query referenced above. This string must specify a single
counter. Wildcard path strings are not permitted.
IN DWORD dwUserData
the user defined data field for this query.
IN HCOUNTER *phCounter
pointer to the buffer that will get the handle value of the
successfully created counter entry.
Return Value:
Returns ERROR_SUCCESS if a new query was created and initialized,
and a PDH_ error value if not.
PDH_INVALID_ARGUMENT is returned when one or more of the arguements
is invalid or incorrect.
PDH_MEMORY_ALLOCATION_FAILURE is returned when a memory buffer could
not be allocated.
PDH_INVALID_HANDLE is returned if the query handle is not valid.
PDH_CSTATUS_NO_COUNTER is returned if the specified counter was
not found
PDH_CSTATUS_NO_OBJECT is returned if the specified object could
not be found
PDH_CSTATUS_NO_MACHINE is returned if a machine entry could not
be created.
PDH_CSTATUS_BAD_COUNTERNAME is returned if the counter name path
string could not be parsed or interpreted
PDH_CSTATUS_NO_COUNTERNAME is returned if an empty counter name
path string is passed in
PDH_FUNCTION_NOT_FOUND is returned if the calculation function
for this counter could not be determined.
--*/
{
PPDHI_COUNTER pNewCounter;
PPDHI_COUNTER pLastCounter;
PPDHI_QUERY pQuery;
PDH_STATUS ReturnStatus = ERROR_SUCCESS;
__try {
WCHAR wChar;
// try writing to return pointer
*phCounter = NULL;
wChar = *szFullCounterPath;
if (wChar == 0) {
ReturnStatus = PDH_INVALID_ARGUMENT;
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
ReturnStatus = PDH_INVALID_ARGUMENT;
}
if (!IsValidQuery(hQuery)) {
// invalid query handle
ReturnStatus = PDH_INVALID_HANDLE;
}
if (ReturnStatus == ERROR_SUCCESS) {
// allocate new memory
pNewCounter = G_ALLOC (GPTR, sizeof (PDHI_COUNTER));
if (pNewCounter == NULL) {
// bail out here since we couldn't allocate the new structure
ReturnStatus = PDH_MEMORY_ALLOCATION_FAILURE;
} else {
//initialize structures & list pointers
// clear the pointers
pNewCounter->next.flink =
pNewCounter->next.blink = NULL;
// assign signature & length values
*(DWORD *)(&pNewCounter->signature[0]) = SigCounter;
pNewCounter->dwLength = sizeof(PDHI_COUNTER);
pQuery = (PPDHI_QUERY)hQuery;
WAIT_FOR_AND_LOCK_MUTEX(pQuery->hMutex);
// link to owning query
pNewCounter->pOwner = pQuery;
// set user data fields
pNewCounter->dwUserData = dwUserData;
// initialize the scale to 1X and let the caller make any changes
pNewCounter->lScale = 0;
pNewCounter->dFactor = 1.0;
// allocate and initialize the path string
pNewCounter->szFullName = G_ALLOC (GPTR,
(lstrlenW(szFullCounterPath) + 1) * sizeof (WCHAR));
if (pNewCounter->szFullName != NULL) {
lstrcpyW (pNewCounter->szFullName, szFullCounterPath);
}
// for starters there is no explain text
pNewCounter->szExplainText = NULL;
pNewCounter->pCounterPath = NULL;
// load counter data using data retrieved from system
if (InitCounter (pNewCounter)) {
// counter successfully initialized so
// update list pointers
// test to see if this is the first query in the list
if (pQuery->pCounterListHead == NULL) {
// then this is the first so fill in the static link pointers
pQuery->pCounterListHead =
pNewCounter->next.flink =
pNewCounter->next.blink = pNewCounter;
} else {
// then there are 1 or more list entries
// insert at end of counter list
// get pointer to "last" entry in list
pLastCounter = pQuery->pCounterListHead->next.blink;
// update new counter's pointers
pNewCounter->next.flink = pQuery->pCounterListHead;
pNewCounter->next.blink = pLastCounter;
// update old pointers
pLastCounter->next.flink = pNewCounter;
pQuery->pCounterListHead->next.blink = pNewCounter;
}
// return new query pointer as a handle.
*phCounter = (HCOUNTER)pNewCounter;
ReturnStatus = ERROR_SUCCESS;
} else {
// get the error value
ReturnStatus = GetLastError();
// unable to initialize this counter so toss it
if (!FreeCounter(pNewCounter)) {
G_FREE(pNewCounter);
}
}
RELEASE_MUTEX (pQuery->hMutex);
}
}
return ReturnStatus;
}
PDH_FUNCTION
PdhAddCounterA (
IN HQUERY hQuery,
IN LPCSTR szFullCounterPath,
IN DWORD dwUserData,
IN HCOUNTER *phCounter
)
/*++
Routine Description:
Creates and initializes a counter structure and attaches it to the
specified query.
Arguments:
IN HQUERY hQuery
handle of the query to attach this counter to once the counter
entry has been successfully created.
IN LPCSTR szFullCounterPath
pointer to the path string that describes the counter to add to
the query referenced above. This string must specify a single
counter. Wildcard path strings are not permitted.
IN DWORD dwUserData
the user defined data field for this query.
IN HCOUNTER *phCounter
pointer to the buffer that will get the handle value of the
successfully created counter entry.
Return Value:
Returns ERROR_SUCCESS if a new query was created and initialized,
and a PDH_ error value if not.
PDH_INVALID_ARGUMENT is returned when one or more of the arguements
is invalid or incorrect.
PDH_MEMORY_ALLOCATION_FAILURE is returned when a memory buffer could
not be allocated.
PDH_INVALID_HANDLE is returned if the query handle is not valid.
PDH_CSTATUS_NO_COUNTER is returned if the specified counter was
not found
PDH_CSTATUS_NO_OBJECT is returned if the specified object could
not be found
PDH_CSTATUS_NO_MACHINE is returned if a machine entry could not
be created.
PDH_CSTATUS_BAD_COUNTERNAME is returned if the counter name path
string could not be parsed or interpreted
PDH_CSTATUS_NO_COUNTERNAME is returned if an empty counter name
path string is passed in
PDH_FUNCTION_NOT_FOUND is returned if the calculation function
for this counter could not be determined.
--*/
{
LPWSTR szWideArg;
DWORD dwLength;
PDH_STATUS ReturnStatus = ERROR_SUCCESS;
__try {
CHAR cChar;
// try writing to return pointer
*phCounter = NULL;
cChar = *szFullCounterPath;
if (cChar == 0) {
ReturnStatus = PDH_INVALID_ARGUMENT;
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
ReturnStatus = PDH_INVALID_ARGUMENT;
}
// query handle is tested by PdhAddCounterW
if (ReturnStatus == ERROR_SUCCESS) {
dwLength = strlen(szFullCounterPath);
szWideArg = G_ALLOC (GPTR,
((dwLength + 1) * sizeof(WCHAR)));
if (szWideArg != NULL) {
// convert ANSI arg to Wide chars and call wide char version
// include null in conversion (i.e. length+1) so wide char
// string is null terminated.
mbstowcs (szWideArg, szFullCounterPath, (dwLength + 1));
// call wide char version of function
ReturnStatus = PdhAddCounterW (hQuery, szWideArg, dwUserData, phCounter);
// free memory
G_FREE (szWideArg);
// and return handle
} else {
ReturnStatus = PDH_MEMORY_ALLOCATION_FAILURE;
}
}
return ReturnStatus;
}
PDH_FUNCTION
PdhRemoveCounter (
IN HCOUNTER hCounter
)
/*++
Routine Description:
Removes the specified counter from the query it is attached to and
closes any handles and frees any memory associated with this
counter
Arguments:
IN HCOUNTER hCounter
handle of the counter to remove from the query.
Return Value:
Returns ERROR_SUCCESS if a new query was created and initialized,
and a PDH_ error value if not.
PDH_INVALID_HANDLE is returned if the counter handle is not valid.
--*/
{
PPDHI_COUNTER pThisCounter;
PPDHI_QUERY pThisQuery;
PPDHI_COUNTER pNextCounter;
if (IsValidCounter(hCounter)) {
// it's ok to cast it to a pointer now.
pThisCounter = (PPDHI_COUNTER)hCounter;
pThisQuery = pThisCounter->pOwner;
WAIT_FOR_AND_LOCK_MUTEX(pThisQuery->hMutex);
if (pThisCounter == pThisQuery->pCounterListHead) {
if (pThisCounter->next.flink == pThisCounter){
// then this is the only counter in the query
FreeCounter (pThisCounter);
pThisQuery->pCounterListHead = NULL;
} else {
// they are deleting the first counter from the list
// so update the list pointer
// Free Counter takes care of the list links, we just
// need to manage the list head pointer
pNextCounter = pThisCounter->next.flink;
FreeCounter (pThisCounter);
pThisQuery->pCounterListHead = pNextCounter;
}
} else {
// remove this from the list
FreeCounter (pThisCounter);
}
RELEASE_MUTEX (pThisQuery->hMutex);
return ERROR_SUCCESS;
} else {
return PDH_INVALID_HANDLE;
}
}
PDH_FUNCTION
PdhCollectQueryData (
IN HQUERY hQuery
)
/*++
Routine Description:
Retrieves the current value of each counter attached to the specified
query.
For this version, each machine associated with this query is polled
sequentially. This is simple and safe, but potentially slow so a
multi-threaded approach will be reviewed for the next version.
Note that while the call may succeed, no data may be available. The
status of each counter MUST be checked before its data is used.
Arguments:
IN HQUERY hQuery
handle of the query to update.
Return Value:
Returns ERROR_SUCCESS if a new query was created and initialized,
and a PDH_ error value if not.
PDH_INVALID_HANDLE is returned if the query handle is not valid.
PDH_NO_DATA is returned if the query does not have any counters defined
yet.
--*/
{
PDH_STATUS Status;
PPDHI_QUERY pQuery;
if (IsValidQuery(hQuery)) {
pQuery = (PPDHI_QUERY)hQuery;
WAIT_FOR_AND_LOCK_MUTEX(pQuery->hMutex);
Status = GetQueryPerfData (pQuery);
RELEASE_MUTEX(pQuery->hMutex);
} else {
Status = PDH_INVALID_HANDLE;
}
return Status;
}
PDH_FUNCTION
PdhCloseQuery (
IN HQUERY hQuery
)
/*++
Routine Description:
closes the query, all counters, connections and other resources
related to this query are freed as well.
Arguments:
IN HQUERY hQuery
the handle of the query to free.
Return Value:
Returns ERROR_SUCCESS if a new query was created and initialized,
and a PDH_ error value if not.
PDH_INVALID_HANDLE is returned if the query handle is not valid.
--*/
{
if (IsValidQuery(hQuery)) {
// lock system data
WAIT_FOR_AND_LOCK_MUTEX(hPdhDataMutex);
// dispose of query
PdhiFreeQuery ((PPDHI_QUERY)hQuery);
// release data lock
RELEASE_MUTEX (hPdhDataMutex);
return ERROR_SUCCESS;
} else {
return PDH_INVALID_HANDLE;
}
}
BOOL
PdhiQueryCleanup (
)
{
PPDHI_QUERY pThisQuery;
WAIT_FOR_AND_LOCK_MUTEX(hPdhDataMutex);
// free any queries in the query list
if ((pThisQuery = DllHeadQueryPtr) != NULL) {
while (pThisQuery->next.blink != pThisQuery->next.flink) {
// delete from list
// the deletion routine updates the blink pointer as it
// removes the specified entry.
PdhiFreeQuery (pThisQuery->next.blink);
}
// remove last query
PdhiFreeQuery (pThisQuery);
DllHeadQueryPtr = NULL;
}
RELEASE_MUTEX (hPdhDataMutex);
return TRUE;
}
PDH_FUNCTION
PdhGetDllVersion(
IN LPDWORD lpdwVersion
)
{
PDH_STATUS pdhStatus = ERROR_SUCCESS;
__try {
*lpdwVersion = PDH_VERSION;
} __except (EXCEPTION_EXECUTE_HANDLER) {
pdhStatus = PDH_INVALID_ARGUMENT;
}
return pdhStatus;
}