windows-nt/Source/XPSP1/NT/multimedia/directx/dplay/dnet/common/osind.cpp

1788 lines
44 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*==========================================================================
*
* Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
*
* File: OSInd.cpp
* Content: OS indirection functions to abstract OS specific items.
*
* History:
* Date By Reason
* ==== == ======
* 07/12/99 jtk Created
* 09/21/99 rodtoll Fixed for retail builds
* 09/22/99 jtk Added callstacks to memory allocations
* 08/28/2000 masonb Voice Merge: Allow new and delete with size of 0
* 11/28/2000 rodtoll: WinBug #206257 - Retail DPNET.DLL links to DebugBreak()
* 12/22/2000 aarono: ManBug # 190380 use process heap for retail.
***************************************************************************/
#include "dncmni.h"
#define PROF_SECT "DirectPlay8"
//**********************************************************************
// Constant definitions
//**********************************************************************
//
// CRC key for validating memory linkages
// Signature for validating memory blocks
//
#ifdef _WIN64
#define MEMORY_CRC 0X5AA55AA55AA55AA5
#define GUARD_SIGNATURE 0x0F1E2D3C4B5A6978
#else
#define MEMORY_CRC 0X5AA55AA5
#define GUARD_SIGNATURE 0x0F1E2D3C
#endif // _WIN64
static CRITICAL_SECTION g_AllocatedMemoryLock;
//
// signature for validating memory blocks
//
//
// enumerated values to indicate how to report memory leaks
//
#if defined( DN_MEMORY_TRACKING ) || defined( DN_CRITICAL_SECTION_TRACKING )
#define MEMORY_LEAK_REPORT_NONE 0x00000000
#define MEMORY_LEAK_REPORT_DPF 0x00000001
#define MEMORY_LEAK_REPORT_DIALOG 0x00000002
#endif
//**********************************************************************
// Macro definitions
//**********************************************************************
//
// Macro to compute the offset of an element inside of a larger structure.
// Copied from MSDEV's STDLIB.H and modified to return INT_PTR
//
#define OFFSETOF(s,m) ( ( INT_PTR ) &( ( (s*) 0 )->m ) )
//
// macro for length of array
//
#define LENGTHOF( arg ) ( sizeof( arg ) / sizeof( arg[ 0 ] ) )
//
// ASSERT macro
//
#ifdef _DEBUG
#ifdef _X86_
#define ASSERT( arg ) if ( arg == FALSE ) { _asm { int 3 }; }
#else
#define ASSERT( arg ) if ( arg == FALSE ) { DebugBreak(); }
#endif
#else // _DEBUG
#define ASSERT( arg )
#endif //_DEBUG
//**********************************************************************
// Structure definitions
//**********************************************************************
//**********************************************************************
// Variable definitions
//**********************************************************************
//
// debug variable to make sure we're initialized before having any functions
// called
//
DEBUG_ONLY( static BOOL g_fOSIndirectionLayerInitialized = FALSE );
//
// time variables
//
static DNCRITICAL_SECTION g_TimeLock;
static DWORD g_dwLastTimeCall = 0;
#ifdef DN_CRITICAL_SECTION_TRACKING
CBilink g_blCritSecs;
DNCRITICAL_SECTION g_CSLock;
#endif
#ifdef DN_MEMORY_TRACKING
DWORD g_dwMemLeakDisplayFlags = MEMORY_LEAK_REPORT_DPF;
#endif
//
// OS items
//
static OSVERSIONINFO g_OSVersionInfo;
static HINSTANCE g_hApplicationInstance;
//
// memory heap
//
HANDLE g_hMemoryHeap = NULL;
PSECURITY_ATTRIBUTES g_psa = NULL;
SECURITY_ATTRIBUTES g_sa;
BYTE g_pSD[SECURITY_DESCRIPTOR_MIN_LENGTH];
BOOL g_fDaclInited = FALSE;
//**********************************************************************
// Function prototypes
//**********************************************************************
#ifdef DN_MEMORY_TRACKING
static int DisplayMemoryLeaks( void );
BOOL DNMemoryTrackInitialize( void );
#endif
#if defined( DN_MEMORY_TRACKING ) || defined( DN_CRITICAL_SECTION_TRACKING )
static int DisplayCallStack( const char *const pszMsg,
const char *const pszTitle,
const char *const pCallStack );
#endif
//**********************************************************************
// Function definitions
//**********************************************************************
typedef BOOL (WINAPI *PFNINITCRITSECANDSPINCOUNT)(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount);
PFNINITCRITSECANDSPINCOUNT g_pfnInitializeCriticalSectionAndSpinCount = NULL;
//**********************************************************************
// ------------------------------
// DNOSIndirectionInit - initialize the OS indirection layer
//
// Entry: Nothing
//
// Exit: Boolean indicating success
// TRUE = initialization successful
// FALSE = initialization unsuccessful
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DNOSIndirectionInit"
BOOL DNOSIndirectionInit( void )
{
BOOL fReturn;
DNASSERT( g_fOSIndirectionLayerInitialized == FALSE );
//
// initialize
//
fReturn = TRUE;
//
// note OS version
//
memset( &g_OSVersionInfo, 0x00, sizeof( g_OSVersionInfo ) );
g_OSVersionInfo.dwOSVersionInfoSize = sizeof( g_OSVersionInfo );
if ( GetVersionEx( &g_OSVersionInfo ) == FALSE )
{
return FALSE;
}
HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
if (hKernel32 != NULL)
{
g_pfnInitializeCriticalSectionAndSpinCount = (PFNINITCRITSECANDSPINCOUNT) GetProcAddress(hKernel32, "InitializeCriticalSectionAndSpinCount");
}
//
// note application instance
//
g_hApplicationInstance = GetModuleHandle( NULL );
if ( g_hApplicationInstance == NULL )
{
DWORD dwError;
dwError = GetLastError();
DPFX(DPFPREP, 0, "Failed to GetModuleHandle: 0x%x", dwError );
goto Failure;
}
#ifdef DN_MEMORY_TRACKING
g_dwMemLeakDisplayFlags = GetProfileIntA( PROF_SECT, "MemoryLeakOutput", MEMORY_LEAK_REPORT_DPF );
#endif
//
// intialize critical section tracking code before anything else!
//
#ifdef DN_CRITICAL_SECTION_TRACKING
g_blCritSecs.Initialize();
if ( DNInitializeCriticalSection(&g_CSLock) == FALSE )
{
DPFX(DPFPREP, 0, "Failed to initialize critical section tracking code!" );
DNASSERT( FALSE );
goto Failure;
}
#endif // DN_CRITICAL_SECTION_TRACKING
//
// intiailize memory tracking before creating new memory heap
//
#ifdef DN_MEMORY_TRACKING
if ( DNMemoryTrackInitialize() == FALSE )
{
DPFX(DPFPREP, 0, "Failed to initialize memory tracking code!" );
DNASSERT( FALSE );
goto Failure;
}
#endif // DN_MEMORY_TRACKING
DNASSERT( g_hMemoryHeap == NULL );
#ifdef _DEBUG
g_hMemoryHeap = HeapCreate( 0, // flags (none)
0, // initial size (default)
0 // maximum heap size (allow heap to grow)
);
#else
g_hMemoryHeap = GetProcessHeap();
#endif
if ( g_hMemoryHeap == NULL )
{
DPFX(DPFPREP, 0, "Failed to create memory heap!" );
goto Failure;
}
//
// get initial time for timebase
//
g_dwLastTimeCall = GETTIMESTAMP();
if ( DNInitializeCriticalSection( &g_TimeLock ) == FALSE )
{
goto Failure;
}
goto Exit;
Exit:
if ( fReturn != FALSE )
{
DEBUG_ONLY( g_fOSIndirectionLayerInitialized = TRUE );
}
return fReturn;
Failure:
fReturn = FALSE;
DNOSIndirectionDeinit();
goto Exit;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// DNOSIndirectionDeinit - deinitialize OS indirection layer
//
// Entry: Nothing
//
// Exit: Nothing
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DNOSIndirectionDeinit"
void DNOSIndirectionDeinit( void )
{
//
// clean up time management resources
//
DNDeleteCriticalSection( &g_TimeLock );
#ifdef DN_CRITICAL_SECTION_TRACKING
//
// Display CritSec leaks before displaying memory leaks, because displaying memory leaks
// may free the memory for the CritSec and corrupt the CritSec bilink
//
BOOL fDisplayLeaks = TRUE;
DNEnterCriticalSection(&g_CSLock);
CBilink* pblCS = g_blCritSecs.GetNext();
while (pblCS != &g_blCritSecs)
{
UINT_PTR MessageReturn;
char CallStackBuffer[ CALLSTACK_BUFFER_SIZE ];
char LeakSizeString[ 50 ];
char DialogTitle[ 1000 ];
DNCRITICAL_SECTION* pCS = CONTAINING_RECORD(pblCS, DNCRITICAL_SECTION, blCritSec);
#ifdef _IA64_
wsprintf( LeakSizeString, "Critical Section leaked at address 0x%p!\n", pCS );
#else
wsprintf( LeakSizeString, "Critical Section leaked at address 0x%08x!\n", pCS );
#endif
strcpy( DialogTitle, "DirectPlay8 critical section leak detected!");
pCS->AllocCallStack.GetCallStackString( CallStackBuffer );
if ( ( g_dwMemLeakDisplayFlags & MEMORY_LEAK_REPORT_DPF ) != 0 )
{
DPFX(DPFPREP, 0, "%s%s%s\n", DialogTitle, LeakSizeString, CallStackBuffer );
}
if ( ( g_dwMemLeakDisplayFlags & MEMORY_LEAK_REPORT_DIALOG ) != 0 )
{
if ( fDisplayLeaks != FALSE )
{
MessageReturn = DisplayCallStack( LeakSizeString, DialogTitle, CallStackBuffer );
switch ( MessageReturn )
{
//
// stop application now
//
case IDABORT:
{
fDisplayLeaks = FALSE;
break;
}
//
// display next leak
//
case IDIGNORE:
{
break;
}
//
// stop in the debugger
//
case IDRETRY:
{
DNASSERT( FALSE );
break;
}
//
// unknown
//
default:
{
DNASSERT( FALSE );
break;
}
}
}
}
pblCS = pblCS->GetNext();
}
DNLeaveCriticalSection(&g_CSLock);
DNDeleteCriticalSection( &g_CSLock );
#endif // DN_CRITICAL_SECTION_TRACKING
//
// Report memory leaks, validate the heap if we're on NT and then destroy
// the heap.
//
if ( g_hMemoryHeap != NULL )
{
//
// report memory leaks, if applicable
//
#ifdef DN_MEMORY_TRACKING
DNMemoryTrackDisplayMemoryLeaks();
DeleteCriticalSection( &g_AllocatedMemoryLock );
#endif // DN_MEMORY_TRACKING
//
// Validate heap contents before shutdown. This code only works on NT.
//
#ifdef _DEBUG
if ( DNGetOSType() == VER_PLATFORM_WIN32_NT)
{
//
// Check heap
//
if ( HeapValidate( g_hMemoryHeap, 0, NULL ) == FALSE )
{
DPFX(DPFPREP, 0, "Problem validating heap on destroy!" );
}
}
//
// destroy heap - debug only, we use the process heap for retail.
//
if ( HeapDestroy( g_hMemoryHeap ) == FALSE )
{
DWORD dwErrorReturn;
dwErrorReturn = GetLastError();
DPFX(DPFPREP, 0, "Problem destroying heap in DNOSIndirectionDeinit!" );
DisplayErrorCode( 0, dwErrorReturn );
}
#endif _DEBUG
g_hMemoryHeap = NULL;
}
//
// clean critical section management resources
//
DEBUG_ONLY( g_fOSIndirectionLayerInitialized = FALSE );
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// DNGetOSType - get OS type
//
// Entry: Nothing
//
// Exit: OS type
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DNGetOSType"
UINT_PTR DNGetOSType( void )
{
DNASSERT( g_fOSIndirectionLayerInitialized != FALSE );
return g_OSVersionInfo.dwPlatformId;
}
//**********************************************************************
// ------------------------------
// DNOSIsXPOrGreater - return TRUE if OS is WindowsXP or later or NT flavor
//
// Entry: Nothing
//
// Exit: BOOL
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DNOSIsXPOrGreater"
BOOL DNOSIsXPOrGreater( void )
{
DNASSERT( g_fOSIndirectionLayerInitialized != FALSE );
return ((g_OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) &&
((g_OSVersionInfo.dwMajorVersion > 5) || ((g_OSVersionInfo.dwMajorVersion == 5) && (g_OSVersionInfo.dwMinorVersion >= 1)))
);
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// DNGetNullDacl - get a SECURITY_ATTRIBUTE structure that specifies a
// NULL DACL which is accesible by all users.
//
// Entry: Nothing
//
// Exit: PSECURITY_ATTRIBUTES
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DNGetNullDacl"
PSECURITY_ATTRIBUTES DNGetNullDacl()
{
// This is done to make this function independent of DNOSIndirectionInit so that the debug
// layer can call it before the indirection layer is initialized.
if (!g_fDaclInited)
{
if (!InitializeSecurityDescriptor((SECURITY_DESCRIPTOR*)g_pSD, SECURITY_DESCRIPTOR_REVISION))
{
DPFX(DPFPREP, 0, "Failed to initialize security descriptor" );
}
else
{
// Add a NULL DACL to the security descriptor..
if (!SetSecurityDescriptorDacl((SECURITY_DESCRIPTOR*)g_pSD, TRUE, (PACL) NULL, FALSE))
{
DPFX(DPFPREP, 0, "Failed to set NULL DACL on security descriptor" );
}
else
{
g_sa.nLength = sizeof(SECURITY_ATTRIBUTES);
g_sa.lpSecurityDescriptor = g_pSD;
g_sa.bInheritHandle = FALSE;
g_psa = &g_sa;
}
}
g_fDaclInited = TRUE;
}
return g_psa;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// DNGetApplcationInstance - application instance
//
// Entry: Nothing
//
// Exit: Application instance
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DNGetApplicationInstance"
HINSTANCE DNGetApplicationInstance( void )
{
DNASSERT( g_fOSIndirectionLayerInitialized != FALSE );
return g_hApplicationInstance;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// DNTimeGet - get time in milliseconds
//
// Entry: Pointer to destination time
//
// Exit: Nothing
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DNTimeGet"
void DNTimeGet( DN_TIME *const pTimeDestination )
{
static DN_TIME Time = { 0 };
DN_TIME DeltaT;
DWORD dwCurrentTime;
DNASSERT( pTimeDestination != NULL );
DNASSERT( g_fOSIndirectionLayerInitialized != FALSE );
DNEnterCriticalSection( &g_TimeLock );
//
// we'll assume that we're getting called more than once every 40 days
// so time wraps can be easily accounted for
//
dwCurrentTime = GETTIMESTAMP();
DeltaT.Time32.TimeHigh = 0;
DeltaT.Time32.TimeLow = dwCurrentTime - g_dwLastTimeCall;
if ( DeltaT.Time32.TimeLow > 0x7FFFFFFF )
{
DNASSERT( FALSE );
DeltaT.Time32.TimeLow = -static_cast<INT>( DeltaT.Time32.TimeLow );
}
g_dwLastTimeCall = dwCurrentTime;
DNTimeAdd( &Time, &DeltaT, &Time );
DBG_CASSERT( sizeof( *pTimeDestination ) == sizeof( Time ) );
memcpy( pTimeDestination, &Time, sizeof( *pTimeDestination ) );
DNLeaveCriticalSection( &g_TimeLock );
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// DNTimeCompare - compare two times
//
// Entry: Pointer to time1
// Pointer to time2
//
// Exit: Value indicating relative magnitude
// -1 = *pTime1 < *pTime2
// 0 = *pTime1 == *pTime2
// 1 = *pTime1 > *pTime2
//
// Notes: This function comes in 32-bit and 64-bit flavors. This function
// will result in a compile error if compiled on an unsupported platform.
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DNTimeCompare"
INT_PTR DNTimeCompare( const DN_TIME *const pTime1, const DN_TIME *const pTime2 )
{
UINT_PTR iReturnValue;
DNASSERT( pTime1 != NULL );
DNASSERT( pTime2 != NULL );
DNASSERT( g_fOSIndirectionLayerInitialized != FALSE );
#pragma TODO( johnkan, "Should this be inlined?" )
//#ifdef _WIN32
if ( pTime1->Time32.TimeHigh < pTime2->Time32.TimeHigh )
{
iReturnValue = -1;
}
else
{
if ( pTime1->Time32.TimeHigh > pTime2->Time32.TimeHigh )
{
iReturnValue = 1;
}
else
{
if ( pTime1->Time32.TimeLow < pTime2->Time32.TimeLow )
{
iReturnValue = -1;
}
else
{
if ( pTime1->Time32.TimeLow == pTime2->Time32.TimeLow )
{
iReturnValue = 0;
}
else
{
iReturnValue = 1;
}
}
}
}
//#endif // _WIN32
//#ifdef _WIN64
// // debug me!
// DNASSERT( FALSE );
//
// if ( pTime1->Time < pTime2->Time )
// {
// iReturnValue = -1;
// }
// else
// {
// if ( pTime1->Time == pTime2->Time )
// {
// iReturnValue = 0;
// }
// else
// {
// iReturnValue = 1;
// }
// }
//#endif // _WIN64
return iReturnValue;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// DNTimeAdd - add two times
//
// Entry: Pointer to time1
// Pointer to time2
// Pointer to time result
//
// Exit: Nothing
//
// Note: This function assumes that the time calculation won't wrap!
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DNTimeAdd"
void DNTimeAdd( const DN_TIME *const pTime1, const DN_TIME *const pTime2, DN_TIME *const pTimeResult )
{
DNASSERT( pTime1 != NULL );
DNASSERT( pTime2 != NULL );
DNASSERT( pTimeResult != NULL );
DNASSERT( g_fOSIndirectionLayerInitialized != FALSE );
#pragma TODO( johnkan, "Should this be inlined?" )
#ifdef _X86_
_asm { mov ecx, pTime1
mov eax, ( DN_TIME [ ecx ] ).Time32.TimeLow;
mov edx, ( DN_TIME [ ecx ] ).Time32.TimeHigh
mov ecx, pTime2
add eax, ( DN_TIME [ ecx ] ).Time32.TimeLow
adc edx, ( DN_TIME [ ecx ] ).Time32.TimeHigh
mov ecx, pTimeResult
mov ( DN_TIME [ ecx ] ).Time32.TimeLow, eax
mov ( DN_TIME [ ecx ] ).Time32.TimeHigh, edx
};
#else // _X86_
/*
#ifdef _ALPHA_
// debug me
DebugBreak();
__asm{ mov $t0, *pTime1
mov $t1, *pTime2
addq $t0, $t1
mov *pTimeResult, $t0
};
#else // _ALPHA_
*/
//#ifdef _WIN32
DWORD dwTempLowTime;
dwTempLowTime = pTime1->Time32.TimeLow;
pTimeResult->Time32.TimeLow = pTime1->Time32.TimeLow + pTime2->Time32.TimeLow;
pTimeResult->Time32.TimeHigh = pTime1->Time32.TimeHigh + pTime2->Time32.TimeHigh;
//
// check for overflow in low 32-bits and increment high value if applicable
//
if ( pTimeResult->Time32.TimeLow < dwTempLowTime )
{
pTimeResult->Time32.TimeHigh++;
}
//#endif // _WIN32
//#ifdef _WIN64
// DEBUG_ONLY( UINT_PTR ReferenceTime );
//
// // debug me!
// DNASSERT( FALSE );
//
// DEBUG_ONLY( ReferenceTime = pTime1->Time );
// *pTimeResult = pTime1->Time + pTime2->Time;
// DNASSERT( *pTimeResult >= ReferenceTime );
//
//#endif // _WIN64
// #endif // _ALPHA_
#endif // _X86_
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// DNTimeSubtract - subtract two times
//
// Entry: Pointer to time1
// Pointer to time2
// Pointer to time result
//
// Exit: Nothing
//
// Notes: This function assumes no underflow!
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DNTimeSubtract"
void DNTimeSubtract( const DN_TIME *const pTime1, const DN_TIME *const pTime2, DN_TIME *const pTimeResult )
{
DNASSERT( pTime1 != NULL );
DNASSERT( pTime2 != NULL );
DNASSERT( pTimeResult != NULL );
DNASSERT( g_fOSIndirectionLayerInitialized != FALSE );
#pragma TODO( johnkan, "Should this be inlined?" )
#ifdef _X86_
_asm { mov ecx, pTime1
mov eax, ( DN_TIME [ ecx ] ).Time32.TimeLow
mov edx, ( DN_TIME [ ecx ] ).Time32.TimeHigh
mov ecx, pTime2
sub eax, ( DN_TIME [ ecx ] ).Time32.TimeLow
sbb edx, ( DN_TIME [ ecx ] ).Time32.TimeHigh
mov ecx, pTimeResult
mov ( DN_TIME [ ecx ] ).Time32.TimeLow, eax
mov ( DN_TIME [ ecx ] ).Time32.TimeHigh, edx
};
#else // _X86_
/*
#ifdef _ALPHA_
// debug me
DebugBreak();
mov $t0, *pTime1
mov $t1, *pTime2
addq $t0, $t1
mov *pTimeResult, $t0
#else // _ALPHA_
*/
//#ifdef _WIN32
DWORD dwTempLowTime;
dwTempLowTime = pTime1->Time32.TimeLow;
pTimeResult->Time32.TimeLow = pTime1->Time32.TimeLow - pTime2->Time32.TimeLow;
pTimeResult->Time32.TimeHigh = pTime1->Time32.TimeHigh - pTime2->Time32.TimeHigh;
//
// check for underflow in low 32-bits and decrement high value if applicable
//
if ( pTimeResult->Time32.TimeLow > dwTempLowTime )
{
pTimeResult->Time32.TimeHigh--;
}
//#endif // _WIN32
//#ifdef _WIN64
// // debug me!
// DNASSERT( FALSE );
//
// DNASSERT( pTime1->Time > pTime2->Time );
// pTimeResult = pTime1->Time - pTime2->Time;
//#endif // _WIN64
// #endif // _ALPHA_
#endif // _X86_
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// DNInitializeCriticalSection - initialize a critical section
//
// Entry: Pointer to critical section
//
// Exit: Boolean indicating success
// TRUE = success
// FALSE = failue
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DNInitializeCriticalSection"
BOOL DNInitializeCriticalSection( DNCRITICAL_SECTION *const pCriticalSection )
{
BOOL fReturn;
DNASSERT( pCriticalSection != NULL );
fReturn = TRUE;
memset( pCriticalSection, 0x00, sizeof( *pCriticalSection ) );
#ifdef DN_CRITICAL_SECTION_TRACKING
pCriticalSection->OwningThreadID = DN_INVALID_THREAD_ID;
pCriticalSection->MaxLockCount = -1;
#endif // DN_CRITICAL_SECTION_TRACKING
//
// attempt to enter the critical section once
//
_try
{
// Do this for Win95 support only
if (g_pfnInitializeCriticalSectionAndSpinCount)
{
// Pre-allocate the critsec event by setting the high bit of the spin count and set spin to 1000
// Win98 and up map calls to this function to InitializeCriticalSection which makes sense since
// 9x only uses one processor. NT also converts the spin to 0 for single proc machines.
fReturn = g_pfnInitializeCriticalSectionAndSpinCount( &pCriticalSection->CriticalSection , 0x80000000 | 1000);
// Believe it or not Win9x defines this function as returning VOID so its return value is garbage
if (g_OSVersionInfo.dwPlatformId != VER_PLATFORM_WIN32_NT)
{
fReturn = TRUE;
}
}
else
{
InitializeCriticalSection( &pCriticalSection->CriticalSection );
}
}
_except( EXCEPTION_EXECUTE_HANDLER )
{
fReturn = FALSE;
}
_try
{
if (fReturn)
{
EnterCriticalSection( &pCriticalSection->CriticalSection );
}
}
_except( EXCEPTION_EXECUTE_HANDLER )
{
DeleteCriticalSection(&pCriticalSection->CriticalSection);
fReturn = FALSE;
}
//
// if we didn't fail on entering the critical section, make sure
// we release it
//
if ( fReturn != FALSE )
{
LeaveCriticalSection( &pCriticalSection->CriticalSection );
#ifdef DN_CRITICAL_SECTION_TRACKING
pCriticalSection->AllocCallStack.NoteCurrentCallStack();
// NOTE: We will not add g_CSLock to our list
if (pCriticalSection != &g_CSLock)
{
DNEnterCriticalSection(&g_CSLock);
pCriticalSection->blCritSec.InsertBefore(&g_blCritSecs);
DNLeaveCriticalSection(&g_CSLock);
}
#endif
}
return fReturn;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// DNDeleteCriticalSection - delete a critical section
//
// Entry: Pointer to critical section
//
// Exit: Nothing
//
// Notes: This function wrapping is overkill, but we're closing down so
// the overhead is negligible.
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DNDeleteCriticalSection"
void DNDeleteCriticalSection( DNCRITICAL_SECTION *const pCriticalSection )
{
DNASSERT( pCriticalSection != NULL );
DNASSERT( g_fOSIndirectionLayerInitialized != FALSE );
#ifdef DN_CRITICAL_SECTION_TRACKING
DNASSERT( pCriticalSection->LockCount == 0 );
// NOTE: We will not remove g_CSLock from our list since we never added it
if (pCriticalSection != &g_CSLock)
{
DNEnterCriticalSection(&g_CSLock);
pCriticalSection->blCritSec.RemoveFromList();
DNLeaveCriticalSection(&g_CSLock);
}
#endif
DeleteCriticalSection( &pCriticalSection->CriticalSection );
memset( &pCriticalSection->CriticalSection, 0x00, sizeof( pCriticalSection->CriticalSection ) );
}
//**********************************************************************
#ifdef DN_MEMORY_TRACKING
//**********************************************************************
//**
//** THIS IS THE MEMORY TRACKING SECTION. ONLY ADD FUNCTIONS HERE THAT ARE
//** FOR MEMORY TRACKING!!
//**
//**********************************************************************
//
// Structure prepended to memory allocations to check for leaks.
// Disable warning 4200 (zero sized structure elements).
//
#pragma warning ( disable : 4200 )
typedef struct _MEMORY_LINK
{
public:
void Initialize( void )
{
m_pNext = this;
m_pPrev = this;
}
BOOL IsValid( void ) const
{
return ( m_Checksum == ( reinterpret_cast<UINT_PTR>( m_pPrev ) ^
reinterpret_cast<UINT_PTR>( m_pNext ) ^
m_Size ^
MEMORY_CRC ) );
}
void UpdateCRC( void )
{
m_Checksum = reinterpret_cast<UINT_PTR>( m_pPrev ) ^
reinterpret_cast<UINT_PTR>( m_pNext ) ^
m_Size ^
MEMORY_CRC;
}
BOOL IsEmpty( void ) { return ( ( m_pNext == this ) && ( m_pPrev == this ) ); }
_MEMORY_LINK *GetNext( void ) const { return m_pNext; }
_MEMORY_LINK *GetPrev( void ) const { return m_pPrev; }
void *GetDataPointer( void ) { return &m_Data[ sizeof( DWORD_PTR ) ]; }
static _MEMORY_LINK *PointerFromData( void *const pData )
{
return reinterpret_cast<_MEMORY_LINK*>( &( reinterpret_cast<BYTE*>( pData )[ - ( OFFSETOF( MEMORY_LINK, m_Data ) + static_cast<int>( sizeof( DWORD_PTR ) ) ) ] ) );
}
void SetSize( const UINT_PTR Size ){ m_Size = Size; }
UINT_PTR GetSize( void ) const { return m_Size; }
#undef DPF_MODNAME
#define DPF_MODNAME "_MEMORY_LINK::LinkAfterOther"
void LinkAfterOther( _MEMORY_LINK &OtherLink )
{
ASSERT( OtherLink.IsValid() != FALSE );
if ( OtherLink.m_pNext != NULL )
{
ASSERT( OtherLink.m_pNext->IsValid() != FALSE );
OtherLink.m_pNext->m_pPrev = this;
OtherLink.m_pNext->UpdateCRC();
}
m_pNext = OtherLink.m_pNext;
m_pPrev = &OtherLink;
UpdateCRC();
OtherLink.m_pNext = this;
OtherLink.UpdateCRC();
}
#undef DPF_MODNAME
#define DPF_MODNAME "_MEMORY_LINK::RemoveFromList"
void RemoveFromList( void )
{
ASSERT( IsValid() != FALSE );
ASSERT( m_pPrev != NULL );
if ( m_pNext != NULL )
{
ASSERT( m_pNext->IsValid() != FALSE );
m_pNext->m_pPrev = m_pPrev;
m_pNext->UpdateCRC();
}
ASSERT( m_pPrev->IsValid() != FALSE );
m_pPrev->m_pNext = m_pNext;
m_pPrev->UpdateCRC();
m_pNext = NULL;
m_pPrev = NULL;
}
void NoteCurrentCallStack( void ) { m_CallStack.NoteCurrentCallStack(); }
void GetCallStack( char *const pBuffer ) const { m_CallStack.GetCallStackString( pBuffer ); }
void SetOverrunSignatures( void )
{
*reinterpret_cast<DWORD_PTR*>( m_Data ) = GUARD_SIGNATURE;
// 6/30/2000(RichGr) - IA64: Specifying UNALIGNED generates the correct IA64 code for non-8-byte alignment.
*reinterpret_cast<UNALIGNED DWORD_PTR*>( &m_Data[ m_Size + sizeof( DWORD_PTR ) ] ) = GUARD_SIGNATURE;
}
BOOL UnderrunDetected( void ) const { return ( *reinterpret_cast<const DWORD_PTR*>( m_Data ) != GUARD_SIGNATURE ); }
// 6/30/2000(RichGr) - IA64: Specifying UNALIGNED generates the correct IA64 code for non-8-byte alignment.
BOOL OverrunDetected( void ) const { return ( *reinterpret_cast<const UNALIGNED DWORD_PTR*>( &m_Data[ m_Size + sizeof( DWORD_PTR ) ] ) != GUARD_SIGNATURE ); }
BOOL IsCorrupted( void ) const { return ( !IsValid() || UnderrunDetected() || OverrunDetected() ); }
protected:
private:
UINT_PTR m_Checksum;
UINT_PTR m_Size;
_MEMORY_LINK *m_pPrev;
_MEMORY_LINK *m_pNext;
CCallStack<DN_MEMORY_CALL_STACK_DEPTH> m_CallStack;
BYTE m_Data[];
} MEMORY_LINK;
#pragma warning ( default : 4200 )
//
// forward structure references
//
typedef struct _MEMORY_LINK MEMORY_LINK;
//
// memory tracking variables
//
static UINT_PTR g_uAllocatedMemoryCount;
static MEMORY_LINK g_AllocatedMemory;
//**********************************************************************
// ------------------------------
// DNMemoryTrackInitialize - initialize memory tracking
//
// Entry: Nothing
//
// Exit: Error code
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DNMemoryTrackInitialize"
static BOOL DNMemoryTrackInitialize( void )
{
BOOL fReturn;
fReturn = TRUE;
memset( &g_AllocatedMemory, 0x00, sizeof ( g_AllocatedMemory ) );
g_uAllocatedMemoryCount = 0;
g_AllocatedMemory.Initialize();
g_AllocatedMemory.UpdateCRC();
InitializeCriticalSection( &g_AllocatedMemoryLock );
return fReturn;
}
//**********************************************************************
//**********************************************************************
//**********************************************************************
// ------------------------------
// DNMemoryTrackHeapAlloc - allocate from heap and track allocations
//
// Entry: Size of memory to allocate
//
// Exit: Pointer to allocated memory
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DNMemoryTrackHeapAlloc"
void *DNMemoryTrackHeapAlloc( const UINT_PTR Size )
{
UINT_PTR RequiredSize;
MEMORY_LINK *pMemoryLink;
void *pReturn;
//
// Voice and lobby currently try allocating 0 byte buffers, can't enable this check yet.
//
//ASSERT( Size > 0 );
RequiredSize = Size + sizeof( MEMORY_LINK ) + ( sizeof( DWORD_PTR ) * 2 );
DNMemoryTrackingValidateMemory();
pMemoryLink = static_cast<MEMORY_LINK*>( HeapAlloc( g_hMemoryHeap, 0, RequiredSize ) );
if ( pMemoryLink != NULL )
{
pMemoryLink->Initialize();
EnterCriticalSection( &g_AllocatedMemoryLock );
g_uAllocatedMemoryCount++;
pMemoryLink->SetSize( Size );
pMemoryLink->LinkAfterOther( g_AllocatedMemory );
pMemoryLink->NoteCurrentCallStack();
pMemoryLink->SetOverrunSignatures();
LeaveCriticalSection( &g_AllocatedMemoryLock );
pReturn = pMemoryLink->GetDataPointer();
}
else
{
pReturn = NULL;
}
return pReturn;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// DNMemoryTrackHeapReAlloc - reallocate from heap and track allocations
//
// Entry: Pointer to old memory
// Size of memory to allocate
//
// Exit: Pointer to allocated memory
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DNMemoryTrackHeapReAlloc"
void *DNMemoryTrackHeapReAlloc( void *const pMemory, const UINT_PTR MemorySize )
{
UINT_PTR RequiredSize;
MEMORY_LINK *pMemoryLink;
void *pReturn;
ASSERT( pMemory != NULL );
//
// Voice and lobby currently try allocating 0 byte buffers, can't enable this check yet.
//
//ASSERT( MemorySize > 0 );
pMemoryLink = MEMORY_LINK::PointerFromData( pMemory );
DNMemoryTrackingValidateMemory();
EnterCriticalSection( &g_AllocatedMemoryLock );
g_uAllocatedMemoryCount--;
pMemoryLink->RemoveFromList();
pMemoryLink->SetSize( 0 );
LeaveCriticalSection( &g_AllocatedMemoryLock );
RequiredSize = MemorySize + sizeof( MEMORY_LINK ) + ( sizeof( DWORD_PTR ) * 2 );
pMemoryLink = static_cast<MEMORY_LINK*>( HeapReAlloc( g_hMemoryHeap, 0, pMemoryLink, RequiredSize ) );
if ( pMemoryLink != NULL )
{
EnterCriticalSection( &g_AllocatedMemoryLock );
g_uAllocatedMemoryCount++;
pMemoryLink->SetSize( MemorySize );
pMemoryLink->LinkAfterOther( g_AllocatedMemory );
pMemoryLink->SetOverrunSignatures();
LeaveCriticalSection( & g_AllocatedMemoryLock );
pReturn = pMemoryLink->GetDataPointer();
}
else
{
pReturn = NULL;
}
return pReturn;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// DNMemoryTrackHeapFree - free from heap and track memory
//
// Entry: Pointer to old memory
//
// Exit: Nothing
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DNMemoryTrackHeapFree"
void DNMemoryTrackHeapFree( void *const pMemory )
{
MEMORY_LINK *pMemoryLink;
ASSERT( pMemory != NULL );
DNMemoryTrackingValidateMemory();
pMemoryLink = MEMORY_LINK::PointerFromData( pMemory );
EnterCriticalSection( &g_AllocatedMemoryLock );
g_uAllocatedMemoryCount--;
pMemoryLink->RemoveFromList();
pMemoryLink->SetSize( 0 );
LeaveCriticalSection( &g_AllocatedMemoryLock );
HeapFree( g_hMemoryHeap, 0, pMemoryLink );
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// DNMemoryTrackValidateMemory - validate allocated memory
//
// Entry: Nothing
//
// Exit: Nothing
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DNMemoryTrackingValidateMemory"
void DNMemoryTrackingValidateMemory( void )
{
MEMORY_LINK *pMemoryLink;
char CallStackBuffer[ CALLSTACK_BUFFER_SIZE ];
//
// validate all of the allocated memory
//
EnterCriticalSection( &g_AllocatedMemoryLock );
pMemoryLink = g_AllocatedMemory.GetNext();
while ( pMemoryLink != &g_AllocatedMemory )
{
if ( pMemoryLink->IsCorrupted() != FALSE )
{
UINT_PTR MessageReturn;
char MessageString[ 1000 ];
wsprintf( MessageString,
// 7/28/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers and handles.
#ifdef _IA64_
// 8/05/2000(RichGr) - IA64: GetSize() returns UINT_PTR (64-bit), so we may as well handle in hex as %d expects a DWORD.
"Memory block: 0x%p\tAllocated size: 0x%p bytes\nCorruption Type: ",
#else
"Memory block: 0x%08x\tAllocated size: %d bytes\nCorruption Type: ",
#endif
pMemoryLink->GetDataPointer(),
pMemoryLink->GetSize() );
if ( !pMemoryLink->IsValid() )
{
strcat( MessageString, " ,INVALID LINK");
}
if ( pMemoryLink->UnderrunDetected() )
{
strcat( MessageString, " ,UNDERRUN DETECTED");
}
if ( pMemoryLink->OverrunDetected() )
{
strcat( MessageString, " ,OVERRUN DETECTED");
}
pMemoryLink->GetCallStack( CallStackBuffer );
MessageReturn = DisplayCallStack( MessageString, "Memory Corruption!", CallStackBuffer );
switch ( MessageReturn )
{
case IDABORT:
{
DNASSERT( FALSE );
break;
}
case IDIGNORE:
{
//
// You're probably going to get stopped in the heap
// manager!!!
//
break;
}
case IDRETRY:
{
DNASSERT( FALSE );
break;
}
}
}
pMemoryLink = pMemoryLink->GetNext();
}
LeaveCriticalSection( &g_AllocatedMemoryLock );
//
// ask the OS to validate the heap
//
if ( HeapValidate( g_hMemoryHeap, 0, NULL ) == FALSE )
{
DNASSERT( FALSE );
}
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// DNMemoryTrackDisplayMemoryLeaks - display memory leaks
//
// Entry: Nothing
//
// Exit: Nothing
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DNMemoryTrackDisplayMemoryLeaks"
static void DNMemoryTrackDisplayMemoryLeaks( void )
{
BOOL fDisplayLeaks;
UINT_PTR uMaxMemoryLeakCount;
UINT_PTR uMemoryLeakIndex;
//
// initialize
//
fDisplayLeaks = TRUE;
uMaxMemoryLeakCount = g_uAllocatedMemoryCount;
uMemoryLeakIndex = 0;
//
// Check for outstanding memory allocations.
//
while ( g_AllocatedMemory.IsEmpty() == FALSE )
{
MEMORY_LINK *pTemp;
UINT_PTR MessageReturn;
char CallStackBuffer[ CALLSTACK_BUFFER_SIZE ];
char LeakSizeString[ 50 ];
char DialogTitle[ 1000 ];
pTemp = g_AllocatedMemory.GetNext();
uMemoryLeakIndex++;
// 7/28/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers and handles.
#ifdef _IA64_
// 8/05/2000(RichGr) - IA64: GetSize() returns UINT_PTR (64-bit), so we may as well handle in hex as %d expects a DWORD.
wsprintf( LeakSizeString, "0x%p bytes leaked at address 0x%p!\n", pTemp->GetSize(), pTemp->GetDataPointer() );
#else
wsprintf( LeakSizeString, "%d bytes leaked at address 0x%08x!\n", pTemp->GetSize(), pTemp->GetDataPointer() );
#endif
wsprintf( DialogTitle,
"DirectPlay8 memory leak detected! ( #%d of %d )",
uMemoryLeakIndex,
uMaxMemoryLeakCount );
pTemp->GetCallStack( CallStackBuffer );
if ( ( g_dwMemLeakDisplayFlags & MEMORY_LEAK_REPORT_DPF ) != 0 )
{
DPFX(DPFPREP, 0, "%s%s%s\n", DialogTitle, LeakSizeString, CallStackBuffer );
}
if ( ( g_dwMemLeakDisplayFlags & MEMORY_LEAK_REPORT_DIALOG ) != 0 )
{
if ( fDisplayLeaks != FALSE )
{
MessageReturn = DisplayCallStack( LeakSizeString, DialogTitle, CallStackBuffer );
switch ( MessageReturn )
{
//
// stop application now
//
case IDABORT:
{
fDisplayLeaks = FALSE;
break;
}
//
// display next leak
//
case IDIGNORE:
{
break;
}
//
// stop in the debugger
//
case IDRETRY:
{
DNASSERT( FALSE );
break;
}
//
// unknown
//
default:
{
DNASSERT( FALSE );
break;
}
}
}
}
DNFree( pTemp->GetDataPointer() );
}
}
//**********************************************************************
//**********************************************************************
//**
//** THIS IS THE END OF THE MEMORY LOGGING SECTION.
//**
//**********************************************************************
#endif // DN_MEMORY_TRACKING
#if defined( DN_MEMORY_TRACKING ) || defined( DN_CRITICAL_SECTION_TRACKING )
//**********************************************************************
// ------------------------------
// DisplayCallStack - display a call stack message box
//
// Entry: Pointer to information string
// Pointer to title string
// Pointer to call stack string
//
// Exit: Dialog return code
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DisplayCallStack"
static int DisplayCallStack( const char *const pszMsg, const char *const pszTitle, const char *const pCallStackString )
{
MSGBOXPARAMS MessageBoxParams;
char szStackTraceMsg[ CALLSTACK_BUFFER_SIZE ];
_snprintf(szStackTraceMsg, CALLSTACK_BUFFER_SIZE-1, "%s%s", pszMsg, pCallStackString);
//
// display message box
//
memset( &MessageBoxParams, 0x00, sizeof( MessageBoxParams ) );
MessageBoxParams.cbSize = sizeof( MessageBoxParams );
MessageBoxParams.lpszText = szStackTraceMsg;
MessageBoxParams.lpszCaption = pszTitle;
MessageBoxParams.dwStyle = MB_ABORTRETRYIGNORE | MB_SETFOREGROUND | MB_TOPMOST | MB_DEFBUTTON2;
MessageBoxParams.hInstance = NULL;
return MessageBoxIndirect( &MessageBoxParams );
}
//**********************************************************************
//**********************************************************************
//**
//** END OF CALL STACK TRACKING SECTION.
//**
//**********************************************************************
#endif // defined( DN_MEMORY_TRACKING ) || defined( DN_CRITICAL_SECTION_TRACKING )
#ifdef DN_CRITICAL_SECTION_TRACKING
//**********************************************************************
//**
//** THIS IS THE CRITICAL-SECTION TRACKING SECTION. DON'T ADD FUNCTIONS HERE
//** THAT ARE NOT FOR CRITICAL SECTIONS!!
//**
//**********************************************************************
//**********************************************************************
// ------------------------------
// DNCSTrackInitialize - initialize critical section tracking code
//
// Entry: Nothing
//
// Exit: Boolean indicating success
// TRUE = initialization succeeded
// FALSE = initialization failed
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DNCSTrackInitialize"
static BOOL DNCSTrackInitialize( void )
{
g_blCritSecs.Initialize();
return DNInitializeCriticalSection(&g_CSLock);
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// DNCSTrackSetCriticalSectionRecursionCount - set the maximum recursion depth
// allowed by a DNCRITICAL_SECTION.
//
// Entry: Pointer to critical section
// Recursion count
//
// Exit: Nothing
//
// Note: The recursion count is the number of times we allow reentry so
// we need to bais by one to allow the user to take the lock at
// least once.
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DNCSTrackSetCriticalRecursionCount"
void DNCSTrackSetCriticalSectionRecursionCount( DNCRITICAL_SECTION *const pCriticalSection, const UINT_PTR RecursionCount )
{
UINT_PTR LocalRecursionCount;
DNASSERT( pCriticalSection != NULL );
//
// make sure we don't overflow
//
LocalRecursionCount = RecursionCount;
if ( LocalRecursionCount == -1 )
{
LocalRecursionCount--;
}
pCriticalSection->MaxLockCount = LocalRecursionCount + 1;
DNASSERT( pCriticalSection->MaxLockCount != 0 );
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// DNCSTrackEnterCriticalSection - enter a debug critical section
//
// Entry: Pointer to critical section
//
// Exit: Nothing
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DNCSTrackEnterCriticalSection"
void DNCSTrackEnterCriticalSection( DNCRITICAL_SECTION *const pCriticalSection )
{
UINT_PTR ThisThreadID;
static BOOL fDisplayCallStacks = TRUE;
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();
}
pCriticalSection->LockCount++;
if ( pCriticalSection->LockCount > pCriticalSection->MaxLockCount )
{
if ( pCriticalSection->MaxLockCount == 1 )
{
if ( fDisplayCallStacks != FALSE )
{
char CallStackBuffer[ CALLSTACK_BUFFER_SIZE ];
//
// Exceeded recursion depth of 1, display stack of call orignally
// holding the lock.
//
pCriticalSection->CallStack.GetCallStackString( CallStackBuffer );
switch ( DisplayCallStack( "Stack trace of function that originally held the lock:",
"DNCritical section has been reentered!",
CallStackBuffer ) )
{
//
// don't display any more critical section warnings!
//
case IDABORT:
{
fDisplayCallStacks = FALSE;
break;
}
//
// acknowledged
//
case IDIGNORE:
{
break;
}
//
// stop in debugger
//
case IDRETRY:
{
DNASSERT( FALSE );
break;
}
}
}
}
else
{
//
// exceeded recursion depth, check your code!!
//
DNASSERT( FALSE );
}
}
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// DNCSTrackLeaveCriticalSection - leave a debug critical section
//
// Entry: Pointer to critical section
//
// Exit: Nothing
// ------------------------------
#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 );
pCriticalSection->LockCount--;
if ( pCriticalSection->LockCount == 0 )
{
memset( &pCriticalSection->CallStack, 0x00, sizeof( pCriticalSection->CallStack ) );
pCriticalSection->OwningThreadID = DN_INVALID_THREAD_ID;
}
LeaveCriticalSection( &pCriticalSection->CriticalSection );
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// DNCSTrackCriticalSectionIsTakenByThisThread - determine if this thread has taken a
// specific critical section
//
// Entry: Pointer to critical section
// Boolean condition to test for
//
// Exit: Nothing
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DNCSTrackCriticalSectionIsTakenByThisThread"
void DNCSTrackCriticalSectionIsTakenByThisThread( const DNCRITICAL_SECTION *const pCriticalSection, const BOOL fFlag )
{
ASSERT( fFlag == ( pCriticalSection->OwningThreadID == GetCurrentThreadId() ) )
}
//**********************************************************************
//**********************************************************************
//**
//** THIS IS THE END OF THE CRITICAL-SECTION TRACKING CODE.
//**
//**********************************************************************
#endif // DN_CRITICAL_SECTION_TRACKING