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.
1102 lines
33 KiB
1102 lines
33 KiB
/**********************************************************************/
|
|
/** Microsoft Windows NT **/
|
|
/** Copyright(c) Microsoft Corp., 1993 **/
|
|
/**********************************************************************/
|
|
|
|
/*
|
|
entrypts.cxx
|
|
|
|
This file implements the Extensible Performance Objects for
|
|
the iis counters.
|
|
|
|
FILE HISTORY:
|
|
EmilyK 24-Aug-2000 Created, based on w3ctrs code.
|
|
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
|
|
//
|
|
// common defines & globals
|
|
//
|
|
#define MAX_STRINGIZED_ULONG_CHAR_COUNT 11 // "4294967295", including the terminating null
|
|
|
|
DWORD g_IIS_SecondsToNotLogFor = 60 * 60 * 12; // 60 seconds = 1 minute * 60 = 1 hour * 12 = 12 hours
|
|
|
|
//
|
|
// Public prototypes.
|
|
//
|
|
|
|
PM_OPEN_PROC OpenW3PerformanceData;
|
|
PM_COLLECT_PROC CollectW3PerformanceData;
|
|
PM_CLOSE_PROC CloseW3PerformanceData;
|
|
|
|
//
|
|
// Global object contecting to the site counters memory.
|
|
//
|
|
CRITICAL_SECTION g_IISMemManagerCriticalSection;
|
|
PERF_SM_MANAGER* g_pIISMemManager;
|
|
LONG g_IISNumberInitialized;
|
|
HANDLE g_hWASProcessWait;
|
|
|
|
// Pointer to the event log class so we can log problems with perf counters.
|
|
EVENT_LOG* g_pEventLog = NULL;
|
|
|
|
//
|
|
// Private Supporting Functions
|
|
//
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
Looks up in the registry all the specific counter values
|
|
that we need to be able to play nice with the other counters
|
|
on the machine.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
DWORD - Win32 Error Code
|
|
|
|
--***************************************************************************/
|
|
DWORD EstablishIndexes()
|
|
{
|
|
DWORD err = NO_ERROR;
|
|
HKEY hkey = NULL;
|
|
DWORD size;
|
|
DWORD type;
|
|
DWORD dwFirstCounter;
|
|
DWORD dwFirstHelp;
|
|
|
|
PERF_COUNTER_DEFINITION* pDefinition = NULL;
|
|
|
|
//
|
|
// Open the HTTP Server service's Performance key.
|
|
//
|
|
|
|
err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
REGISTRY_KEY_W3SVC_PERFORMANCE_KEY_A,
|
|
0,
|
|
KEY_QUERY_VALUE,
|
|
&hkey );
|
|
|
|
if( err == NO_ERROR)
|
|
{
|
|
|
|
//
|
|
// Read the first counter DWORD.
|
|
//
|
|
|
|
size = sizeof(DWORD);
|
|
|
|
err = RegQueryValueEx( hkey,
|
|
"First Counter",
|
|
NULL,
|
|
&type,
|
|
(LPBYTE)&dwFirstCounter,
|
|
&size );
|
|
if( err == NO_ERROR && type == REG_DWORD )
|
|
{
|
|
//
|
|
// Read the first help DWORD.
|
|
//
|
|
|
|
size = sizeof(DWORD);
|
|
|
|
err = RegQueryValueEx( hkey,
|
|
"First Help",
|
|
NULL,
|
|
&type,
|
|
(LPBYTE)&dwFirstHelp,
|
|
&size );
|
|
|
|
if ( err == NO_ERROR && type == REG_DWORD )
|
|
{
|
|
//
|
|
// First establish all of the W3 Service Counters
|
|
// ==============================================
|
|
|
|
//
|
|
// Update the object & counter name & help indicies.
|
|
//
|
|
W3DataDefinition.W3ObjectType.ObjectNameTitleIndex
|
|
+= dwFirstCounter;
|
|
W3DataDefinition.W3ObjectType.ObjectHelpTitleIndex
|
|
+= dwFirstHelp;
|
|
|
|
//
|
|
// Figure out the first counter definition. It starts
|
|
// after the PERF_OBJECT_TYPE structure, which is the
|
|
// first iten in the W3DataDefinition.
|
|
//
|
|
pDefinition = (PERF_COUNTER_DEFINITION*) ((LPBYTE) (&W3DataDefinition)
|
|
+ sizeof(PERF_OBJECT_TYPE));
|
|
|
|
//
|
|
// Now simply walk through the counters incrementing
|
|
// the pDefinition by on PERF_COUNTER_DEFINITION as you go.
|
|
//
|
|
for (int i = 0; i < NUMBER_OF_W3_COUNTERS; i++, pDefinition++)
|
|
{
|
|
pDefinition->CounterNameTitleIndex += dwFirstCounter;
|
|
pDefinition->CounterHelpTitleIndex += dwFirstHelp;
|
|
}
|
|
|
|
//
|
|
// Now do all of the W3 Global Service Counters
|
|
// ============================================
|
|
|
|
//
|
|
// Update the object & counter name & help indicies.
|
|
//
|
|
W3GlobalDataDefinition.W3GlobalObjectType.ObjectNameTitleIndex
|
|
+= dwFirstCounter;
|
|
W3GlobalDataDefinition.W3GlobalObjectType.ObjectHelpTitleIndex
|
|
+= dwFirstHelp;
|
|
|
|
//
|
|
// Figure out the first counter definition. It starts
|
|
// after the PERF_OBJECT_TYPE structure, which is the
|
|
// first iten in the W3DataDefinition.
|
|
//
|
|
pDefinition = (PERF_COUNTER_DEFINITION*)
|
|
((LPBYTE) (&W3GlobalDataDefinition)
|
|
+ sizeof(PERF_OBJECT_TYPE));
|
|
|
|
//
|
|
// Now simply walk through the counters incrementing
|
|
// the pDefinition by on PERF_COUNTER_DEFINITION as you go.
|
|
//
|
|
for ( int i = 0;
|
|
i < NUMBER_OF_W3_GLOBAL_COUNTERS;
|
|
i++, pDefinition++ )
|
|
{
|
|
pDefinition->CounterNameTitleIndex += dwFirstCounter;
|
|
pDefinition->CounterHelpTitleIndex += dwFirstHelp;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
if( hkey != NULL )
|
|
{
|
|
RegCloseKey( hkey );
|
|
hkey = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
Routine deletes the shared memory if it is in existence.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Note: It should always be called from inside a critical section.
|
|
|
|
--***************************************************************************/
|
|
VOID FreeSharedManager(BOOL HandleCallbackAsWell
|
|
)
|
|
{
|
|
|
|
//
|
|
// Only clean up the callback handle if we are told
|
|
// to, this is so we don't clean it up if we are
|
|
// in the middle of a callback call.
|
|
//
|
|
if ( HandleCallbackAsWell && g_hWASProcessWait )
|
|
{
|
|
if ( !UnregisterWait( g_hWASProcessWait ) )
|
|
{
|
|
DPERROR((
|
|
DBG_CONTEXT,
|
|
HRESULT_FROM_WIN32(GetLastError()),
|
|
"Could not unregister the old process wait handle \n"
|
|
));
|
|
|
|
}
|
|
|
|
g_hWASProcessWait = NULL;
|
|
}
|
|
|
|
//
|
|
// Now clean up the shared memory object.
|
|
//
|
|
if ( g_pIISMemManager )
|
|
{
|
|
delete g_pIISMemManager;
|
|
g_pIISMemManager = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
Routine drops the shared memory if the managing process of the memory
|
|
goes away.
|
|
|
|
Arguments:
|
|
|
|
LPVOID lpParameter - Unused
|
|
BOOL bUnused - Unused
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--***************************************************************************/
|
|
VOID CALLBACK ShutdownMemory(
|
|
PVOID,
|
|
BOOLEAN
|
|
)
|
|
{
|
|
|
|
EnterCriticalSection ( &g_IISMemManagerCriticalSection );
|
|
|
|
FreeSharedManager(FALSE);
|
|
|
|
LeaveCriticalSection ( &g_IISMemManagerCriticalSection );
|
|
|
|
}
|
|
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
Helper function to hook up to shared memory when we are ready to
|
|
provide counters.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
DWORD - Win32 Error Code
|
|
|
|
--***************************************************************************/
|
|
DWORD
|
|
HookUpSharedMemory()
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
DWORD size = 0;
|
|
DWORD type = 0;
|
|
DWORD dwRegSettingValue = 0;
|
|
HKEY hkey = NULL;
|
|
|
|
//
|
|
// If we are not hooked up to the manager than hook up.
|
|
//
|
|
if ( !g_pIISMemManager )
|
|
{
|
|
//
|
|
// Hook up to the manager of the shared memory.
|
|
//
|
|
g_pIISMemManager = new PERF_SM_MANAGER();
|
|
if ( ! g_pIISMemManager )
|
|
{
|
|
dwErr = ERROR_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Initialize the memory manager for readonly access
|
|
//
|
|
dwErr = g_pIISMemManager->Initialize(FALSE);
|
|
if ( dwErr != ERROR_SUCCESS )
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// This ( in the Initialize call above ) is when we read
|
|
// the wait times for the perf counters
|
|
// from the registry so this is when we should set the logging
|
|
// wait time as well.
|
|
//
|
|
dwErr = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
|
|
REGISTRY_KEY_W3SVC_PERFORMANCE_KEY_W,
|
|
0,
|
|
KEY_QUERY_VALUE,
|
|
&hkey );
|
|
|
|
if( dwErr == ERROR_SUCCESS)
|
|
{
|
|
|
|
size = sizeof(DWORD);
|
|
|
|
dwErr = RegQueryValueExW( hkey,
|
|
REGISTRY_VALUE_W3SVC_PERF_EVENT_LOG_DELAY_OVERRIDE_W,
|
|
NULL,
|
|
&type,
|
|
(LPBYTE)&dwRegSettingValue,
|
|
&size );
|
|
if( dwErr == ERROR_SUCCESS && type == REG_DWORD )
|
|
{
|
|
if ( dwRegSettingValue != 0 )
|
|
{
|
|
g_IIS_SecondsToNotLogFor = dwRegSettingValue;
|
|
}
|
|
}
|
|
|
|
if( hkey != NULL )
|
|
{
|
|
RegCloseKey( hkey );
|
|
hkey = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
// Press on in the face of errors.
|
|
dwErr = ERROR_SUCCESS;
|
|
|
|
//
|
|
|
|
|
|
//
|
|
// if we re-initialized then we need to setup the
|
|
// wait on the process again. it is possible that
|
|
// the previous wait has not been cleaned up (since
|
|
// we can't clean it up in the callback function) so
|
|
// if this is the case we need to clean it up first.
|
|
//
|
|
if ( g_hWASProcessWait != NULL )
|
|
{
|
|
if ( !UnregisterWait( g_hWASProcessWait ) )
|
|
{
|
|
DPERROR((
|
|
DBG_CONTEXT,
|
|
HRESULT_FROM_WIN32(GetLastError()),
|
|
"Could not unregister the old process wait handle \n"
|
|
));
|
|
|
|
}
|
|
|
|
g_hWASProcessWait = NULL;
|
|
}
|
|
|
|
//
|
|
// Register to wait on the managing process,
|
|
// so we release any shared memory if the managing
|
|
// process shutsdown or crashes.
|
|
//
|
|
if ( !RegisterWaitForSingleObject( &g_hWASProcessWait,
|
|
g_pIISMemManager->GetWASProcessHandle(),
|
|
&ShutdownMemory,
|
|
NULL,
|
|
INFINITE,
|
|
WT_EXECUTEONLYONCE |
|
|
WT_EXECUTEINIOTHREAD ) )
|
|
{
|
|
dwErr = GetLastError();
|
|
|
|
DPERROR((
|
|
DBG_CONTEXT,
|
|
HRESULT_FROM_WIN32(dwErr),
|
|
"Could not register to wait on the process handle \n"
|
|
));
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
//
|
|
// Initialize a reader to point to the appropriate
|
|
// counter set.
|
|
//
|
|
dwErr = g_pIISMemManager->CreateNewCounterSet( SITE_COUNTER_SET );
|
|
if ( dwErr != ERROR_SUCCESS )
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Initialize a reader to point to the appropriate
|
|
// counter set.
|
|
//
|
|
dwErr = g_pIISMemManager->CreateNewCounterSet( GLOBAL_COUNTER_SET );
|
|
if ( dwErr != ERROR_SUCCESS )
|
|
{
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Whether we just hooked up to the memory or not, we still want
|
|
// to do one final check to make sure the memory is still valid.
|
|
// It might have been invalidated in since the last gathering, or
|
|
// it might have been invalidated while we were hooking up the
|
|
// wait on the process id. Either way, if it is now not valid,
|
|
// drop it.
|
|
//
|
|
|
|
if ( g_pIISMemManager->ReleaseIsNeeded() )
|
|
{
|
|
//
|
|
// The exit will take care of deleteing
|
|
// the memory manager which will release
|
|
// the files.
|
|
//
|
|
dwErr = ERROR_NOT_READY;
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
|
|
if ( dwErr != ERROR_SUCCESS )
|
|
{
|
|
FreeSharedManager(TRUE);
|
|
}
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
//
|
|
// Public Exported functions.
|
|
//
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
Is called to initialize any memory data structures needed for
|
|
supporting the performance counter publishing.
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
DWORD - Win32 Error Code
|
|
|
|
--***************************************************************************/
|
|
DWORD OpenW3PerformanceData( LPWSTR )
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
static BOOL fInit = FALSE;
|
|
|
|
|
|
IF_DEBUG( WEB_ADMIN_SERVICE_PERFCOUNT )
|
|
{
|
|
DBGPRINTF((
|
|
DBG_CONTEXT,
|
|
"Entering W3CTRS - OpenW3PerformanceData routine \n"
|
|
));
|
|
}
|
|
|
|
//
|
|
// If we are the first one here then we can setup the
|
|
// objects the correct way.
|
|
//
|
|
// Note: this is not neccessarily completely safe, but
|
|
// it really isn't that big of a problem if these
|
|
// objects get setup twice.
|
|
//
|
|
if ( !fInit )
|
|
{
|
|
//
|
|
// Setup the event log so we can log errors.
|
|
//
|
|
// If this fails then the g_pEventLog will still
|
|
// be null. We would not fail in this case, and
|
|
// since we do not have the event viewer we really
|
|
// don't have any place to log a message. We will
|
|
// validate that this has been set before using it
|
|
// throughout the code.
|
|
//
|
|
g_pEventLog = new EVENT_LOG(L"W3CTRS");
|
|
|
|
//
|
|
// Establish all machine static information about
|
|
// the counters.
|
|
//
|
|
dwErr = EstablishIndexes();
|
|
if ( dwErr != ERROR_SUCCESS )
|
|
{
|
|
if ( g_pEventLog )
|
|
{
|
|
g_pEventLog->
|
|
LogEvent(
|
|
W3_W3SVC_REGISTRATION_MAY_BE_BAD, // message id
|
|
0, // count of strings
|
|
NULL, // array of strings
|
|
HRESULT_FROM_WIN32(dwErr) // error code
|
|
);
|
|
}
|
|
|
|
goto exit;
|
|
}
|
|
|
|
fInit = TRUE;
|
|
|
|
|
|
}
|
|
|
|
exit:
|
|
|
|
IF_DEBUG( WEB_ADMIN_SERVICE_PERFCOUNT )
|
|
{
|
|
DBGPRINTF((
|
|
DBG_CONTEXT,
|
|
"Exiting W3CTRS - OpenW3PerformanceData routine \n"
|
|
));
|
|
}
|
|
|
|
return dwErr;
|
|
|
|
} // OpenW3PerformanceData
|
|
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
Is called to retrieve counters from our library.
|
|
|
|
Arguments:
|
|
|
|
LPWSTR lpValueName - Name fo the set of counters to retrieve.
|
|
|
|
LPVOID * lppData - On entry contains a pointer to the buffer to
|
|
receive the completed PerfDataBlock & subordinate
|
|
structures. On exit, points to the first bytes
|
|
*after* the data structures added by this routine.
|
|
|
|
LPDWORD lpcbTotalBytes - On entry contains a pointer to the
|
|
size (in BYTEs) of the buffer referenced by lppData.
|
|
On exit, contains the number of BYTEs added by this
|
|
routine.
|
|
|
|
LPDWORD lpNumObjectTypes - Receives the number of objects added
|
|
by this routine.
|
|
|
|
Return Value:
|
|
|
|
DWORD - Win32 Error Code (MUST be either NO_ERROR or ERROR_MORE_DATA)
|
|
|
|
--***************************************************************************/
|
|
DWORD CollectW3PerformanceData(
|
|
LPWSTR lpValueName,
|
|
LPVOID * lppData,
|
|
LPDWORD lpcbTotalBytes,
|
|
LPDWORD lpNumObjectTypes
|
|
)
|
|
{
|
|
DBG_ASSERT ( lppData );
|
|
DBG_ASSERT ( lpcbTotalBytes );
|
|
DBG_ASSERT ( lpNumObjectTypes );
|
|
|
|
static DWORD s_FirstFailureAt = 0;
|
|
static DWORD s_NumberOfTimesTookToLong = 0;
|
|
|
|
LPVOID pData = *lppData;
|
|
|
|
COUNTER_GLOBAL_STRUCT* pSiteObject = NULL;
|
|
LPVOID pSiteInstance = NULL;
|
|
COUNTER_GLOBAL_STRUCT* pGlobalObject = NULL;
|
|
LPVOID pGlobalInstance = NULL;
|
|
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
DWORD dwSiteSize = 0;
|
|
DWORD dwGlobalSize = 0;
|
|
DWORD dwTotalSize = 0;
|
|
|
|
DWORD dwQueryType = GetQueryType( lpValueName );
|
|
|
|
BOOL fGetSites = TRUE;
|
|
BOOL fGetGlobal = TRUE;
|
|
|
|
DWORD NumObjects = 2;
|
|
|
|
|
|
//
|
|
// Figure out if it is a query type we do not support.
|
|
//
|
|
if (( dwQueryType == QUERY_FOREIGN ) || (dwQueryType == QUERY_COSTLY))
|
|
{
|
|
// We don't do foreign queries
|
|
|
|
*lpcbTotalBytes = 0;
|
|
*lpNumObjectTypes = 0;
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// If it is a query by item, then figure out if we own any of the
|
|
// items it is referring to.
|
|
//
|
|
if( dwQueryType == QUERY_ITEMS )
|
|
{
|
|
//
|
|
// The registry is asking for a specific object. Let's
|
|
// see if we're one of the chosen.
|
|
//
|
|
|
|
if( !IsNumberInUnicodeList(
|
|
W3DataDefinition.W3ObjectType.ObjectNameTitleIndex,
|
|
lpValueName ) )
|
|
{
|
|
fGetSites = FALSE;
|
|
NumObjects--;
|
|
|
|
}
|
|
|
|
if( !IsNumberInUnicodeList(
|
|
W3GlobalDataDefinition.W3GlobalObjectType.ObjectNameTitleIndex,
|
|
lpValueName ) )
|
|
{
|
|
fGetGlobal = FALSE;
|
|
NumObjects--;
|
|
|
|
}
|
|
|
|
if ( NumObjects == 0 )
|
|
{
|
|
*lpcbTotalBytes = 0;
|
|
*lpNumObjectTypes = 0;
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
IF_DEBUG( WEB_ADMIN_SERVICE_PERFCOUNT )
|
|
{
|
|
DBGPRINTF((
|
|
DBG_CONTEXT,
|
|
"Entering W3CTRS - CollectW3PerformanceData routine \n"
|
|
));
|
|
}
|
|
|
|
//
|
|
// if we got this far then we know that we want to get something.
|
|
//
|
|
EnterCriticalSection ( &g_IISMemManagerCriticalSection );
|
|
|
|
dwErr = HookUpSharedMemory();
|
|
if ( dwErr != ERROR_SUCCESS )
|
|
{
|
|
DWORD dwSizeNeeded = 0;
|
|
|
|
DBG_ASSERT ( fGetSites || fGetGlobal );
|
|
|
|
if ( fGetSites )
|
|
{
|
|
dwSizeNeeded += sizeof(W3DataDefinition) +
|
|
sizeof(PERF_INSTANCE_DEFINITION) +
|
|
(sizeof(WCHAR) * MAX_INSTANCE_NAME ) +
|
|
sizeof(W3_COUNTER_BLOCK);
|
|
}
|
|
|
|
if ( fGetGlobal )
|
|
{
|
|
dwSizeNeeded += sizeof( W3GlobalDataDefinition )
|
|
+ sizeof( W3_GLOBAL_COUNTER_BLOCK );
|
|
}
|
|
|
|
if ( dwSizeNeeded > *lpcbTotalBytes )
|
|
{
|
|
*lpcbTotalBytes = 0;
|
|
*lpNumObjectTypes = 0;
|
|
dwErr = ERROR_MORE_DATA;
|
|
}
|
|
else
|
|
{
|
|
|
|
if ( fGetSites )
|
|
{
|
|
memcpy (pData, &W3DataDefinition, sizeof(W3DataDefinition));
|
|
((PERF_OBJECT_TYPE*) pData)->NumInstances = 1;
|
|
((PERF_OBJECT_TYPE*) pData)->TotalByteLength = sizeof(W3DataDefinition) +
|
|
sizeof(PERF_INSTANCE_DEFINITION) +
|
|
(sizeof(WCHAR) * MAX_INSTANCE_NAME) +
|
|
sizeof(W3_COUNTER_BLOCK);
|
|
pData = (LPBYTE) pData + sizeof(W3DataDefinition);
|
|
|
|
// Copy in a _Total instance
|
|
|
|
// First Setup the Instance Definition
|
|
|
|
((PERF_INSTANCE_DEFINITION*) pData)->ByteLength = sizeof(PERF_INSTANCE_DEFINITION) +
|
|
MAX_INSTANCE_NAME * sizeof(WCHAR);
|
|
((PERF_INSTANCE_DEFINITION*) pData)->ParentObjectTitleIndex = 0;
|
|
((PERF_INSTANCE_DEFINITION*) pData)->ParentObjectInstance = 0;
|
|
((PERF_INSTANCE_DEFINITION*) pData)->UniqueID = PERF_NO_UNIQUE_ID;
|
|
((PERF_INSTANCE_DEFINITION*) pData)->NameOffset = sizeof(PERF_INSTANCE_DEFINITION);
|
|
((PERF_INSTANCE_DEFINITION*) pData)->NameLength = (DWORD) ((wcslen(L"_Total") + 1) * sizeof(WCHAR));
|
|
|
|
pData = (LPBYTE) pData + sizeof(PERF_INSTANCE_DEFINITION);
|
|
|
|
// Next copy in the Instance Name including the
|
|
// NULL, we know we have enough room because of
|
|
// the check above for size.
|
|
wcsncpy ( (LPWSTR) pData, L"_Total", wcslen(L"_Total") + 1 );
|
|
|
|
// To avoid suttle differences we use the same MAX_INSTANCE_NAME
|
|
// amount of space even for this faked up _Total Site.
|
|
pData = (LPBYTE) pData + ( MAX_INSTANCE_NAME * sizeof(WCHAR));
|
|
|
|
// Lastly copy in a block of zero's for the _Total site data.
|
|
memset ( pData, 0, sizeof(W3_COUNTER_BLOCK) );
|
|
|
|
// This is setting the size in the structure, it is the first
|
|
// DWORD in the W3_CONTER_BLOCK.
|
|
*((DWORD*) (pData)) = sizeof(W3_COUNTER_BLOCK);
|
|
pData = (LPBYTE) pData + sizeof(W3_COUNTER_BLOCK);
|
|
|
|
}
|
|
|
|
if ( fGetGlobal )
|
|
{
|
|
memcpy (pData, &W3GlobalDataDefinition, sizeof(W3GlobalDataDefinition));
|
|
((PERF_OBJECT_TYPE*) pData)->NumInstances = PERF_NO_INSTANCES;
|
|
((PERF_OBJECT_TYPE*) pData)->TotalByteLength = sizeof(W3GlobalDataDefinition) +
|
|
sizeof(W3_GLOBAL_COUNTER_BLOCK);
|
|
pData = (LPBYTE) pData + sizeof(W3GlobalDataDefinition);
|
|
|
|
// Copy in the actual data for global
|
|
memset ( pData, 0, sizeof(W3_GLOBAL_COUNTER_BLOCK) );
|
|
|
|
// This is setting the size in the structure, it is the first
|
|
// DWORD in the W3_GLOBAL_CONTER_BLOCK.
|
|
*((DWORD*) (pData)) = sizeof(W3_GLOBAL_COUNTER_BLOCK);
|
|
pData = (LPBYTE) pData + sizeof(W3_GLOBAL_COUNTER_BLOCK);
|
|
|
|
}
|
|
|
|
// Make sure we didn't lie about the size.
|
|
DBG_ASSERT ( dwSizeNeeded == DIFF((PCHAR) pData - (PCHAR) (*lppData)) );
|
|
|
|
*lpcbTotalBytes = dwSizeNeeded;
|
|
*lpNumObjectTypes = NumObjects;
|
|
*lppData = pData;
|
|
|
|
dwErr = ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
goto exit;
|
|
}
|
|
|
|
|
|
|
|
DBG_ASSERT ( g_pIISMemManager );
|
|
|
|
//
|
|
// Now check that the memory has been updated recently. If it has
|
|
// not been then we need to ping WAS and let them know that we need
|
|
// new data, and wait on that new data.
|
|
//
|
|
if ( ! g_pIISMemManager->EvaluateIfCountersAreFresh() )
|
|
{
|
|
if ( g_pEventLog )
|
|
{
|
|
IF_DEBUG( WEB_ADMIN_SERVICE_PERFCOUNT )
|
|
{
|
|
DBGPRINTF((
|
|
DBG_CONTEXT,
|
|
"Perf Counters did not refresh in a timely manner: \n"
|
|
" CurrentSecondsCount = %d \n"
|
|
" FirstFailure was %d \n"
|
|
" Time to wait to restart is %d \n"
|
|
" NumberFailures = %d \n",
|
|
GetCurrentTimeInSeconds(),
|
|
s_FirstFailureAt,
|
|
g_IIS_SecondsToNotLogFor,
|
|
s_NumberOfTimesTookToLong
|
|
));
|
|
}
|
|
|
|
if ( ( s_FirstFailureAt == 0 ) ||
|
|
( ( s_FirstFailureAt + g_IIS_SecondsToNotLogFor ) < GetCurrentTimeInSeconds() ) )
|
|
{
|
|
s_FirstFailureAt = GetCurrentTimeInSeconds();
|
|
s_NumberOfTimesTookToLong = 0;
|
|
}
|
|
|
|
|
|
s_NumberOfTimesTookToLong++;
|
|
|
|
if ( s_NumberOfTimesTookToLong == 1 )
|
|
{
|
|
g_pEventLog->
|
|
LogEvent(
|
|
W3_W3SVC_REFRESH_TAKING_TOO_LONG, // message id
|
|
0, // count of strings
|
|
NULL, // array of strings
|
|
0 // error code
|
|
);
|
|
}
|
|
|
|
if ( s_NumberOfTimesTookToLong == 2 )
|
|
{
|
|
DWORD Hours = g_IIS_SecondsToNotLogFor / 60 / 60;
|
|
DWORD Minutes = ( g_IIS_SecondsToNotLogFor - ( Hours * 60 * 60 ) ) / 60;
|
|
DWORD Seconds = g_IIS_SecondsToNotLogFor - ( Hours * 60 * 60 ) - ( Minutes * 60 );
|
|
|
|
const WCHAR * EventLogStrings[1];
|
|
|
|
// Format is "DWORD:DWORD:DWORD" So 3 max dwords plus two colons and a null
|
|
WCHAR StringizedTimeLimit[ (MAX_STRINGIZED_ULONG_CHAR_COUNT * 3) + 3 ];
|
|
|
|
_snwprintf( StringizedTimeLimit,
|
|
sizeof( StringizedTimeLimit ) / sizeof ( WCHAR ),
|
|
L"%lu:%02lu:%02lu",
|
|
Hours,
|
|
Minutes,
|
|
Seconds);
|
|
|
|
EventLogStrings[0] = StringizedTimeLimit;
|
|
|
|
g_pEventLog->
|
|
LogEvent(
|
|
W3_W3SVC_REFRESH_TAKING_TOO_LONG_STOPPING_LOGGING, // message id
|
|
sizeof( EventLogStrings ) / sizeof( const WCHAR * ), // count of strings
|
|
EventLogStrings, // array of strings
|
|
0 // error code
|
|
);
|
|
|
|
// if s_NumberOfTimesTookToLong is anything else
|
|
// then we don't bother printing anything.
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( fGetSites)
|
|
{
|
|
//
|
|
// Get the counter information from shared memory.
|
|
//
|
|
dwErr = g_pIISMemManager->GetCounterInfo(SITE_COUNTER_SET,
|
|
&pSiteObject,
|
|
&pSiteInstance);
|
|
if ( dwErr != ERROR_SUCCESS )
|
|
{
|
|
if ( g_pEventLog )
|
|
{
|
|
g_pEventLog->
|
|
LogEvent(
|
|
W3_UNABLE_QUERY_W3SVC_DATA, // message id
|
|
0, // count of strings
|
|
NULL, // array of strings
|
|
HRESULT_FROM_WIN32(dwErr) // error code
|
|
);
|
|
}
|
|
|
|
//
|
|
// According to the perf by laws you can only
|
|
// return Success or More Data from here so
|
|
// we will need to log the error and then return
|
|
// Success, since this does not mean we have more data.
|
|
//
|
|
|
|
*lpcbTotalBytes = 0;
|
|
*lpNumObjectTypes = 0;
|
|
dwErr = ERROR_SUCCESS;
|
|
|
|
goto exit;
|
|
}
|
|
|
|
dwSiteSize = sizeof(W3DataDefinition) + pSiteObject->SizeData;
|
|
|
|
}
|
|
|
|
|
|
if ( fGetGlobal )
|
|
{
|
|
//
|
|
// Get the counter information from shared memory.
|
|
//
|
|
dwErr = g_pIISMemManager->GetCounterInfo(GLOBAL_COUNTER_SET,
|
|
&pGlobalObject,
|
|
&pGlobalInstance);
|
|
if ( dwErr != ERROR_SUCCESS )
|
|
{
|
|
if ( g_pEventLog )
|
|
{
|
|
g_pEventLog->
|
|
LogEvent(
|
|
W3_UNABLE_QUERY_W3SVC_DATA, // message id
|
|
0, // count of strings
|
|
NULL, // array of strings
|
|
HRESULT_FROM_WIN32(dwErr) // error code
|
|
);
|
|
}
|
|
|
|
//
|
|
// According to the perf by laws you can only
|
|
// return Success or More Data from here so
|
|
// we will need to log the error and then return
|
|
// Success, since this does not mean we have more data.
|
|
//
|
|
|
|
*lpcbTotalBytes = 0;
|
|
*lpNumObjectTypes = 0;
|
|
dwErr = ERROR_SUCCESS;
|
|
|
|
goto exit;
|
|
}
|
|
|
|
dwGlobalSize = sizeof(W3GlobalDataDefinition) +
|
|
pGlobalObject->SizeData;
|
|
|
|
}
|
|
|
|
//
|
|
// Figure out the total size of the memory
|
|
//
|
|
dwTotalSize = dwSiteSize + dwGlobalSize;
|
|
|
|
//
|
|
// If we don't have room tell the counter library.
|
|
//
|
|
if ( dwTotalSize > *lpcbTotalBytes )
|
|
{
|
|
*lpcbTotalBytes = 0;
|
|
*lpNumObjectTypes = 0;
|
|
dwErr = ERROR_MORE_DATA;
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
if ( fGetSites )
|
|
{
|
|
//
|
|
// Copy in the definition of the data for sites.
|
|
//
|
|
memcpy (pData, &W3DataDefinition, sizeof(W3DataDefinition));
|
|
((PERF_OBJECT_TYPE*) pData)->NumInstances = pSiteObject->NumInstances;
|
|
((PERF_OBJECT_TYPE*) pData)->TotalByteLength = dwSiteSize;
|
|
pData = (LPBYTE) pData + sizeof(W3DataDefinition);
|
|
|
|
// Copy in the actual data for sites
|
|
memcpy ( pData, pSiteInstance, pSiteObject->SizeData );
|
|
pData = (LPBYTE) pData + pSiteObject->SizeData;
|
|
}
|
|
|
|
if ( fGetGlobal )
|
|
{
|
|
//
|
|
// Copy in the definition of the data for global
|
|
//
|
|
memcpy (pData, &W3GlobalDataDefinition, sizeof(W3GlobalDataDefinition));
|
|
((PERF_OBJECT_TYPE*) pData)->NumInstances = pGlobalObject->NumInstances;
|
|
((PERF_OBJECT_TYPE*) pData)->TotalByteLength = dwGlobalSize;
|
|
pData = (LPBYTE) pData + sizeof(W3GlobalDataDefinition);
|
|
|
|
// Copy in the actual data for global
|
|
memcpy ( pData, pGlobalInstance, pGlobalObject->SizeData );
|
|
pData = (LPBYTE) pData + pGlobalObject->SizeData;
|
|
}
|
|
|
|
// Make sure we didn't lie about the size.
|
|
DBG_ASSERT ( dwTotalSize == DIFF((PCHAR) pData - (PCHAR) (*lppData)) );
|
|
|
|
*lpcbTotalBytes = dwTotalSize;
|
|
*lpNumObjectTypes = NumObjects;
|
|
*lppData = pData;
|
|
|
|
//
|
|
// Let WAS know that we need new counters.
|
|
//
|
|
g_pIISMemManager->PingWASToRefreshCounters();
|
|
|
|
exit:
|
|
|
|
LeaveCriticalSection ( &g_IISMemManagerCriticalSection );
|
|
|
|
IF_DEBUG( WEB_ADMIN_SERVICE_PERFCOUNT )
|
|
{
|
|
DBGPRINTF((
|
|
DBG_CONTEXT,
|
|
"Exiting W3CTRS - CollectW3PerformanceData routine \n"
|
|
));
|
|
}
|
|
|
|
return dwErr;
|
|
|
|
} // CollectW3PerformanceData
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
Terminates the performance counters.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
DWORD - Win32 Error Code
|
|
|
|
--***************************************************************************/
|
|
DWORD CloseW3PerformanceData( VOID )
|
|
{
|
|
//
|
|
// On tclose tell the timer queue to stop launching
|
|
// the checking code.
|
|
//
|
|
// Note if someone calls close and then collect again
|
|
// we will have stopped listening to notifications from
|
|
// w3svc and will not know when to drop the memory.
|
|
//
|
|
IF_DEBUG( WEB_ADMIN_SERVICE_PERFCOUNT )
|
|
{
|
|
DBGPRINTF((
|
|
DBG_CONTEXT,
|
|
"Entering W3CTRS - CloseW3PerformanceData routine \n"
|
|
));
|
|
}
|
|
|
|
EnterCriticalSection ( &g_IISMemManagerCriticalSection );
|
|
|
|
FreeSharedManager(TRUE);
|
|
|
|
LeaveCriticalSection( &g_IISMemManagerCriticalSection );
|
|
|
|
if ( g_pEventLog )
|
|
{
|
|
delete g_pEventLog;
|
|
|
|
g_pEventLog = NULL;
|
|
}
|
|
|
|
IF_DEBUG( WEB_ADMIN_SERVICE_PERFCOUNT )
|
|
{
|
|
DBGPRINTF((
|
|
DBG_CONTEXT,
|
|
"Exiting W3CTRS - CloseW3PerformanceData routine \n"
|
|
));
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
} // CloseW3PerformanceData
|
|
|
|
|
|
|
|
|
|
|