/*++ Copyright (c) 1998-2001 Microsoft Corporation Module Name: counters.cxx Abstract: Contains the performance monitoring counter management code Author: Eric Stenson (ericsten) 25-Sep-2000 Revision History: --*/ #include "precomp.h" #include "countersp.h" #ifdef ALLOC_PRAGMA #pragma alloc_text( INIT, UlInitializeCounters ) #pragma alloc_text( PAGE, UlTerminateCounters ) #pragma alloc_text( PAGE, UlCreateSiteCounterEntry ) #if REFERENCE_DEBUG #pragma alloc_text( PAGE, UlReferenceSiteCounterEntry ) #pragma alloc_text( PAGE, UlDereferenceSiteCounterEntry ) #endif #pragma alloc_text( PAGE, UlGetGlobalCounters ) #pragma alloc_text( PAGE, UlGetSiteCounters ) #endif // ALLOC_PRAGMA #if 0 NOT PAGEABLE -- UlIncCounter NOT PAGEABLE -- UlDecCounter NOT PAGEABLE -- UlAddCounter NOT PAGEABLE -- UlResetCounter NOT PAGEABLE -- UlIncSiteCounter NOT PAGEABLE -- UlDecSiteCounter NOT PAGEABLE -- UlAddSiteCounter NOT PAGEABLE -- UlResetSiteCounter NOT PAGEABLE -- UlMaxSiteCounter NOT PAGEABLE -- UlMaxSiteCounter64 #endif BOOLEAN g_InitCountersCalled = FALSE; HTTP_GLOBAL_COUNTERS g_UlGlobalCounters; FAST_MUTEX g_SiteCounterListMutex; LIST_ENTRY g_SiteCounterListHead = {NULL,NULL}; LONG g_SiteCounterListCount = 0; /***************************************************************************++ Routine Description: Performs global initialization of the global (cache) and instance (per site) counters. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlInitializeCounters( VOID ) { NTSTATUS Status = STATUS_SUCCESS; // // Sanity check. // PAGED_CODE(); ASSERT( !g_InitCountersCalled ); UlTrace(PERF_COUNTERS, ("http!UlInitializeCounters\n")); if (!g_InitCountersCalled) { // // zero out global counter block // RtlZeroMemory(&g_UlGlobalCounters, sizeof(HTTP_GLOBAL_COUNTERS)); // // init Site Counter list // ExInitializeFastMutex(&g_SiteCounterListMutex); InitializeListHead(&g_SiteCounterListHead); g_SiteCounterListCount = 0; // done! g_InitCountersCalled = TRUE; } RETURN( Status ); } // UlInitializeCounters /***************************************************************************++ Routine Description: Performs global cleanup of the global (cache) and instance (per site) counters. --***************************************************************************/ VOID UlTerminateCounters( VOID ) { // // [debug only] Walk list of counters and check the ref count for each counter block. // #if DBG PLIST_ENTRY pEntry; PUL_SITE_COUNTER_ENTRY pCounterEntry; if (!g_InitCountersCalled) { goto End; } if (IsListEmpty(&g_SiteCounterListHead)) { ASSERT(0 == g_SiteCounterListCount); // Good! No counters left behind! goto End; } // // Walk list of Site Counter Entries // pEntry = g_SiteCounterListHead.Flink; while (pEntry != &g_SiteCounterListHead) { pCounterEntry = CONTAINING_RECORD( pEntry, UL_SITE_COUNTER_ENTRY, ListEntry ); ASSERT(IS_VALID_SITE_COUNTER_ENTRY(pCounterEntry)); UlTrace(PERF_COUNTERS, ("http!UlTerminateCounters: Error: pCounterEntry %p SiteId %d RefCount %d\n", pCounterEntry, pCounterEntry->Counters.SiteId, pCounterEntry->RefCount )); pEntry = pEntry->Flink; } End: return; #endif // DBG } /////////////////////////////////////////////////////////////////////////////// // Site Counter Entry // /***************************************************************************++ Routine Description: Creates a new site counter entry for the given SiteId. Arguments: SiteId - the site id for the site counters. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlCreateSiteCounterEntry( IN OUT PUL_CONFIG_GROUP_OBJECT pConfigGroup, ULONG SiteId ) { NTSTATUS Status; PUL_SITE_COUNTER_ENTRY pNewEntry; // // Sanity check. // PAGED_CODE(); ASSERT( pConfigGroup != NULL ); // // Setup locals so we know how to cleanup on exit. // Status = STATUS_SUCCESS; // // [debug only] Check to see if the SiteId is already // in the list of existing Site Counter Entries. // ASSERT(!UlpIsInSiteCounterList(SiteId)); // Alloc new struct w/space from Non Paged Pool pNewEntry = UL_ALLOCATE_STRUCT( NonPagedPool, UL_SITE_COUNTER_ENTRY, UL_SITE_COUNTER_ENTRY_POOL_TAG); if (pNewEntry) { UlTrace( PERF_COUNTERS, ("http!UlCreateSiteCounterEntry: pNewEntry %p, pConfigGroup %p, SiteId %d\n", pNewEntry, pConfigGroup, SiteId ) ); pNewEntry->Signature = UL_SITE_COUNTER_ENTRY_POOL_TAG; pNewEntry->RefCount = 1; // Zero out counters RtlZeroMemory(&(pNewEntry->Counters), sizeof(HTTP_SITE_COUNTERS)); // Set Site ID pNewEntry->Counters.SiteId = SiteId; // Init Counter Mutex ExInitializeFastMutex(&(pNewEntry->EntryMutex)); // Add to Site Counter List ExAcquireFastMutex(&g_SiteCounterListMutex); InsertTailList( &g_SiteCounterListHead, &(pNewEntry->ListEntry) ); g_SiteCounterListCount++; ExReleaseFastMutex(&g_SiteCounterListMutex); // Check for wrap-around of Site List count. ASSERT( 0 != g_SiteCounterListCount ); } else { UlTrace( PERF_COUNTERS, ("http!UlCreateSiteCounterEntry: Error: NO_MEMORY pConfigGroup %p, SiteId %d\n", pNewEntry, pConfigGroup, SiteId ) ); Status = STATUS_NO_MEMORY; } pConfigGroup->pSiteCounters = pNewEntry; RETURN( Status ); } #if REFERENCE_DEBUG /***************************************************************************++ Routine Description: increments the refcount. Arguments: pEntry - the object to increment. Return Value: NTSTATUS - Completion status. --***************************************************************************/ VOID UlReferenceSiteCounterEntry( IN PUL_SITE_COUNTER_ENTRY pEntry REFERENCE_DEBUG_FORMAL_PARAMS ) { LONG refCount; // // Sanity check. // PAGED_CODE(); ASSERT( IS_VALID_SITE_COUNTER_ENTRY(pEntry) ); refCount = InterlockedIncrement( &pEntry->RefCount ); // // Tracing. // WRITE_REF_TRACE_LOG( g_pSiteCounterTraceLog, REF_ACTION_REFERENCE_SITE_COUNTER_ENTRY, refCount, pEntry, pFileName, LineNumber ); UlTrace( REFCOUNT, ("http!UlReferenceSiteCounterEntry pEntry=%p refcount=%d SiteId=%d\n", pEntry, refCount, pEntry->Counters.SiteId) ); } // UlReferenceAppPool /***************************************************************************++ Routine Description: decrements the refcount. if it hits 0, destruct's the site counter entry block. Arguments: pEntry - the object to decrement. Return Value: NTSTATUS - Completion status. --***************************************************************************/ VOID UlDereferenceSiteCounterEntry( IN PUL_SITE_COUNTER_ENTRY pEntry REFERENCE_DEBUG_FORMAL_PARAMS ) { LONG refCount; NTSTATUS Status; // // Sanity check. // PAGED_CODE(); ASSERT( IS_VALID_SITE_COUNTER_ENTRY(pEntry) ); refCount = InterlockedDecrement( &pEntry->RefCount ); // // Tracing. // WRITE_REF_TRACE_LOG( g_pSiteCounterTraceLog, REF_ACTION_DEREFERENCE_SITE_COUNTER_ENTRY, refCount, pEntry, pFileName, LineNumber ); UlTrace( REFCOUNT, ("http!UlDereferenceSiteCounter pEntry=%p refcount=%d SiteId=%d\n", pEntry, refCount, pEntry->Counters.SiteId) ); // // Remove from the list if we hit zero // if (refCount == 0) { ASSERT( 0 != g_SiteCounterListCount ); UlTrace( PERF_COUNTERS, ("http!UlDereferenceSiteCounter: Removing pEntry=%p SiteId=%d\n", pEntry, pEntry->Counters.SiteId) ); // Remove from list ExAcquireFastMutex(&g_SiteCounterListMutex); RemoveEntryList(&pEntry->ListEntry); pEntry->ListEntry.Flink = pEntry->ListEntry.Blink = NULL; g_SiteCounterListCount--; ExReleaseFastMutex(&g_SiteCounterListMutex); // Release memory UL_FREE_POOL_WITH_SIG(pEntry, UL_SITE_COUNTER_ENTRY_POOL_TAG); } } #endif /////////////////////////////////////////////////////////////////////////////// // Collection // /***************************************************************************++ Routine Description: Gets the Global (cache) counters. Arguments: pCounter - pointer to block of memory where the counter data should be written. BlockSize - Maximum size available at pCounter. pBytesWritten - On success, count of bytes written into the block of memory at pCounter. On failure, the required count of bytes for the memory at pCounter. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlGetGlobalCounters( PVOID IN OUT pCounter, ULONG IN BlockSize, PULONG OUT pBytesWritten ) { ULONG i; PAGED_CODE(); ASSERT( pBytesWritten ); UlTraceVerbose(PERF_COUNTERS, ("http!UlGetGlobalCounters\n")); if (BlockSize < sizeof(HTTP_GLOBAL_COUNTERS)) { // // Tell the caller how many bytes are required. // *pBytesWritten = sizeof(HTTP_GLOBAL_COUNTERS); RETURN( STATUS_BUFFER_TOO_SMALL ); } RtlCopyMemory( pCounter, &g_UlGlobalCounters, sizeof(g_UlGlobalCounters) ); // // Zero out any counters that must be zeroed. // for ( i = 0; i < HttpGlobalCounterMaximum; i++ ) { if (TRUE == aIISULGlobalDescription[i].WPZeros) { // Zero it out UlResetCounter((HTTP_GLOBAL_COUNTER_ID) i); } } *pBytesWritten = sizeof(HTTP_GLOBAL_COUNTERS); RETURN( STATUS_SUCCESS ); } // UlpGetGlobalCounters /***************************************************************************++ Routine Description: Gets the Site (instance) counters for all sites Arguments: pCounter - pointer to block of memory where the counter data should be written. BlockSize - Maximum size available at pCounter. pBytesWritten - On success, count of bytes written into the block of memory at pCounter. On failure, the required count of bytes for the memory at pCounter. pBlocksWritten - (optional) On success, count of site counter blocks written to pCounter. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlGetSiteCounters( PVOID IN OUT pCounter, ULONG IN BlockSize, PULONG OUT pBytesWritten, PULONG OUT pBlocksWritten OPTIONAL ) { NTSTATUS Status; ULONG i; ULONG BytesNeeded; ULONG BytesToGo; ULONG BlocksSeen; PUCHAR pBlock; PLIST_ENTRY pEntry; PUL_SITE_COUNTER_ENTRY pCounterEntry; PAGED_CODE(); ASSERT( pBytesWritten ); UlTraceVerbose(PERF_COUNTERS, ("http!UlGetSiteCounters\n")); // // Setup locals so we know how to cleanup on exit. // Status = STATUS_SUCCESS; BytesToGo = BlockSize; BlocksSeen = 0; pBlock = (PUCHAR) pCounter; BytesNeeded = g_SiteCounterListCount * sizeof(HTTP_SITE_COUNTERS); if (BytesNeeded > BlockSize) { // Need more space *pBytesWritten = BytesNeeded; Status = STATUS_BUFFER_TOO_SMALL; goto End; } if (IsListEmpty(&g_SiteCounterListHead)) { // No counters to return. goto End; } // // NOTE: g_SiteCounterListHead is the only member of // the list which isn't contained within a UL_SITE_COUNTER_ENTRY. // pEntry = g_SiteCounterListHead.Flink; // // Walk list of Site Counter Entries // while (pEntry != &g_SiteCounterListHead) { pCounterEntry = CONTAINING_RECORD( pEntry, UL_SITE_COUNTER_ENTRY, ListEntry ); if (BytesToGo < sizeof(HTTP_SITE_COUNTERS)) { // NOTE: the only way this can happen is if someone // added a site to the end of the site list before // we finished walking the counter list. *pBytesWritten = BlockSize + sizeof(HTTP_SITE_COUNTERS); Status = STATUS_BUFFER_TOO_SMALL; goto End; } RtlCopyMemory(pBlock, &(pCounterEntry->Counters), sizeof(HTTP_SITE_COUNTERS) ); // // Zero out any counters that must be zeroed. // for ( i = 0; i < HttpSiteCounterMaximum; i++ ) { if (TRUE == aIISULSiteDescription[i].WPZeros) { // Zero it out UlResetSiteCounter(pCounterEntry, (HTTP_SITE_COUNTER_ID) i); } } // // Continue to next block // pBlock += sizeof(HTTP_SITE_COUNTERS); BytesToGo -= sizeof(HTTP_SITE_COUNTERS); BlocksSeen++; pEntry = pEntry->Flink; } End: // // Set callers values // if (STATUS_SUCCESS == Status) { // REVIEW: If we failed, *pBytesWritten already contains // the bytes required value. *pBytesWritten = DIFF(pBlock - ((PUCHAR)pCounter)); } if (pBlocksWritten) { *pBlocksWritten = BlocksSeen; } RETURN( Status ); } // UlpGetSiteCounters #if REFERENCE_DEBUG /////////////////////////////////////////////////////////////////////////////// // Global Counter functions // /***************************************************************************++ Routine Description: Increment a Global (cache) performance counter. Arguments: Ctr - ID of Counter to increment --***************************************************************************/ VOID UlIncCounter( HTTP_GLOBAL_COUNTER_ID Ctr ) { PCHAR pCtr; ASSERT( g_InitCountersCalled ); ASSERT( Ctr < HttpGlobalCounterMaximum ); // REVIEW: signed/unsigned issues? UlTraceVerbose( PERF_COUNTERS, ("http!UlIncCounter (Ctr == %d)\n", Ctr) ); // // figure out offset of Ctr in g_UlGlobalCounters // pCtr = (PCHAR) &g_UlGlobalCounters; pCtr += aIISULGlobalDescription[Ctr].Offset; // figure out data size of Ctr and do // apropriate thread-safe increment if (sizeof(ULONG) == aIISULGlobalDescription[Ctr].Size) { // ULONG InterlockedIncrement((PLONG) pCtr); } else { // ULONGLONG UlInterlockedIncrement64((PLONGLONG) pCtr); } } // UlIncCounter /***************************************************************************++ Routine Description: Decrement a Global (cache) performance counter. Arguments: Ctr - ID of Counter to decrement --***************************************************************************/ VOID UlDecCounter( HTTP_GLOBAL_COUNTER_ID Ctr ) { PCHAR pCtr; ASSERT( g_InitCountersCalled ); ASSERT( Ctr < HttpGlobalCounterMaximum ); // REVIEW: signed/unsigned issues? UlTraceVerbose( PERF_COUNTERS, ("http!UlDecCounter (Ctr == %d)\n", Ctr)); // // figure out offset of Ctr in g_UlGlobalCounters // pCtr = (PCHAR) &g_UlGlobalCounters; pCtr += aIISULGlobalDescription[Ctr].Offset; // figure out data size of Ctr and do // apropriate thread-safe increment if (sizeof(ULONG) == aIISULGlobalDescription[Ctr].Size) { // ULONG InterlockedDecrement((PLONG) pCtr); } else { // ULONGLONG UlInterlockedDecrement64((PLONGLONG) pCtr); } } /***************************************************************************++ Routine Description: Add a ULONG value to a Global (cache) performance counter. Arguments: Ctr - ID of counter to which the Value should be added Value - The amount to add to the counter --***************************************************************************/ VOID UlAddCounter( HTTP_GLOBAL_COUNTER_ID Ctr, ULONG Value ) { PCHAR pCtr; ASSERT( g_InitCountersCalled ); ASSERT( Ctr < HttpGlobalCounterMaximum ); // REVIEW: signed/unsigned issues? UlTraceVerbose( PERF_COUNTERS, ("http!UlAddCounter (Ctr == %d, Value == %d)\n", Ctr, Value)); // // figure out offset of Ctr in g_UlGlobalCounters // pCtr = (PCHAR) &g_UlGlobalCounters; pCtr += aIISULGlobalDescription[Ctr].Offset; // // figure out data size of Ctr and do // apropriate thread-safe increment // if (sizeof(ULONG) == aIISULGlobalDescription[Ctr].Size) { // ULONG InterlockedExchangeAdd((PLONG) pCtr, Value); } else { // ULONGLONG UlInterlockedAdd64((PLONGLONG) pCtr, Value); } } // UlAddCounter /***************************************************************************++ Routine Description: Zero-out a Global (cache) performance counter. Arguments: Ctr - ID of Counter to be reset. --***************************************************************************/ VOID UlResetCounter( HTTP_GLOBAL_COUNTER_ID Ctr ) { // Special Case PCHAR pCtr; ASSERT( g_InitCountersCalled ); ASSERT( Ctr < HttpGlobalCounterMaximum ); // REVIEW: signed/unsigned issues? UlTraceVerbose(PERF_COUNTERS, ("http!UlResetCounter (Ctr == %d)\n", Ctr)); // // figure out offset of Ctr in g_UlGlobalCounters // pCtr = (PCHAR) &g_UlGlobalCounters; pCtr += aIISULGlobalDescription[Ctr].Offset; // // do apropriate "set" for data size of Ctr // if (sizeof(ULONG) == aIISULGlobalDescription[Ctr].Size) { // ULONG InterlockedExchange((PLONG) pCtr, 0); } else { // ULONGLONG LONGLONG localCtr; LONGLONG originalCtr; LONGLONG localZero = 0; do { localCtr = *((volatile LONGLONG *) pCtr); originalCtr = InterlockedCompareExchange64( (PLONGLONG) pCtr, localZero, localCtr ); } while (originalCtr != localCtr); } } // UlResetCounter /////////////////////////////////////////////////////////////////////////////// // Site Counter functions // /***************************************************************************++ Routine Description: Increment a NonCritical Site performance counter. Arguments: pEntry - pointer to Site Counter entry CounterId - ID of Counter to increment Returns: Nothing --***************************************************************************/ VOID UlIncSiteNonCriticalCounterUlong( PUL_SITE_COUNTER_ENTRY pEntry, HTTP_SITE_COUNTER_ID CounterId ) { PCHAR pCounter; PLONG plValue; pCounter = (PCHAR) &(pEntry->Counters); pCounter += aIISULSiteDescription[CounterId].Offset; plValue = (PLONG) pCounter; ++(*plValue); } /***************************************************************************++ Routine Description: Increment a NonCritical Site performance counter. Arguments: pEntry - pointer to Site Counter entry CounterId - ID of Counter to increment Returns: Nothing --***************************************************************************/ VOID UlIncSiteNonCriticalCounterUlonglong( PUL_SITE_COUNTER_ENTRY pEntry, HTTP_SITE_COUNTER_ID CounterId ) { PCHAR pCounter; PLONGLONG pllValue; pCounter = (PCHAR) &(pEntry->Counters); pCounter += aIISULSiteDescription[CounterId].Offset; pllValue = (PLONGLONG) pCounter; ++(*pllValue); } /***************************************************************************++ Routine Description: Increment a Site performance counter. Arguments: pEntry - pointer to Site Counter entry Ctr - ID of Counter to increment Returns: Value of counter after incrementing --***************************************************************************/ LONGLONG UlIncSiteCounter( PUL_SITE_COUNTER_ENTRY pEntry, HTTP_SITE_COUNTER_ID Ctr ) { PCHAR pCtr; LONGLONG llValue; ASSERT( g_InitCountersCalled ); ASSERT( Ctr < HttpSiteCounterMaximum ); // REVIEW: signed/unsigned issues? ASSERT( IS_VALID_SITE_COUNTER_ENTRY(pEntry) ); UlTraceVerbose( PERF_COUNTERS, ("http!UlIncSiteCounter Ctr=%d SiteId=%d\n", Ctr, pEntry->Counters.SiteId )); // // figure out offset of Ctr in HTTP_SITE_COUNTERS // pCtr = (PCHAR) &(pEntry->Counters); pCtr += aIISULSiteDescription[Ctr].Offset; // figure out data size of Ctr and do // apropriate thread-safe increment if (sizeof(ULONG) == aIISULSiteDescription[Ctr].Size) { // ULONG llValue = (LONGLONG) InterlockedIncrement((PLONG) pCtr); } else { // ULONGLONG llValue = UlInterlockedIncrement64((PLONGLONG) pCtr); } return llValue; } /***************************************************************************++ Routine Description: Decrement a Site performance counter. Arguments: pEntry - pointer to Site Counter entry Ctr - ID of Counter to decrement --***************************************************************************/ VOID UlDecSiteCounter( PUL_SITE_COUNTER_ENTRY pEntry, HTTP_SITE_COUNTER_ID Ctr ) { PCHAR pCtr; ASSERT( g_InitCountersCalled ); ASSERT( Ctr < HttpSiteCounterMaximum ); // REVIEW: signed/unsigned issues? ASSERT( IS_VALID_SITE_COUNTER_ENTRY(pEntry) ); UlTraceVerbose( PERF_COUNTERS, ("http!UlDecSiteCounter Ctr=%d SiteId=%d\n", Ctr, pEntry->Counters.SiteId )); // // figure out offset of Ctr in HTTP_SITE_COUNTERS // pCtr = (PCHAR) &(pEntry->Counters); pCtr += aIISULSiteDescription[Ctr].Offset; // figure out data size of Ctr and do // apropriate thread-safe increment if (sizeof(ULONG) == aIISULSiteDescription[Ctr].Size) { // ULONG InterlockedDecrement((PLONG) pCtr); } else { // ULONGLONG UlInterlockedDecrement64((PLONGLONG) pCtr); } } /***************************************************************************++ Routine Description: Add a ULONG value to a 32-bit site performance counter. Arguments: pEntry - pointer to Site Counter entry Ctr - ID of counter to which the Value should be added Value - The amount to add to the counter --***************************************************************************/ VOID UlAddSiteCounter( PUL_SITE_COUNTER_ENTRY pEntry, HTTP_SITE_COUNTER_ID Ctr, ULONG Value ) { PCHAR pCtr; ASSERT( g_InitCountersCalled ); ASSERT( Ctr < HttpSiteCounterMaximum ); // REVIEW: signed/unsigned issues? ASSERT( IS_VALID_SITE_COUNTER_ENTRY(pEntry) ); UlTraceVerbose( PERF_COUNTERS, ("http!UlAddSiteCounter Ctr=%d SiteId=%d Value=%d\n", Ctr, pEntry->Counters.SiteId, Value )); // // figure out offset of Ctr in HTTP_SITE_COUNTERS // pCtr = (PCHAR) &(pEntry->Counters); pCtr += aIISULSiteDescription[Ctr].Offset; // figure out data size of Ctr and do // apropriate thread-safe increment ASSERT(sizeof(ULONG) == aIISULSiteDescription[Ctr].Size); InterlockedExchangeAdd((PLONG) pCtr, Value); } /***************************************************************************++ Routine Description: Add a ULONGLONG value to a 64-bit site performance counter. Arguments: pEntry - pointer to Site Counter entry Ctr - ID of counter to which the Value should be added Value - The amount to add to the counter --***************************************************************************/ VOID UlAddSiteCounter64( PUL_SITE_COUNTER_ENTRY pEntry, HTTP_SITE_COUNTER_ID Ctr, ULONGLONG llValue ) { PCHAR pCtr; ASSERT( g_InitCountersCalled ); ASSERT( Ctr < HttpSiteCounterMaximum ); // REVIEW: signed/unsigned issues? ASSERT( IS_VALID_SITE_COUNTER_ENTRY(pEntry) ); UlTraceVerbose( PERF_COUNTERS, ("http!UlAddSiteCounter64 Ctr=%d SiteId=%d Value=%I64d\n", Ctr, pEntry->Counters.SiteId, llValue )); // // figure out offset of Ctr in HTTP_SITE_COUNTERS // pCtr = (PCHAR) &(pEntry->Counters); pCtr += aIISULSiteDescription[Ctr].Offset; ASSERT(sizeof(ULONGLONG) == aIISULSiteDescription[Ctr].Size); UlInterlockedAdd64((PLONGLONG) pCtr, llValue); } /***************************************************************************++ Routine Description: Reset a Site performance counter. Arguments: pEntry - pointer to Site Counter entry Ctr - ID of counter to be reset --***************************************************************************/ VOID UlResetSiteCounter( PUL_SITE_COUNTER_ENTRY pEntry, HTTP_SITE_COUNTER_ID Ctr ) { PCHAR pCtr; ASSERT( g_InitCountersCalled ); ASSERT( Ctr < HttpSiteCounterMaximum ); // REVIEW: signed/unsigned issues? ASSERT( IS_VALID_SITE_COUNTER_ENTRY(pEntry) ); UlTraceVerbose( PERF_COUNTERS, ("http!UlResetSiteCounter Ctr=%d SiteId=%d\n", Ctr, pEntry->Counters.SiteId )); // // figure out offset of Ctr in HTTP_SITE_COUNTERS // pCtr = (PCHAR) &(pEntry->Counters); pCtr += aIISULSiteDescription[Ctr].Offset; // // do apropriate "set" for data size of Ctr // if (sizeof(ULONG) == aIISULSiteDescription[Ctr].Size) { // ULONG InterlockedExchange((PLONG) pCtr, 0); } else { // ULONGLONG LONGLONG localCtr; LONGLONG originalCtr; LONGLONG localZero = 0; do { localCtr = *((volatile LONGLONG *) pCtr); originalCtr = InterlockedCompareExchange64( (PLONGLONG) pCtr, localZero, localCtr ); } while (originalCtr != localCtr); } } /***************************************************************************++ Routine Description: Determine if a new maximum value of a Site performance counter has been hit and set the counter to the new maximum if necessary. (ULONG version) Arguments: pEntry - pointer to Site Counter entry Ctr - ID of counter Value - possible new maximum (NOTE: Assumes that the counter Ctr is a 32-bit value) --***************************************************************************/ VOID UlMaxSiteCounter( PUL_SITE_COUNTER_ENTRY pEntry, HTTP_SITE_COUNTER_ID Ctr, ULONG Value ) { PCHAR pCtr; ASSERT( g_InitCountersCalled ); ASSERT( Ctr < HttpSiteCounterMaximum ); // REVIEW: signed/unsigned issues? ASSERT( IS_VALID_SITE_COUNTER_ENTRY(pEntry) ); UlTraceVerbose( PERF_COUNTERS, ("http!UlMaxSiteCounter Ctr=%d SiteId=%d Value=%d\n", Ctr, pEntry->Counters.SiteId, Value )); // // figure out offset of Ctr in HTTP_SITE_COUNTERS // pCtr = (PCHAR) &(pEntry->Counters); pCtr += aIISULSiteDescription[Ctr].Offset; // Grab counter block mutex ExAcquireFastMutex(&pEntry->EntryMutex); if (Value > (ULONG) *pCtr) { InterlockedExchange((PLONG) pCtr, Value); } // Release counter block mutex ExReleaseFastMutex(&pEntry->EntryMutex); } /***************************************************************************++ Routine Description: Determine if a new maximum value of a Site performance counter has been hit and set the counter to the new maximum if necessary. (LONGLONG version) Arguments: pEntry - pointer to Site Counter entry Ctr - ID of counter Value - possible new maximum (NOTE: Assumes that the counter Ctr is a 64-bit value) --***************************************************************************/ VOID UlMaxSiteCounter64( PUL_SITE_COUNTER_ENTRY pEntry, HTTP_SITE_COUNTER_ID Ctr, LONGLONG llValue ) { PCHAR pCtr; ASSERT( g_InitCountersCalled ); ASSERT( Ctr < HttpSiteCounterMaximum ); // REVIEW: signed/unsigned issues? ASSERT( IS_VALID_SITE_COUNTER_ENTRY(pEntry) ); UlTraceVerbose( PERF_COUNTERS, ("http!UlMaxSiteCounter64 Ctr=%d SiteId=%d Value=%I64d\n", Ctr, pEntry->Counters.SiteId, llValue )); // // figure out offset of Ctr in HTTP_SITE_COUNTERS // pCtr = (PCHAR) &(pEntry->Counters); pCtr += aIISULSiteDescription[Ctr].Offset; // Grab counter block mutex ExAcquireFastMutex(&pEntry->EntryMutex); if (llValue > (LONGLONG) *pCtr) { *((PLONGLONG) pCtr) = llValue; #if 0 // REVIEW: There *must* be a better way to do this... // REVIEW: I want to do: (LONGLONG) *pCtr = llValue; // REVIEW: But casting something seems to make it a constant. // REVIEW: Also, there isn't an "InterlockedExchange64" for x86. // REVIEW: Any suggestions? --EricSten RtlCopyMemory( pCtr, &llValue, sizeof(LONGLONG) ); #endif // 0 } // Release counter block mutex ExReleaseFastMutex(&pEntry->EntryMutex); } #endif /***************************************************************************++ Routine Description: Predicate to test if a site counter entry already exists for the given SiteId Arguments: SiteId - ID of site Return Value: TRUE if found FALSE if not found --***************************************************************************/ BOOLEAN UlpIsInSiteCounterList(ULONG SiteId) { PLIST_ENTRY pEntry; PUL_SITE_COUNTER_ENTRY pCounterEntry; BOOLEAN IsFound = FALSE; if (IsListEmpty(&g_SiteCounterListHead)) { ASSERT(0 == g_SiteCounterListCount); // Good! No counters left behind! goto End; } // // Walk list of Site Counter Entries // pEntry = g_SiteCounterListHead.Flink; while (pEntry != &g_SiteCounterListHead) { pCounterEntry = CONTAINING_RECORD( pEntry, UL_SITE_COUNTER_ENTRY, ListEntry ); ASSERT(IS_VALID_SITE_COUNTER_ENTRY(pCounterEntry)); if (SiteId == pCounterEntry->Counters.SiteId) { IsFound = TRUE; goto End; } pEntry = pEntry->Flink; } End: return IsFound; }