316 lines
8 KiB
C++
316 lines
8 KiB
C++
/*++
|
||
|
||
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
|
||
|