windows-nt/Source/XPSP1/NT/multimedia/directx/dplay/dpnathlp/common/critsectracking.cpp
2020-09-26 16:20:57 +08:00

397 lines
9.9 KiB
C++

/*==========================================================================
*
* Copyright (C) 2002 Microsoft Corporation. All Rights Reserved.
*
* File: MemoryTracking.cpp
* Content: Debug memory tracking for detecting leaks, overruns, etc.
*
* History:
* Date By Reason
* ==== == ======
* 1/10/2002 masonb Created
*
***************************************************************************/
#include "dncmni.h"
#ifndef DPNBUILD_ONLYONETHREAD
#ifdef DBG
//
// Uncomment this line to turn critical section internal structure validation on.
//
//#define DNCS_VALIDATE
#define DN_INVALID_THREAD_ID -1
CBilink g_blAllCritSecs;
CBilink g_blGlobalCritSecsHeldGroup;
CRITICAL_SECTION g_CSLock;
DWORD g_dwNumCritSecsAllocated = 0;
DWORD g_dwNumCritSecsEntered = 0;
#ifdef DNCS_VALIDATE
void DNCSTrackInternalValidate();
#else // ! DNCS_VALIDATE
#define DNCSTrackInternalValidate()
#endif // DNCS_VALIDATE
#undef DPF_MODNAME
#define DPF_MODNAME "DNCSTrackInitialize"
BOOL DNCSTrackInitialize()
{
g_blAllCritSecs.Initialize();
g_blGlobalCritSecsHeldGroup.Initialize();
if ( DNOSInitializeCriticalSection(&g_CSLock) == FALSE )
{
DPFX(DPFPREP, 0, "Failed to initialize critical section tracking code!" );
DNASSERT( FALSE );
return FALSE;
}
return TRUE;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DNCSTrackDeinitialize"
void DNCSTrackDeinitialize()
{
DeleteCriticalSection(&g_CSLock);
}
#undef DPF_MODNAME
#define DPF_MODNAME "DNCSTrackDumpLeaks"
BOOL DNCSTrackDumpLeaks()
{
DNCRITICAL_SECTION* pCS;
TCHAR CallStackBuffer[CALLSTACK_BUFFER_SIZE];
BOOL fLeaked = FALSE;
EnterCriticalSection(&g_CSLock);
while (!g_blAllCritSecs.IsEmpty())
{
pCS = CONTAINING_OBJECT(g_blAllCritSecs.GetNext(), DNCRITICAL_SECTION, blAllCritSecs);
pCS->AllocCallStack.GetCallStackString(CallStackBuffer);
DPFX(DPFPREP, 0, "Critical Section leaked at address 0x%p\n%s", pCS, CallStackBuffer );
pCS->blAllCritSecs.RemoveFromList();
DeleteCriticalSection(&pCS->CriticalSection);
fLeaked = TRUE;
}
LeaveCriticalSection(&g_CSLock);
return fLeaked;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DNCSTrackInitializeCriticalSection"
BOOL DNCSTrackInitializeCriticalSection( DNCRITICAL_SECTION *const pCriticalSection )
{
BOOL fReturn;
DNASSERT( pCriticalSection != NULL );
memset( pCriticalSection, 0x00, sizeof( *pCriticalSection ) );
pCriticalSection->OwningThreadID = DN_INVALID_THREAD_ID;
pCriticalSection->MaxLockCount = -1;
pCriticalSection->blCritSecsHeld.Initialize();
pCriticalSection->blAllCritSecs.Initialize();
pCriticalSection->pblCritSecsHeldGroup = &g_blGlobalCritSecsHeldGroup;
fReturn = DNOSInitializeCriticalSection(&pCriticalSection->CriticalSection);
if ( fReturn != FALSE )
{
pCriticalSection->AllocCallStack.NoteCurrentCallStack();
EnterCriticalSection(&g_CSLock);
pCriticalSection->blAllCritSecs.InsertBefore(&g_blAllCritSecs);
g_dwNumCritSecsAllocated++;
DNCSTrackInternalValidate();
LeaveCriticalSection(&g_CSLock);
}
return fReturn;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DNCSTrackDeleteCriticalSection"
void DNCSTrackDeleteCriticalSection( DNCRITICAL_SECTION *const pCriticalSection )
{
DNASSERT( pCriticalSection != NULL );
DNASSERT( pCriticalSection->LockCount == 0 );
EnterCriticalSection(&g_CSLock);
pCriticalSection->blAllCritSecs.RemoveFromList();
g_dwNumCritSecsAllocated--;
// NOTE: If they delete the CS without leaving it, still remove it from the held list.
// If asserts are on, this will have asserted above at LockCount == 0.
// Calling this is safe whether it is on the list or not.
pCriticalSection->blCritSecsHeld.RemoveFromList();
DNCSTrackInternalValidate();
LeaveCriticalSection(&g_CSLock);
DeleteCriticalSection( &pCriticalSection->CriticalSection );
memset( &pCriticalSection->CriticalSection, 0x00, sizeof( pCriticalSection->CriticalSection ) );
}
#undef DPF_MODNAME
#define DPF_MODNAME "DNCSTrackSetCriticalRecursionCount"
void DNCSTrackSetCriticalSectionRecursionCount( DNCRITICAL_SECTION *const pCriticalSection, const UINT_PTR RecursionCount )
{
DNASSERT( pCriticalSection != NULL );
pCriticalSection->MaxLockCount = RecursionCount + 1;
DNASSERT( pCriticalSection->MaxLockCount != 0 );
}
#undef DPF_MODNAME
#define DPF_MODNAME "DNCSTrackSetCriticalSectionGroup"
void DNCSTrackSetCriticalSectionGroup( DNCRITICAL_SECTION *const pCriticalSection, CBilink * const pblGroup )
{
DNASSERT( pCriticalSection != NULL );
DNASSERT( pblGroup != NULL );
pCriticalSection->pblCritSecsHeldGroup = pblGroup;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DNCSTrackSetCriticalSectionLockOrder"
void DNCSTrackSetCriticalSectionLockOrder( DNCRITICAL_SECTION *const pCriticalSection, const DWORD dwLockOrder )
{
DNASSERT( pCriticalSection != NULL );
DNASSERT( dwLockOrder > 0 );
pCriticalSection->dwLockOrder = dwLockOrder;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DNCSTrackEnterCriticalSection"
void DNCSTrackEnterCriticalSection( DNCRITICAL_SECTION *const pCriticalSection )
{
UINT_PTR ThisThreadID;
DNASSERT( pCriticalSection != NULL );
EnterCriticalSection( &pCriticalSection->CriticalSection );
ThisThreadID = GetCurrentThreadId();
if ( pCriticalSection->OwningThreadID != ThisThreadID )
{
DNASSERT( pCriticalSection->OwningThreadID == DN_INVALID_THREAD_ID );
pCriticalSection->OwningThreadID = ThisThreadID;
DNASSERT( pCriticalSection->LockCount == 0 );
}
else
{
DNASSERT( pCriticalSection->LockCount != 0 );
}
if ( pCriticalSection->LockCount == 0 )
{
pCriticalSection->CallStack.NoteCurrentCallStack();
// Track this critical section that was just entered for the first time.
EnterCriticalSection(&g_CSLock);
pCriticalSection->LockCount++;
//
// If this critical section has a lock order, assert that we're not
// violating it.
//
if (pCriticalSection->dwLockOrder != 0)
{
CBilink * pBilink;
DNCRITICAL_SECTION * pCS;
pBilink = pCriticalSection->pblCritSecsHeldGroup->GetNext();
while (pBilink != pCriticalSection->pblCritSecsHeldGroup)
{
pCS = CONTAINING_OBJECT(pBilink, DNCRITICAL_SECTION, blCritSecsHeld);
if (pCS->dwLockOrder != 0)
{
DNASSERT( pCS->dwLockOrder <= pCriticalSection->dwLockOrder );
}
pBilink = pBilink->GetNext();
}
}
pCriticalSection->blCritSecsHeld.InsertBefore(pCriticalSection->pblCritSecsHeldGroup);
DNASSERT(g_dwNumCritSecsEntered < g_dwNumCritSecsAllocated);
g_dwNumCritSecsEntered++;
DNCSTrackInternalValidate();
LeaveCriticalSection(&g_CSLock);
}
else
{
pCriticalSection->LockCount++;
}
if ( pCriticalSection->LockCount > pCriticalSection->MaxLockCount )
{
if ( pCriticalSection->MaxLockCount == 1 )
{
TCHAR CallStackBuffer[ CALLSTACK_BUFFER_SIZE ];
//
// Exceeded recursion depth of 1, display stack of call originally
// holding the lock.
//
pCriticalSection->CallStack.GetCallStackString( CallStackBuffer );
DPFX(DPFPREP, 0, "Critical section 0x%p has been reentered!\nOriginal Holder's Stack:\n%s", pCriticalSection, CallStackBuffer);
DNASSERT(FALSE);
}
else
{
//
// exceeded recursion depth, check your code!!
//
DNASSERT(FALSE);
}
}
}
#undef DPF_MODNAME
#define DPF_MODNAME "DNCSTrackLeaveCriticalSection"
void DNCSTrackLeaveCriticalSection( DNCRITICAL_SECTION *const pCriticalSection )
{
DNASSERT( pCriticalSection != NULL );
DNASSERT( pCriticalSection->OwningThreadID == GetCurrentThreadId() );
DNASSERT( pCriticalSection->LockCount <= pCriticalSection->MaxLockCount );
DNASSERT( pCriticalSection->LockCount != 0 );
if ( pCriticalSection->LockCount == 1 )
{
memset( &pCriticalSection->CallStack, 0x00, sizeof( pCriticalSection->CallStack ) );
pCriticalSection->OwningThreadID = DN_INVALID_THREAD_ID;
// Track this critical section being left for the last time.
EnterCriticalSection(&g_CSLock);
pCriticalSection->LockCount--;
pCriticalSection->blCritSecsHeld.RemoveFromList();
DNASSERT(g_dwNumCritSecsEntered > 0);
g_dwNumCritSecsEntered--;
DNCSTrackInternalValidate();
LeaveCriticalSection(&g_CSLock);
}
else
{
pCriticalSection->LockCount--;
}
LeaveCriticalSection( &pCriticalSection->CriticalSection );
}
#undef DPF_MODNAME
#define DPF_MODNAME "DNCSTrackCriticalSectionIsTakenByThisThread"
void DNCSTrackCriticalSectionIsTakenByThisThread( const DNCRITICAL_SECTION *const pCriticalSection, const BOOL fFlag )
{
DNASSERT( fFlag == ( pCriticalSection->OwningThreadID == GetCurrentThreadId() ) );
}
#undef DPF_MODNAME
#define DPF_MODNAME "DNCSTrackNoCriticalSectionsTakenByThisThread"
void DNCSTrackNoCriticalSectionsTakenByThisThread( CBilink * pblGroup )
{
CBilink* pBilink;
DNCRITICAL_SECTION* pCS;
if (pblGroup == NULL)
{
pblGroup = &g_blGlobalCritSecsHeldGroup;
}
EnterCriticalSection(&g_CSLock);
pBilink = pblGroup->GetNext();
while (pBilink != pblGroup)
{
pCS = CONTAINING_OBJECT(pBilink, DNCRITICAL_SECTION, blCritSecsHeld);
DNASSERT( pCS->OwningThreadID != GetCurrentThreadId() );
pBilink = pBilink->GetNext();
}
DNCSTrackInternalValidate();
LeaveCriticalSection(&g_CSLock);
}
#ifdef DNCS_VALIDATE
#undef DPF_MODNAME
#define DPF_MODNAME "DNCSTrackInternalValidate"
void DNCSTrackInternalValidate()
{
CBilink* pBilink;
DNCRITICAL_SECTION* pCS;
DWORD dwNumAllocated = 0;
DWORD dwNumEntered = 0;
//
// The global critical section lock must be held!
//
DNASSERT(g_dwNumCritSecsEntered <= g_dwNumCritSecsAllocated);
pBilink = g_blAllCritSecs.GetNext();
while (pBilink != &g_blAllCritSecs)
{
DNASSERT(pBilink->GetNext() != pBilink);
DNASSERT(pBilink->GetPrev() != pBilink);
DNASSERT(pBilink->IsListMember(&g_blAllCritSecs));
pCS = CONTAINING_OBJECT(pBilink, DNCRITICAL_SECTION, blAllCritSecs);
dwNumAllocated++;
if (pCS->blCritSecsHeld.IsEmpty())
{
DNASSERT(pCS->LockCount == 0);
}
else
{
DNASSERT(pCS->LockCount > 0);
dwNumEntered++;
}
pBilink = pBilink->GetNext();
}
DNASSERT(dwNumAllocated == g_dwNumCritSecsAllocated);
DNASSERT(dwNumEntered == g_dwNumCritSecsEntered);
}
#endif // DNCS_VALIDATE
#endif // DBG
#endif // !DPNBUILD_ONLYONETHREAD