/*++ Copyright (c) 1998-2002 Microsoft Corporation Module Name: counters.h Abstract: Contains the performance monitoring counter management function declarations Author: Eric Stenson (ericsten) 25-Sep-2000 Revision History: --*/ #ifndef __COUNTERS_H__ #define __COUNTERS_H__ // // structure to hold info for Site Counters. // typedef struct _UL_SITE_COUNTER_ENTRY { // // Signature is UL_SITE_COUNTER_ENTRY_POOL_TAG // ULONG Signature; // // Ref count for this Site Counter Entry // LONG RefCount; // // links Control Channel site counter entries // LIST_ENTRY ListEntry; // // links Global site counter entries // LIST_ENTRY GlobalListEntry; // // Lock protets counter data; used primarily when touching // 64-bit counters and reading counters // FAST_MUTEX EntryMutex; // // the block which actually contains the counter data to be // passed back to WAS // HTTP_SITE_COUNTERS Counters; } UL_SITE_COUNTER_ENTRY, *PUL_SITE_COUNTER_ENTRY; #define IS_VALID_SITE_COUNTER_ENTRY( entry ) \ HAS_VALID_SIGNATURE(entry, UL_SITE_COUNTER_ENTRY_POOL_TAG) // // Private globals // extern BOOLEAN g_InitCountersCalled; extern HTTP_GLOBAL_COUNTERS g_UlGlobalCounters; extern FAST_MUTEX g_SiteCounterListMutex; extern LIST_ENTRY g_SiteCounterListHead; extern LONG g_SiteCounterListCount; extern HTTP_PROP_DESC aIISULGlobalDescription[]; extern HTTP_PROP_DESC aIISULSiteDescription[]; // // Init // NTSTATUS UlInitializeCounters( VOID ); VOID UlTerminateCounters( VOID ); // // Site Counter Entry // NTSTATUS UlCreateSiteCounterEntry( IN OUT PUL_CONFIG_GROUP_OBJECT pConfigGroup, IN ULONG SiteId ); // // DO NOT CALL THESE REF FUNCTIONS DIRECTLY: // These are the backing implementations; use the // REFERENCE_*/DEREFERENCE_* macros instead. // __inline LONG UlReferenceSiteCounterEntry( IN PUL_SITE_COUNTER_ENTRY pEntry ) { return InterlockedIncrement(&pEntry->RefCount); } __inline LONG UlDereferenceSiteCounterEntry( IN PUL_SITE_COUNTER_ENTRY pEntry ) { LONG ref; ref = InterlockedDecrement(&pEntry->RefCount); if ( 0 == ref ) { // // Remove from Site Counter List(s) // ExAcquireFastMutex(&g_SiteCounterListMutex); // we should already be removed from the control channel's list ASSERT(NULL == pEntry->ListEntry.Flink); RemoveEntryList(&(pEntry->GlobalListEntry)); pEntry->GlobalListEntry.Flink = pEntry->GlobalListEntry.Blink = NULL; g_SiteCounterListCount--; ExReleaseFastMutex(&g_SiteCounterListMutex); UL_FREE_POOL_WITH_SIG(pEntry, UL_SITE_COUNTER_ENTRY_POOL_TAG); } return ref; } // UlDereferenceSiteCounterEntry #if REFERENCE_DEBUG VOID UlDbgDereferenceSiteCounterEntry( IN PUL_SITE_COUNTER_ENTRY pEntry REFERENCE_DEBUG_FORMAL_PARAMS ); #define DEREFERENCE_SITE_COUNTER_ENTRY( pSC ) \ UlDbgDereferenceSiteCounterEntry( \ (pSC) \ REFERENCE_DEBUG_ACTUAL_PARAMS \ ) VOID UlDbgReferenceSiteCounterEntry( IN PUL_SITE_COUNTER_ENTRY pEntry REFERENCE_DEBUG_FORMAL_PARAMS ); #define REFERENCE_SITE_COUNTER_ENTRY( pSC ) \ UlDbgReferenceSiteCounterEntry( \ (pSC) \ REFERENCE_DEBUG_ACTUAL_PARAMS \ ) #else #define REFERENCE_SITE_COUNTER_ENTRY (VOID)UlReferenceSiteCounterEntry #define DEREFERENCE_SITE_COUNTER_ENTRY (VOID)UlDereferenceSiteCounterEntry #endif /*++ Routine Description: Removes Site Counter from UL_CONFIG_GROUP_OBJECT, removing it fromt the Control Channel's Site Counter List. Object should remain on Global list if there are still references Arguments: pConfigGroup - the UL_CONFIG_GROUP_OBJECT from which we should decouple the UL_SITE_COUNTER_ENTRY --*/ __inline VOID UlDecoupleSiteCounterEntry( IN PUL_CONFIG_GROUP_OBJECT pConfigGroup ) { ASSERT(IS_VALID_CONFIG_GROUP(pConfigGroup)); ASSERT(IS_VALID_CONTROL_CHANNEL(pConfigGroup->pControlChannel)); if (pConfigGroup->pSiteCounters) { // Remove from Control Channel's list ExAcquireFastMutex(&g_SiteCounterListMutex); RemoveEntryList(&pConfigGroup->pSiteCounters->ListEntry); pConfigGroup->pSiteCounters->ListEntry.Flink = NULL; pConfigGroup->pSiteCounters->ListEntry.Blink = NULL; pConfigGroup->pControlChannel->SiteCounterCount--; ExReleaseFastMutex(&g_SiteCounterListMutex); // Remove Config Group's reference outside of Mutex : we // might take ref to 0 and need to remove from Global // Site Counter list DEREFERENCE_SITE_COUNTER_ENTRY(pConfigGroup->pSiteCounters); pConfigGroup->pSiteCounters = NULL; } } // // Global (cache) counters // __inline VOID UlIncCounterRtl( IN HTTP_GLOBAL_COUNTER_ID CounterId ) { PCHAR pCounter; pCounter = (PCHAR)&g_UlGlobalCounters; pCounter += aIISULGlobalDescription[CounterId].Offset; if (sizeof(ULONG) == aIISULGlobalDescription[CounterId].Size) { InterlockedIncrement((PLONG)pCounter); } else { UlInterlockedIncrement64((PLONGLONG)pCounter); } } __inline VOID UlDecCounterRtl( IN HTTP_GLOBAL_COUNTER_ID CounterId ) { PCHAR pCounter; pCounter = (PCHAR)&g_UlGlobalCounters; pCounter += aIISULGlobalDescription[CounterId].Offset; if (sizeof(ULONG) == aIISULGlobalDescription[CounterId].Size) { InterlockedDecrement((PLONG)pCounter); } else { UlInterlockedDecrement64((PLONGLONG)pCounter); } } __inline VOID UlAddCounterRtl( IN HTTP_GLOBAL_COUNTER_ID CounterId, IN ULONG Value ) { PCHAR pCounter; pCounter = (PCHAR)&g_UlGlobalCounters; pCounter += aIISULGlobalDescription[CounterId].Offset; if (sizeof(ULONG) == aIISULGlobalDescription[CounterId].Size) { InterlockedExchangeAdd((PLONG)pCounter, Value); } else { UlInterlockedAdd64((PLONGLONG)pCounter, Value); } } __inline VOID UlResetCounterRtl( IN HTTP_GLOBAL_COUNTER_ID CounterId ) { PCHAR pCounter; pCounter = (PCHAR)&g_UlGlobalCounters; pCounter += aIISULGlobalDescription[CounterId].Offset; if (sizeof(ULONG) == aIISULGlobalDescription[CounterId].Size) { InterlockedExchange((PLONG)pCounter, 0); } else { UlInterlockedExchange64((PLONGLONG)pCounter, 0); } } #if DBG VOID UlIncCounterDbg( HTTP_GLOBAL_COUNTER_ID Ctr ); VOID UlDecCounterDbg( HTTP_GLOBAL_COUNTER_ID Ctr ); VOID UlAddCounterDbg( HTTP_GLOBAL_COUNTER_ID Ctr, ULONG Value ); VOID UlResetCounterDbg( HTTP_GLOBAL_COUNTER_ID Ctr ); #define UlIncCounter UlIncCounterDbg #define UlDecCounter UlDecCounterDbg #define UlAddCounter UlAddCounterDbg #define UlResetCounter UlResetCounterDbg #else // DBG #define UlIncCounter UlIncCounterRtl #define UlDecCounter UlDecCounterRtl #define UlAddCounter UlAddCounterRtl #define UlResetCounter UlResetCounterRtl #endif // DBG // // Instance (site) counters // __inline 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); } __inline 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); } // // NOTE: DO NOT CALL *Rtl vesrions directly! // __inline LONGLONG UlIncSiteCounterRtl( IN PUL_SITE_COUNTER_ENTRY pEntry, IN HTTP_SITE_COUNTER_ID CounterId ) { PCHAR pCounter; pCounter = (PCHAR)&pEntry->Counters; pCounter += aIISULSiteDescription[CounterId].Offset; switch(aIISULSiteDescription[CounterId].Size) { case sizeof(ULONG): return (LONGLONG)InterlockedIncrement((PLONG)pCounter); case sizeof(LONGLONG): return UlInterlockedIncrement64((PLONGLONG)pCounter); default: ASSERT(!"UlIncSiteCounterRtl: ERROR: Invalid counter size!\n"); } return 0L; } __inline VOID UlDecSiteCounterRtl( IN PUL_SITE_COUNTER_ENTRY pEntry, IN HTTP_SITE_COUNTER_ID CounterId ) { PCHAR pCounter; pCounter = (PCHAR)&pEntry->Counters; pCounter += aIISULSiteDescription[CounterId].Offset; switch(aIISULSiteDescription[CounterId].Size) { case sizeof(ULONG): InterlockedDecrement((PLONG)pCounter); break; case sizeof(ULONGLONG): UlInterlockedDecrement64((PLONGLONG)pCounter); break; default: ASSERT(!"UlDecSiteCounterRtl: ERROR: Invalid counter size!\n"); } } __inline VOID UlAddSiteCounterRtl( IN PUL_SITE_COUNTER_ENTRY pEntry, IN HTTP_SITE_COUNTER_ID CounterId, IN ULONG Value ) { PCHAR pCounter; pCounter = (PCHAR)&pEntry->Counters; pCounter += aIISULSiteDescription[CounterId].Offset; InterlockedExchangeAdd((PLONG)pCounter, Value); } __inline VOID UlAddSiteCounter64Rtl( IN PUL_SITE_COUNTER_ENTRY pEntry, IN HTTP_SITE_COUNTER_ID CounterId, IN ULONGLONG Value ) { PCHAR pCounter; pCounter = (PCHAR)&pEntry->Counters; pCounter += aIISULSiteDescription[CounterId].Offset; UlInterlockedAdd64((PLONGLONG)pCounter, Value); } __inline VOID UlResetSiteCounterRtl( IN PUL_SITE_COUNTER_ENTRY pEntry, IN HTTP_SITE_COUNTER_ID CounterId ) { PCHAR pCounter; pCounter = (PCHAR)&pEntry->Counters; pCounter += aIISULSiteDescription[CounterId].Offset; switch(aIISULSiteDescription[CounterId].Size) { case sizeof(ULONG): InterlockedExchange((PLONG)pCounter, 0); break; case sizeof(ULONGLONG): UlInterlockedExchange64((PLONGLONG)pCounter, 0); break; default: ASSERT(!"UlResetSiteCounterRtl: ERROR: Invalid counter size!\n"); } } __inline VOID UlMaxSiteCounterRtl( IN PUL_SITE_COUNTER_ENTRY pEntry, IN HTTP_SITE_COUNTER_ID CounterId, IN ULONG Value ) { PCHAR pCounter; LONG LocalMaxed; pCounter = (PCHAR)&pEntry->Counters; pCounter += aIISULSiteDescription[CounterId].Offset; do { LocalMaxed = *((volatile LONG *)pCounter); if ((LONG)Value <= LocalMaxed) { break; } PAUSE_PROCESSOR; } while (LocalMaxed != InterlockedCompareExchange( (PLONG)pCounter, Value, LocalMaxed )); } __inline VOID UlMaxSiteCounter64Rtl( IN PUL_SITE_COUNTER_ENTRY pEntry, IN HTTP_SITE_COUNTER_ID CounterId, IN LONGLONG Value ) { PCHAR pCounter; LONGLONG LocalMaxed; pCounter = (PCHAR)&pEntry->Counters; pCounter += aIISULSiteDescription[CounterId].Offset; do { LocalMaxed = *((volatile LONGLONG *)pCounter); if (Value <= LocalMaxed) { break; } PAUSE_PROCESSOR; } while (LocalMaxed != InterlockedCompareExchange64( (PLONGLONG)pCounter, Value, LocalMaxed )); } #if DBG LONGLONG UlIncSiteCounterDbg( PUL_SITE_COUNTER_ENTRY pEntry, HTTP_SITE_COUNTER_ID Ctr ); VOID UlDecSiteCounterDbg( PUL_SITE_COUNTER_ENTRY pEntry, HTTP_SITE_COUNTER_ID Ctr ); VOID UlAddSiteCounterDbg( PUL_SITE_COUNTER_ENTRY pEntry, HTTP_SITE_COUNTER_ID Ctr, ULONG Value ); VOID UlAddSiteCounter64Dbg( PUL_SITE_COUNTER_ENTRY pEntry, HTTP_SITE_COUNTER_ID Ctr, ULONGLONG llValue ); VOID UlResetSiteCounterDbg( PUL_SITE_COUNTER_ENTRY pEntry, HTTP_SITE_COUNTER_ID Ctr ); VOID UlMaxSiteCounterDbg( PUL_SITE_COUNTER_ENTRY pEntry, HTTP_SITE_COUNTER_ID Ctr, ULONG Value ); VOID UlMaxSiteCounter64Dbg( PUL_SITE_COUNTER_ENTRY pEntry, HTTP_SITE_COUNTER_ID Ctr, LONGLONG llValue ); #define UlIncSiteCounter UlIncSiteCounterDbg #define UlDecSiteCounter UlDecSiteCounterDbg #define UlAddSiteCounter UlAddSiteCounterDbg #define UlAddSiteCounter64 UlAddSiteCounter64Dbg #define UlResetSiteCounter UlResetSiteCounterDbg #define UlMaxSiteCounter UlMaxSiteCounterDbg #define UlMaxSiteCounter64 UlMaxSiteCounter64Dbg #else // !DBG #define UlIncSiteCounter UlIncSiteCounterRtl #define UlDecSiteCounter UlDecSiteCounterRtl #define UlAddSiteCounter UlAddSiteCounterRtl #define UlAddSiteCounter64 UlAddSiteCounter64Rtl #define UlResetSiteCounter UlResetSiteCounterRtl #define UlMaxSiteCounter UlMaxSiteCounterRtl #define UlMaxSiteCounter64 UlMaxSiteCounter64Rtl #endif // DBG // // Collection // NTSTATUS UlGetGlobalCounters( IN OUT PVOID pCounter, IN ULONG BlockSize, OUT PULONG pBytesWritten ); NTSTATUS UlGetSiteCounters( IN PUL_CONTROL_CHANNEL pControlChannel, IN OUT PVOID pCounter, IN ULONG BlockSize, OUT PULONG pBytesWritten, OUT PULONG pBlocksWritten OPTIONAL ); #endif // __COUNTERS_H__