windows-nt/Source/XPSP1/NT/inetsrv/iis/staxinc/export/rwinst.h
2020-09-26 16:20:57 +08:00

363 lines
11 KiB
C++

//-----------------------------------------------------------------------------
//
//
// File: rwinst.h
//
// Description: Instramented share lock implementations. Our current
// sharelock implementation is non-reentrant. This wrapper can also
// be used to check for possible deadlocks.
//
// Author: Mike Swafford (MikeSwa)
//
// History:
// 5/10/99 - MikeSwa Created
// 8/6/99 - MikeSwa created phatq version
// 11/6/99 - MikeSwa updated to use CShareLockNH
//
// Copyright (C) 1999 Microsoft Corporation
//
//-----------------------------------------------------------------------------
#ifndef __PTRWINST_H__
#define __PTRWINST_H__
#include "rwnew.h"
#include "listmacr.h"
#define SHARE_LOCK_INST_SIG 'kcoL'
#define SHARE_LOCK_INST_SIG_FREE '!koL'
#define THREAD_ID_BLOCK_SIG 'klBT'
#define THREAD_ID_BLOCK_SIG_FREE '!lBT'
#define THREAD_ID_BLOCK_UNUSED 0xFFFFFFFF
//Flag values that describe the type of tracking to do
//These can be passed to the constructor to allow different levels of
//tracking for different instances.
enum
{
SHARE_LOCK_INST_TRACK_CONTENTION = 0x00000001,
SHARE_LOCK_INST_TRACK_SHARED_THREADS = 0x00000002,
SHARE_LOCK_INST_TRACK_EXCLUSIVE_THREADS = 0x00000004,
SHARE_LOCK_INST_ASSERT_SHARED_DEADLOCKS = 0x00000008,
SHARE_LOCK_INST_TRACK_IN_GLOBAL_LIST = 0x00000010,
SHARE_LOCK_INST_TRACK_NOTHING = 0x80000000,
};
//Define some useful flag combinations
//This combination of flags has minimal perf impact, but does
//allow easier exclusive deadlock detection
#define SHARE_LOCK_INST_TRACK_MINIMALS ( \
SHARE_LOCK_INST_TRACK_EXCLUSIVE_THREADS | \
SHARE_LOCK_INST_TRACK_SHARED_THREADS | \
SHARE_LOCK_INST_TRACK_IN_GLOBAL_LIST )
//This combination of flags uses all of the tracking functionality of
//this class.
#define SHARE_LOCK_INST_TRACK_ALL (\
SHARE_LOCK_INST_TRACK_CONTENTION | \
SHARE_LOCK_INST_TRACK_SHARED_THREADS | \
SHARE_LOCK_INST_TRACK_EXCLUSIVE_THREADS | \
SHARE_LOCK_INST_ASSERT_SHARED_DEADLOCKS | \
SHARE_LOCK_INST_TRACK_IN_GLOBAL_LIST )
//A user can define their own defaults before including this file
//$$TODO - scale back the defaults for debug builds
#ifndef SHARE_LOCK_INST_TRACK_DEFAULTS
#ifdef DEBUG
#define SHARE_LOCK_INST_TRACK_DEFAULTS SHARE_LOCK_INST_TRACK_ALL
#else //not DEBUG
#define SHARE_LOCK_INST_TRACK_DEFAULTS SHARE_LOCK_INST_TRACK_MINIMALS
#endif //not DEBUG
#endif //SHARE_LOCK_INST_TRACK_DEFAULTS
#ifndef SHARE_LOCK_INST_DEFAULT_MAX_THREADS
#define SHARE_LOCK_INST_DEFAULT_MAX_THREADS 200
#endif //SHARE_LOCK_INST_DEFAULT_MAX_THREADS
//---[ CThreadIdBlock ]--------------------------------------------------------
//
//
// Description:
// An structure that represents a thread and the required info to
// hash it.
// Hungarian:
// tblk, ptblk
//
//-----------------------------------------------------------------------------
class CThreadIdBlock
{
protected:
DWORD m_dwSignature;
DWORD m_dwThreadId;
DWORD m_cThreadRecursionCount;
CThreadIdBlock *m_ptblkNext;
public:
CThreadIdBlock()
{
m_dwSignature = THREAD_ID_BLOCK_SIG;
m_dwThreadId = THREAD_ID_BLOCK_UNUSED;
m_cThreadRecursionCount = 0;
m_ptblkNext = NULL;
};
~CThreadIdBlock()
{
m_dwSignature = THREAD_ID_BLOCK_SIG_FREE;
if (m_ptblkNext)
delete m_ptblkNext;
m_ptblkNext = NULL;
};
DWORD cIncThreadCount(DWORD dwThreadId);
DWORD cDecThreadCount(DWORD dwThreadId);
DWORD cMatchesId(DWORD dwThreadId);
};
//---[ dwHashThreadId ]--------------------------------------------------------
//
//
// Description:
// Given a thread ID (return by GetCurrentThreadId()) it returns a hashed
// index. This is designed to be used in conjuction with a array (of
// size dwMax) of CThreadIdBlock's. Each CThreadIdBlock will implement
// linear chaining. A hash lookup can be implemented by somehthing as
// simple as:
// rgtblk[dwhashThreadId(GetCurrentThreadId()),
// sizeof(rgtblk)].cIncThreadCount();
// Parameters:
// dwThreadId Thread Id to hash
// dwMax Max hash value (actual max value +1)
// Returns:
// Hashed thread Id
// History:
// 8/9/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
inline DWORD dwHashThreadId(DWORD dwThreadId, DWORD dwMax)
{
//Typically IDs are between 0x100 and 0xFFF
//Also, the handles are multiples of 4 (ie end in 0, 4, 8, or C)
//For these conditions, this hash will give unique results for
//dwMax of 1000. (0xFFF-0x100)/4 < 1000
const DWORD dwMinExpectedThread = 0x100;
DWORD dwHash = dwThreadId;
dwHash -= dwMinExpectedThread;
dwHash >>= 2;
dwHash %= dwMax;
return dwHash;
};
typedef CShareLockNH CShareLockInstBase;
//---[ CShareLockInst ]--------------------------------------------------------
//
//
// Description:
// An intstramented version of CShareLockInstBase
// Hungarian:
// sli, psli
//
//-----------------------------------------------------------------------------
class CShareLockInst : public CShareLockInstBase
{
protected:
//Static lock-tracking variables
static LIST_ENTRY s_liLocks;
static volatile DWORD s_dwLock;
static DWORD s_cLockSpins;
static DWORD s_dwSignature;
static inline void AcquireStaticSpinLock();
static inline void ReleaseStaticSpinLock();
protected:
DWORD m_dwSignature;
//Flags describing types of tracking to be performed
DWORD m_dwFlags;
//List entry for list of all locks - used by a debugger extension
LIST_ENTRY m_liLocks;
//The total number of attempts to enter this lock in a shared mode
DWORD m_cShareAttempts;
//The total number of attempts to enter shared that blocked
DWORD m_cShareAttemptsBlocked;
//The total number ot attempts to enter this lock exclusively
DWORD m_cExclusiveAttempts;
//The total number ot attempts to enter this lock exclusively that blocked
DWORD m_cExclusiveAttemptsBlocked;
//Constant string descrition passed in
LPCSTR m_szDescription;
//ID of the thread that holds this lock exclusively
DWORD m_dwExclusiveThread;
//Array of thread IDs that hold this lock shared
CThreadIdBlock *m_rgtblkSharedThreadIDs;
//Maximum number of shared threads that can be tracked
DWORD m_cMaxTrackedSharedThreadIDs;
//The current number of shared threads
DWORD m_cCurrentSharedThreads;
//The most theads that have ever held this lock shared
DWORD m_cMaxConcurrentSharedThreads;
//Used internally, to see if the private functions need to be called
inline BOOL fTrackingEnabled();
BOOL fTrackContention()
{return (SHARE_LOCK_INST_TRACK_CONTENTION & m_dwFlags);};
BOOL fTrackSharedThreads()
{return (m_cMaxTrackedSharedThreadIDs &&
(SHARE_LOCK_INST_TRACK_SHARED_THREADS & m_dwFlags));};
BOOL fTrackExclusiveThreads()
{return (SHARE_LOCK_INST_TRACK_EXCLUSIVE_THREADS & m_dwFlags);};
BOOL fAssertSharedDeadlocks()
{return (fTrackSharedThreads() &&
(SHARE_LOCK_INST_ASSERT_SHARED_DEADLOCKS & m_dwFlags));};
BOOL fTrackInGlobalList()
{return (SHARE_LOCK_INST_TRACK_IN_GLOBAL_LIST & m_dwFlags);};
//statisics helper functions
void LogAcquireShareLock(BOOL fTry);
void LogReleaseShareLock();
void PrvShareLock();
void PrvShareUnlock();
BOOL PrvTryShareLock();
void PrvExclusiveLock();
void PrvExclusiveUnlock();
BOOL PrvTryExclusiveLock();
void PrvAssertIsLocked();
public:
CShareLockInst(
LPCSTR szDescription = NULL,
DWORD dwFlags = SHARE_LOCK_INST_TRACK_DEFAULTS,
DWORD cMaxTrackedSharedThreadIDs = SHARE_LOCK_INST_DEFAULT_MAX_THREADS);
~CShareLockInst();
//wrappers for sharelock functions
inline void ShareLock();
inline void ShareUnlock();
inline BOOL TryShareLock();
inline void ExclusiveLock();
inline void ExclusiveUnlock();
inline BOOL TryExclusiveLock();
inline void AssertIsLocked();
};
//---[ inline ShareLock wrapper functions ]------------------------------------
//
//
// Description:
// These functions are all thin wrappers for the sharelock wrapper
// functions. If there is any tracking enabled for this object, then
// the private (non-inline) functions are called.
//
// The idea is that you should be able to have these sharelocks in your
// code with minimal perf-impact when logging is turned off.
// Parameters:
//
// Returns:
//
// History:
// 5/24/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
void CShareLockInst::ShareLock()
{
if (fTrackContention() || fTrackSharedThreads() || fAssertSharedDeadlocks())
PrvShareLock();
else
CShareLockInstBase::ShareLock();
};
void CShareLockInst::ShareUnlock()
{
if (fTrackSharedThreads() || fAssertSharedDeadlocks())
PrvShareUnlock();
else
CShareLockInstBase::ShareUnlock();
};
BOOL CShareLockInst::TryShareLock()
{
if (fTrackContention() || fTrackSharedThreads() || fAssertSharedDeadlocks())
return PrvTryShareLock();
else
return CShareLockInstBase::TryShareLock();
};
void CShareLockInst::ExclusiveLock()
{
if (fTrackContention() || fTrackExclusiveThreads())
PrvExclusiveLock();
else
CShareLockInstBase::ExclusiveLock();
};
void CShareLockInst::ExclusiveUnlock()
{
if (fTrackExclusiveThreads())
PrvExclusiveUnlock();
else
CShareLockInstBase::ExclusiveUnlock();
};
BOOL CShareLockInst::TryExclusiveLock()
{
if (fTrackContention() || fTrackExclusiveThreads())
return PrvTryExclusiveLock();
else
return CShareLockInstBase::TryExclusiveLock();
};
//---[ AssertIsLocked ]--------------------------------------------------------
//
//
// Description:
// In Debug code, will assert if this is not locked by the calling thread.
// NOTE: This requires the following flags are specified at object
// creation time:
// SHARE_LOCK_INST_TRACK_SHARED_THREADS
// SHARE_LOCK_INST_TRACK_EXCLUSIVE_THREADS
// Parameters:
// -
// Returns:
// -
// History:
// 5/24/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
void CShareLockInst::AssertIsLocked()
{
#ifdef DEBUG
if ((SHARE_LOCK_INST_TRACK_SHARED_THREADS & m_dwFlags) &&
(SHARE_LOCK_INST_TRACK_EXCLUSIVE_THREADS & m_dwFlags))
{
PrvAssertIsLocked();
}
#endif //DEBUG
};
#endif //__PTRWINST_H__