441 lines
7.8 KiB
C++
441 lines
7.8 KiB
C++
|
/*++
|
||
|
|
||
|
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
|
||
|
)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
/********************************************************************
|
||
|
|
||
|
State
|
||
|
|
||
|
********************************************************************/
|
||
|
|
||
|
#if DBG
|
||
|
TState::
|
||
|
TState(
|
||
|
VOID
|
||
|
) : _StateVar(0)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
TState::
|
||
|
TState(
|
||
|
STATEVAR StateVar
|
||
|
) : _StateVar(StateVar)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
TState::
|
||
|
~TState(
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
STATEVAR
|
||
|
TState::
|
||
|
operator|=(
|
||
|
STATEVAR StateVarOn
|
||
|
)
|
||
|
{
|
||
|
SPLASSERT( bValidateSet( StateVarOn ));
|
||
|
|
||
|
_BackTrace.hCapture( _StateVar, StateVarOn );
|
||
|
|
||
|
_StateVar |= StateVarOn;
|
||
|
return _StateVar;
|
||
|
}
|
||
|
|
||
|
STATEVAR
|
||
|
TState::
|
||
|
operator&=(
|
||
|
STATEVAR StateVarMask
|
||
|
)
|
||
|
{
|
||
|
SPLASSERT( bValidateMask( StateVarMask ));
|
||
|
|
||
|
_BackTrace.hCapture( _StateVar, StateVarMask );
|
||
|
|
||
|
_StateVar &= StateVarMask;
|
||
|
return _StateVar;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
/********************************************************************
|
||
|
|
||
|
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 )
|
||
|
{
|
||
|
InitializeCriticalSection( &_CritSec );
|
||
|
_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_ERROR, ( "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_ERROR, ( "CritSec: Not outside 0x%x!\n",this ));
|
||
|
return FALSE;
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/********************************************************************
|
||
|
|
||
|
TCritSecHardLock
|
||
|
|
||
|
********************************************************************/
|
||
|
|
||
|
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
|