windows-nt/Source/XPSP1/NT/inetsrv/query/qperf/perfci.cxx
2020-09-26 16:20:57 +08:00

1071 lines
31 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1993 - 2002.
//
// File: perfCI.cxx
//
// Contents: Functions for collecting data to Performance Monitor
//
// History: 23-March-94 t-joshh Created
// 10-May-99 dlee Cleanup
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include <perfci.hxx>
#include "prfutil.hxx"
#include "perfobj2.hxx"
extern FILTER_DATA_DEFINITION FILTERDataDefinition;
extern CI_DATA_DEFINITION CIDataDefinition;
extern BOOL g_fPerfmonCounterHackIsProcessDetached;
CReadUserPerfData * g_pReadUserPerfData = 0;
CReadKernelPerfData * g_pReadKernelPerfData = 0;
WCHAR FILTERPerformanceKeyName[] =
TEXT("SYSTEM\\CurrentControlSet\\Services\\ContentFilter\\Performance");
WCHAR CIPerformanceKeyName[] =
TEXT("SYSTEM\\CurrentControlSet\\Services\\ContentIndex\\Performance");
WCHAR FirstCounterKeyName [] = TEXT("First Counter");
WCHAR FirstHelpKeyName [] = TEXT("First Help");
const CI_DATA_DEFINITION CIDataDefinitionFixed = {
{ sizeof(CI_DATA_DEFINITION)+
CI_SIZE_OF_COUNTER_BLOCK, // Total Bytes ( Size of this header, the counter definitions
// and the size of the actual counter data )
sizeof(CI_DATA_DEFINITION), // Definition length ( This header and the counter definitions )
sizeof(PERF_OBJECT_TYPE), // Header Length ( This header )
CIOBJECT, // Object Name Title Index
0, // Object Name Title
CIOBJECT, // Object Help Title Index
0, // Object Help Title
PERF_DETAIL_NOVICE, // Detail Level
CI_TOTAL_NUM_COUNTERS, // Number of Counters
0, // Default Counters
0, // Num Instances
0, // Code Page
{0,0}, // Perf Time
{0,0} // Perf Freq
},
{ sizeof(PERF_COUNTER_DEFINITION), // Wordlist
NUM_WORDLIST,
0,
NUM_WORDLIST,
0,
0,
PERF_DETAIL_NOVICE,
PERF_COUNTER_RAWCOUNT,
sizeof(DWORD),
NUM_WORDLIST_OFF
},
{ sizeof(PERF_COUNTER_DEFINITION), // PersistentIndex
NUM_PERSISTENT_INDEX,
0,
NUM_PERSISTENT_INDEX,
0,
0,
PERF_DETAIL_NOVICE,
PERF_COUNTER_RAWCOUNT,
sizeof(DWORD),
NUM_PERSISTENT_INDEX_OFF
},
{ sizeof(PERF_COUNTER_DEFINITION), // Index Size
INDEX_SIZE,
0,
INDEX_SIZE,
0,
0,
PERF_DETAIL_NOVICE,
PERF_COUNTER_RAWCOUNT,
sizeof(DWORD),
INDEX_SIZE_OFF
},
{ sizeof(PERF_COUNTER_DEFINITION), // Files to-be-filtered
FILES_TO_BE_FILTERED,
0,
FILES_TO_BE_FILTERED,
0,
0,
PERF_DETAIL_NOVICE,
PERF_COUNTER_RAWCOUNT,
sizeof(DWORD),
FILES_TO_BE_FILTERED_OFF
},
{ sizeof(PERF_COUNTER_DEFINITION), // Number of unique keys
NUM_UNIQUE_KEY,
0,
NUM_UNIQUE_KEY,
0,
0,
PERF_DETAIL_NOVICE,
PERF_COUNTER_RAWCOUNT,
sizeof(DWORD),
NUM_UNIQUE_KEY_OFF
},
{ sizeof(PERF_COUNTER_DEFINITION), // Running Queries
RUNNING_QUERIES,
0,
RUNNING_QUERIES,
0,
0,
PERF_DETAIL_NOVICE,
PERF_COUNTER_RAWCOUNT,
sizeof(DWORD),
RUNNING_QUERIES_OFF
},
{ sizeof(PERF_COUNTER_DEFINITION), // Merge Progress
MERGE_PROGRESS,
0,
MERGE_PROGRESS,
0,
0,
PERF_DETAIL_NOVICE,
PERF_COUNTER_RAWCOUNT,
sizeof(DWORD),
MERGE_PROGRESS_OFF
},
{ sizeof(PERF_COUNTER_DEFINITION), // Number of documents filtered
DOCUMENTS_FILTERED,
0,
DOCUMENTS_FILTERED,
0,
0,
PERF_DETAIL_NOVICE,
PERF_COUNTER_RAWCOUNT,
sizeof(DWORD),
DOCUMENTS_FILTERED_OFF
},
{ sizeof(PERF_COUNTER_DEFINITION), // Number of unique documents
NUM_DOCUMENTS,
0,
NUM_DOCUMENTS,
0,
0,
PERF_DETAIL_NOVICE,
PERF_COUNTER_RAWCOUNT,
sizeof(DWORD),
NUM_DOCUMENTS_OFF
},
{ sizeof(PERF_COUNTER_DEFINITION), // Total queries
TOTAL_QUERIES,
0,
TOTAL_QUERIES,
0,
0,
PERF_DETAIL_NOVICE,
PERF_COUNTER_RAWCOUNT,
sizeof(DWORD),
TOTAL_QUERIES_OFF
},
{ sizeof(PERF_COUNTER_DEFINITION), // Files deferred for filtering (Secondary Q)
DEFERRED_FILTER_FILES,
0,
DEFERRED_FILTER_FILES,
0,
0,
PERF_DETAIL_NOVICE,
PERF_COUNTER_RAWCOUNT,
sizeof(DWORD),
DEFERRED_FILTER_FILES_OFF
}
};
const FILTER_DATA_DEFINITION FILTERDataDefinitionFixed = {
{ sizeof(FILTER_DATA_DEFINITION)+
FILTER_SIZE_OF_COUNTER_BLOCK, // Total Bytes ( Size of this header, the counter definitions
// and the size of the actual counter data )
sizeof(FILTER_DATA_DEFINITION), // Definition length ( This header and the counter definitions )
sizeof(PERF_OBJECT_TYPE), // Header Length ( This header )
FILTEROBJECT, // Object Name Title Index
0, // Object Name Title
FILTEROBJECT, // Object Help Title Index
0, // Object Help Title
PERF_DETAIL_NOVICE, // Detail Level
FILTER_TOTAL_NUM_COUNTERS, // Number of Counters
0, // Default Counters
0, // Num Instances
0, // Code Page
{0,0}, // Perf Time
{0,0} // Perf Freq
},
{ sizeof(PERF_COUNTER_DEFINITION), // Total Filter Time
FILTER_TIME_TOTAL,
0,
FILTER_TIME_TOTAL,
0,
0,
PERF_DETAIL_NOVICE,
PERF_COUNTER_RAWCOUNT,
sizeof(DWORD),
FILTER_TIME_TOTAL_OFF
},
{ sizeof(PERF_COUNTER_DEFINITION), // Binding Time for one file
BIND_TIME,
0,
BIND_TIME,
0,
-1,
PERF_DETAIL_NOVICE,
PERF_COUNTER_RAWCOUNT,
sizeof(DWORD),
BIND_TIME_OFF
},
{ sizeof(PERF_COUNTER_DEFINITION), // Filter Time
FILTER_TIME,
0,
FILTER_TIME,
0,
0,
PERF_DETAIL_NOVICE,
PERF_COUNTER_RAWCOUNT,
sizeof(DWORD),
FILTER_TIME_OFF
}
};
//+---------------------------------------------------------------------------
//
// Function: CloseKey
//
// Synopsis: Close the registry key handle
//
// Arguments: [hOpenKey] -- Key. NULL if closed.
//
//----------------------------------------------------------------------------
inline void CloseKey ( HKEY hOpenKey )
{
if ( 0 != hOpenKey )
RegCloseKey (hOpenKey); // close key to registry
}
CStaticMutexSem g_mtxQPerf; // Serialization during "ReadUser/KernelPerfData"
LONG g_cKernelRefs = 0;
LONG g_cUserRefs = 0;
UINT g_KernSeqNo; // "CI" sequence number
UINT g_UserSeqNo; // "Filter" sequence number
//+---------------------------------------------------------------------------
//
// Function : InitializeFILTERPerformanceData
//
// Purpose : Build and initialize the performance data structure and create
// perfCI.ini file
//
// Arguments :
// [pInstance] -- dummy variable
//
// History : 23-March-94 t-joshh Created
//
// Note : Must start cidaemon before executing this function
//
//----------------------------------------------------------------------------
DWORD InitializeFILTERPerformanceData( LPWSTR pInstance )
{
CLock lock( g_mtxQPerf );
g_cUserRefs++;
if ( g_cUserRefs > 1 )
return NO_ERROR;
//
// Start with a clean slate. Note that in some cases the final Done() may
// have been called but the dll wasn't unloaded.
//
RtlCopyMemory( &FILTERDataDefinition,
&FILTERDataDefinitionFixed,
sizeof FILTERDataDefinition );
//
// Open the registry which contain the last key's index
//
HKEY hKeyPerf = 0;
LONG status = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
FILTERPerformanceKeyName,
0L, KEY_READ,
&hKeyPerf );
if (status != ERROR_SUCCESS)
{
CloseKey( hKeyPerf );
PerfDebugOut(( DEB_ERROR, "Error in RegOpenKeyEx\n"));
return status;
}
//
// Get the index of the first counter
//
DWORD dwFirstCounter;
DWORD size = sizeof dwFirstCounter;
DWORD type;
status = RegQueryValueEx( hKeyPerf, FirstCounterKeyName, 0L, &type,
(LPBYTE)&dwFirstCounter, &size);
if (status != ERROR_SUCCESS)
{
PerfDebugOut(( DEB_ERROR, "Error in Query First Counter\n"));
CloseKey( hKeyPerf );
return status;
}
//
// Get the index of the first help
//
DWORD dwFirstHelp;
size = sizeof dwFirstHelp;
status = RegQueryValueEx( hKeyPerf, FirstHelpKeyName,
0L, &type, (LPBYTE)&dwFirstHelp, &size );
if (status != ERROR_SUCCESS)
{
PerfDebugOut(( DEB_ERROR, "Error in Query First Help Key\n"));
CloseKey( hKeyPerf );
return status;
}
//
// Update the index of both title and help of each counter
//
FILTERDataDefinition.FILTERObjectType.ObjectNameTitleIndex += dwFirstCounter;
FILTERDataDefinition.FILTERObjectType.ObjectHelpTitleIndex += dwFirstHelp;
PERF_COUNTER_DEFINITION * pTmp = (PERF_COUNTER_DEFINITION *) ((BYTE *)&FILTERDataDefinition
+ sizeof(PERF_OBJECT_TYPE) );
for ( unsigned i = 0;
i < FILTERDataDefinition.FILTERObjectType.NumCounters;
i++)
{
pTmp->CounterNameTitleIndex += dwFirstCounter;
pTmp->CounterHelpTitleIndex += dwFirstHelp;
pTmp++;
}
//
// Close the registry key
//
CloseKey( hKeyPerf );
DWORD dwErr = ERROR_SUCCESS;
BOOL fNoServer = FALSE;
CTranslateSystemExceptions translate;
TRY
{
if ( 0 == g_pReadUserPerfData )
g_pReadUserPerfData = new CReadUserPerfData;
if ( g_pReadUserPerfData->InitForRead() )
g_UserSeqNo = g_pReadUserPerfData->GetSeqNo();
else
{
fNoServer = TRUE;
dwErr = ERROR_CAN_NOT_COMPLETE;
}
PerfDebugOut((DEB_ITRACE, "InitializeFilterPerformanceData : Done\n" ));
}
CATCH( CException, e )
{
dwErr = ERROR_CAN_NOT_COMPLETE; // lie here
}
END_CATCH;
if ( NO_ERROR != dwErr )
{
delete g_pReadUserPerfData;
g_pReadUserPerfData = 0;
// Lie if cisvc isn't running, and Collect() will return no data
if ( fNoServer )
dwErr = NO_ERROR;
}
return dwErr;
} //InitializeFILTERPerformanceData
//+---------------------------------------------------------------------------
//
// Function : CollectFILTERPerformanceData
//
// Purpose : Collect Performance Data of Content Index to PerfMon
//
// Arguments:
// [lpValueName] -- pointer to a wide character string passed by registry
//
// [lppData] -- IN: pointer to the address of the buffer to receive the
// completed PerfDataBlock and subordinate structures. This
// routine will append its data to the buffer starting at
// the point referenced by *lppData.
//
// OUT: points to the first byte after the data structure
// added by this routine. This routine updated the value at
// lppdata after appending its data.
//
// [lpcbTotalBytes] -- IN: the address of the DWORD that tells the size in bytes
// of the buffer referenced by the lppData argument
//
// OUT: the number of bytes added by this routine is written
// to the DWORD pointed to by this argument
//
// [lpNumObjectTypes] -- IN: the address of the DWORD to receive the number of
// objects added by this routine
//
// OUT: the number of objects added by this routine is written
// to the DWORD pointed to by this argument
//
// History : 23-March-94 t-joshh Created
//
// Return : ERROR_MORE_DATA if the size of the input buffer is too small
// ERROR_SUCCESS if success
//----------------------------------------------------------------------------
DWORD CollectFILTERPerformanceData( LPWSTR lpValueName,
LPVOID *lppData,
LPDWORD lpcbTotalBytes,
LPDWORD lpNumObjectTypes)
{
//
// if initial procedure failed, exit
//
if ( 0 == g_pReadUserPerfData || !g_pReadUserPerfData->InitOK())
{
*lpcbTotalBytes = 0;
*lpNumObjectTypes = 0;
return ERROR_SUCCESS; // yes, this is a successful exit
}
if ( g_pReadUserPerfData->GetSeqNo() != g_UserSeqNo )
{
CLock lock( g_mtxQPerf );
g_UserSeqNo = g_pReadUserPerfData->GetSeqNo();
if (!g_pReadUserPerfData->InitForRead())
{
*lpcbTotalBytes = 0;
*lpNumObjectTypes = 0;
return ERROR_SUCCESS; // yes, this is a successful exit
}
}
//
// see if this is a foreign (i.e. non-NT) computer data request
//
DWORD dwQueryType = GetQueryType (lpValueName);
if (dwQueryType == QUERY_FOREIGN)
{
//
// this routine does not service requests for data from
// Non-NT computers
//
*lpcbTotalBytes = 0;
*lpNumObjectTypes = 0;
return ERROR_SUCCESS;
}
//
// If the caller only wanted some counter, check if we have them
//
if (dwQueryType == QUERY_ITEMS)
{
if ( !(IsNumberInUnicodeList (
FILTERDataDefinition.FILTERObjectType.ObjectNameTitleIndex,
lpValueName)))
{
//
// request received for data object not provided by this routine
//
*lpcbTotalBytes = 0;
*lpNumObjectTypes = 0;
return ERROR_SUCCESS;
}
}
//
// Check whether there is enough space allocated in the lppData
//
ULONG ulSpaceNeeded = sizeof(FILTER_DATA_DEFINITION);
if ( *lpcbTotalBytes < (DWORD) ulSpaceNeeded)
{
*lpcbTotalBytes = 0;
*lpNumObjectTypes = 0;
return ERROR_MORE_DATA;
}
//
// Copy the Data Definition to the buffer first
//
FILTER_DATA_DEFINITION * pFILTERDataDefinition = (FILTER_DATA_DEFINITION *) *lppData;
RtlCopyMemory(pFILTERDataDefinition,
&FILTERDataDefinition,
sizeof(FILTER_DATA_DEFINITION));
PERF_INSTANCE_DEFINITION * pFILTERInstanceDefinition = (PERF_INSTANCE_DEFINITION *)( (BYTE *)*lppData
+ sizeof(FILTER_DATA_DEFINITION));
PerfDebugOut(( DEB_ITRACE, "No. of Instance %d\n", g_pReadUserPerfData->NumberOfInstance() ));
//
// Check how many instance exist (how many OFS drive have cidaemon running on)
//
for ( int i = 0;
i < g_pReadUserPerfData->NumberOfInstance();
i++ )
{
//
// Check whether there is enough space
//
UINT uiLen = wcslen(g_pReadUserPerfData->GetInstanceName(i));
ulSpaceNeeded += ( sizeof(PERF_INSTANCE_DEFINITION) +
FILTER_SIZE_OF_COUNTER_BLOCK +
(4+1+uiLen) * sizeof(WCHAR) );
if ( *lpcbTotalBytes < ulSpaceNeeded )
{
*lpcbTotalBytes = 0;
*lpNumObjectTypes = 0;
return ERROR_MORE_DATA;
}
//
// Make a copy of the instance name with UNICODE_STRING type
//
UNICODE_STRING usName;
usName.Length = (USHORT) uiLen * sizeof(WCHAR);
usName.MaximumLength = (USHORT) (uiLen+1)*sizeof(WCHAR);
usName.Buffer = g_pReadUserPerfData->GetInstanceName(i);
PERF_COUNTER_BLOCK * pCounterBlock;
MonBuildInstanceDefinition ( pFILTERInstanceDefinition,
(PVOID *) &pCounterBlock,
0,
0,
PERF_NO_UNIQUE_ID, // use name, not index
&usName );
pCounterBlock->ByteLength = FILTER_SIZE_OF_COUNTER_BLOCK;
//
// Put each counter value into the buffer
//
DWORD * pdwCounter = (DWORD *) ((BYTE *)pCounterBlock + sizeof(PERF_COUNTER_BLOCK));
for ( UINT j = 0 ;
j < FILTERDataDefinition.FILTERObjectType.NumCounters;
j++)
{
*pdwCounter = g_pReadUserPerfData->GetCounterValue( (int)i, (int)j );
pdwCounter++;
}
//
// Point to the next location of instance definition
//
pFILTERInstanceDefinition = (PERF_INSTANCE_DEFINITION *)pdwCounter;
}
*lppData = (LPVOID) pFILTERInstanceDefinition;
//
// Fill in the number of instances
//
pFILTERDataDefinition->FILTERObjectType.NumInstances = g_pReadUserPerfData->NumberOfInstance();
//
// Number of Object are always 1
//
*lpNumObjectTypes = 1;
//
// Fill in the number of bytes copied including object and counter
// definition and counter data
//
*lpcbTotalBytes = (DWORD) ((BYTE *) *lppData - (BYTE *) pFILTERDataDefinition);
pFILTERDataDefinition->FILTERObjectType.TotalByteLength = *lpcbTotalBytes;
PerfDebugOut((DEB_ITRACE, "CollectFilterPerformanceData : Done\n"));
return ERROR_SUCCESS;
} //CollectFILTERPerformanceData
//+---------------------------------------------------------------------------
//
// Function : DoneFILTERPerformanceData
//
// Purpose : dummy function
//
// Argument : none
//
// History : 23-March-94 t-joshh Created
//
//----------------------------------------------------------------------------
DWORD DoneFILTERPerformanceData( void )
{
CLock lock( g_mtxQPerf );
//
// A bug in a perfmon dll makes them call this function after we've
// been process detached! They call us in their process detach, which
// is well after we've been detached and destroyed our heap.
//
if ( g_fPerfmonCounterHackIsProcessDetached )
return ERROR_SUCCESS;
g_cUserRefs--;
if ( 0 == g_cUserRefs )
{
delete g_pReadUserPerfData;
g_pReadUserPerfData = 0;
}
return ERROR_SUCCESS;
} //DoneFILTERPerformanceData
//+---------------------------------------------------------------------------
//
// Function : InitializeCIPerformanceData
//
// Purpose : Build and initialize the performance data structure and create
// perfCI.ini file
//
// Arguments :
// [pInstance] -- dummy variable
//
// History : 23-March-94 t-joshh Created
//
//----------------------------------------------------------------------------
DWORD InitializeCIPerformanceData( LPWSTR pInstance )
{
LONG status;
HKEY hKeyPerf = 0;
DWORD size;
DWORD type;
DWORD dwFirstCounter;
DWORD dwFirstHelp;
CLock lock( g_mtxQPerf );
g_cKernelRefs++;
if ( g_cKernelRefs > 1 )
return NO_ERROR;
//
// Start with a clean slate. Note that in some cases the final Done() may
// have been called but the dll wasn't unloaded.
//
RtlCopyMemory( &CIDataDefinition,
&CIDataDefinitionFixed,
sizeof CIDataDefinition );
//
// Open the registry which contain the last key's index
//
status = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
CIPerformanceKeyName,
0L, KEY_READ,
&hKeyPerf );
if (status != ERROR_SUCCESS)
{
CloseKey( hKeyPerf );
PerfDebugOut(( DEB_ERROR, "Error in RegOpenKeyEx\n"));
return status;
}
//
// Get the index of the first counter
//
size = sizeof (dwFirstCounter);
status = RegQueryValueEx( hKeyPerf, FirstCounterKeyName, 0L, &type,
(LPBYTE)&dwFirstCounter, &size);
if (status != ERROR_SUCCESS)
{
PerfDebugOut(( DEB_ERROR, "Error in Query First Counter\n"));
CloseKey( hKeyPerf );
return status;
}
//
// Get the index of the first help
//
size = sizeof (dwFirstHelp);
status = RegQueryValueEx( hKeyPerf, FirstHelpKeyName,
0L, &type, (LPBYTE)&dwFirstHelp, &size );
if (status != ERROR_SUCCESS)
{
PerfDebugOut(( DEB_ERROR, "Error in Query First Help Key\n" ));
CloseKey( hKeyPerf );
return status;
}
//
// Update the index of both title and help of each counter
//
CIDataDefinition.CIObjectType.ObjectNameTitleIndex += dwFirstCounter;
CIDataDefinition.CIObjectType.ObjectHelpTitleIndex += dwFirstHelp;
PERF_COUNTER_DEFINITION * pTmp = (PERF_COUNTER_DEFINITION *) ((BYTE *)&CIDataDefinition
+ sizeof(PERF_OBJECT_TYPE) );
for ( unsigned i = 0;
i < CIDataDefinition.CIObjectType.NumCounters;
i++)
{
pTmp->CounterNameTitleIndex += dwFirstCounter;
pTmp->CounterHelpTitleIndex += dwFirstHelp;
pTmp += 1;
}
//
// Close the registry key
//
CloseKey( hKeyPerf );
DWORD dwErr = ERROR_SUCCESS;
BOOL fNoServer = FALSE;
CTranslateSystemExceptions translate;
TRY
{
if ( 0 == g_pReadKernelPerfData )
g_pReadKernelPerfData = new CReadKernelPerfData;
BOOL fOK = g_pReadKernelPerfData->InitForRead();
if ( fOK )
g_KernSeqNo = g_pReadKernelPerfData->GetSeqNo();
else
{
fNoServer = TRUE;
dwErr = ERROR_CAN_NOT_COMPLETE;
}
PerfDebugOut(( DEB_ITRACE, "InitialCIPerformanceData : Finish\n" ));
}
CATCH( CException, e )
{
dwErr = ERROR_CAN_NOT_COMPLETE; // lie here
}
END_CATCH;
if ( NO_ERROR != dwErr )
{
delete g_pReadKernelPerfData;
g_pReadKernelPerfData = 0;
// Lie if cisvc isn't running, and Collect() will return no data
if ( fNoServer )
dwErr = NO_ERROR;
}
return dwErr;
} //InitializeCIPerformanceData
//+---------------------------------------------------------------------------
//
// Function : CollectCIPerformanceData
//
// Purpose : Collect Performance Data of Content Index to PerfMon
//
// Arguments:
// [lpValueName] -- pointer to a wide character string passed by registry
//
// [lppData] -- IN: pointer to the address of the buffer to receive the
// completed PerfDataBlock and subordinate structures. This
// routine will append its data to the buffer starting at
// the point referenced by *lppData.
//
// OUT: points to the first byte after the data structure
// added by this routine. This routine updated the value at
// lppdata after appending its data.
//
// [lpcbTotalBytes] -- IN: the address of the DWORD that tells the size in bytes
// of the buffer referenced by the lppData argument
//
// OUT: the number of bytes added by this routine is written
// to the DWORD pointed to by this argument
//
// [lpNumObjectTypes] -- IN: the address of the DWORD to receive the number of
// objects added by this routine
//
// OUT: the number of objects added by this routine is written
// to the DWORD pointed to by this argument
//
// History : 23-March-94 t-joshh Created
//
// Return : ERROR_MORE_DATA if the size of the input buffer is too small
// ERROR_SUCCESS if success
//----------------------------------------------------------------------------
DWORD CollectCIPerformanceData( LPWSTR lpValueName,
LPVOID *lppData,
LPDWORD lpcbTotalBytes,
LPDWORD lpNumObjectTypes)
{
ULONG ulSpaceNeeded = 0;
DWORD dwQueryType;
//
// if initial procedure failed, exit
//
if ( 0 == g_pReadKernelPerfData || !g_pReadKernelPerfData->InitOK())
{
*lpcbTotalBytes = 0;
*lpNumObjectTypes = 0;
return ERROR_SUCCESS; // yes, this is a successful exit
}
if ( g_pReadKernelPerfData->GetSeqNo() != g_KernSeqNo )
{
CLock lock( g_mtxQPerf );
g_pReadKernelPerfData->InitForRead();
if (!g_pReadKernelPerfData->InitOK())
{
*lpcbTotalBytes = 0;
*lpNumObjectTypes = 0;
return ERROR_SUCCESS; // yes, this is a successful exit
}
g_KernSeqNo = g_pReadKernelPerfData->GetSeqNo();
}
//
// see if this is a foreign (i.e. non-NT) computer data request
//
dwQueryType = GetQueryType (lpValueName);
if (dwQueryType == QUERY_FOREIGN)
{
//
// this routine does not service requests for data from
// Non-NT computers
//
*lpcbTotalBytes = 0;
*lpNumObjectTypes = 0;
return ERROR_SUCCESS;
}
//
// If the caller only wanted some counter, check if we have them
//
if (dwQueryType == QUERY_ITEMS)
{
if ( !(IsNumberInUnicodeList(
CIDataDefinition.CIObjectType.ObjectNameTitleIndex,
lpValueName)) )
{
//
// request received for data object not provided by this routine
//
*lpcbTotalBytes = 0;
*lpNumObjectTypes = 0;
return ERROR_SUCCESS;
}
}
//
// Check whether there is enough space allocated in the lppData
//
ulSpaceNeeded = sizeof(CI_DATA_DEFINITION);
if ( *lpcbTotalBytes < (DWORD) ulSpaceNeeded)
{
*lpcbTotalBytes = 0;
*lpNumObjectTypes = 0;
return ERROR_MORE_DATA;
}
//
// Copy the Data Definition to the buffer first
//
CI_DATA_DEFINITION * pCIDataDefinition = (CI_DATA_DEFINITION *) *lppData;
RtlCopyMemory(pCIDataDefinition,
&CIDataDefinition,
sizeof(CI_DATA_DEFINITION));
PERF_INSTANCE_DEFINITION * pCIInstanceDefinition = (PERF_INSTANCE_DEFINITION *)( (BYTE *)*lppData
+ sizeof(CI_DATA_DEFINITION));
PerfDebugOut(( DEB_ITRACE, "*lppData: %#x\n", *lppData ));
PerfDebugOut(( DEB_ITRACE, "pCIInstanceDefinition: %#x\n", pCIInstanceDefinition ));
//
// Check how many instance exist (how many OFS drive have cidaemon running on)
//
for ( int i = 0;
i < g_pReadKernelPerfData->NumberOfInstance();
i++ )
{
//
// Check whether there is enough space
//
UINT uiLen = wcslen(g_pReadKernelPerfData->GetInstanceName(i));
ulSpaceNeeded += ( sizeof(PERF_INSTANCE_DEFINITION) +
CI_SIZE_OF_COUNTER_BLOCK +
(4+1+uiLen) * sizeof(WCHAR) );
if ( *lpcbTotalBytes < ulSpaceNeeded )
{
*lpcbTotalBytes = (DWORD) 0;
*lpNumObjectTypes = (DWORD) 0;
return ERROR_MORE_DATA;
}
//
// Make a copy of the instance name with UNICODE_STRING type
//
UNICODE_STRING usName;
usName.Length = (USHORT) uiLen * sizeof(WCHAR);
usName.MaximumLength = (USHORT) (uiLen+1)*sizeof(WCHAR);
usName.Buffer = g_pReadKernelPerfData->GetInstanceName(i);
PERF_COUNTER_BLOCK * pCounterBlock;
MonBuildInstanceDefinition ( pCIInstanceDefinition,
(PVOID *) &pCounterBlock,
0,
0,
PERF_NO_UNIQUE_ID, // use name, not index
&usName );
pCounterBlock->ByteLength = CI_SIZE_OF_COUNTER_BLOCK;
//
// Refresh the buffer
//
g_pReadKernelPerfData->Refresh( i );
//
// Put each counter value into the buffer
//
DWORD * pdwCounter = (DWORD *) ((BYTE *)pCounterBlock + sizeof(PERF_COUNTER_BLOCK));
for ( UINT j = 0 ;
j < CIDataDefinition.CIObjectType.NumCounters;
j++)
{
*pdwCounter = g_pReadKernelPerfData->GetCounterValue( (int)j );
pdwCounter++;
}
//
// Point to the next location of instance definition
//
pCIInstanceDefinition = (PERF_INSTANCE_DEFINITION *)pdwCounter;
}
*lppData = (LPVOID) pCIInstanceDefinition;
//
// Fill in the number of instances
//
pCIDataDefinition->CIObjectType.NumInstances = g_pReadKernelPerfData->NumberOfInstance();
//
// Number of Object are always 1
//
*lpNumObjectTypes = 1;
//
// Fill in the number of bytes copied including object and counter
// definition and counter data
//
*lpcbTotalBytes = (DWORD) ((BYTE *) *lppData - (BYTE *) pCIDataDefinition);
pCIDataDefinition->CIObjectType.TotalByteLength = *lpcbTotalBytes;
PerfDebugOut(( DEB_ITRACE, "CollectCIPerformanceData : Done\n" ));
Win4Assert( *lpcbTotalBytes == EIGHT_BYTE_MULTIPLE(*lpcbTotalBytes) );
return ERROR_SUCCESS;
} //CollectCIPerformanceData
//+---------------------------------------------------------------------------
//
// Function : DoneCIPerformanceData
//
// Purpose : dummy function
//
// Argument : none
//
// History : 23-March-94 t-joshh Created
//
//----------------------------------------------------------------------------
DWORD DoneCIPerformanceData( void )
{
CLock lock( g_mtxQPerf );
//
// A bug in a perfmon dll makes them call this function after we've
// been process detached! They call us in their process detach, which
// is well after we've been detached and destroyed our heap.
//
if ( g_fPerfmonCounterHackIsProcessDetached )
return ERROR_SUCCESS;
g_cKernelRefs--;
if ( 0 == g_cKernelRefs )
{
delete g_pReadKernelPerfData;
g_pReadKernelPerfData = 0;
}
return ERROR_SUCCESS;
} //DoneCIPerformanceData