/*++ Copyright (c) 2001-2001 Microsoft Corporation Module Name: ownerref.cxx Abstract: This module implements a reference count tracing facility. Author: Keith Moore (keithmo) 10-Jun-1998 Revision History: --*/ #include "precomp.h" // Globals LIST_ENTRY g_OwnerRefTraceLogGlobalListHead; UL_SPIN_LOCK g_OwnerRefTraceLogGlobalSpinLock; LONG g_OwnerRefTraceLogGlobalCount; VOID UlInitializeOwnerRefTraceLog( VOID) { InitializeListHead(&g_OwnerRefTraceLogGlobalListHead); UlInitializeSpinLock( &g_OwnerRefTraceLogGlobalSpinLock, "OwnerRefTraceLogGlobal" ); g_OwnerRefTraceLogGlobalCount = 0; } // UlInitializeOwnerRefTraceLog VOID UlTerminateOwnerRefTraceLog( VOID) { ASSERT( IsListEmpty(&g_OwnerRefTraceLogGlobalListHead) ); ASSERT( 0 == g_OwnerRefTraceLogGlobalCount ); } // UlTerminateOwnerRefTraceLog #if ENABLE_OWNER_REF_TRACE POWNER_REF_TRACELOG CreateOwnerRefTraceLog( IN ULONG LogSize, IN ULONG ExtraBytesInHeader ) { POWNER_REF_TRACELOG pOwnerRefTraceLog = NULL; PTRACE_LOG pTraceLog = CreateTraceLog( OWNER_REF_TRACELOG_SIGNATURE, LogSize, sizeof(OWNER_REF_TRACELOG) - FIELD_OFFSET(OWNER_REF_TRACELOG, OwnerHeader) + ExtraBytesInHeader, sizeof(OWNER_REF_TRACE_LOG_ENTRY) ); if (pTraceLog != NULL) { pOwnerRefTraceLog = (POWNER_REF_TRACELOG) pTraceLog; ASSERT(pOwnerRefTraceLog->TraceLog.TypeSignature == OWNER_REF_TRACELOG_SIGNATURE); InitializeListHead(&pOwnerRefTraceLog->OwnerHeader.ListHead); UlInitializeSpinLock( &pOwnerRefTraceLog->OwnerHeader.SpinLock, "OwnerRefTraceLog" ); pOwnerRefTraceLog->OwnerHeader.MonotonicId = 0; pOwnerRefTraceLog->OwnerHeader.OwnersCount = 0; // insert into global list ExInterlockedInsertTailList( &g_OwnerRefTraceLogGlobalListHead, &pOwnerRefTraceLog->OwnerHeader.GlobalListEntry, KSPIN_LOCK_FROM_UL_SPIN_LOCK(&g_OwnerRefTraceLogGlobalSpinLock) ); InterlockedIncrement(&g_OwnerRefTraceLogGlobalCount); } return pOwnerRefTraceLog; } // CreateOwnerRefTraceLog PREF_OWNER NewRefOwner( POWNER_REF_TRACELOG pOwnerRefTraceLog, PVOID pOwner, IN PPREF_OWNER ppRefOwner, IN ULONG OwnerSignature ) { PREF_OWNER pRefOwner; ASSERT( UlDbgSpinLockOwned( &pOwnerRefTraceLog->OwnerHeader.SpinLock ) ); pRefOwner = UL_ALLOCATE_STRUCT( NonPagedPool, REF_OWNER, UL_OWNER_REF_POOL_TAG ); if (pRefOwner != NULL) { int i; pRefOwner->Signature = OWNER_REF_SIGNATURE; pRefOwner->OwnerSignature = OwnerSignature; InsertTailList( &pOwnerRefTraceLog->OwnerHeader.ListHead, &pRefOwner->ListEntry ); ++pOwnerRefTraceLog->OwnerHeader.OwnersCount; pRefOwner->pOwner = pOwner; pRefOwner->pOwnerRefTraceLog = pOwnerRefTraceLog; pRefOwner->RelativeRefCount = 0; pRefOwner->OwnedNextEntry = -1; for (i = 0; i < OWNED_REF_NUM_ENTRIES; ++i) { pRefOwner->RecentEntries[i].RefIndex = -1; pRefOwner->RecentEntries[i].MonotonicId = -1; pRefOwner->RecentEntries[i].Action = -1; } *ppRefOwner = pRefOwner; } return pRefOwner; } // NewRefOwner VOID InsertRefOwner( IN POWNER_REF_TRACELOG pOwnerRefTraceLog, IN PVOID pOwner, IN PPREF_OWNER ppRefOwner, IN ULONG OwnerSignature, IN LONGLONG RefIndex, IN LONG MonotonicId, IN LONG IncrementValue, IN USHORT Action ) { PREF_OWNER pRefOwner = NULL; KIRQL OldIrql; ASSERT(RefIndex >= 0); UlAcquireSpinLock(&pOwnerRefTraceLog->OwnerHeader.SpinLock, &OldIrql); pRefOwner = *ppRefOwner; if (pRefOwner == NULL) { pRefOwner = NewRefOwner( pOwnerRefTraceLog, pOwner, ppRefOwner, OwnerSignature ); } if (pRefOwner != NULL) { ULONG Index; ASSERT(pRefOwner->Signature == OWNER_REF_SIGNATURE); ASSERT(pRefOwner->pOwner == pOwner); ASSERT(pRefOwner->OwnerSignature == OwnerSignature); ASSERT(pRefOwner->pOwnerRefTraceLog == pOwnerRefTraceLog); Index = ((ULONG) ++pRefOwner->OwnedNextEntry) % OWNED_REF_NUM_ENTRIES; pRefOwner->RecentEntries[Index].RefIndex = RefIndex; pRefOwner->RecentEntries[Index].MonotonicId = MonotonicId; pRefOwner->RecentEntries[Index].Action = Action; if (IncrementValue > 0) ++pRefOwner->RelativeRefCount; else if (IncrementValue < 0) --pRefOwner->RelativeRefCount; // else do nothing if IncrementValue == 0. ASSERT(pRefOwner->RelativeRefCount >= 0); } UlReleaseSpinLock(&pOwnerRefTraceLog->OwnerHeader.SpinLock, OldIrql); } // InsertRefOwner LONGLONG WriteOwnerRefTraceLog( IN POWNER_REF_TRACELOG pOwnerRefTraceLog, IN PVOID pOwner, IN PPREF_OWNER ppRefOwner, IN ULONG OwnerSignature, IN USHORT Action, IN LONG NewRefCount, IN LONG MonotonicId, IN LONG IncrementValue, IN PVOID pFileName, IN USHORT LineNumber ) { OWNER_REF_TRACE_LOG_ENTRY entry; LONGLONG RefIndex; ASSERT(NULL != ppRefOwner); ASSERT(Action < (1 << REF_TRACE_ACTION_BITS)); if (NULL == pOwnerRefTraceLog) return -1; entry.NewRefCount = NewRefCount; entry.pOwner = pOwner; entry.pFileName = pFileName; entry.LineNumber = LineNumber; entry.Action = Action; RefIndex = WriteTraceLog( &pOwnerRefTraceLog->TraceLog, &entry ); InsertRefOwner( pOwnerRefTraceLog, pOwner, ppRefOwner, OwnerSignature, RefIndex, MonotonicId, IncrementValue, Action ); return RefIndex; } // WriteOwnerRefTraceLog VOID DestroyOwnerRefTraceLog( IN POWNER_REF_TRACELOG pOwnerRefTraceLog ) { if (pOwnerRefTraceLog != NULL) { KIRQL OldIrql; PLIST_ENTRY pEntry; int i = 0; UlAcquireSpinLock(&pOwnerRefTraceLog->OwnerHeader.SpinLock, &OldIrql); for (pEntry = pOwnerRefTraceLog->OwnerHeader.ListHead.Flink; pEntry != &pOwnerRefTraceLog->OwnerHeader.ListHead; ++i) { PREF_OWNER pRefOwner = CONTAINING_RECORD(pEntry, REF_OWNER, ListEntry); pEntry = pEntry->Flink; // save before deletion ASSERT(pRefOwner->Signature == OWNER_REF_SIGNATURE); ASSERT(pRefOwner->RelativeRefCount == 0); UL_FREE_POOL_WITH_SIG(pRefOwner, UL_OWNER_REF_POOL_TAG); } UlReleaseSpinLock(&pOwnerRefTraceLog->OwnerHeader.SpinLock, OldIrql); ASSERT(i == pOwnerRefTraceLog->OwnerHeader.OwnersCount); // Remove log from global list UlAcquireSpinLock(&g_OwnerRefTraceLogGlobalSpinLock, &OldIrql); RemoveEntryList(&pOwnerRefTraceLog->OwnerHeader.GlobalListEntry); UlReleaseSpinLock(&g_OwnerRefTraceLogGlobalSpinLock, OldIrql); InterlockedDecrement(&g_OwnerRefTraceLogGlobalCount); DestroyTraceLog( (PTRACE_LOG) pOwnerRefTraceLog ); } } // DestroyOwnerRefTraceLog VOID ResetOwnerRefTraceLog( IN POWNER_REF_TRACELOG pOwnerRefTraceLog ) { // CODEWORK: reset OwnerHeader? if (pOwnerRefTraceLog != NULL) { ResetTraceLog(&pOwnerRefTraceLog->TraceLog); } } // ResetOwnerRefTraceLog #endif // ENABLE_OWNER_REF_TRACE