|
|
/*++
Copyright (c) 1994 Microsoft Corporation All rights reserved.
Module Name:
State.cxx
Abstract:
State abstraction and critical section
Author:
Albert Ting (AlbertT) 28-May-1994
Revision History:
--*/
#include "spllibp.hxx"
#pragma hdrstop
#if DBG
MCritSec* MRefCom::gpcsCom; #endif
/********************************************************************
Ref counting
********************************************************************/
VOID MRefQuick:: vIncRef( VOID ) { #if DBG
LONG cRefOld = _cRef; _BackTrace.hCapture( cRefOld, cRefOld + 1 ); #endif
++_cRef; }
LONG MRefQuick:: cDecRef( VOID ) { #if DBG
LONG cRefOld = _cRef; _BackTrace.hCapture( cRefOld, cRefOld - 1 ); #endif
--_cRef;
if( !_cRef ){
vRefZeroed(); return 0; } return _cRef; }
VOID MRefQuick:: vDecRefDelete( VOID ) { #if DBG
LONG cRefOld = _cRef; _BackTrace.hCapture( cRefOld, cRefOld ); #endif
--_cRef;
if( !_cRef ){ vRefZeroed(); } }
/********************************************************************
MRefCom: Reference counting using interlocked references. This avoids creating a common critical section.
vDeleteDecRef is the same as vDecRef, but it logs differently.
********************************************************************/
VOID MRefCom:: vIncRef( VOID ) { #if DBG
gpcsCom->vEnter(); LONG cRefOld = _cRef; gpcsCom->vLeave();
_BackTrace.hCapture( cRefOld, cRefOld+1 ); #endif
InterlockedIncrement( &_cRef ); }
LONG MRefCom:: cDecRef( VOID ) { #if DBG
gpcsCom->vEnter(); LONG cRefOld = _cRef; gpcsCom->vLeave();
_BackTrace.hCapture( cRefOld, cRefOld - 1 ); #endif
LONG cRefReturn = InterlockedDecrement( &_cRef );
if( !cRefReturn ){ vRefZeroed(); } return cRefReturn; }
VOID MRefCom:: vDecRefDelete( VOID ) { #if DBG
gpcsCom->vEnter(); LONG cRefOld = _cRef; gpcsCom->vLeave();
_BackTrace.hCapture( cRefOld, cRefOld ); #endif
if( !InterlockedDecrement( &_cRef )){ vRefZeroed(); } }
VOID MRefCom:: vRefZeroed( VOID ) { }
/********************************************************************
Critical section implementation
Logging:
CS initialized: 00000000 00000000 00000000
CS acquired: 1eeeeeee bbbbbbbb tttttttt e New entry count. b TickCount thread was blocked before acquiring CS. t Total tickcount all threads have blocked before acquiring CS
CS released: 0eeeeeee iiiiiiii tttttttt e New entry count. i Time spent inside the CS, from _first_ acquisition. t Total tickcount all threads inside CS.
********************************************************************/
#if DBG
MCritSec:: MCritSec( VOID ) : _dwThreadOwner( 0 ), _dwEntryCount( 0 ), _dwTickCountBlockedTotal( 0 ), _dwTickCountInsideTotal( 0 ), _dwEntryCountTotal( 0 ) { InitializeCriticalSectionAndSpinCount( &_CritSec, 0x80000000 ); _BackTrace.hCapture( 0, 0, 0 ); }
MCritSec:: ~MCritSec( VOID ) { DeleteCriticalSection( &_CritSec ); }
VOID MCritSec:: vEnter( VOID ) { DWORD dwTickCountBefore = GetTickCount();
EnterCriticalSection( &_CritSec );
++_dwEntryCountTotal;
DWORD dwTickCountBlocked = 0;
//
// Re-entrant case: only start the TickCountEntered counter
// if this is the first time we've entered the cs.
//
if( _dwEntryCount == 0 ){
//
// Check how long it took us to enter the critical section.
//
_dwTickCountEntered = GetTickCount(); dwTickCountBlocked = _dwTickCountEntered - dwTickCountBefore;
//
// Update the amount of time this thread blocked on this cs.
//
_dwTickCountBlockedTotal += dwTickCountBlocked; }
//
// We have entered the critical section; update the count
// and the thread owner.
//
++_dwEntryCount; _dwThreadOwner = GetCurrentThreadId();
_BackTrace.hCapture( 0x10000000 | _dwEntryCount, dwTickCountBlocked, _dwTickCountBlockedTotal );
}
VOID MCritSec:: vLeave( VOID ) { SPLASSERT( bInside( ));
DWORD dwTickCountInside = GetTickCount() - _dwTickCountEntered;
--_dwEntryCount;
//
// Verify that we don't leave a CritSecHardLock.
//
TIter Iter; TCritSecHardLock *pCritSecHardLock;
for( CritSecHardLock_vIterInit( Iter ), Iter.vNext(); Iter.bValid(); Iter.vNext( )){
pCritSecHardLock = CritSecHardLock_pConvert( Iter );
//
// If you hit this assert, then you have created a hard
// lock, but someone is trying to leave it. See header file
// for more info (state.hxx).
//
if( _dwEntryCount < pCritSecHardLock->_dwEntryCountMarker ){ DBGMSG( DBG_ERROR, ( "CritSec.vLeave: Leaving a hard lock.\n" )); } }
//
// If this leave frees the critical section, then capture
// the total time the section was held (from the very first enter).
//
if( !_dwEntryCount ){ _dwTickCountInsideTotal += dwTickCountInside;
//
// Since we are leaving the critical section for the last
// time, the CS is now unowned. We set the thread owner to 0.
//
_dwThreadOwner = 0; }
//
// Note: dwTickCountInsideTotal is based on _first_ entrance
// of critical section, not the most recent.
//
_BackTrace.hCapture( ~0x10000000 & _dwEntryCount, dwTickCountInside, _dwTickCountInsideTotal );
LeaveCriticalSection( &_CritSec ); }
BOOL MCritSec:: bInside( VOID ) const { if( !_dwEntryCount || GetCurrentThreadId() != _dwThreadOwner ){
DBGMSG( DBG_NONE, ( "CritSec: Not inside 0x%x!\n", this )); return FALSE; } return TRUE; }
BOOL MCritSec:: bOutside( VOID ) const { //
// We are outside if dwThreadOwner is not our thread id.
//
DWORD dwThreadOwner = (DWORD)InterlockedCompareExchange( (PLONG)&_dwThreadOwner, 0, 0 );
if( dwThreadOwner == GetCurrentThreadId( )){
DBGMSG( DBG_NONE, ( "CritSec: Not outside 0x%x!\n",this )); return FALSE; } return TRUE; }
#else // !DBG
MCritSec:: MCritSec() { InitializeCriticalSectionAndSpinCount(&_CritSec, 0); }
#endif
/********************************************************************
TCritSecHardLock
********************************************************************/
#if DBG
TCritSecHardLock:: TCritSecHardLock( MCritSec& CritSec ) : _CritSec( CritSec ) { _CritSec.vEnter();
//
// Add ourselves to the linked list and remember what the entry
// count is. Everytime we leave the critical section, we'll look
// at all the items in the list and see if the current entry count
// is < all hard locks.
//
_CritSec.CritSecHardLock_vAdd( this ); _dwEntryCountMarker = _CritSec._dwEntryCount; }
TCritSecHardLock:: ~TCritSecHardLock( VOID ) { CritSecHardLock_vDelinkSelf(); _CritSec.vLeave(); }
#endif
|