#ifndef _SYNC_HXX_INCLUDED
#define _SYNC_HXX_INCLUDED

#include "nt.h"
#include "ntrtl.h"
#include "nturtl.h"
#include "windows.h"

#pragma warning ( disable : 4786 )	//  we allow huge symbol names


//  Build Options

#define SYNC_USE_X86_ASM			//  use x86 assembly for atomic memory manipulation
//#define SYNC_ANALYZE_PERFORMANCE	//  analyze performance of synchronization objects
#ifdef SYNC_ANALYZE_PERFORMANCE
#define SYNC_DUMP_PERF_DATA			//  dump performance analysis of synchronization objects
#endif  //  SYNC_ANALYZE_PERFORMANCE
//#define SYNC_DEADLOCK_DETECTION		//  perform deadlock detection
//#define SYNC_VALIDATE_IRKSEM_USAGE	//  validate IRKSEM (CReferencedKernelSemaphore) usage

#ifdef DEBUG
#ifdef DBG
#else  //  !DBG
#define SYNC_DEADLOCK_DETECTION		//  always perform deadlock detection in DEBUG
#define SYNC_VALIDATE_IRKSEM_USAGE	//  always validate IRKSEM (CReferencedKernelSemaphore) usage in DEBUG
#endif  //  DBG
#endif  //  DEBUG


//	copied from basestd.h to make LONG_PTR available.

#ifdef __cplusplus
extern "C" {
#endif

//
// The following types are guaranteed to be signed and 32 bits wide.
//

typedef int LONG32, *PLONG32;
typedef int INT32, *PINT32;

//
// The following types are guaranteed to be unsigned and 32 bits wide.
//

typedef unsigned int ULONG32, *PULONG32;
typedef unsigned int DWORD32, *PDWORD32;
typedef unsigned int UINT32, *PUINT32;

//
// The INT_PTR is guaranteed to be the same size as a pointer.  Its
// size with change with pointer size (32/64).  It should be used
// anywhere that a pointer is cast to an integer type. UINT_PTR is
// the unsigned variation.
//
// __int3264 is intrinsic to 64b MIDL but not to old MIDL or to C compiler.
//
#if ( 501 < __midl )

    typedef __int3264 INT_PTR, *PINT_PTR;
    typedef unsigned __int3264 UINT_PTR, *PUINT_PTR;

    typedef __int3264 LONG_PTR, *PLONG_PTR;
    typedef unsigned __int3264 ULONG_PTR, *PULONG_PTR;

#else  // midl64
// old midl and C++ compiler

#ifdef _WIN64
    typedef __int64 INT_PTR, *PINT_PTR;
    typedef unsigned __int64 UINT_PTR, *PUINT_PTR;

    typedef __int64 LONG_PTR, *PLONG_PTR;
    typedef unsigned __int64 ULONG_PTR, *PULONG_PTR;

    #define __int3264   __int64
#else
    typedef int INT_PTR, *PINT_PTR;
    typedef unsigned int UINT_PTR, *PUINT_PTR;

    typedef long LONG_PTR, *PLONG_PTR;
    typedef unsigned long ULONG_PTR, *PULONG_PTR;

    #define __int3264   __int32
#endif

#endif //midl64

typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR;


//
// The following types are guaranteed to be signed and 64 bits wide.
//

typedef __int64 LONG64, *PLONG64;
typedef __int64 INT64,  *PINT64;


//
// The following types are guaranteed to be unsigned and 64 bits wide.
//

typedef unsigned __int64 ULONG64, *PULONG64;
typedef unsigned __int64 DWORD64, *PDWORD64;
typedef unsigned __int64 UINT64,  *PUINT64;

//
// SIZE_T used for counts or ranges which need to span the range of
// of a pointer.  SSIZE_T is the signed variation.
//

typedef ULONG_PTR SIZE_T, *PSIZE_T;
typedef LONG_PTR SSIZE_T, *PSSIZE_T;

//
//	useful macros for both 32/64
//

#define OffsetOf(s,m)   (SIZE_T)&(((s *)0)->m)

#ifdef __cplusplus
}
#endif


#pragma warning ( disable : 4355 )


#include <limits.h>
#include <new.h>
#include <stdarg.h>
#include <stdlib.h>


//  calling convention

#define OSSYNCAPI __stdcall


//  basic types

typedef int BOOL;
#define fFalse BOOL( 0 )
#define fTrue  BOOL( !0 )

typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long DWORD;
typedef unsigned __int64 QWORD;


//  Assertions

//  Assertion Failure action
//
//  called to indicate to the developer that an assumption is not true

void OSSYNCAPI AssertFail( const char* szMessage, const char* szFilename, long lLine );

//  Assert Macros

//  asserts that the given expression is true or else fails with the specified message

#define OSSYNCAssertSzRTL( exp, sz )	( ( exp ) ? (void) 0 : AssertFail( sz, __FILE__, __LINE__ ) )
#ifdef DEBUG
#define OSSYNCAssertSz( exp, sz )		OSSYNCAssertSzRTL( exp, sz )
#else  //  !DEBUG
#define OSSYNCAssertSz( exp, sz )
#endif  //  DEBUG

//  asserts that the given expression is true or else fails with that expression

#define OSSYNCAssertRTL( exp )			OSSYNCAssertSzRTL( exp, #exp )
#define OSSYNCAssert( exp )				OSSYNCAssertSz( exp, #exp )


//  Enforces

//  Enforce Failure action
//
//  called when a strictly enforced condition has been violated

void OSSYNCAPI EnforceFail( const char* szMessage, const char* szFilename, long lLine );

//  Enforce Macros

//  the given expression MUST be true or else fails with the specified message

#define OSSYNCEnforceSz( exp, sz )		( ( exp ) ? (void) 0 : EnforceFail( sz, __FILE__, __LINE__ ) )

//  the given expression MUST be true or else fails with that expression

#define OSSYNCEnforce( exp )			OSSYNCEnforceSz( exp, #exp )

#ifdef SYNC_VALIDATE_IRKSEM_USAGE
#define OSSYNCEnforceIrksem( exp, sz )	OSSYNCEnforceSz( exp, sz )
#else  //  !SYNC_VALIDATE_IRKSEM_USAGE
#define OSSYNCEnforceIrksem( exp, sz )
#endif  //  SYNC_VALIDATE_IRKSEM_USAGE


//  OSSYNC_FOREVER marks all convergence loops

#if defined( _M_IX86 ) && defined( SYNC_USE_X86_ASM )
inline void OSSyncPause() { __asm rep nop }
#else  //  !_M_IX86 || !SYNC_USE_X86_ASM
inline void OSSyncPause() {}
#endif  //  _M_IX86 && SYNC_USE_X86_ASM

#ifdef DEBUG
#define OSSYNC_FOREVER for ( int cLoop = 0; ; cLoop++, OSSyncPause() )
#else  //  !DEBUG
#define OSSYNC_FOREVER for ( ; ; OSSyncPause() )
#endif  //  DEBUG


namespace OSSYNC {


class CDumpContext;


//  Context Local Storage

class COwner;
class CLockDeadlockDetectionInfo;

struct CLS
	{
#ifdef SYNC_DEADLOCK_DETECTION

	COwner*						pownerLockHead;				//  list of locks owned by this context
	DWORD						cDisableOwnershipTracking;	//  lock ownerships are not tracked for this context
	BOOL						fOverrideDeadlock;			//  next lock ownership will not be a deadlock
	
	CLockDeadlockDetectionInfo*	plddiLockWait;				//  lock for which this context is waiting
	DWORD						groupLockWait;				//  lock group for which this context is waiting

#endif  //  SYNC_DEADLOCK_DETECTION
	};

//  returns the pointer to the current context's local storage

CLS* const OSSYNCAPI Pcls();


//  Processor Information

//  returns the maximum number of processors this process can utilize

int OSSYNCAPI OSSyncGetProcessorCountMax();

//  returns the current number of processors this process can utilize

int OSSYNCAPI OSSyncGetProcessorCount();

//  returns the processor number that the current context _MAY_ be executing on
//
//  NOTE:  the current context may change processors at any time

int OSSYNCAPI OSSyncGetCurrentProcessor();

//  sets the processor number returned by OSSyncGetCurrentProcessor()

void OSSYNCAPI OSSyncSetCurrentProcessor( const int iProc );

	
//  High Resolution Timer

//  returns the current HRT frequency

QWORD OSSYNCAPI QwOSTimeHRTFreq();

//  returns the current HRT count

QWORD OSSYNCAPI QwOSTimeHRTCount();


//  Timer

//  returns the current tick count where one tick is one millisecond

DWORD OSSYNCAPI DwOSTimeGetTickCount();


//  Global Synchronization Constants

//    wait time used for testing the state of the kernel object

extern const int cmsecTest;

//    wait time used for infinite wait on a kernel object

extern const int cmsecInfinite;

//    maximum wait time on a kernel object before a deadlock is suspected

extern const int cmsecDeadlock;

//    wait time used for infinite wait on a kernel object without deadlock

extern const int cmsecInfiniteNoDeadlock;

//    cache line size

extern const int cbCacheLine;


//  Atomic Memory Manipulations

//  returns fTrue if the given data is properly aligned for atomic modification

inline const BOOL IsAtomicallyModifiable( long* plTarget )
	{
	return ULONG_PTR( plTarget ) % sizeof( long ) == 0;
	}

inline const BOOL IsAtomicallyModifiablePointer( void*const* ppvTarget )
	{
	return ULONG_PTR( ppvTarget ) % sizeof( void* ) == 0;
	}


#if defined( _M_IX86 ) && defined( SYNC_USE_X86_ASM )

#pragma warning( disable:  4035 )

//  atomically compares the current value of the target with the specified
//  initial value and if equal sets the target to the specified final value.
//  the initial value of the target is returned.  the exchange is successful
//  if the value returned equals the specified initial value.  the target
//  must be aligned to a four byte boundary

inline long AtomicCompareExchange( long* const plTarget, const long lInitial, const long lFinal )
	{
	OSSYNCAssert( IsAtomicallyModifiable( plTarget ) );
	
	__asm mov			ecx, plTarget
	__asm mov			edx, lFinal
	__asm mov			eax, lInitial
	__asm lock cmpxchg	[ecx], edx
	}

inline void* AtomicCompareExchangePointer( void** const ppvTarget, void* const pvInitial, void* const pvFinal )
	{
	OSSYNCAssert( IsAtomicallyModifiablePointer( ppvTarget ) );
	
	return (void*) AtomicCompareExchange( (long* const) ppvTarget, (const long) pvInitial, (const long) pvFinal );
	}

//  atomically sets the target to the specified value, returning the target's
//  initial value.  the target must be aligned to a four byte boundary

inline long AtomicExchange( long* const plTarget, const long lValue )
	{
	OSSYNCAssert( IsAtomicallyModifiable( plTarget ) );
	
	__asm mov			ecx, plTarget
	__asm mov			eax, lValue
	__asm lock xchg		[ecx], eax
	}

inline void* AtomicExchangePointer( void* const * ppvTarget, void* const pvValue )
	{
	OSSYNCAssert( IsAtomicallyModifiablePointer( ppvTarget ) );
	
	return (void*) AtomicExchange( (long* const) ppvTarget, (const long) pvValue );
	}

//  atomically adds the specified value to the target, returning the target's
//  initial value.  the target must be aligned to a four byte boundary

inline long AtomicExchangeAdd( long* const plTarget, const long lValue )
	{
	OSSYNCAssert( IsAtomicallyModifiable( plTarget ) );
	
	__asm mov			ecx, plTarget
	__asm mov			eax, lValue
	__asm lock xadd		[ecx], eax
	}

#pragma warning( default:  4035 )

#elif defined( _WIN64 )

inline long AtomicExchange( long* const plTarget, const long lValue )
	{
	OSSYNCAssert( IsAtomicallyModifiable( plTarget ) );
	
	return InterlockedExchange( plTarget, lValue );
	}

inline long AtomicExchangeAdd( long* const plTarget, const long lValue )
	{
	OSSYNCAssert( IsAtomicallyModifiable( plTarget ) );
	
	return InterlockedExchangeAdd( plTarget, lValue );
	}

inline long AtomicCompareExchange( long* const plTarget, const long lInitial, const long lFinal )
	{
	OSSYNCAssert( IsAtomicallyModifiable( plTarget ) );
	
	return InterlockedCompareExchange( plTarget, lFinal, lInitial );
	}

inline void* AtomicExchangePointer( void* const * ppvTarget, void* const pvValue )
	{
	OSSYNCAssert( IsAtomicallyModifiablePointer( ppvTarget ) );
	
	return InterlockedExchangePointer( (void **)ppvTarget, pvValue );
	}
	
inline void* AtomicCompareExchangePointer( void** const ppvTarget, void* const pvInitial, void* const pvFinal )
	{
	OSSYNCAssert( IsAtomicallyModifiablePointer( ppvTarget ) );
	
	return InterlockedCompareExchangePointer( ppvTarget, pvFinal, pvInitial );
	}

#else

long OSSYNCAPI AtomicCompareExchange( long* const plTarget, const long lInitial, const long lFinal );
void* OSSYNCAPI AtomicCompareExchangePointer( void** const ppvTarget, void* const pvInitial, void* const pvFinal );
long OSSYNCAPI AtomicExchange( long* const plTarget, const long lValue );
void* OSSYNCAPI AtomicExchangePointer( void* const * ppvTarget, void* const pvValue );
long OSSYNCAPI AtomicExchangeAdd( long* const plTarget, const long lValue );

#endif

//  atomically adds the specified value to the target, returning the target's
//	initial value.  the target must be aligned to a pointer boundary.

inline void* AtomicExchangeAddPointer( void** const ppvTarget, void* const pvValue )
	{
	void*	pvInitial;
	void*	pvFinal;
	void*	pvResult;

	OSSYNCAssert( IsAtomicallyModifiablePointer( ppvTarget ) );

	OSSYNC_FOREVER
		{
		pvInitial	= *((void* volatile *)ppvTarget);
		pvFinal		= (void*)( ULONG_PTR( pvInitial ) + ULONG_PTR( pvValue ) );
		pvResult	= AtomicCompareExchangePointer( ppvTarget, pvInitial, pvFinal );

		if ( pvResult == pvInitial )
			{
			break;
			}
		}

	return pvResult;
	}

//  atomically increments the target, returning the incremented value.  the
//  target must be aligned to a four byte boundary

inline long AtomicIncrement( long* const plTarget )
	{
	return AtomicExchangeAdd( plTarget, 1 ) + 1;
	}

//  atomically decrements the target, returning the decremented value.  the
//  target must be aligned to a four byte boundary

inline long AtomicDecrement( long* const plTarget )
	{
	return AtomicExchangeAdd( plTarget, -1 ) - 1;
	}

//  atomically adds the specified value to the target.  the target must be
//  aligned to a four byte boundary

inline void AtomicAdd( QWORD* const pqwTarget, const QWORD qwValue )
	{
#ifdef _WIN64
	AtomicExchangeAddPointer( (VOID **)pqwTarget, (VOID *)qwValue );
#else
	DWORD* const	pdwTargetLow	= (DWORD*)pqwTarget;
	DWORD* const	pdwTargetHigh	= pdwTargetLow + 1;

	const DWORD		dwValueLow		= DWORD( qwValue );
	DWORD			dwValueHigh		= DWORD( qwValue >> 32 );

	if ( dwValueLow )
		{
		if ( DWORD( AtomicExchangeAdd( (long*)pdwTargetLow, dwValueLow ) ) + dwValueLow < dwValueLow )
			{
			dwValueHigh++;
			}
		}
	if ( dwValueHigh )
		{
		AtomicExchangeAdd( (long*)pdwTargetHigh, dwValueHigh );
		}
#endif	
	}


//	Atomically increments a DWORD counter, returning TRUE if the final
//	value is less than or equal to a specified maximum, or FALSE otherwise.
//	The pre-incremented value is returned in *pdwInitial
//	WARNING: to determine if the maximum value has been reached, an UNSIGNED
//	comparison is performed

inline BOOL FAtomicIncrementMax(
	volatile DWORD * const	pdw,
	DWORD * const			pdwInitial,
	const DWORD				dwMax )
	{
	OSSYNC_FOREVER
		{
		const DWORD		dwInitial	= *pdw;
		if ( dwInitial < dwMax )
			{
			const DWORD	dwFinal		= dwInitial + 1;
			if ( dwInitial == (DWORD)AtomicCompareExchange( (LONG *)pdw, (LONG)dwInitial, (LONG)dwFinal ) )
				{
				*pdwInitial = dwInitial;
				return fTrue;
				}
			}
		else
			return fFalse;
		}

	//	should be impossible
	OSSYNCAssert( fFalse );
	return fFalse;
	}


//	Atomically increments a pointer-sized counter, returning TRUE if the final
//	value is less than or equal to a specified maximum, or FALSE otherwise.
//	The pre-incremented value is returned in *ppvInitial
//	WARNING: to determine if the maximum value has been reached, an UNSIGNED
//	comparison is performed

inline BOOL FAtomicIncrementPointerMax(
	volatile VOID ** const	ppv,
	VOID ** const			ppvInitial,
	const VOID * const		pvMax )
	{
	OSSYNC_FOREVER
		{
		const QWORD		qwInitial	= QWORD( *ppv );
		if ( qwInitial < (QWORD)pvMax )
			{
			const QWORD	qwFinal		= qwInitial + 1;
			if ( qwInitial == (QWORD)AtomicCompareExchangePointer( (VOID **)ppv, (VOID *)qwInitial, (VOID *)qwFinal ) )
				{
				*ppvInitial = (VOID *)qwInitial;
				return fTrue;
				}
			}
		else
			return fFalse;
		}

	//	should be impossible
	OSSYNCAssert( fFalse );
	return fFalse;
	}



//  Enhanced Synchronization Object State Container
//
//  This class manages a "simple" or normal state for an arbitrary sync object
//  and its "enhanced" counterpart.  Which type is used depends on the build.
//  The goal is to maintain a footprint equal to the normal state so that other
//  classes that contain this object do not fluctuate in size depending on what
//  build options have been selected.  For example, a performance build might
//  need extra storage to collect performance stats on the object.  This data
//  will force the object to be allocated elsewhere in memory but will not change
//  the size of the object in its containing class.
//
//  Template Arguments:
//
//    CState            sync object state class
//    CStateInit        sync object state class ctor arg type
//    CInformation      sync object information class
//    CInformationInit  sync object information class ctor arg type

void* OSSYNCAPI ESMemoryNew( size_t cb );
void OSSYNCAPI ESMemoryDelete( void* pv );

//    determine when enhanced state is needed

#if defined( SYNC_ANALYZE_PERFORMANCE ) || defined( SYNC_DEADLOCK_DETECTION )
#define SYNC_ENHANCED_STATE
#endif  //  SYNC_ANALYZE_PERFORMANCE || SYNC_DEADLOCK_DETECTION

template< class CState, class CStateInit, class CInformation, class CInformationInit >
class CEnhancedStateContainer
	{
	public:

		//  types

		//    enhanced state
	
		class CEnhancedState
			:	public CState,
				public CInformation
			{
			public:

				CEnhancedState( const CStateInit& si, const CInformationInit& ii )
					:	CState( si ),
						CInformation( ii )
						
					{
					}
					
				void* operator new( size_t cb ) { return ESMemoryNew( cb ); }
				void operator delete( void* pv ) { ESMemoryDelete( pv ); }
			};

		//  member functions

		//    ctors / dtors

		CEnhancedStateContainer( const CStateInit& si, const CInformationInit& ii )
			{
#ifdef SYNC_ENHANCED_STATE

			m_pes = new CEnhancedState( si, ii );

#else  //  !SYNC_ENHANCED_STATE

			new( (CState*) m_rgbState ) CState( si );

#endif  //  SYNC_ENHANCED_STATE
			}

		~CEnhancedStateContainer()
			{
#ifdef SYNC_ENHANCED_STATE

			delete m_pes;
#ifdef DEBUG
			m_pes = NULL;
#endif  //  DEBUG

#else  //  !SYNC_ENHANCED_STATE

			( (CState*) m_rgbState )->~CState();

#endif  //  SYNC_ENHANCED_STATE
			}

		//    accessors

		CEnhancedState& State() const
			{
#ifdef SYNC_ENHANCED_STATE

			return *m_pes;

#else  //  !SYNC_ENHANCED_STATE

			//  NOTE:  this assumes that CInformation has no storage!

			return *( (CEnhancedState*) m_rgbState );

#endif  //  SYNC_ENHANCED_STATE
			}
		
		//    debugging support

		void Dump( CDumpContext& dc ) const;
			
	private:

		//  data members

		//    either a pointer to the enhanced state elsewhere in memory or the
		//      actual state data, depending on the mode of the sync object
		
		union
			{
			CEnhancedState*	m_pes;
			BYTE			m_rgbState[ sizeof( CState ) ];
			};
	};


//  Synchronization Object Base Class
//
//  All Synchronization Objects are derived from this class

class CSyncObject
	{
	public:

		//  member functions
	
		//    ctors / dtors

		CSyncObject() {}
		~CSyncObject() {}

	private:

		//  member functions

		//    operators
		
		CSyncObject& operator=( CSyncObject& );  //  disallowed
	};


//  Synchronization Object Basic Information

class CSyncBasicInfo
	{
	public:

		//  member functions
	
		//    ctors / dtors

		CSyncBasicInfo( const char* szInstanceName );
		~CSyncBasicInfo();

		//    manipulators

		void SetTypeName( const char* szTypeName );
		void SetInstance( const CSyncObject* const psyncobj );

		//    accessors

#ifdef SYNC_ENHANCED_STATE

		const char* SzInstanceName() const { return m_szInstanceName; }
		const char* SzTypeName() const { return m_szTypeName; }
		const CSyncObject* const Instance() const { return m_psyncobj; }

#endif  //  SYNC_ENHANCED_STATE
		
		//    debugging support

		void Dump( CDumpContext& dc ) const;

	private:

		//  member functions

		//    operators
		
		CSyncBasicInfo& operator=( CSyncBasicInfo& );  //  disallowed

		//  data members

#ifdef SYNC_ENHANCED_STATE

		//    Instance Name

		const char*		m_szInstanceName;

		//    Type Name

		const char*		m_szTypeName;

		//    Instance

		const CSyncObject*	m_psyncobj;

#endif  //  SYNC_ENHANCED_STATE
	};

//  sets the type name for the synchronization object

inline void CSyncBasicInfo::SetTypeName( const char* szTypeName )
	{
#ifdef SYNC_ENHANCED_STATE

	m_szTypeName = szTypeName;

#endif  //  SYNC_ENHANCED_STATE
	}

//  sets the instance pointer for the synchronization object
	
inline void CSyncBasicInfo::SetInstance( const CSyncObject* const psyncobj )
	{
#ifdef SYNC_ENHANCED_STATE

	m_psyncobj = psyncobj;

#endif  //  SYNC_ENHANCED_STATE
	}


//  Synchronization Object Performance:  Wait Times

class CSyncPerfWait
	{
	public:

		//  member functions
	
		//    ctors / dtors

		CSyncPerfWait();
		~CSyncPerfWait();

		//  member functions

		//    manipulators

		void StartWait();
		void StopWait();
		
		//    accessors

#ifdef SYNC_ANALYZE_PERFORMANCE

		QWORD	CWaitTotal() const		{ return m_cWait; }
		double	CsecWaitElapsed() const	{ return	(double)(signed __int64)m_qwHRTWaitElapsed /
													(double)(signed __int64)QwOSTimeHRTFreq(); }

#endif  //  SYNC_ANALYZE_PERFORMANCE
		
		//    debugging support

		void Dump( CDumpContext& dc ) const;

	private:

		//  member functions

		//    operators
		
		CSyncPerfWait& operator=( CSyncPerfWait& );  //  disallowed

		//  data members

#ifdef SYNC_ANALYZE_PERFORMANCE

		//    wait count

		volatile QWORD m_cWait;

		//    elapsed wait time

		volatile QWORD m_qwHRTWaitElapsed;

#endif  //  SYNC_ANALYZE_PERFORMANCE
	};

//  starts the wait timer for the sync object

inline void CSyncPerfWait::StartWait()
	{
#ifdef SYNC_ANALYZE_PERFORMANCE

	//  increment the wait count

	AtomicAdd( (QWORD*)&m_cWait, 1 );

	//  subtract the start wait time from the elapsed wait time.  this starts
	//  an elapsed time computation for this context.  StopWait() will later
	//  add the end wait time to the elapsed time, causing the following net
	//  effect:
	//
	//  m_qwHRTWaitElapsed += <end time> - <start time>
	//
	//  we simply choose to go ahead and do the subtraction now to save storage

	AtomicAdd( (QWORD*)&m_qwHRTWaitElapsed, QWORD( -__int64( QwOSTimeHRTCount() ) ) );

#endif  //  SYNC_ANALYZE_PERFORMANCE
	}

//  stops the wait timer for the sync object

inline void CSyncPerfWait::StopWait()
	{
#ifdef SYNC_ANALYZE_PERFORMANCE

	//  add the end wait time to the elapsed wait time.  this completes the
	//  computation started in StartWait()

	AtomicAdd( (QWORD*)&m_qwHRTWaitElapsed, QwOSTimeHRTCount() );

#endif  //  SYNC_ANALYZE_PERFORMANCE
	}


//  Null Synchronization Object State Initializer

class CSyncStateInitNull
	{
	};

extern const CSyncStateInitNull syncstateNull;


//  Kernel Semaphore Information

class CKernelSemaphoreInfo
	:	public CSyncBasicInfo,
		public CSyncPerfWait
	{
	public:

		//  member functions
	
		//    ctors / dtors

		CKernelSemaphoreInfo( const CSyncBasicInfo& sbi )
			:	CSyncBasicInfo( sbi )
			{
			}
		
		//    debugging support

		void Dump( CDumpContext& dc ) const;
	};


//  Kernel Semaphore State

class CKernelSemaphoreState
	{
	public:

		//  member functions
	
		//    ctors / dtors

		CKernelSemaphoreState( const CSyncStateInitNull& null ) : m_handle( 0 ) {}

		//    manipulators

		void SetHandle( void * handle ) { m_handle = handle; }
		
		//    accessors

		void* Handle() { return m_handle; }
		
		//    debugging support

		void Dump( CDumpContext& dc ) const;

	private:

		//  member functions

		//    operators
		
		CKernelSemaphoreState& operator=( CKernelSemaphoreState& );  //  disallowed

		//  data members

		//    kernel semaphore handle

		void* m_handle;
	};


//  Kernel Semaphore

class CKernelSemaphore
	:	private CSyncObject,
		private CEnhancedStateContainer< CKernelSemaphoreState, CSyncStateInitNull, CKernelSemaphoreInfo, CSyncBasicInfo >
	{
	public:

		//  member functions
	
		//    ctors / dtors

		CKernelSemaphore( const CSyncBasicInfo& sbi );
		~CKernelSemaphore();

		//    init / term

		const BOOL FInit();
		void Term();

		//    manipulators

		void Acquire();
		const BOOL FTryAcquire();
		const BOOL FAcquire( const int cmsecTimeout );
		void Release( const int cToRelease = 1 );
		
		//    accessors

		const BOOL FReset();

		//    debugging support

		void Dump( CDumpContext& dc ) const;

	private:

		//  member functions

		//    operators
		
		CKernelSemaphore& operator=( CKernelSemaphore& );  //  disallowed

		//    accessors

		const BOOL FInitialized();
	};

//  acquire one count of the semaphore, waiting forever if necessary

inline void CKernelSemaphore::Acquire()
	{
	//  semaphore should be initialized

	OSSYNCAssert( FInitialized() );

	//  wait for the semaphore
	
	const BOOL fAcquire = FAcquire( cmsecInfinite );
	OSSYNCAssert( fAcquire );
	}

//  try to acquire one count of the semaphore without waiting.  returns 0 if a
//  count could not be acquired

inline const BOOL CKernelSemaphore::FTryAcquire()
	{
	//  semaphore should be initialized

	OSSYNCAssert( FInitialized() );

	//  test the semaphore
	
	return FAcquire( cmsecTest );
	}

//  returns fTrue if the semaphore has no available counts

inline const BOOL CKernelSemaphore::FReset()
	{
	//  semaphore should be initialized

	OSSYNCAssert( FInitialized() );

	//  test the semaphore
	
	return !FTryAcquire();
	}

//  returns fTrue if the semaphore has been initialized

inline const BOOL CKernelSemaphore::FInitialized()
	{
	return State().Handle() != 0;
	}


//  Kernel Semaphore Pool

class CKernelSemaphorePool
	{
	public:

		//  types
	
		//    index to a ref counted kernel semaphore

		typedef unsigned short IRKSEM;
		enum { irksemAllocated = 0xFFFE, irksemNil = 0xFFFF };

		//  member functions

		//    ctors / dtors

		CKernelSemaphorePool();
		~CKernelSemaphorePool();

		//    init / term

		const BOOL FInit();
		void Term();

		//    manipulators

		const IRKSEM Allocate( const CSyncObject* const psyncobj );
		void Reference( const IRKSEM irksem );
		void Unreference( const IRKSEM irksem );

		//    accessors

		CKernelSemaphore& Ksem( const IRKSEM irksem, const CSyncObject* const psyncobj ) const;

		const BOOL FInitialized() const;

		long CksemAlloc() const { return m_cksem; }

	private:

		//  types

		//    reference counted kernel semaphore

		class CReferencedKernelSemaphore
			:	public CKernelSemaphore
			{
			public:

				//  member functions

				//    ctors / dtors

				CReferencedKernelSemaphore();
				~CReferencedKernelSemaphore();

				//    init / term

				const BOOL FInit();
				void Term();

				//    manipulators

				BOOL FAllocate();
				void Release();

				void SetUser( const CSyncObject* const psyncobj );
				
				void Reference();
				const BOOL FUnreference();

				//    accessors

				const BOOL FInUse() const { return m_fInUse; }
				const int CReference() const { return m_cReference; }

#ifdef SYNC_VALIDATE_IRKSEM_USAGE
				const CSyncObject* const PsyncobjUser() const { return m_psyncobjUser; }
#endif  //  SYNC_VALIDATE_IRKSEM_USAGE

			private:

				//  member functions

				//    operators

				CReferencedKernelSemaphore& operator=( CReferencedKernelSemaphore& );  //  disallowed

				//  data members

				//    transacted state representation

				union
					{
					volatile long		m_l;
					struct
						{
						volatile unsigned short	m_cReference:15;	//  0 <= m_cReference <= ( 1 << 15 ) - 1
						volatile unsigned short m_fInUse:1;			//  m_fInUse = { 0, 1 }
						};
					};

				volatile long		m_fAvailable;

#ifdef SYNC_VALIDATE_IRKSEM_USAGE

				//    sync object currently using this semaphore

				const CSyncObject* volatile	m_psyncobjUser;

#else  //  SYNC_VALIDATE_IRKSEM_USAGE

				BYTE				m_rgbReserved1[4];

#endif  //  SYNC_VALIDATE_IRKSEM_USAGE

				BYTE				m_rgbReserved2[16];
			};

		//  member functions

		//    operators
		
		CKernelSemaphorePool& operator=( CKernelSemaphorePool& );  //  disallowed

		//    manipulators

		const IRKSEM AllocateNew();
		void Free( const IRKSEM irksem );

		//  data members

		//    semaphore index to semaphore map

		CReferencedKernelSemaphore*		m_mpirksemrksem;

		//    semaphore count

		volatile long					m_cksem;
	};

//  allocates an IRKSEM from the pool on behalf of the specified sync object
//
//  NOTE:  the returned IRKSEM has one reference count

inline const CKernelSemaphorePool::IRKSEM CKernelSemaphorePool::Allocate( const CSyncObject* const psyncobj )
	{
	//  semaphore pool should be initialized

	OSSYNCAssert( FInitialized() );

	//  there are semaphores in the semaphore pool

	IRKSEM irksem = irksemNil;
	if ( m_cksem )
		{
		//  hash into the semaphore pool based on this context's CLS and the time

		IRKSEM irksemHash = IRKSEM( UINT_PTR( UINT_PTR( Pcls() ) / sizeof( CLS ) + UINT_PTR( QwOSTimeHRTCount() ) ) % m_cksem );
		OSSYNCAssert( irksemHash >= 0 && irksemHash < m_cksem );

		//  try to allocate a semaphore, scanning forwards through the pool

		for (	long cLoop = 0;
				cLoop < m_cksem;
				cLoop++, irksemHash = IRKSEM( ++irksemHash % m_cksem ) )
			{
			if ( m_mpirksemrksem[ irksemHash ].FAllocate() )
				{
				irksem = irksemHash;
				break;
				}
			}
		}

	//  if we do not yet have a semaphore, allocate one

	if ( irksem == irksemNil )
		{
		irksem = AllocateNew();
		}

	//  validate irksem retrieved

	OSSYNCAssert( irksem != irksemNil );
	OSSYNCAssert( irksem >= 0 );
	OSSYNCAssert( irksem < m_cksem );

	//  set the user for this semaphore

	m_mpirksemrksem[irksem].SetUser( psyncobj );

	//  ensure that the semaphore we retrieved is reset

	OSSYNCEnforceIrksem(	m_mpirksemrksem[irksem].FReset(),
							"Illegal allocation of a Kernel Semaphore with available counts!"  );

	//  return the allocated semaphore

	return irksem;
	}

//  add a reference count to an IRKSEM

inline void CKernelSemaphorePool::Reference( const IRKSEM irksem )
	{
	//  validate IN args

	OSSYNCAssert( irksem != irksemNil );
	OSSYNCAssert( irksem >= 0 );
	OSSYNCAssert( irksem < m_cksem );

	//  semaphore pool should be initialized

	OSSYNCAssert( FInitialized() );
	
	//  increment the reference count for this IRKSEM

	m_mpirksemrksem[irksem].Reference();
	}

//  remove a reference count from an IRKSEM, freeing it if the reference count
//  drops to zero and it is not currently in use

inline void CKernelSemaphorePool::Unreference( const IRKSEM irksem )
	{
	//  validate IN args

	OSSYNCAssert( irksem != irksemNil );
	OSSYNCAssert( irksem >= 0 );
	OSSYNCAssert( irksem < m_cksem );

	//  semaphore pool should be initialized

	OSSYNCAssert( FInitialized() );
	
	//  decrement the reference count for this IRKSEM

	const BOOL fFree = m_mpirksemrksem[irksem].FUnreference();

	//  we need to free the semaphore

	if ( fFree )
		{
		//  free the IRKSEM back to the allocation stack

		Free( irksem );
		}
	}

//  returns the CKernelSemaphore object associated with the given IRKSEM

inline CKernelSemaphore& CKernelSemaphorePool::Ksem( const IRKSEM irksem, const CSyncObject* const psyncobj ) const
	{
	//  validate IN args

	OSSYNCAssert( irksem != irksemNil );
	OSSYNCAssert( irksem >= 0 );
	OSSYNCAssert( irksem < m_cksem );

	//  semaphore pool should be initialized

	OSSYNCAssert( FInitialized() );

	//  we had better be retrieving this semaphore for the right sync object

	OSSYNCEnforceIrksem(	m_mpirksemrksem[irksem].PsyncobjUser() == psyncobj,
							"Illegal use of a Kernel Semaphore by another Synchronization Object"  );
	
	//  return kernel semaphore

	return m_mpirksemrksem[irksem];
	}

//  returns fTrue if the semaphore pool has been initialized

inline const BOOL CKernelSemaphorePool::FInitialized() const
	{
	return m_mpirksemrksem != NULL;
	}

//  allocates a new irksem and adds it to the stack's irksem pool

inline const CKernelSemaphorePool::IRKSEM CKernelSemaphorePool::AllocateNew()
	{
	//  atomically allocate a position in the stack's irksem pool for our new
	//  irksem
	
	const long lDelta = 0x00000001;
	const long lBI = AtomicExchangeAdd( (long*) &m_cksem, lDelta );
	
	const IRKSEM irksem = IRKSEM( lBI );

	//  initialize this irksem

	new ( &m_mpirksemrksem[irksem] ) CReferencedKernelSemaphore;
	
	BOOL fInitKernelSemaphore = m_mpirksemrksem[irksem].FInit();
	OSSYNCEnforceSz( fInitKernelSemaphore, "Could not allocate a Kernel Semaphore" );

	//  return the irksem for use

	return irksem;
	}

//  frees the given IRKSEM back to the allocation stack

inline void CKernelSemaphorePool::Free( const IRKSEM irksem )
	{
	//  validate IN args

	OSSYNCAssert( irksem != irksemNil );
	OSSYNCAssert( irksem >= 0 );
	OSSYNCAssert( irksem < m_cksem );

	//  semaphore pool should be initialized

	OSSYNCAssert( FInitialized() );

	//  the semaphore to free had better not be in use

	OSSYNCEnforceIrksem(	!m_mpirksemrksem[irksem].FInUse(),
							"Illegal free of a Kernel Semaphore that is still in use"  );

	//  the semaphore had better not already be freed
	
	OSSYNCEnforceIrksem(	!m_mpirksemrksem[irksem].FAllocate(),
							"Illegal free of a Kernel Semaphore that is already free"  );
	
	//  ensure that the semaphore to free is reset

	OSSYNCEnforceIrksem(	m_mpirksemrksem[irksem].FReset(),
							"Illegal free of a Kernel Semaphore that has available counts"  );

	//  release the semaphore to the pool

	m_mpirksemrksem[irksem].Release();
	}


//  Referenced Kernel Semaphore

//  attempts to allocate the semaphore, returning fTrue on success

inline BOOL CKernelSemaphorePool::CReferencedKernelSemaphore::FAllocate()
	{
	return m_fAvailable && AtomicExchange( (long*)&m_fAvailable, 0 );
	}

//  releases the semaphore

inline void CKernelSemaphorePool::CReferencedKernelSemaphore::Release()
	{
	AtomicExchange( (long*)&m_fAvailable, 1 );
	}

//  sets the user for the semaphore and gives the user an initial reference

inline void CKernelSemaphorePool::CReferencedKernelSemaphore::SetUser( const CSyncObject* const psyncobj )
	{
	//  this semaphore had better not already be in use

	OSSYNCEnforceIrksem(	!m_fInUse,
							"Illegal allocation of a Kernel Semaphore that is already in use" );
	OSSYNCEnforceIrksem(	!m_psyncobjUser,
							"Illegal allocation of a Kernel Semaphore that is already in use" );

	//  mark this semaphore as in use and add an initial reference count for the
	//  user

	AtomicExchangeAdd( (long*) &m_l, 0x00008001 );
#ifdef SYNC_VALIDATE_IRKSEM_USAGE
	m_psyncobjUser	= psyncobj;
#endif  //  SYNC_VALIDATE_IRKSEM_USAGE
	}

//  add a reference count to the semaphore

inline void CKernelSemaphorePool::CReferencedKernelSemaphore::Reference()
	{
	//  increment the reference count
	
	AtomicIncrement( (long*) &m_l );

	//  there had better be at least one reference count!

	OSSYNCAssert( m_cReference > 0 );
	}

//  remove a reference count from the semaphore, returning fTrue if the last
//  reference count on the semaphore was removed and the semaphore was in use
//  (this is the condition on which we can free the semaphore to the stack)

inline const BOOL CKernelSemaphorePool::CReferencedKernelSemaphore::FUnreference()
	{
	//  there had better be at least one reference count!

	OSSYNCAssert( m_cReference > 0 );

	//  try forever until we succeed in removing our reference count

	long lBI;
	OSSYNC_FOREVER
		{
		//  read the current state of the control word as our expected before image

		const long lBIExpected = m_l;

		//  compute the after image of the control word by decrementing the
		//  reference count and reseting the In Use bit if and only if we are
		//  removing the last reference count

		const long lAI =	lBIExpected +
							(	lBIExpected == 0x00008001 ?
									0xFFFF7FFF :
									0xFFFFFFFF );

		//  attempt to perform the transacted state transition on the control word

		lBI = AtomicCompareExchange( (long*)&m_l, lBIExpected, lAI );

		//  the transaction failed

		if ( lBI != lBIExpected )
			{
			//  try again

			continue;
			}

		//  the transaction succeeded

		else
			{
			// we're done

			break;
			}
		}

	//  return fTrue if we removed the last reference count and reset the In Use bit

	if ( lBI == 0x00008001 )
		{
#ifdef SYNC_VALIDATE_IRKSEM_USAGE
		m_psyncobjUser = NULL;
#endif  //  SYNC_VALIDATE_IRKSEM_USAGE
		return fTrue;
		}
	else
		{
		return fFalse;
		}
	}


//  Global Kernel Semaphore Pool

extern CKernelSemaphorePool ksempoolGlobal;


//  Synchronization Object Performance:  Acquisition

class CSyncPerfAcquire
	{
	public:

		//  member functions
	
		//    ctors / dtors

		CSyncPerfAcquire();
		~CSyncPerfAcquire();

		//  member functions

		//    manipulators

		void SetAcquire();
		
		void SetContend();
		
		//    accessors

#ifdef SYNC_ANALYZE_PERFORMANCE

		QWORD	CAcquireTotal() const	{ return m_cAcquire; }
		QWORD	CContendTotal() const	{ return m_cContend; }

#endif  //  SYNC_ANALYZE_PERFORMANCE
		
		//    debugging support

		void Dump( CDumpContext& dc ) const;

	private:

		//  member functions

		//    operators
		
		CSyncPerfAcquire& operator=( CSyncPerfAcquire& );  //  disallowed

		//  data members

#ifdef SYNC_ANALYZE_PERFORMANCE

		//    acquire count

		volatile QWORD m_cAcquire;

		//    contend count

		volatile QWORD m_cContend;

#endif  //  SYNC_ANALYZE_PERFORMANCE
	};

//  specifies that the sync object was acquired

inline void CSyncPerfAcquire::SetAcquire()
	{
#ifdef SYNC_ANALYZE_PERFORMANCE

	AtomicAdd( (QWORD*)&m_cAcquire, 1 );

#endif  //  SYNC_ANALYZE_PERFORMANCE
	}

//  specifies that a contention occurred while acquiring the sync object

inline void CSyncPerfAcquire::SetContend()
	{
#ifdef SYNC_ANALYZE_PERFORMANCE

	AtomicAdd( (QWORD*)&m_cContend, 1 );

#endif  //  SYNC_ANALYZE_PERFORMANCE
	}


//  Semaphore Information

class CSemaphoreInfo
	:	public CSyncBasicInfo,
		public CSyncPerfWait,
		public CSyncPerfAcquire
	{
	public:

		//  member functions
	
		//    ctors / dtors

		CSemaphoreInfo( const CSyncBasicInfo& sbi )
			:	CSyncBasicInfo( sbi )
			{
			}
		
		//    debugging support

		void Dump( CDumpContext& dc ) const;
	};


//  Semaphore State

class CSemaphoreState
	{
	public:

		//  member functions

		//    ctors / dtors

		CSemaphoreState( const CSyncStateInitNull& null ) : m_cAvail( 0 ) {}
		CSemaphoreState( const int cAvail );
		CSemaphoreState( const int cWait, const int irksem );
		~CSemaphoreState() {}

		//    operators
		
		CSemaphoreState& operator=( CSemaphoreState& state ) { m_cAvail = state.m_cAvail;  return *this; }

		//    manipulators

		const BOOL FChange( const CSemaphoreState& stateCur, const CSemaphoreState& stateNew );
		const BOOL FIncAvail( const int cToInc );
		const BOOL FDecAvail();
		
		//    accessors

		const BOOL FNoWait() const { return m_cAvail >= 0; }
		const BOOL FWait() const { return m_cAvail < 0; }
		const BOOL FAvail() const { return m_cAvail > 0; }
		const BOOL FNoWaitAndNoAvail() const { return m_cAvail == 0; }
		
		const int CAvail() const { OSSYNCAssert( FNoWait() ); return m_cAvail; }
		const int CWait() const { OSSYNCAssert( FWait() ); return -m_cWaitNeg; }
		const CKernelSemaphorePool::IRKSEM Irksem() const { OSSYNCAssert( FWait() ); return CKernelSemaphorePool::IRKSEM( m_irksem ); }
		
		//    debugging support

		void Dump( CDumpContext& dc ) const;
	
	private:

		//  data members

		//    transacted state representation (switched on bit 31)
		
		union
			{
			//  Mode 0:  no waiters
			
			volatile long				m_cAvail;		//  0 <= m_cAvail <= ( 1 << 31 ) - 1

			//  Mode 1:  waiters
			
			struct
				{
				volatile unsigned short	m_irksem;		//  0 <= m_irksem <= ( 1 << 16 ) - 2
				volatile short			m_cWaitNeg;		//  -( ( 1 << 15 ) - 1 ) <= m_cWaitNeg <= -1
				};
			};
	};

//  ctor

inline CSemaphoreState::CSemaphoreState( const int cAvail )
	{
	//  validate IN args
	
	OSSYNCAssert( cAvail >= 0 );
	OSSYNCAssert( cAvail <= 0x7FFFFFFF );

	//  set available count
	
	m_cAvail = long( cAvail );
	}

//  ctor

inline CSemaphoreState::CSemaphoreState( const int cWait, const int irksem )
	{
	//  validate IN args
	
	OSSYNCAssert( cWait > 0 );
	OSSYNCAssert( cWait <= 0x7FFF );
	OSSYNCAssert( irksem >= 0 );
	OSSYNCAssert( irksem <= 0xFFFE );

	//  set waiter count
	
	m_cWaitNeg = short( -cWait );

	//  set semaphore
	
	m_irksem = (unsigned short) irksem;
	}

//  changes the transacted state of the semaphore using a transacted memory
//  compare/exchange operation, returning fFalse on failure

inline const BOOL CSemaphoreState::FChange( const CSemaphoreState& stateCur, const CSemaphoreState& stateNew )
	{
	return AtomicCompareExchange( (long*)&m_cAvail, stateCur.m_cAvail, stateNew.m_cAvail ) == stateCur.m_cAvail;
	}

//  tries to increase the available count on the semaphore by the count
//  given using a transacted memory compare/exchange operation, returning fFalse
//  on failure

__forceinline const BOOL CSemaphoreState::FIncAvail( const int cToInc )
	{
	//  try forever to change the state of the semaphore

	OSSYNC_FOREVER
		{
		//  get current value

		const long cAvail = m_cAvail;
		
		//  munge start value such that the transaction will only work if we are in
		//  mode 0 (we do this to save a branch)
		
		const long cAvailStart = cAvail & 0x7FFFFFFF;

		//  compute end value relative to munged start value
		
		const long cAvailEnd = cAvailStart + cToInc;

		//  validate transaction

		OSSYNCAssert( cAvail < 0 || ( cAvailStart >= 0 && cAvailEnd <= 0x7FFFFFFF && cAvailEnd == cAvailStart + cToInc ) );

		//  attempt the transaction

		const long cAvailOld = AtomicCompareExchange( (long*)&m_cAvail, cAvailStart, cAvailEnd );

		//  the transaction succeeded

		if ( cAvailOld == cAvailStart )
			{
			//  return success
			
			return fTrue;
			}

		//  the transaction failed

		else
			{
			//  the transaction failed because of a collision with another context

			if ( cAvailOld >= 0 )
				{
				//  try again

				continue;
				}

			//  the transaction failed because there are waiters

			else
				{
				//  return failure

				return fFalse;
				}
			}
		}
	}

//  tries to decrease the available count on the semaphore by one using a
//  transacted memory compare/exchange operation, returning fFalse on failure

__forceinline const BOOL CSemaphoreState::FDecAvail()
	{
	//  try forever to change the state of the semaphore

	OSSYNC_FOREVER
		{
		//  get current value

		const long cAvail = m_cAvail;
		
		//  this function has no effect on 0x80000000, so this MUST be an illegal
		//  value!
		
		OSSYNCAssert( cAvail != 0x80000000 );
		
		//  munge end value such that the transaction will only work if we are in
		//  mode 0 and we have at least one available count (we do this to save a
		//  branch)
		
		const long cAvailEnd = ( cAvail - 1 ) & 0x7FFFFFFF;

		//  compute start value relative to munged end value
		
		const long cAvailStart = cAvailEnd + 1;

		//  validate transaction

		OSSYNCAssert( cAvail <= 0 || ( cAvailStart > 0 && cAvailEnd >= 0 && cAvailEnd == cAvail - 1 ) );

		//  attempt the transaction

		const long cAvailOld = AtomicCompareExchange( (long*)&m_cAvail, cAvailStart, cAvailEnd );

		//  the transaction succeeded

		if ( cAvailOld == cAvailStart )
			{
			//  return success
			
			return fTrue;
			}

		//  the transaction failed

		else
			{
			//  the transaction failed because of a collision with another context

			if ( cAvailOld > 0 )
				{
				//  try again

				continue;
				}

			//  the transaction failed because there are no available counts

			else
				{
				//  return failure

				return fFalse;
				}
			}
		}
	}


//  Semaphore

class CSemaphore
	:	private CSyncObject,
		private CEnhancedStateContainer< CSemaphoreState, CSyncStateInitNull, CSemaphoreInfo, CSyncBasicInfo >
	{
	public:

		//  member functions

		//    ctors / dtors

		CSemaphore( const CSyncBasicInfo& sbi );
		~CSemaphore();

		//    manipulators

		void Acquire();
		const BOOL FTryAcquire();
		const BOOL FAcquire( const int cmsecTimeout );
		void Release( const int cToRelease = 1 );

		//    accessors

		const int CWait() const;
		const int CAvail() const;
		
		//    debugging support

		void Dump( CDumpContext& dc ) const;

	private:

		//  member functions

		//    operators
		
		CSemaphore& operator=( CSemaphore& );  //  disallowed

		//    manipulators

		const BOOL _FAcquire( const int cmsecTimeout );
		void _Release( const int cToRelease );
	};

//  acquire one count of the semaphore, waiting forever if necessary

inline void CSemaphore::Acquire()
	{
	//  we will wait forever, so we should not timeout
	
	int fAcquire = FAcquire( cmsecInfinite );
	OSSYNCAssert( fAcquire );
	}

//  try to acquire one count of the semaphore without waiting or spinning.
//  returns fFalse if a count could not be acquired

inline const BOOL CSemaphore::FTryAcquire()
	{
	//  only try to perform a simple decrement of the available count
	
	const BOOL fAcquire = State().FDecAvail();

	//  we did not acquire the semaphore

	if ( !fAcquire )
		{
		//  this is a contention

		State().SetContend();
		}

	//  we did acquire the semaphore

	else
		{
		//  note that we acquired a count

		State().SetAcquire();
		}

	return fAcquire;
	}

//  acquire one count of the semaphore, waiting only for the specified interval.
//  returns fFalse if the wait timed out before a count could be acquired

inline const BOOL CSemaphore::FAcquire( const int cmsecTimeout )
	{
	//  first try to quickly grab an available count.  if that doesn't work,
	//  retry acquire using the full state machine
	
	return FTryAcquire() || _FAcquire( cmsecTimeout );
	}

//  releases the given number of counts to the semaphore, waking the appropriate
//  number of waiters

inline void CSemaphore::Release( const int cToRelease )
	{
	//  we failed to perform a simple increment of the available count
	
	if ( !State().FIncAvail( cToRelease ) )
		{
		//  retry release using the full state machine
		
		_Release( cToRelease );
		}
	}

//  returns the number of execution contexts waiting on the semaphore

inline const int CSemaphore::CWait() const
	{
	//  read the current state of the semaphore
	
	const CSemaphoreState stateCur = (CSemaphoreState&) State();

	//  return the waiter count

	return stateCur.FWait() ? stateCur.CWait() : 0;
	}

//  returns the number of available counts on the semaphore

inline const int CSemaphore::CAvail() const
	{
	//  read the current state of the semaphore
	
	const CSemaphoreState stateCur = (CSemaphoreState&) State();

	//  return the available count

	return stateCur.FNoWait() ? stateCur.CAvail() : 0;
	}


//  Auto-Reset Signal Information

class CAutoResetSignalInfo
	:	public CSyncBasicInfo,
		public CSyncPerfWait,
		public CSyncPerfAcquire
	{
	public:

		//  member functions
	
		//    ctors / dtors

		CAutoResetSignalInfo( const CSyncBasicInfo& sbi )
			:	CSyncBasicInfo( sbi )
			{
			}
		
		//    debugging support

		void Dump( CDumpContext& dc ) const;
	};


//  Auto-Reset Signal State

class CAutoResetSignalState
	{
	public:

		//  member functions

		//    ctors / dtors
		
		CAutoResetSignalState( const CSyncStateInitNull& null ) : m_fSet( 0 ) {}
		CAutoResetSignalState( const int fSet );
		CAutoResetSignalState( const int cWait, const int irksem );
		~CAutoResetSignalState() {}

		//    operators
		
		CAutoResetSignalState& operator=( CAutoResetSignalState& state ) { m_fSet = state.m_fSet;  return *this; }

		//    manipulators

		const BOOL FChange( const CAutoResetSignalState& stateCur, const CAutoResetSignalState& stateNew );
		const BOOL FSimpleSet();
		const BOOL FSimpleReset();
		
		//    accessors

		const BOOL FNoWait() const { return m_fSet >= 0; }
		const BOOL FWait() const { return m_fSet < 0; }
		const BOOL FNoWaitAndSet() const { return m_fSet > 0; }
		const BOOL FNoWaitAndNotSet() const { return m_fSet == 0; }

		const BOOL FSet() const { OSSYNCAssert( FNoWait() ); return m_fSet; }
		const int CWait() const { OSSYNCAssert( FWait() ); return -m_cWaitNeg; }
		const CKernelSemaphorePool::IRKSEM Irksem() const { OSSYNCAssert( FWait() ); return CKernelSemaphorePool::IRKSEM( m_irksem ); }
		
		//    debugging support

		void Dump( CDumpContext& dc ) const;
	
	private:

		//  data members

		//    transacted state representation (switched on bit 31)
		
		union
			{
			//  Mode 0:  no waiters
			
			volatile long				m_fSet;			//  m_fSet = { 0, 1 }

			//  Mode 1:  waiters
			
			struct
				{
				volatile unsigned short	m_irksem;		//  0 <= m_irksem <= ( 1 << 16 ) - 2
				volatile short			m_cWaitNeg;		//  -( ( 1 << 15 ) - 1 ) <= m_cWaitNeg <= -1
				};
			};
	};

//  ctor

inline CAutoResetSignalState::CAutoResetSignalState( const int fSet )
	{
	//  validate IN args
	
	OSSYNCAssert( fSet == 0 || fSet == 1 );

	//  set state
	
	m_fSet = long( fSet );
	}

//  ctor

inline CAutoResetSignalState::CAutoResetSignalState( const int cWait, const int irksem )
	{
	//  validate IN args
	
	OSSYNCAssert( cWait > 0 );
	OSSYNCAssert( cWait <= 0x7FFF );
	OSSYNCAssert( irksem >= 0 );
	OSSYNCAssert( irksem <= 0xFFFE );

	//  set waiter count
	
	m_cWaitNeg = short( -cWait );

	//  set semaphore
	
	m_irksem = (unsigned short) irksem;
	}

//  changes the transacted state of the signal using a transacted memory
//  compare/exchange operation, returning 0 on failure

inline const BOOL CAutoResetSignalState::FChange( const CAutoResetSignalState& stateCur, const CAutoResetSignalState& stateNew )
	{
	return AtomicCompareExchange( (long*)&m_fSet, stateCur.m_fSet, stateNew.m_fSet ) == stateCur.m_fSet;
	}

//  tries to set the signal state from either the set or reset with no waiters states
//  using a transacted memory compare/exchange operation, returning fFalse on failure

__forceinline const BOOL CAutoResetSignalState::FSimpleSet()
	{
	//  try forever to change the state of the signal

	OSSYNC_FOREVER
		{
		//  get current value

		const long fSet = m_fSet;
		
		//  munge start value such that the transaction will only work if we are in
		//  mode 0 (we do this to save a branch)
		
		const long fSetStart = fSet & 0x7FFFFFFF;

		//  compute end value relative to munged start value
		
		const long fSetEnd = 1;

		//  validate transaction

		OSSYNCAssert( fSet < 0 || ( ( fSetStart == 0 || fSetStart == 1 ) && fSetEnd == 1 ) );

		//  attempt the transaction

		const long fSetOld = AtomicCompareExchange( (long*)&m_fSet, fSetStart, fSetEnd );
		
		//  the transaction succeeded

		if ( fSetOld == fSetStart )
			{
			//  return success
			
			return fTrue;
			}

		//  the transaction failed

		else
			{
			//  the transaction failed because of a collision with another context

			if ( fSetOld >= 0 )
				{
				//  try again

				continue;
				}

			//  the transaction failed because there are waiters

			else
				{
				//  return failure

				return fFalse;
				}
			}
		}
	}

//  tries to reset the signal state from either the set or reset with no waiters states
//  using a transacted memory compare/exchange operation, returning fFalse on failure

__forceinline const BOOL CAutoResetSignalState::FSimpleReset()
	{
	//  try forever to change the state of the signal

	OSSYNC_FOREVER
		{
		//  get current value

		const long fSet = m_fSet;
		
		//  munge start value such that the transaction will only work if we are in
		//  mode 0 (we do this to save a branch)
		
		const long fSetStart = fSet & 0x7FFFFFFF;

		//  compute end value relative to munged start value
		
		const long fSetEnd = 0;

		//  validate transaction

		OSSYNCAssert( fSet < 0 || ( ( fSetStart == 0 || fSetStart == 1 ) && fSetEnd == 0 ) );

		//  attempt the transaction

		const long fSetOld = AtomicCompareExchange( (long*)&m_fSet, fSetStart, fSetEnd );
		
		//  the transaction succeeded

		if ( fSetOld == fSetStart )
			{
			//  return success
			
			return fTrue;
			}

		//  the transaction failed

		else
			{
			//  the transaction failed because of a collision with another context

			if ( fSetOld >= 0 )
				{
				//  try again

				continue;
				}

			//  the transaction failed because there are waiters

			else
				{
				//  return failure

				return fFalse;
				}
			}
		}
	}


//  Auto-Reset Signal

class CAutoResetSignal
	:	private CSyncObject,
		private CEnhancedStateContainer< CAutoResetSignalState, CSyncStateInitNull, CAutoResetSignalInfo, CSyncBasicInfo >
	{
	public:

		//  member functions

		//    ctors / dtors

		CAutoResetSignal( const CSyncBasicInfo& sbi );
		~CAutoResetSignal();

		//    manipulators

		void Wait();
		const BOOL FTryWait();
		const BOOL FWait( const int cmsecTimeout );

		void Set();
		void Reset();
		void Pulse();

		//    debugging support

		void Dump( CDumpContext& dc ) const;

	private:

		//  member functions

		//    operators
		
		CAutoResetSignal& operator=( CAutoResetSignal& );  //  disallowed

		//    manipulators

		const BOOL _FWait( const int cmsecTimeout );

		void _Set();
		void _Pulse();
	};

//  waits for the signal to be set, forever if necessary.  when the wait completes,
//  the signal will be reset

inline void CAutoResetSignal::Wait()
	{
	//  we will wait forever, so we should not timeout
	
	const BOOL fWait = FWait( cmsecInfinite );
	OSSYNCAssert( fWait );
	}

//  tests the state of the signal without waiting or spinning, returning fFalse
//  if the signal was not set.  if the signal was set, the signal will be reset

inline const BOOL CAutoResetSignal::FTryWait()
	{
	//  we can satisfy the wait if we can successfully change the state of the
	//  signal from set to reset with no waiters

	const BOOL fSuccess = State().FChange( CAutoResetSignalState( 1 ), CAutoResetSignalState( 0 ) );

	//  we did not successfully wait for the signal

	if ( !fSuccess )
		{
		//  this is a contention

		State().SetContend();
		}

	//  we did successfully wait for the signal

	else
		{
		//  note that we acquired the signal

		State().SetAcquire();
		}

	return fSuccess;
	}

//  wait for the signal to be set, but only for the specified interval,
//  returning fFalse if the wait timed out before the signal was set.  if the
//  wait completes, the signal will be reset

inline const BOOL CAutoResetSignal::FWait( const int cmsecTimeout )
	{
	//  first try to quickly pass through the signal.  if that doesn't work,
	//  retry wait using the full state machine

	return FTryWait() || _FWait( cmsecTimeout );
	}

//  sets the signal, releasing up to one waiter.  if a waiter is released, then
//  the signal will be reset.  if a waiter is not released, the signal will
//  remain set

inline void CAutoResetSignal::Set()
	{
	//  we failed to change the signal state from reset with no waiters to set
	//  or from set to set (a nop)

	if ( !State().FSimpleSet() )
		{
		//  retry set using the full state machine
		
		_Set();
		}
	}

//  resets the signal

inline void CAutoResetSignal::Reset()
	{
	//  if and only if the signal is in the set state, change it to the reset state
	
	State().FChange( CAutoResetSignalState( 1 ), CAutoResetSignalState( 0 ) );
	}

//  resets the signal, releasing up to one waiter

inline void CAutoResetSignal::Pulse()
	{
	//  wa failed to change the signal state from set to reset with no waiters
	//  or from reset with no waiters to reset with no waiters (a nop)

	if ( !State().FSimpleReset() )
		{
		//  retry pulse using the full state machine

		_Pulse();
		}
	}


//  Manual-Reset Signal Information

class CManualResetSignalInfo
	:	public CSyncBasicInfo,
		public CSyncPerfWait,
		public CSyncPerfAcquire
	{
	public:

		//  member functions
	
		//    ctors / dtors

		CManualResetSignalInfo( const CSyncBasicInfo& sbi )
			:	CSyncBasicInfo( sbi )
			{
			}
		
		//    debugging support

		void Dump( CDumpContext& dc ) const;
	};


//  Manual-Reset Signal State

class CManualResetSignalState
	{
	public:

		//  member functions

		//    ctors / dtors
		
		CManualResetSignalState( const CSyncStateInitNull& null ) : m_fSet( 0 ) {}
		CManualResetSignalState( const int fSet );
		CManualResetSignalState( const int cWait, const int irksem );
		~CManualResetSignalState() {}

		//    operators
		
		CManualResetSignalState& operator=( CManualResetSignalState& state ) { m_fSet = state.m_fSet;  return *this; }

		//    manipulators

		const BOOL FChange( const CManualResetSignalState& stateCur, const CManualResetSignalState& stateNew );
		const CManualResetSignalState Set();
		const CManualResetSignalState Reset();
		
		//    accessors

		const BOOL FNoWait() const { return m_fSet >= 0; }
		const BOOL FWait() const { return m_fSet < 0; }
		const BOOL FNoWaitAndSet() const { return m_fSet > 0; }
		const BOOL FNoWaitAndNotSet() const { return m_fSet == 0; }

		const BOOL FSet() const { OSSYNCAssert( FNoWait() ); return m_fSet; }
		const int CWait() const { OSSYNCAssert( FWait() ); return -m_cWaitNeg; }
		const CKernelSemaphorePool::IRKSEM Irksem() const { OSSYNCAssert( FWait() ); return CKernelSemaphorePool::IRKSEM( m_irksem ); }
		
		//    debugging support

		void Dump( CDumpContext& dc ) const;
	
	private:

		//  data members

		//    transacted state representation (switched on bit 31)
		
		union
			{
			//  Mode 0:  no waiters
			
			volatile long				m_fSet;			//  m_fSet = { 0, 1 }

			//  Mode 1:  waiters
			
			struct
				{
				volatile unsigned short	m_irksem;		//  0 <= m_irksem <= ( 1 << 16 ) - 2
				volatile short			m_cWaitNeg;		//  -( ( 1 << 15 ) - 1 ) <= m_cWaitNeg <= -1
				};
			};
	};

//  ctor

inline CManualResetSignalState::CManualResetSignalState( const int fSet )
	{
	//  set state
	
	m_fSet = long( fSet );
	}

//  ctor

inline CManualResetSignalState::CManualResetSignalState( const int cWait, const int irksem )
	{
	//  validate IN args
	
	OSSYNCAssert( cWait > 0 );
	OSSYNCAssert( cWait <= 0x7FFF );
	OSSYNCAssert( irksem >= 0 );
	OSSYNCAssert( irksem <= 0xFFFE );

	//  set waiter count
	
	m_cWaitNeg = short( -cWait );

	//  set semaphore
	
	m_irksem = (unsigned short) irksem;
	}

//  changes the transacted state of the signal using a transacted memory
//  compare/exchange operation, returning fFalse on failure

inline const BOOL CManualResetSignalState::FChange( const CManualResetSignalState& stateCur, const CManualResetSignalState& stateNew )
	{
	return AtomicCompareExchange( (long*)&m_fSet, stateCur.m_fSet, stateNew.m_fSet ) == stateCur.m_fSet;
	}

//  changes the transacted state of the signal to set using a transacted memory
//  exchange operation and returns the original state of the signal

inline const CManualResetSignalState CManualResetSignalState::Set()
	{
	const CManualResetSignalState stateNew( 1 );
	return CManualResetSignalState( AtomicExchange( (long*)&m_fSet, stateNew.m_fSet ) );
	}

//  changes the transacted state of the signal to reset using a transacted memory
//  exchange operation and returns the original state of the signal

inline const CManualResetSignalState CManualResetSignalState::Reset()
	{
	const CManualResetSignalState stateNew( 0 );
	return CManualResetSignalState( AtomicExchange( (long*)&m_fSet, stateNew.m_fSet ) );
	}


//  Manual-Reset Signal

class CManualResetSignal
	:	private CSyncObject,
		private CEnhancedStateContainer< CManualResetSignalState, CSyncStateInitNull, CManualResetSignalInfo, CSyncBasicInfo >
	{
	public:

		//  member functions

		//    ctors / dtors

		CManualResetSignal( const CSyncBasicInfo& sbi );
		~CManualResetSignal();

		//    manipulators

		void Wait();
		const BOOL FTryWait();
		const BOOL FWait( const int cmsecTimeout );

		void Set();
		void Reset();
		void Pulse();

		//    debugging support

		void Dump( CDumpContext& dc ) const;

	private:

		//  member functions

		//    operators
		
		CManualResetSignal& operator=( CManualResetSignal& );  //  disallowed

		//    manipulators

		const BOOL _FWait( const int cmsecTimeout );
	};

//  waits for the signal to be set, forever if necessary

inline void CManualResetSignal::Wait()
	{
	//  we will wait forever, so we should not timeout
	
	int fWait = FWait( cmsecInfinite );
	OSSYNCAssert( fWait );
	}

//  tests the state of the signal without waiting or spinning, returning fFalse
//  if the signal was not set

inline const BOOL CManualResetSignal::FTryWait()
	{
	const BOOL fSuccess = State().FNoWaitAndSet();
	
	//  we did not successfully wait for the signal

	if ( !fSuccess )
		{
		//  this is a contention

		State().SetContend();
		}

	//  we did successfully wait for the signal

	else
		{
		//  note that we acquired the signal

		State().SetAcquire();
		}

	return fSuccess;
	}

//  wait for the signal to be set, but only for the specified interval,
//  returning fFalse if the wait timed out before the signal was set

inline const BOOL CManualResetSignal::FWait( const int cmsecTimeout )
	{
	//  first try to quickly pass through the signal.  if that doesn't work,
	//  retry wait using the full state machine

	return FTryWait() || _FWait( cmsecTimeout );
	}

//  sets the signal, releasing any waiters

inline void CManualResetSignal::Set()
	{
	//  change the signal state to set

	const CManualResetSignalState stateOld = State().Set();

	//  there were waiters on the signal

	if ( stateOld.FWait() )
		{
		//  release all the waiters

		ksempoolGlobal.Ksem( stateOld.Irksem(), this ).Release( stateOld.CWait() );
		}
	}

//  resets the signal

inline void CManualResetSignal::Reset()
	{
	//  if and only if the signal is in the set state, change it to the reset state
	
	State().FChange( CManualResetSignalState( 1 ), CManualResetSignalState( 0 ) );
	}

//  resets the signal, releasing any waiters

inline void CManualResetSignal::Pulse()
	{
	//  change the signal state to reset

	const CManualResetSignalState stateOld = State().Reset();

	//  there were waiters on the signal

	if ( stateOld.FWait() )
		{
		//  release all the waiters

		ksempoolGlobal.Ksem( stateOld.Irksem(), this ).Release( stateOld.CWait() );
		}
	}


//  Lock Object Base Class
//
//  All Lock Objects are derived from this class

class CLockObject
	:	public CSyncObject
	{
	public:

		//  member functions
	
		//    ctors / dtors

		CLockObject() {}
		~CLockObject() {}

	private:

		//  member functions

		//    operators
		
		CLockObject& operator=( CLockObject& );  //  disallowed
	};


//  Lock Object Basic Information

class CLockBasicInfo
	:	public CSyncBasicInfo
	{
	public:

		//  member functions
	
		//    ctors / dtors

		CLockBasicInfo( const CSyncBasicInfo& sbi, const int rank, const int subrank );
		~CLockBasicInfo();

		//    accessors

#ifdef SYNC_DEADLOCK_DETECTION

		const int Rank() const { return m_rank; }
		const int SubRank() const { return m_subrank; }

#endif  //  SYNC_DEADLOCK_DETECTION
		
		//    debugging support

		void Dump( CDumpContext& dc ) const;

	private:

		//  member functions

		//    operators
		
		CLockBasicInfo& operator=( CLockBasicInfo& );  //  disallowed

		//  data members

#ifdef SYNC_DEADLOCK_DETECTION

		//    Rank and Subrank

		int	m_rank;
		int	m_subrank;

#endif  //  SYNC_DEADLOCK_DETECTION
	};


//  Lock Object Performance:  Hold

class CLockPerfHold
	{
	public:

		//  member functions
	
		//    ctors / dtors

		CLockPerfHold();
		~CLockPerfHold();

		//  member functions

		//    manipulators

		void StartHold();
		void StopHold();
		
		//    accessors

#ifdef SYNC_ANALYZE_PERFORMANCE

		QWORD	CHoldTotal() const		{ return m_cHold; }
		double	CsecHoldElapsed() const	{ return	(double)(signed __int64)m_qwHRTHoldElapsed /
													(double)(signed __int64)QwOSTimeHRTFreq(); }

#endif  //  SYNC_ANALYZE_PERFORMANCE
		
		//    debugging support

		void Dump( CDumpContext& dc ) const;

	private:

		//  member functions

		//    operators
		
		CLockPerfHold& operator=( CLockPerfHold& );  //  disallowed

		//  data members

#ifdef SYNC_ANALYZE_PERFORMANCE

		//    hold count

		volatile QWORD m_cHold;

		//    elapsed hold time

		volatile QWORD m_qwHRTHoldElapsed;

#endif  //  SYNC_ANALYZE_PERFORMANCE
	};

//  starts the hold timer for the lock object

inline void CLockPerfHold::StartHold()
	{
#ifdef SYNC_ANALYZE_PERFORMANCE

	//  increment the hold count

	AtomicAdd( (QWORD*)&m_cHold, 1 );

	//  subtract the start hold time from the elapsed hold time.  this starts
	//  an elapsed time computation for this context.  StopHold() will later
	//  add the end hold time to the elapsed time, causing the following net
	//  effect:
	//
	//  m_qwHRTHoldElapsed += <end time> - <start time>
	//
	//  we simply choose to go ahead and do the subtraction now to save storage

	AtomicAdd( (QWORD*)&m_qwHRTHoldElapsed, QWORD( -__int64( QwOSTimeHRTCount() ) ) );

#endif  //  SYNC_ANALYZE_PERFORMANCE
	}

//  stops the hold timer for the lock object

inline void CLockPerfHold::StopHold()
	{
#ifdef SYNC_ANALYZE_PERFORMANCE

	//  add the end hold time to the elapsed hold time.  this completes the
	//  computation started in StartHold()

	AtomicAdd( (QWORD*)&m_qwHRTHoldElapsed, QwOSTimeHRTCount() );

#endif  //  SYNC_ANALYZE_PERFORMANCE
	}


//  Lock Owner Record

class CLockDeadlockDetectionInfo;

class COwner
	{
	public:

		//  member functions
	
		//    ctors / dtors

		COwner();
		~COwner();

		void* operator new( size_t cb ) { return ESMemoryNew( cb ); }
		void operator delete( void* pv ) { ESMemoryDelete( pv ); }

	public:

		//  member functions

		//    operators
		
		COwner& operator=( COwner& );  //  disallowed

		//  data members

		//    owning context

		CLS*							m_pclsOwner;

		//    next context owning this lock

		COwner*							m_pownerContextNext;

		//    owned lock object

		CLockDeadlockDetectionInfo*		m_plddiOwned;

		//    next lock owned by this context

		COwner*							m_pownerLockNext;

		//    owning group for this context and lock

		DWORD							m_group;
	};


//  Lock Object Deadlock Detection Information

class CLockDeadlockDetectionInfo
	{
	public:

		//  types

		//    subrank used to disable deadlock detection at the subrank level

		enum
			{
			subrankNoDeadlock = INT_MAX
			};

		//  member functions
	
		//    ctors / dtors

		CLockDeadlockDetectionInfo( const CLockBasicInfo& lbi );
		~CLockDeadlockDetectionInfo();

		//  member functions

		//    manipulators

		void AddAsWaiter( const DWORD group = -1 );
		void RemoveAsWaiter( const DWORD group = -1 );
		
		void AddAsOwner( const DWORD group = -1 );
		void RemoveAsOwner( const DWORD group = -1 );

		static void OSSYNCAPI NextOwnershipIsNotADeadlock();
		static void OSSYNCAPI DisableOwnershipTracking();
		static void OSSYNCAPI EnableOwnershipTracking();

		//    accessors

		const BOOL FOwner( const DWORD group = -1 );
		const BOOL FNotOwner( const DWORD group = -1 );
		const BOOL FOwned();
		const BOOL FNotOwned();

		const BOOL FCanBeWaiter();
		const BOOL FWaiter( const DWORD group = -1 );
		const BOOL FNotWaiter( const DWORD group = -1 );

#ifdef SYNC_DEADLOCK_DETECTION

		const CLockBasicInfo& Info() { return *m_plbiParent; }

#endif  //  SYNC_DEADLOCK_DETECTION
		
		//    debugging support

		void Dump( CDumpContext& dc ) const;

	private:

		//  member functions

		//    operators
		
		CLockDeadlockDetectionInfo& operator=( CLockDeadlockDetectionInfo& );  //  disallowed

		//  data members

#ifdef SYNC_DEADLOCK_DETECTION

		//    parent lock object information

		const CLockBasicInfo*			m_plbiParent;

		//    semaphore protecting owner list

		CSemaphore						m_semOwnerList;

		//    owner list head

		COwner							m_ownerHead;

#endif  //  SYNC_DEADLOCK_DETECTION
	};

//  adds the current context as a waiter for the lock object as a member of the
//  specified group

inline void CLockDeadlockDetectionInfo::AddAsWaiter( const DWORD group )
	{
	//  this context had better not be a waiter for the lock

	OSSYNCAssert( FNotWaiter( group ) );

#ifdef SYNC_DEADLOCK_DETECTION

	//  we had better not already be waiting for something else!

	CLS* const pcls	= Pcls();
	OSSYNCAssert( !pcls->plddiLockWait );
	OSSYNCAssert( !pcls->groupLockWait );

	//  add this context as a waiter for the lock

	pcls->plddiLockWait = this;
	pcls->groupLockWait = group;

#endif  //  SYNC_DEADLOCK_DETECTION

	//  this context had better be a waiter for the lock

	OSSYNCAssert( FWaiter( group ) );
	}

//  removes the current context as a waiter for the lock object

inline void CLockDeadlockDetectionInfo::RemoveAsWaiter( const DWORD group )
	{
	//  this context had better be a waiter for the lock

	OSSYNCAssert( FWaiter( group ) );

#ifdef SYNC_DEADLOCK_DETECTION

	//  remove this context as a waiter for the lock

	CLS* const pcls	= Pcls();
	pcls->plddiLockWait = NULL;
	pcls->groupLockWait = 0;

#endif  //  SYNC_DEADLOCK_DETECTION

	//  this context had better not be a waiter for the lock anymore

	OSSYNCAssert( FNotWaiter( group ) );
	}

//  adds the current context as an owner of the lock object as a member of the
//  specified group

inline void CLockDeadlockDetectionInfo::AddAsOwner( const DWORD group )
	{
	//  this context had better not be an owner of the lock

	OSSYNCAssert( FNotOwner( group ) );

#ifdef SYNC_DEADLOCK_DETECTION

	//  add this context as an owner of the lock

	CLS* const pcls	= Pcls();

	if ( !pcls->cDisableOwnershipTracking )
		{
		COwner* powner	= &m_ownerHead;

		if ( AtomicCompareExchangePointer( (void **)&powner->m_pclsOwner, NULL, pcls ) != NULL )
			{
			powner = new COwner;
			OSSYNCEnforceSz( powner,  "Failed to allocate Deadlock Detection Owner Record"  );
			
			m_semOwnerList.Acquire();
			
			powner->m_pclsOwner				= pcls;
			powner->m_pownerContextNext		= m_ownerHead.m_pownerContextNext;
			m_ownerHead.m_pownerContextNext	= powner;

			m_semOwnerList.Release();
			}

		powner->m_plddiOwned		= this;
		powner->m_pownerLockNext	= pcls->pownerLockHead;
		pcls->pownerLockHead		= powner;
		powner->m_group				= group;
		}

	//  reset override

	pcls->fOverrideDeadlock = fFalse;

#endif  //  SYNC_DEADLOCK_DETECTION

	//  this context had better be an owner of the lock

	OSSYNCAssert( FOwner( group ) );
	}

//  removes the current context as an owner of the lock object

inline void CLockDeadlockDetectionInfo::RemoveAsOwner( const DWORD group )
	{
	//  this context had better be an owner of the lock

	OSSYNCAssert( FOwner( group ) );

#ifdef SYNC_DEADLOCK_DETECTION

	//  remove this context as an owner of the lock

	CLS* const pcls = Pcls();

	if ( !pcls->cDisableOwnershipTracking )
		{
		COwner** ppownerLock = &pcls->pownerLockHead;
		while ( (*ppownerLock)->m_plddiOwned != this )
			{
			ppownerLock = &(*ppownerLock)->m_pownerLockNext;
			}

		COwner* pownerLock = *ppownerLock;
		*ppownerLock = pownerLock->m_pownerLockNext;
		
		pownerLock->m_plddiOwned		= NULL;
		pownerLock->m_pownerLockNext	= NULL;
		pownerLock->m_group				= 0;

		if ( AtomicCompareExchangePointer( (void**) &m_ownerHead.m_pclsOwner, pcls, NULL ) != pcls )
			{
			m_semOwnerList.Acquire();
			
			COwner** ppownerContext = &m_ownerHead.m_pownerContextNext;
			while ( (*ppownerContext)->m_pclsOwner != pcls )
				{
				ppownerContext = &(*ppownerContext)->m_pownerContextNext;
				}

			COwner* pownerContext = *ppownerContext;
			*ppownerContext = pownerContext->m_pownerContextNext;
			
			m_semOwnerList.Release();

			delete pownerContext;
			}
		}

#endif  //  SYNC_DEADLOCK_DETECTION

	//  this context had better not be an owner of the lock anymore

	OSSYNCAssert( FNotOwner( group ) );
	}

//  overrides deadlock detection using ranks for the next ownership

inline void OSSYNCAPI CLockDeadlockDetectionInfo::NextOwnershipIsNotADeadlock()
	{
#ifdef SYNC_DEADLOCK_DETECTION

	Pcls()->fOverrideDeadlock = fTrue;

#endif  //  SYNC_DEADLOCK_DETECTION
	}

//  disables ownership tracking for this context

inline void OSSYNCAPI CLockDeadlockDetectionInfo::DisableOwnershipTracking()
	{
#ifdef SYNC_DEADLOCK_DETECTION

	Pcls()->cDisableOwnershipTracking++;

#endif  //  SYNC_DEADLOCK_DETECTION
	}

//  enables ownership tracking for this context

inline void OSSYNCAPI CLockDeadlockDetectionInfo::EnableOwnershipTracking()
	{
#ifdef SYNC_DEADLOCK_DETECTION

	Pcls()->cDisableOwnershipTracking--;

#endif  //  SYNC_DEADLOCK_DETECTION
	}

//  returns fTrue if the current context is an owner of the lock object
//
//  NOTE:  if deadlock detection is disabled, this function will always return
//  fTrue

inline const BOOL CLockDeadlockDetectionInfo::FOwner( const DWORD group )
	{
#ifdef SYNC_DEADLOCK_DETECTION

	COwner* pownerLock = Pcls()->pownerLockHead;
	while ( pownerLock && pownerLock->m_plddiOwned != this )
		{
		pownerLock = pownerLock->m_pownerLockNext;
		}

	return	Pcls()->cDisableOwnershipTracking != 0 ||
			pownerLock && pownerLock->m_group == group;

#else  //  !SYNC_DEADLOCK_DETECTION

	return fTrue;

#endif  //  SYNC_DEADLOCK_DETECTION
	}

//  returns fTrue if the current context is not an owner of the lock object
//
//  NOTE:  if deadlock detection is disabled, this function will always return
//  fTrue

inline const BOOL CLockDeadlockDetectionInfo::FNotOwner( const DWORD group )
	{
#ifdef SYNC_DEADLOCK_DETECTION

	return Pcls()->cDisableOwnershipTracking != 0 || !FOwner( group );

#else  //  !SYNC_DEADLOCK_DETECTION

	return fTrue;

#endif  //  SYNC_DEADLOCK_DETECTION
	}

//  returns fTrue if any context is an owner of the lock object
//
//  NOTE:  if deadlock detection is disabled, this function will always return
//  fTrue

inline const BOOL CLockDeadlockDetectionInfo::FOwned()
	{
#ifdef SYNC_DEADLOCK_DETECTION

	return m_ownerHead.m_pclsOwner || m_ownerHead.m_pownerContextNext;

#else  //  !SYNC_DEADLOCK_DETECTION

	return fTrue;

#endif  //  SYNC_DEADLOCK_DETECTION
	}

//  returns fTrue if no context is an owner of the lock object
//
//  NOTE:  if deadlock detection is disabled, this function will always return
//  fTrue

inline const BOOL CLockDeadlockDetectionInfo::FNotOwned()
	{
#ifdef SYNC_DEADLOCK_DETECTION

	return !FOwned();

#else  //  !SYNC_DEADLOCK_DETECTION

	return fTrue;

#endif  //  SYNC_DEADLOCK_DETECTION
	}

//  returns fTrue if the current context can wait for the lock object without
//  violating any deadlock constraints
//
//  NOTE:  if deadlock detection is disabled, this function will always return
//  fTrue

inline const BOOL CLockDeadlockDetectionInfo::FCanBeWaiter()
	{
#ifdef SYNC_DEADLOCK_DETECTION

	//  find the minimum rank, subrank of all locks owned by the current context

	CLS* const	pcls	= Pcls();
	COwner*		powner	= pcls->pownerLockHead;
	int			Rank	= INT_MAX;
	int			SubRank	= INT_MAX;

	while ( powner )
		{
		if (	powner->m_plddiOwned->Info().Rank() < Rank ||
				(	powner->m_plddiOwned->Info().Rank() == Rank &&
					powner->m_plddiOwned->Info().SubRank() < SubRank ) )
			{
			Rank	= powner->m_plddiOwned->Info().Rank();
			SubRank	= powner->m_plddiOwned->Info().SubRank();
			}

		powner = powner->m_pownerLockNext;
		}

	//  test this rank, subrank against our rank, subrank

	return	Rank > Info().Rank() ||
			( Rank == Info().Rank() && SubRank > Info().SubRank() ) ||
			(	Rank == Info().Rank() && SubRank == Info().SubRank() &&
				SubRank == subrankNoDeadlock ) ||
			pcls->fOverrideDeadlock;

#else  //  !SYNC_DEADLOCK_DETECTION

	return fTrue;

#endif  //  SYNC_DEADLOCK_DETECTION
	}

//  returns fTrue if the current context is a waiter of the lock object
//
//  NOTE:  if deadlock detection is disabled, this function will always return
//  fTrue

inline const BOOL CLockDeadlockDetectionInfo::FWaiter( const DWORD group )
	{
#ifdef SYNC_DEADLOCK_DETECTION

	CLS* const pcls	= Pcls();
	return pcls->plddiLockWait == this && pcls->groupLockWait == group;

#else  //  !SYNC_DEADLOCK_DETECTION

	return fTrue;

#endif  //  SYNC_DEADLOCK_DETECTION
	}

//  returns fTrue if the current context is not a waiter of the lock object
//
//  NOTE:  if deadlock detection is disabled, this function will always return
//  fTrue

inline const BOOL CLockDeadlockDetectionInfo::FNotWaiter( const DWORD group )
	{
#ifdef SYNC_DEADLOCK_DETECTION

	return !FWaiter( group );

#else  //  !SYNC_DEADLOCK_DETECTION

	return fTrue;

#endif  //  SYNC_DEADLOCK_DETECTION
	}


//  Critical Section (non-nestable) Information

class CCriticalSectionInfo
	:	public CLockBasicInfo,
		public CLockPerfHold,
		public CLockDeadlockDetectionInfo
	{
	public:

		//  member functions
	
		//    ctors / dtors

		CCriticalSectionInfo( const CLockBasicInfo& lbi )
			:	CLockBasicInfo( lbi ),
				CLockDeadlockDetectionInfo( (CLockBasicInfo&) *this )
			{
			}
		
		//    debugging support

		void Dump( CDumpContext& dc ) const;
	};


//  Critical Section (non-nestable) State

class CCriticalSectionState
	{
	public:

		//  member functions

		//    ctors / dtors
		
		CCriticalSectionState( const CSyncBasicInfo& sbi );
		~CCriticalSectionState();

		//    accessors

		CSemaphore& Semaphore() { return m_sem; }
		
		//    debugging support

		void Dump( CDumpContext& dc ) const;
	
	private:

		//  member functions

		//    operators
		
		CCriticalSectionState& operator=( CCriticalSectionState& );  //  disallowed

		//  data members

		//    semaphore

		CSemaphore		m_sem;
	};


//  Critical Section (non-nestable)

class CCriticalSection
	:	private CLockObject,
		private CEnhancedStateContainer< CCriticalSectionState, CSyncBasicInfo, CCriticalSectionInfo, CLockBasicInfo >
	{
	public:

		//  member functions

		//    ctors / dtors

		CCriticalSection( const CLockBasicInfo& lbi );
		~CCriticalSection();

		//    manipulators

		void Enter();
		const BOOL FTryEnter();
		const BOOL FEnter( const int cmsecTimeout );
		void Leave();

		//    accessors

		const int CWait() { return State().Semaphore().CWait(); }

		const BOOL FOwner() { return State().FOwner(); }
		const BOOL FNotOwner() { return State().FNotOwner(); }

		//    debugging support

		void Dump( CDumpContext& dc ) const;

	private:

		//  member functions

		//    operators
		
		CCriticalSection& operator=( CCriticalSection& );  //  disallowed
	};

//  enter the critical section, waiting forever if someone else is currently the
//  owner.  the critical section can not be re-entered until it has been left

inline void CCriticalSection::Enter()
	{
	//  check for deadlock

	OSSYNCAssertSzRTL( State().FCanBeWaiter(),  "Potential Deadlock Detected (Rank Violation)"  );

	//  acquire the semaphore

	State().AddAsWaiter();
	
	State().Semaphore().Acquire();
	
	State().RemoveAsWaiter();

	//  there had better be no available counts on the semaphore
	
	OSSYNCAssert( !State().Semaphore().CAvail() );

	//  we are now the owner of the critical section

	State().AddAsOwner();
	State().StartHold();
	}
	
//  try to enter the critical section without waiting or spinning, returning
//  fFalse if someone else currently is the owner.  the critical section can not
//  be re-entered until it has been left

inline const BOOL CCriticalSection::FTryEnter()
	{
	//  try to acquire the semaphore without waiting or spinning
	//
	//  NOTE:  there is no potential for deadlock here, so don't bother to check
	
	BOOL fAcquire = State().Semaphore().FTryAcquire();

	//  we are now the owner of the critical section

	if ( fAcquire )
		{
		//  there had better be no available counts on the semaphore
		
		OSSYNCAssert( !State().Semaphore().CAvail() );

		//  add ourself as the owner
		
		State().AddAsOwner();
		State().StartHold();
		}

	return fAcquire;
	}
	
//  try to enter the critical section waiting only for the specified interval,
//  returning fFalse if the wait timed out before the critical section could be
//  acquired.  the critical section can not be re-entered until it has been left

inline const BOOL CCriticalSection::FEnter( const int cmsecTimeout )
	{
	//  check for deadlock if we are waiting forever

	OSSYNCAssertSzRTL( cmsecTimeout != cmsecInfinite || State().FCanBeWaiter(), "Potential Deadlock Detected (Rank Violation)" );

	//  try to acquire the semaphore, timing out as requested
	//
	//  NOTE:  there is still a potential for deadlock, but that will be detected
	//  at the OS level
	
	State().AddAsWaiter();
	
	BOOL fAcquire = State().Semaphore().FAcquire( cmsecTimeout );
	
	State().RemoveAsWaiter();

	//  we are now the owner of the critical section

	if ( fAcquire )
		{
		//  there had better be no available counts on the semaphore
		
		OSSYNCAssert( !State().Semaphore().CAvail() );

		//  add ourself as the owner
		
		State().AddAsOwner();
		State().StartHold();
		}

	return fAcquire;
	}
	
//  leaves the critical section, releasing it for ownership by someone else

inline void CCriticalSection::Leave()
	{
	//  remove ourself as the owner

	State().RemoveAsOwner();

	//  we are no longer holding the lock

	State().StopHold();

	//  there had better be no available counts on the semaphore
	
	OSSYNCAssert( !State().Semaphore().CAvail() );

	//  release the semaphore
	
	State().Semaphore().Release();
	}


//  Nestable Critical Section Information

class CNestableCriticalSectionInfo
	:	public CLockBasicInfo,
		public CLockPerfHold,
		public CLockDeadlockDetectionInfo
	{
	public:

		//  member functions
	
		//    ctors / dtors

		CNestableCriticalSectionInfo( const CLockBasicInfo& lbi )
			:	CLockBasicInfo( lbi ),
				CLockDeadlockDetectionInfo( (CLockBasicInfo&) *this )
			{
			}
		
		//    debugging support

		void Dump( CDumpContext& dc ) const;
	};


//  Nestable Critical Section State

class CNestableCriticalSectionState
	{
	public:

		//  member functions

		//    ctors / dtors
		
		CNestableCriticalSectionState( const CSyncBasicInfo& sbi );
		~CNestableCriticalSectionState();

		//    manipulators

		void SetOwner( CLS* const pcls );
		
		void Enter();
		void Leave();
		
		//    accessors

		CSemaphore& Semaphore() { return m_sem; }
		CLS* PclsOwner() { return m_pclsOwner; }
		int CEntry() { return m_cEntry; }
		
		//    debugging support

		void Dump( CDumpContext& dc ) const;
	
	private:

		//  member functions

		//    operators
		
		CNestableCriticalSectionState& operator=( CNestableCriticalSectionState& );  //  disallowed

		//  data members

		//    semaphore

		CSemaphore		m_sem;

		//    owning context (protected by the semaphore)

		CLS* volatile	m_pclsOwner;

		//    entry count (only valid when the owner id is valid)

		volatile int	m_cEntry;
	};

//  set the owner

inline void CNestableCriticalSectionState::SetOwner( CLS* const pcls )
	{
	//  we had either be clearing the owner or setting a new owner.  we should
	//  never be overwriting another owner

	OSSYNCAssert( !pcls || !m_pclsOwner );

	//  set the new owner

	m_pclsOwner = pcls;
	}

//  increment the entry count

inline void CNestableCriticalSectionState::Enter()
	{
	//  we had better have an owner already!

	OSSYNCAssert( m_pclsOwner );
	
	//  we should not overflow the entry count

	OSSYNCAssert( int( m_cEntry + 1 ) >= 1 );

	//  increment the entry count

	m_cEntry++;
	}

//  decrement the entry count

inline void CNestableCriticalSectionState::Leave()
	{
	//  we had better have an owner already!

	OSSYNCAssert( m_pclsOwner );
	
	//  decrement the entry count

	m_cEntry--;
	}


//  Nestable Critical Section

class CNestableCriticalSection
	:	private CLockObject,
		private CEnhancedStateContainer< CNestableCriticalSectionState, CSyncBasicInfo, CNestableCriticalSectionInfo, CLockBasicInfo >
	{
	public:

		//  member functions

		//    ctors / dtors

		CNestableCriticalSection( const CLockBasicInfo& lbi );
		~CNestableCriticalSection();

		//    manipulators

		void Enter();
		const BOOL FTryEnter();
		const BOOL FEnter( const int cmsecTimeout );
		void Leave();

		//    accessors

		const int CWait() { return State().Semaphore().CWait(); }
		
		const BOOL FOwner() { return State().FOwner(); }
		const BOOL FNotOwner() { return State().FNotOwner(); }

		//    debugging support

		void Dump( CDumpContext& dc ) const;

	private:

		//  member functions

		//    operators
		
		CNestableCriticalSection& operator=( CNestableCriticalSection& );  //  disallowed
	};

//  enter the critical section, waiting forever if someone else is currently the
//  owner.  the critical section can be reentered without waiting or deadlocking

inline void CNestableCriticalSection::Enter()
	{
	//  get our context

	CLS* const pcls = Pcls();
	
	//  we own the critical section

	if ( State().PclsOwner() == pcls )
		{
		//  there had better be no available counts on the semaphore
		
		OSSYNCAssert( !State().Semaphore().CAvail() );

		//  we should have at least one entry count

		OSSYNCAssert( State().CEntry() >= 1 );

		//  increment our entry count

		State().Enter();
		}

	//  we do not own the critical section

	else
		{
		OSSYNCAssert( State().PclsOwner() != pcls );

		//  check for deadlock

		OSSYNCAssertSzRTL( State().FCanBeWaiter(), "Potential Deadlock Detected (Rank Violation)" );

		//  acquire the semaphore

		State().AddAsWaiter();

		State().Semaphore().Acquire();

		State().RemoveAsWaiter();

		//  there had better be no available counts on the semaphore
		
		OSSYNCAssert( !State().Semaphore().CAvail() );

		//  we are now the owner of the critical section

		State().AddAsOwner();
		State().StartHold();

		//  save our context as the owner

		State().SetOwner( pcls );

		//  set initial entry count

		State().Enter();
		}
	}

//  try to enter the critical section without waiting or spinning, returning
//  fFalse if someone else currently is the owner.  the critical section can be
//  reentered without waiting or deadlocking

inline const BOOL CNestableCriticalSection::FTryEnter()
	{
	//  get our context

	CLS* const pcls = Pcls();
	
	//  we own the critical section

	if ( State().PclsOwner() == pcls )
		{
		//  there had better be no available counts on the semaphore
		
		OSSYNCAssert( !State().Semaphore().CAvail() );

		//  we should have at least one entry count

		OSSYNCAssert( State().CEntry() >= 1 );

		//  increment our entry count

		State().Enter();

		//  return success

		return fTrue;
		}

	//  we do not own the critical section

	else
		{
		OSSYNCAssert( State().PclsOwner() != pcls );

		//  try to acquire the semaphore without waiting or spinning
		//
		//  NOTE:  there is no potential for deadlock here, so don't bother to check

		const BOOL fAcquired = State().Semaphore().FTryAcquire();

		//  we now own the critical section

		if ( fAcquired )
			{
			//  there had better be no available counts on the semaphore
			
			OSSYNCAssert( !State().Semaphore().CAvail() );

			//  add ourself as the owner
			
			State().AddAsOwner();
			State().StartHold();
			
			//  save our context as the owner

			State().SetOwner( pcls );

			//  set initial entry count

			State().Enter();
			}

		//  return result

		return fAcquired;
		}
	}

//  try to enter the critical section waiting only for the specified interval,
//  returning fFalse if the wait timed out before the critical section could be
//  acquired.  the critical section can be reentered without waiting or
//  deadlocking

inline const BOOL CNestableCriticalSection::FEnter( const int cmsecTimeout )
	{
	//  get our context

	CLS* const pcls = Pcls();
	
	//  we own the critical section

	if ( State().PclsOwner() == pcls )
		{
		//  there had better be no available counts on the semaphore
		
		OSSYNCAssert( !State().Semaphore().CAvail() );

		//  we should have at least one entry count

		OSSYNCAssert( State().CEntry() >= 1 );

		//  increment our entry count

		State().Enter();

		//  return success

		return fTrue;
		}

	//  we do not own the critical section

	else
		{
		OSSYNCAssert( State().PclsOwner() != pcls );

		//  check for deadlock if we are waiting forever

		OSSYNCAssertSzRTL( cmsecTimeout != cmsecInfinite || State().FCanBeWaiter(), "Potential Deadlock Detected (Rank Violation)" );

		//  try to acquire the semaphore, timing out as requested
		//
		//  NOTE:  there is still a potential for deadlock, but that will be detected
		//  at the OS level

		State().AddAsWaiter();

		const BOOL fAcquired = State().Semaphore().FAcquire( cmsecTimeout );

		State().RemoveAsWaiter();

		//  we now own the critical section

		if ( fAcquired )
			{
			//  there had better be no available counts on the semaphore
			
			OSSYNCAssert( !State().Semaphore().CAvail() );

			//  add ourself as the owner
			
			State().AddAsOwner();
			State().StartHold();

			//  save our context as the owner

			State().SetOwner( pcls );

			//  set initial entry count

			State().Enter();
			}

		//  return result

		return fAcquired;
		}
	}

//  leave the critical section.  if leave has been called for every enter that
//  has completed successfully, the critical section is released for ownership
//  by someone else

inline void CNestableCriticalSection::Leave()
	{
	//  we had better be the current owner

	OSSYNCAssert( State().PclsOwner() == Pcls() );

	//  there had better be no available counts on the semaphore
	
	OSSYNCAssert( !State().Semaphore().CAvail() );

	//  there had better be at least one entry count

	OSSYNCAssert( State().CEntry() >= 1 );

	//  release one entry count

	State().Leave();

	//  we released the last entry count

	if ( !State().CEntry() )
		{
		//  reset the owner id

		State().SetOwner( 0 );

		//  remove ourself as the owner

		State().RemoveAsOwner();

		//  we are no longer holding the lock

		State().StopHold();
		
		//  release the semaphore

		State().Semaphore().Release();
		}
	}


//  Gate Information

class CGateInfo
	:	public CSyncBasicInfo,
		public CSyncPerfWait
	{
	public:

		//  member functions
	
		//    ctors / dtors

		CGateInfo( const CSyncBasicInfo& sbi )
			:	CSyncBasicInfo( sbi )
			{
			}
		
		//    debugging support

		void Dump( CDumpContext& dc ) const;
	};


//  Gate State

class CGateState
	{
	public:

		//  member functions

		//    ctors / dtors
		
		CGateState( const CSyncStateInitNull& null ) : m_cWait( 0 ), m_irksem( CKernelSemaphorePool::irksemNil ) {}
		CGateState( const int cWait, const int irksem );
		~CGateState() {}

		//    manipulators

		void SetWaitCount( const int cWait );
		void SetIrksem( const CKernelSemaphorePool::IRKSEM irksem );

		//    accessors

		const int CWait() const { return m_cWait; }
		const CKernelSemaphorePool::IRKSEM Irksem() const { return CKernelSemaphorePool::IRKSEM( m_irksem ); }
		
		//    debugging support

		void Dump( CDumpContext& dc ) const;
	
	private:

		//  member functions

		//    operators
		
		CGateState& operator=( CGateState& );  //  disallowed

		//  data members

		//    waiter count

		volatile short	m_cWait;			//  0 <= m_cWait <= ( 1 << 15 ) - 1

		//    reference kernel semaphore
		
		volatile unsigned short	m_irksem;	//  0 <= m_irksem <= ( 1 << 16 ) - 2
	};

//  sets the wait count for the gate

inline void CGateState::SetWaitCount( const int cWait )
	{
	//  it must be a valid wait count
	
	OSSYNCAssert( cWait >= 0 );
	OSSYNCAssert( cWait <= 0x7FFF );

	//  set the wait count

	m_cWait = (unsigned short) cWait;
	}

//  sets the referenced kernel semaphore for the gate

inline void CGateState::SetIrksem( const CKernelSemaphorePool::IRKSEM irksem )
	{
	//  it must be a valid irksem
	
	OSSYNCAssert( irksem >= 0 );
	OSSYNCAssert( irksem <= 0xFFFF );

	//  set the irksem

	m_irksem = (unsigned short) irksem;
	}


//  Gate

class CGate
	:	private CSyncObject,
		private CEnhancedStateContainer< CGateState, CSyncStateInitNull, CGateInfo, CSyncBasicInfo >
	{
	public:

		//  member functions

		//    ctors / dtors

		CGate( const CSyncBasicInfo& sbi );
		~CGate();

		//    manipulators

		void Wait( CCriticalSection& crit );
		void Release( CCriticalSection& crit, const int cToRelease = 1 );
		void ReleaseAndHold( CCriticalSection& crit, const int cToRelease = 1 );

		//    accessors

		const int CWait() const { return State().CWait(); }

		//    debugging support

		void Dump( CDumpContext& dc ) const;

	private:

		//  member functions

		//    operators
		
		CGate& operator=( CGate& );  //  disallowed
	};


//  Null Lock Object State Initializer

class CLockStateInitNull
	{
	};

extern const CLockStateInitNull lockstateNull;


//  Binary Lock Performance Information

class CBinaryLockPerfInfo
	:	public CSyncPerfWait,
		public CSyncPerfAcquire,
		public CLockPerfHold
	{
	public:

		//  member functions
	
		//    ctors / dtors

		CBinaryLockPerfInfo()
			{
			}
		
		//    debugging support

		void Dump( CDumpContext& dc ) const;
	};


//  Binary Lock Group Information

class CBinaryLockGroupInfo
	{
	public:

		//  member functions
	
		//    ctors / dtors

		CBinaryLockGroupInfo() {}
		~CBinaryLockGroupInfo() {}

		//    manipulators

		void StartWait( const int iGroup ) { m_rginfo[iGroup].StartWait(); }
		void StopWait( const int iGroup ) { m_rginfo[iGroup].StopWait(); }

		void SetAcquire( const int iGroup ) { m_rginfo[iGroup].SetAcquire(); }
		void SetContend( const int iGroup ) { m_rginfo[iGroup].SetContend(); }

		void StartHold( const int iGroup ) { m_rginfo[iGroup].StartHold(); }
		void StopHold( const int iGroup ) { m_rginfo[iGroup].StopHold(); }
		
		//    accessors

#ifdef SYNC_ANALYZE_PERFORMANCE

		QWORD	CWaitTotal( const int iGroup ) const		{ return m_rginfo[iGroup].CWaitTotal(); }
		double	CsecWaitElapsed( const int iGroup ) const	{ return m_rginfo[iGroup].CsecWaitElapsed(); }
		
		QWORD	CAcquireTotal( const int iGroup ) const		{ return m_rginfo[iGroup].CAcquireTotal(); }
		QWORD	CContendTotal( const int iGroup ) const		{ return m_rginfo[iGroup].CContendTotal(); }
		
		QWORD	CHoldTotal( const int iGroup ) const		{ return m_rginfo[iGroup].CHoldTotal(); }
		double	CsecHoldElapsed( const int iGroup ) const	{ return m_rginfo[iGroup].CsecHoldElapsed(); }

#endif  //  SYNC_ANALYZE_PERFORMANCE
		
		//    debugging support

		void Dump( CDumpContext& dc ) const;

	private:

		//  member functions

		//    operators

		CBinaryLockGroupInfo& operator=( CBinaryLockGroupInfo& );  //  disallowed

		//  data members

		//    performance info for each group

		CBinaryLockPerfInfo m_rginfo[2];
	};


//  Binary Lock Information

class CBinaryLockInfo
	:	public CLockBasicInfo,
		public CBinaryLockGroupInfo,
		public CLockDeadlockDetectionInfo
	{
	public:

		//  member functions
	
		//    ctors / dtors

		CBinaryLockInfo( const CLockBasicInfo& lbi )
			:	CLockBasicInfo( lbi ),
				CLockDeadlockDetectionInfo( (CLockBasicInfo&) *this )
			{
			}
		
		//    debugging support

		void Dump( CDumpContext& dc ) const;
	};


//  Binary Lock State

class CBinaryLockState
	{
	public:
	
		//  types

		//    control word

		typedef DWORD ControlWord;

		//  member functions

		//    ctors / dtors
		
		CBinaryLockState( const CSyncBasicInfo& sbi );
		~CBinaryLockState();
		
		//    debugging support

		void Dump( CDumpContext& dc ) const;

		//  data members

		//    control word

		union
			{
			volatile ControlWord	m_cw;
			
			struct
				{
				volatile DWORD			m_cOOW1:15;
				volatile DWORD			m_fQ1:1;
				volatile DWORD			m_cOOW2:15;
				volatile DWORD			m_fQ2:1;
				};
			};

		//    quiesced owner count
		
		volatile DWORD			m_cOwner;

		//    sempahore used by Group 1 to wait for lock ownership
		
		CSemaphore				m_sem1;

		//    sempahore used by Group 2 to wait for lock ownership
		
		CSemaphore				m_sem2;
		
	private:

		//  member functions

		//    operators
		
		CBinaryLockState& operator=( CBinaryLockState& );  //  disallowed
	};


//  Binary Lock

class CBinaryLock
	:	private CLockObject,
		private CEnhancedStateContainer< CBinaryLockState, CSyncBasicInfo, CBinaryLockInfo, CLockBasicInfo >
	{
	public:

		//  types

		//    control word

		typedef CBinaryLockState::ControlWord ControlWord;

		//    transition reasons for state machine
		
		enum TransitionReason
			{
			trIllegal = 0,
			trEnter1 = 1,
			trLeave1 = 2,
			trEnter2 = 4,
			trLeave2 = 8,
			};

		//  member functions

		//    ctors / dtors

		CBinaryLock( const CLockBasicInfo& lbi );
		~CBinaryLock();

		//    manipulators

		void Enter1();
		const BOOL FTryEnter1();
		void Leave1();

		void Enter2();
		const BOOL FTryEnter2();
		void Leave2();

		//    accessors

		const BOOL FGroup1Quiesced()	{ return State().m_cw & 0x00008000; }
		const BOOL FGroup2Quiesced()	{ return State().m_cw & 0x80000000; }

		const BOOL FMemberOfGroup1()	{ return State().FOwner( 0 ); }
		const BOOL FNotMemberOfGroup1()	{ return State().FNotOwner( 0 ); }
		const BOOL FMemberOfGroup2()	{ return State().FOwner( 1 ); }
		const BOOL FNotMemberOfGroup2()	{ return State().FNotOwner( 1 ); }

		//    debugging support

		void Dump( CDumpContext& dc ) const;

	private:

		//  member functions

		//    operators
		
		CBinaryLock& operator=( CBinaryLock& );  //  disallowed

		//    verification
		
		int _StateFromControlWord( const ControlWord cw );
		BOOL _FValidStateTransition(	const ControlWord cwBI,
										const ControlWord cwAI,
										const TransitionReason tr );

		//    manipulators

		void _Enter1( const ControlWord cwBIOld );
		void _Enter2( const ControlWord cwBIOld );

		void _UpdateQuiescedOwnerCountAsGroup1( const DWORD cOwnerDelta );
		void _UpdateQuiescedOwnerCountAsGroup2( const DWORD cOwnerDelta );
	};

//  enters the binary lock as a member of Group 1, waiting forever if necessary
//
//  NOTE:  trying to enter the lock as a member of Group 1 when you already own
//  the lock as a member of Group 2 will cause a deadlock.

inline void CBinaryLock::Enter1()
	{
	//  we had better not already own this lock as either group

	OSSYNCAssert( State().FNotOwner( 0 ) );
	OSSYNCAssert( State().FNotOwner( 1 ) );
	
	//  check for deadlock

	OSSYNCAssertSzRTL( State().FCanBeWaiter(), "Potential Deadlock Detected (Rank Violation)" );

	//  try forever until we successfully change the lock state

	OSSYNC_FOREVER
		{
		//  read the current state of the control word as our expected before image

		const ControlWord cwBIExpected = State().m_cw;

		//  compute the after image of the control word by performing the global
		//  transform for the Enter1 state transition

		const ControlWord cwAI =	ControlWord( ( ( cwBIExpected & ( ( LONG_PTR( long( cwBIExpected ) ) >> 31 ) |
									0x0000FFFF ) ) | 0x80000000 ) + 0x00000001 );

		//  validate the transaction

		OSSYNCAssert( _FValidStateTransition( cwBIExpected, cwAI, trEnter1 ) );

		//  attempt to perform the transacted state transition on the control word

		const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );

		//  the transaction failed or Group 1 was quiesced from ownership

		if ( ( cwBI ^ cwBIExpected ) | ( cwBI & 0x00008000 ) )
			{
			//  the transaction failed because another context changed the control word

			if ( cwBI != cwBIExpected )
				{
				//  try again

				continue;
				}

			//  the transaction succeeded but Group 1 was quiesced from ownership

			else
				{
				//  this is a contention for Group 1

				State().SetContend( 0 );

				//  wait to own the lock as a member of Group 1

				_Enter1( cwBI );

				//  we now own the lock, so we're done

				break;
				}
			}

		//  the transaction succeeded and Group 1 was not quiesced from ownership

		else
			{
			//  we now own the lock, so we're done

			break;
			}
		}

	//  we are now an owner of the lock for Group 1

	State().SetAcquire( 0 );
	State().AddAsOwner( 0 );
	State().StartHold( 0 );
	}

//  tries to enter the binary lock as a member of Group 1 without waiting or
//  spinning, returning fFalse if Group 1 is quiesced from ownership
//
//  NOTE:  trying to enter the lock as a member of Group 1 when you already own
//  the lock as a member of Group 2 will cause a deadlock.

inline const BOOL CBinaryLock::FTryEnter1()
	{
	//  we had better not already own this lock as either group

	OSSYNCAssert( State().FNotOwner( 0 ) );
	OSSYNCAssert( State().FNotOwner( 1 ) );
	
	//  try forever until we successfully change the lock state

	OSSYNC_FOREVER
		{
		//  read the current state of the control word as our expected before image

		ControlWord cwBIExpected = State().m_cw;

		//  change the expected before image so that the transaction will only work if
		//  Group 1 ownership is not quiesced

		cwBIExpected = cwBIExpected & 0xFFFF7FFF;

		//  compute the after image of the control word by performing the global
		//  transform for the Enter1 state transition

		const ControlWord cwAI =	ControlWord( ( ( cwBIExpected & ( ( LONG_PTR( long( cwBIExpected ) ) >> 31 ) |
									0x0000FFFF ) ) | 0x80000000 ) + 0x00000001 );

		//  validate the transaction

		OSSYNCAssert(	_StateFromControlWord( cwBIExpected ) < 0 ||
				_FValidStateTransition( cwBIExpected, cwAI, trEnter1 ) );

		//  attempt to perform the transacted state transition on the control word

		const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );

		//  the transaction failed

		if ( cwBI != cwBIExpected )
			{
			//  the transaction failed because Group 1 ownership is quiesced

			if ( cwBI & 0x00008000 )
				{
				//  return failure

				return fFalse;
				}

			//  the transaction failed because another context changed the control word

			else
				{
				//  try again

				continue;
				}
			}

		//  the transaction succeeded

		else
			{
			//  we are now an owner of the lock for Group 1

			State().SetAcquire( 0 );
			State().AddAsOwner( 0 );
			State().StartHold( 0 );

			//  return success

			return fTrue;
			}
		}
	}

//  leaves the binary lock as a member of Group 1
//
//  NOTE:  you must leave the lock as a member of the same Group for which you entered
//  the lock or deadlocks may occur

inline void CBinaryLock::Leave1()
	{
	//  we are no longer an owner of the lock

	State().RemoveAsOwner( 0 );
	
	//  we are no longer holding the lock

	State().StopHold( 0 );

	//  try forever until we successfully change the lock state

	OSSYNC_FOREVER
		{
		//  read the current state of the control word as our expected before image

		ControlWord cwBIExpected = State().m_cw;

		//  change the expected before image so that the transaction will only work if
		//  Group 1 ownership is not quiesced

		cwBIExpected = cwBIExpected & 0xFFFF7FFF;

		//  compute the after image of the control word by performing the transform that
		//  will take us either from state 2 to state 0 or state 2 to state 2

		ControlWord cwAI =	cwBIExpected + 0xFFFFFFFF;
		cwAI = cwAI - ( ( ( cwAI + 0xFFFFFFFF ) << 16 ) & 0x80000000 );

		//  validate the transaction

		OSSYNCAssert(	_StateFromControlWord( cwBIExpected ) < 0 ||
				_FValidStateTransition( cwBIExpected, cwAI, trLeave1 ) );

		//  attempt to perform the transacted state transition on the control word

		const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );

		//  the transaction failed

		if ( cwBI != cwBIExpected )
			{
			//  the transaction failed because Group 1 ownership is quiesced

			if ( cwBI & 0x00008000 )
				{
				//  leave the lock as a quiesced owner

				_UpdateQuiescedOwnerCountAsGroup1( 0xFFFFFFFF );

				//  we're done

				break;
				}

			//  the transaction failed because another context changed the control word

			else
				{
				//  try again

				continue;
				}
			}

		//  the transaction succeeded

		else
			{
			// we're done

			break;
			}
		}
	}

//  enters the binary lock as a member of Group 2, waiting forever if necessary
//
//  NOTE:  trying to enter the lock as a member of Group 2 when you already own
//  the lock as a member of Group 1 will cause a deadlock.

inline void CBinaryLock::Enter2()
	{
	//  we had better not already own this lock as either group

	OSSYNCAssert( State().FNotOwner( 0 ) );
	OSSYNCAssert( State().FNotOwner( 1 ) );
	
	//  check for deadlock

	OSSYNCAssertSzRTL( State().FCanBeWaiter(), "Potential Deadlock Detected (Rank Violation)" );

	//  try forever until we successfully change the lock state

	OSSYNC_FOREVER
		{
		//  read the current state of the control word as our expected before image

		const ControlWord cwBIExpected = State().m_cw;

		//  compute the after image of the control word by performing the global
		//  transform for the Enter2 state transition

		const ControlWord cwAI =	ControlWord( ( ( cwBIExpected & ( ( LONG_PTR( long( cwBIExpected << 16 ) ) >> 31 ) |
									0xFFFF0000 ) ) | 0x00008000 ) + 0x00010000 );

		//  validate the transaction

		OSSYNCAssert( _FValidStateTransition( cwBIExpected, cwAI, trEnter2 ) );

		//  attempt to perform the transacted state transition on the control word

		const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );

		//  the transaction failed or Group 2 was quiesced from ownership

		if ( ( cwBI ^ cwBIExpected ) | ( cwBI & 0x80000000 ) )
			{
			//  the transaction failed because another context changed the control word

			if ( cwBI != cwBIExpected )
				{
				//  try again

				continue;
				}

			//  the transaction succeeded but Group 2 was quiesced from ownership

			else
				{
				//  this is a contention for Group 2

				State().SetContend( 1 );

				//  wait to own the lock as a member of Group 2

				_Enter2( cwBI );

				//  we now own the lock, so we're done

				break;
				}
			}

		//  the transaction succeeded and Group 2 was not quiesced from ownership

		else
			{
			//  we now own the lock, so we're done

			break;
			}
		}

	//  we are now an owner of the lock for Group 2

	State().SetAcquire( 1 );
	State().AddAsOwner( 1 );
	State().StartHold( 1 );
	}

//  tries to enter the binary lock as a member of Group 2 without waiting or
//  spinning, returning fFalse if Group 2 is quiesced from ownership
//
//  NOTE:  trying to enter the lock as a member of Group 2 when you already own
//  the lock as a member of Group 1 will cause a deadlock.

inline const BOOL CBinaryLock::FTryEnter2()
	{
	//  we had better not already own this lock as either group

	OSSYNCAssert( State().FNotOwner( 0 ) );
	OSSYNCAssert( State().FNotOwner( 1 ) );
	
	//  try forever until we successfully change the lock state

	OSSYNC_FOREVER
		{
		//  read the current state of the control word as our expected before image

		ControlWord cwBIExpected = State().m_cw;

		//  change the expected before image so that the transaction will only work if
		//  Group 2 ownership is not quiesced

		cwBIExpected = cwBIExpected & 0x7FFFFFFF;

		//  compute the after image of the control word by performing the global
		//  transform for the Enter2 state transition

		const ControlWord cwAI =	ControlWord( ( ( cwBIExpected & ( ( LONG_PTR( long( cwBIExpected << 16 ) ) >> 31 ) |
									0xFFFF0000 ) ) | 0x00008000 ) + 0x00010000 );

		//  validate the transaction

		OSSYNCAssert(	_StateFromControlWord( cwBIExpected ) < 0 ||
				_FValidStateTransition( cwBIExpected, cwAI, trEnter2 ) );

		//  attempt to perform the transacted state transition on the control word

		const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );

		//  the transaction failed

		if ( cwBI != cwBIExpected )
			{
			//  the transaction failed because Group 2 ownership is quiesced

			if ( cwBI & 0x80000000 )
				{
				//  return failure

				return fFalse;
				}

			//  the transaction failed because another context changed the control word

			else
				{
				//  try again

				continue;
				}
			}

		//  the transaction succeeded

		else
			{
			//  we are now an owner of the lock for Group 2

			State().SetAcquire( 1 );
			State().AddAsOwner( 1 );
			State().StartHold( 1 );

			//  return success

			return fTrue;
			}
		}
	}

//  leaves the binary lock as a member of Group 2
//
//  NOTE:  you must leave the lock as a member of the same Group for which you entered
//  the lock or deadlocks may occur

inline void CBinaryLock::Leave2()
	{
	//  we are no longer an owner of the lock

	State().RemoveAsOwner( 1 );
	
	//  we are no longer holding the lock

	State().StopHold( 1 );

	//  try forever until we successfully change the lock state

	OSSYNC_FOREVER
		{
		//  read the current state of the control word as our expected before image

		ControlWord cwBIExpected = State().m_cw;

		//  change the expected before image so that the transaction will only work if
		//  Group 2 ownership is not quiesced

		cwBIExpected = cwBIExpected & 0x7FFFFFFF;

		//  compute the after image of the control word by performing the transform that
		//  will take us either from state 1 to state 0 or state 1 to state 1

		ControlWord cwAI =	cwBIExpected + 0xFFFF0000;
		cwAI = cwAI - ( ( ( cwAI + 0xFFFF0000 ) >> 16 ) & 0x00008000 );

		//  validate the transaction

		OSSYNCAssert(	_StateFromControlWord( cwBIExpected ) < 0 ||
				_FValidStateTransition( cwBIExpected, cwAI, trLeave2 ) );

		//  attempt to perform the transacted state transition on the control word

		const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );

		//  the transaction failed

		if ( cwBI != cwBIExpected )
			{
			//  the transaction failed because Group 2 ownership is quiesced

			if ( cwBI & 0x80000000 )
				{
				//  leave the lock as a quiesced owner

				_UpdateQuiescedOwnerCountAsGroup2( 0xFFFFFFFF );

				//  we're done

				break;
				}

			//  the transaction failed because another context changed the control word

			else
				{
				//  try again

				continue;
				}
			}

		//  the transaction succeeded

		else
			{
			// we're done

			break;
			}
		}
	}


//  Reader / Writer Lock Performance Information

class CReaderWriterLockPerfInfo
	:	public CSyncPerfWait,
		public CSyncPerfAcquire,
		public CLockPerfHold
	{
	public:

		//  member functions
	
		//    ctors / dtors

		CReaderWriterLockPerfInfo()
			{
			}
		
		//    debugging support

		void Dump( CDumpContext& dc ) const;
	};


//  Reader / Writer Lock Group Information

class CReaderWriterLockGroupInfo
	{
	public:

		//  member functions
	
		//    ctors / dtors

		CReaderWriterLockGroupInfo() {}
		~CReaderWriterLockGroupInfo() {}

		//    manipulators

		void StartWait( const int iGroup ) { m_rginfo[iGroup].StartWait(); }
		void StopWait( const int iGroup ) { m_rginfo[iGroup].StopWait(); }

		void SetAcquire( const int iGroup ) { m_rginfo[iGroup].SetAcquire(); }
		void SetContend( const int iGroup ) { m_rginfo[iGroup].SetContend(); }

		void StartHold( const int iGroup ) { m_rginfo[iGroup].StartHold(); }
		void StopHold( const int iGroup ) { m_rginfo[iGroup].StopHold(); }
		
		//    accessors

#ifdef SYNC_ANALYZE_PERFORMANCE

		QWORD	CWaitTotal( const int iGroup ) const		{ return m_rginfo[iGroup].CWaitTotal(); }
		double	CsecWaitElapsed( const int iGroup ) const	{ return m_rginfo[iGroup].CsecWaitElapsed(); }
		
		QWORD	CAcquireTotal( const int iGroup ) const		{ return m_rginfo[iGroup].CAcquireTotal(); }
		QWORD	CContendTotal( const int iGroup ) const		{ return m_rginfo[iGroup].CContendTotal(); }
		
		QWORD	CHoldTotal( const int iGroup ) const		{ return m_rginfo[iGroup].CHoldTotal(); }
		double	CsecHoldElapsed( const int iGroup ) const	{ return m_rginfo[iGroup].CsecHoldElapsed(); }

#endif  //  SYNC_ANALYZE_PERFORMANCE
		
		//    debugging support

		void Dump( CDumpContext& dc ) const;

	private:

		//  member functions

		//    operators

		CReaderWriterLockGroupInfo& operator=( CReaderWriterLockGroupInfo& );  //  disallowed

		//  data members

		//    performance info for each group

		CReaderWriterLockPerfInfo m_rginfo[2];
	};


//  Reader / Writer Lock Information

class CReaderWriterLockInfo
	:	public CLockBasicInfo,
		public CReaderWriterLockGroupInfo,
		public CLockDeadlockDetectionInfo
	{
	public:

		//  member functions
	
		//    ctors / dtors

		CReaderWriterLockInfo( const CLockBasicInfo& lbi )
			:	CLockBasicInfo( lbi ),
				CLockDeadlockDetectionInfo( (CLockBasicInfo&) *this )
			{
			}
		
		//    debugging support

		void Dump( CDumpContext& dc ) const;
	};


//  Reader / Writer Lock State

class CReaderWriterLockState
	{
	public:
	
		//  types

		//    control word

		typedef DWORD ControlWord;

		//  member functions

		//    ctors / dtors
		
		CReaderWriterLockState( const CSyncBasicInfo& sbi );
		~CReaderWriterLockState();
		
		//    debugging support

		void Dump( CDumpContext& dc ) const;

		//  data members

		//    control word

		union
			{
			volatile ControlWord	m_cw;
			
			struct
				{
				volatile DWORD			m_cOAOWW:15;
				volatile DWORD			m_fQW:1;
				volatile DWORD			m_cOOWR:15;
				volatile DWORD			m_fQR:1;
				};
			};

		//    quiesced owner count
		
		volatile DWORD			m_cOwner;

		//    sempahore used by writers to wait for lock ownership
		
		CSemaphore				m_semWriter;

		//    sempahore used by readers to wait for lock ownership
		
		CSemaphore				m_semReader;
		
	private:

		//  member functions

		//    operators
		
		CReaderWriterLockState& operator=( CReaderWriterLockState& );  //  disallowed
	};


//  Reader / Writer Lock

class CReaderWriterLock
	:	private CLockObject,
		private CEnhancedStateContainer< CReaderWriterLockState, CSyncBasicInfo, CReaderWriterLockInfo, CLockBasicInfo >
	{
	public:

		//  types

		//    control word

		typedef CReaderWriterLockState::ControlWord ControlWord;

		//    transition reasons for state machine
		
		enum TransitionReason
			{
			trIllegal = 0,
			trEnterAsWriter = 1,
			trLeaveAsWriter = 2,
			trEnterAsReader = 4,
			trLeaveAsReader = 8,
			};

		//  member functions

		//    ctors / dtors

		CReaderWriterLock( const CLockBasicInfo& lbi );
		~CReaderWriterLock();

		//    manipulators

		void EnterAsWriter();
		const BOOL FTryEnterAsWriter();
		void LeaveAsWriter();

		void EnterAsReader();
		const BOOL FTryEnterAsReader();
		void LeaveAsReader();

		//    accessors

		const BOOL FWritersQuiesced()	{ return State().m_cw & 0x00008000; }
		const BOOL FReadersQuiesced()	{ return State().m_cw & 0x80000000; }

		const BOOL FWriter()	{ return State().FOwner( 0 ); }
		const BOOL FNotWriter()	{ return State().FNotOwner( 0 ); }
		const BOOL FReader()	{ return State().FOwner( 1 ); }
		const BOOL FNotReader()	{ return State().FNotOwner( 1 ); }

		//    debugging support

		void Dump( CDumpContext& dc ) const;

	private:

		//  member functions

		//    operators
		
		CReaderWriterLock& operator=( CReaderWriterLock& );  //  disallowed

		//    verification
		
		int _StateFromControlWord( const ControlWord cw );
		BOOL _FValidStateTransition(	const ControlWord cwBI,
										const ControlWord cwAI,
										const TransitionReason tr );

		//    manipulators

		void _EnterAsWriter( const ControlWord cwBIOld );
		void _EnterAsReader( const ControlWord cwBIOld );

		void _UpdateQuiescedOwnerCountAsWriter( const DWORD cOwnerDelta );
		void _UpdateQuiescedOwnerCountAsReader( const DWORD cOwnerDelta );
	};

//  enters the reader / writer lock as a writer, waiting forever if necessary
//
//  NOTE:  trying to enter the lock as a writer when you already own the lock
//  as a reader will cause a deadlock.

inline void CReaderWriterLock::EnterAsWriter()
	{
	//  we had better not already own this lock as either a reader or a writer

	OSSYNCAssert( State().FNotOwner( 0 ) );
	OSSYNCAssert( State().FNotOwner( 1 ) );
	
	//  check for deadlock

	OSSYNCAssertSzRTL( State().FCanBeWaiter(), "Potential Deadlock Detected (Rank Violation)");

	//  try forever until we successfully change the lock state

	OSSYNC_FOREVER
		{
		//  read the current state of the control word as our expected before image

		const ControlWord cwBIExpected = State().m_cw;

		//  compute the after image of the control word by performing the global
		//  transform for the EnterAsWriter state transition

		const ControlWord cwAI =	ControlWord( ( ( cwBIExpected & ( ( LONG_PTR( long( cwBIExpected ) ) >> 31 ) |
									0x0000FFFF ) ) | 0x80000000 ) + 0x00000001 );

		//  validate the transaction

		OSSYNCAssert( _FValidStateTransition( cwBIExpected, cwAI, trEnterAsWriter ) );

		//  attempt to perform the transacted state transition on the control word

		const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );

		//  the transaction failed or writers are quiesced from ownership or a
		//  writer already owns the lock

		if ( ( cwBI ^ cwBIExpected ) | ( cwBI & 0x0000FFFF ) )
			{
			//  the transaction failed because another context changed the control word

			if ( cwBI != cwBIExpected )
				{
				//  try again

				continue;
				}

			//  the transaction succeeded but writers are quiesced from ownership
			//  or a writer already owns the lock

			else
				{
				//  this is a contention for writers

				State().SetContend( 0 );

				//  wait to own the lock as a writer

				_EnterAsWriter( cwBI );

				//  we now own the lock, so we're done

				break;
				}
			}

		//  the transaction succeeded and writers were not quiesced from ownership
		//  and a writer did not already own the lock

		else
			{
			//  we now own the lock, so we're done

			break;
			}
		}

	//  we are now an owner of the lock for writers

	State().SetAcquire( 0 );
	State().AddAsOwner( 0 );
	State().StartHold( 0 );
	}

//  tries to enter the reader / writer lock as a writer without waiting or
//  spinning, returning fFalse if writers are quiesced from ownership or
//  another writer already owns the lock
//
//  NOTE:  trying to enter the lock as a writer when you already own the lock
//  as a reader will cause a deadlock.

inline const BOOL CReaderWriterLock::FTryEnterAsWriter()
	{
	//  we had better not already own this lock as either a reader or a writer

	OSSYNCAssert( State().FNotOwner( 0 ) );
	OSSYNCAssert( State().FNotOwner( 1 ) );
	
	//  try forever until we successfully change the lock state

	OSSYNC_FOREVER
		{
		//  read the current state of the control word as our expected before image

		ControlWord cwBIExpected = State().m_cw;

		//  change the expected before image so that the transaction will only work if
		//  writers were not quiesced from ownership and another writer doesn't already
		//  own the lock

		cwBIExpected = cwBIExpected & 0xFFFF0000;

		//  compute the after image of the control word by performing the global
		//  transform for the EnterAsWriter state transition

		const ControlWord cwAI =	ControlWord( ( ( cwBIExpected & ( ( LONG_PTR( long( cwBIExpected ) ) >> 31 ) |
									0x0000FFFF ) ) | 0x80000000 ) + 0x00000001 );

		//  validate the transaction

		OSSYNCAssert(	_StateFromControlWord( cwBIExpected ) < 0 ||
				_FValidStateTransition( cwBIExpected, cwAI, trEnterAsWriter ) );

		//  attempt to perform the transacted state transition on the control word

		const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );

		//  the transaction failed

		if ( cwBI != cwBIExpected )
			{
			//  the transaction failed because writers were quiesced from ownership
			//  or another writer already owns the lock

			if ( cwBI & 0x0000FFFF )
				{
				//  return failure

				return fFalse;
				}

			//  the transaction failed because another context changed the control word

			else
				{
				//  try again

				continue;
				}
			}

		//  the transaction succeeded

		else
			{
			//  we are now an owner of the lock for writers

			State().SetAcquire( 0 );
			State().AddAsOwner( 0 );
			State().StartHold( 0 );
			
			// return success

			return fTrue;
			}
		}
	}

//  leaves the reader / writer lock as a writer
//
//  NOTE:  you must leave the lock as a member of the same group for which you entered
//  the lock or deadlocks may occur

inline void CReaderWriterLock::LeaveAsWriter()
	{
	//  we are no longer an owner of the lock

	State().RemoveAsOwner( 0 );

	//  we are no longer holding the lock

	State().StopHold( 0 );

	//  try forever until we successfully change the lock state

	OSSYNC_FOREVER
		{
		//  read the current state of the control word as our expected before image

		ControlWord cwBIExpected = State().m_cw;

		//  change the expected before image so that the transaction will only work if
		//  writers were not quiesced from ownership

		cwBIExpected = cwBIExpected & 0xFFFF7FFF;

		//  compute the after image of the control word by performing the transform that
		//  will take us either from state 2 to state 0 or state 2 to state 2

		ControlWord cwAI =	cwBIExpected + 0xFFFFFFFF;
		cwAI = cwAI - ( ( ( cwAI + 0xFFFFFFFF ) << 16 ) & 0x80000000 );

		//  validate the transaction

		OSSYNCAssert(	_StateFromControlWord( cwBIExpected ) < 0 ||
				_FValidStateTransition( cwBIExpected, cwAI, trLeaveAsWriter ) );

		//  attempt to perform the transacted state transition on the control word

		const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );

		//  the transaction failed

		if ( cwBI != cwBIExpected )
			{
			//  the transaction failed because writers were quiesced from ownership

			if ( cwBI & 0x00008000 )
				{
				//  leave the lock as a quiesced owner

				_UpdateQuiescedOwnerCountAsWriter( 0xFFFFFFFF );

				//  we're done

				break;
				}

			//  the transaction failed because another context changed the control word

			else
				{
				//  try again

				continue;
				}
			}

		//  the transaction succeeded

		else
			{
			//  there were other writers waiting for ownership of the lock

			if ( cwAI & 0x00007FFF )
				{
				//  release the next writer into ownership of the lock

				State().m_semWriter.Release();
				}
			
			// we're done

			break;
			}
		}
	}

//  enters the reader / writer lock as a reader, waiting forever if necessary
//
//  NOTE:  trying to enter the lock as a reader when you already own the lock
//  as a writer will cause a deadlock.

inline void CReaderWriterLock::EnterAsReader()
	{
	//  we had better not already own this lock as either a reader or a writer

	OSSYNCAssert( State().FNotOwner( 0 ) );
	OSSYNCAssert( State().FNotOwner( 1 ) );
	
	//  check for deadlock

	OSSYNCAssertSzRTL( State().FCanBeWaiter(), "Potential Deadlock Detected (Rank Violation)" );

	//  try forever until we successfully change the lock state

	OSSYNC_FOREVER
		{
		//  read the current state of the control word as our expected before image

		const ControlWord cwBIExpected = State().m_cw;

		//  compute the after image of the control word by performing the global
		//  transform for the EnterAsReader state transition

		const ControlWord cwAI =	( cwBIExpected & 0xFFFF7FFF ) +
									(	( cwBIExpected & 0x80008000 ) == 0x80000000 ?
											0x00017FFF :
											0x00018000 );

		//  validate the transaction

		OSSYNCAssert( _FValidStateTransition( cwBIExpected, cwAI, trEnterAsReader ) );

		//  attempt to perform the transacted state transition on the control word

		const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );

		//  the transaction failed or readers were quiesced from ownership

		if ( ( cwBI ^ cwBIExpected ) | ( cwBI & 0x80000000 ) )
			{
			//  the transaction failed because another context changed the control word

			if ( cwBI != cwBIExpected )
				{
				//  try again

				continue;
				}

			//  the transaction succeeded but readers were quiesced from ownership

			else
				{
				//  this is a contention for readers

				State().SetContend( 1 );

				//  wait to own the lock as a reader

				_EnterAsReader( cwBI );

				//  we now own the lock, so we're done

				break;
				}
			}

		//  the transaction succeeded and readers were not quiesced from ownership

		else
			{
			//  we now own the lock, so we're done

			break;
			}
		}

	//  we are now an owner of the lock for readers

	State().SetAcquire( 1 );
	State().AddAsOwner( 1 );
	State().StartHold( 1 );
	}

//  tries to enter the reader / writer lock as a reader without waiting or
//  spinning, returning fFalse if readers are quiesced from ownership
//
//  NOTE:  trying to enter the lock as a reader when you already own the lock
//  as a writer will cause a deadlock.

inline const BOOL CReaderWriterLock::FTryEnterAsReader()
	{
	//  we had better not already own this lock as either a reader or a writer

	OSSYNCAssert( State().FNotOwner( 0 ) );
	OSSYNCAssert( State().FNotOwner( 1 ) );
	
	//  try forever until we successfully change the lock state

	OSSYNC_FOREVER
		{
		//  read the current state of the control word as our expected before image

		ControlWord cwBIExpected = State().m_cw;

		//  change the expected before image so that the transaction will only work if
		//  readers were not quiesced from ownership

		cwBIExpected = cwBIExpected & 0x7FFFFFFF;

		//  compute the after image of the control word by performing the global
		//  transform for the EnterAsReader state transition

		const ControlWord cwAI =	( cwBIExpected & 0xFFFF7FFF ) +
									(	( cwBIExpected & 0x80008000 ) == 0x80000000 ?
											0x00017FFF :
											0x00018000 );

		//  validate the transaction

		OSSYNCAssert(	_StateFromControlWord( cwBIExpected ) < 0 ||
				_FValidStateTransition( cwBIExpected, cwAI, trEnterAsReader ) );

		//  attempt to perform the transacted state transition on the control word

		const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );

		//  the transaction failed

		if ( cwBI != cwBIExpected )
			{
			//  the transaction failed because readers were quiesced from ownership

			if ( cwBI & 0x80000000 )
				{
				//  return failure

				return fFalse;
				}

			//  the transaction failed because another context changed the control word

			else
				{
				//  try again

				continue;
				}
			}

		//  the transaction succeeded

		else
			{
			//  we are now an owner of the lock for readers

			State().SetAcquire( 1 );
			State().AddAsOwner( 1 );
			State().StartHold( 1 );

			// return success

			return fTrue;
			}
		}
	}

//  leaves the reader / writer lock as a reader
//
//  NOTE:  you must leave the lock as a member of the same group for which you entered
//  the lock or deadlocks may occur

inline void CReaderWriterLock::LeaveAsReader()
	{
	//  we are no longer an owner of the lock

	State().RemoveAsOwner( 1 );

	//  we are no longer holding the lock

	State().StopHold( 1 );

	//  try forever until we successfully change the lock state

	OSSYNC_FOREVER
		{
		//  read the current state of the control word as our expected before image

		ControlWord cwBIExpected = State().m_cw;

		//  change the expected before image so that the transaction will only work if
		//  readers were not quiesced from ownership

		cwBIExpected = cwBIExpected & 0x7FFFFFFF;

		//  compute the after image of the control word by performing the transform that
		//  will take us either from state 1 to state 0 or state 1 to state 1

		const ControlWord cwAI =	ControlWord( cwBIExpected + 0xFFFF0000 +
									( ( LONG_PTR( long( cwBIExpected + 0xFFFE0000 ) ) >> 31 ) & 0xFFFF8000 ) );

		//  validate the transaction

		OSSYNCAssert(	_StateFromControlWord( cwBIExpected ) < 0 ||
				_FValidStateTransition( cwBIExpected, cwAI, trLeaveAsReader ) );

		//  attempt to perform the transacted state transition on the control word

		const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );

		//  the transaction failed

		if ( cwBI != cwBIExpected )
			{
			//  the transaction failed because readers were quiesced from ownership

			if ( cwBI & 0x80000000 )
				{
				//  leave the lock as a quiesced owner

				_UpdateQuiescedOwnerCountAsReader( 0xFFFFFFFF );

				//  we're done

				break;
				}

			//  the transaction failed because another context changed the control word

			else
				{
				//  try again

				continue;
				}
			}

		//  the transaction succeeded

		else
			{
			// we're done

			break;
			}
		}
	}


//  Metered Section

class CMeteredSection
	:	private CSyncObject
	{
	public:
	
		//  types

		//    control word

		typedef DWORD ControlWord;

		//  callback used to notify the user when a partition of the current
		//  group has been completed

		typedef void (*PFNPARTITIONCOMPLETE)( const DWORD_PTR dwCompletionKey );
											
		//  member functions

		//    ctors / dtors

		CMeteredSection();
		~CMeteredSection();

		//    manipulators

		int Enter();
		void Leave( const int group );

		void Partition(	const PFNPARTITIONCOMPLETE	pfnPartitionComplete	= NULL,
						const DWORD_PTR				dwCompletionKey			= NULL );

		//    accessors

		int ActiveGroup()	{ return int( m_groupCurrent ); }

		//    debugging support

		void Dump( CDumpContext& dc ) const;

	private:
	
		//  data members

		//    partition complete callback

		PFNPARTITIONCOMPLETE	m_pfnPartitionComplete;
		DWORD_PTR				m_dwPartitionCompleteKey;
		
		//    control word

		union
			{
			volatile ControlWord	m_cw;

			struct
				{
				volatile DWORD			m_cCurrent:15;
				volatile DWORD			m_groupCurrent:1;
				volatile DWORD			m_cQuiesced:15;
				volatile DWORD			m_groupQuiesced:1;
				};
			};

		//  member functions

		//    operators
		
		CMeteredSection& operator=( CMeteredSection& );  //  disallowed

		//    manipulators

		void _PartitionAsync(	const PFNPARTITIONCOMPLETE	pfnPartitionComplete,
								const DWORD_PTR				dwCompletionKey );
		static void _PartitionSyncComplete( CAutoResetSignal* const pasig );
	};


//  ctor

inline CMeteredSection::CMeteredSection()
	:	m_cw( 0x80000000 ),
		m_pfnPartitionComplete( NULL ),
		m_dwPartitionCompleteKey( NULL )
	{
	}

//  dtor
	
inline CMeteredSection::~CMeteredSection()
	{
	}

//  enter the metered section, returning the group id for which the current
//  context has acquired the metered section

inline int CMeteredSection::Enter()
	{
	//  increment the count for the current group
	
	const DWORD cwDelta = 0x00000001;
	const DWORD cwBI = AtomicExchangeAdd( (long*) &m_cw, (long) cwDelta );

	//  there had better not be any overflow!

	OSSYNCAssert( ( cwBI & 0x80008000 ) == ( ( cwBI + cwDelta ) & 0x80008000 ) );
	
	//  return the group we referenced

	return int( ( cwBI >> 15 ) & 1 );
	}

//  leave the metered section using the specified group id.  this group id must
//  be the group id returned by the corresponding call to Enter()

inline void CMeteredSection::Leave( const int group )
	{
	//  try forever until we successfully leave
	
	OSSYNC_FOREVER
		{
		//  read the current state of the control word as our expected before image

		const ControlWord cwBIExpected = m_cw;

		//  compute the after image of the control word

		const ControlWord cwAI = cwBIExpected - ( ( ( ( cwBIExpected & 0x80008000 ) ^ 0x80008000 ) >> 15 ) ^ ( ( group << 16 ) | group ) );

		//  there had better not be any underflow!

		OSSYNCAssert( ( cwBIExpected & 0x80008000 ) == ( cwAI & 0x80008000 ) );
		
		//  attempt to perform the transacted state transition on the control word

		const ControlWord cwBI = AtomicCompareExchange( (long*)&m_cw, cwBIExpected, cwAI );

		//  the transaction failed

		if ( cwBI != cwBIExpected )
			{
			//  try again

			continue;
			}

		//  the transaction succeeded

		else
			{
			//  our update resulted in a partition completion

			if ( ( cwBI & 0x7FFF0000 ) + ( cwAI & 0x7FFF0000 ) == 0x00010000 )
				{
				//  execute the completion function

				m_pfnPartitionComplete( m_dwPartitionCompleteKey );
				}
				
			//  we're done

			break;
			}
		}
	}

//  partitions all execution contexts entering the metered section into two groups.
//  all contexts entering the section after this call are in a different group than
//  all the contexts that entered the section before this call.  when all contexts
//  in the old group have left the metered section, the partition will be completed
//
//  there are two ways to complete a partition:  asynchronously and synchronously.
//  asynchronous operation is selected if a completion function and key are provided.
//  the last thread to leave the metered section for the previous group will
//  execute asynchronous completions
//
//  NOTE:  it is illegal to have multiple concurrent partition requests.  any attempt
//  to do so will result in undefined behavior

inline void CMeteredSection::Partition(	const PFNPARTITIONCOMPLETE	pfnPartitionComplete,
										const DWORD_PTR				dwCompletionKey )
	{
	//  this is an async partition request
	
	if ( pfnPartitionComplete )
		{
		//  execute the parititon request
		
		_PartitionAsync( pfnPartitionComplete, dwCompletionKey );
		}

	//  this is a sync partition request
	
	else
		{
		//  create a signal to wait for completion
		
		CAutoResetSignal asig( CSyncBasicInfo( "CMeteredSection::Partition()::asig" ) );

		//  issue an async partition request
		
		_PartitionAsync(	PFNPARTITIONCOMPLETE( _PartitionSyncComplete ),
							DWORD_PTR( &asig ) );

		//  wait for the partition to complete

		asig.Wait();
		}
	}

//  performs an async partition request

inline void CMeteredSection::_PartitionAsync(	const PFNPARTITIONCOMPLETE	pfnPartitionComplete,
												const DWORD_PTR				dwCompletionKey )
	{
	//  we should not be calling this if there is already a partition pending

	OSSYNCAssertSz( !( m_cw & 0x7FFF0000 ), "Illegal concurrent use of Partitioning" );

	//  save the callback and key for the future completion

	m_pfnPartitionComplete		= pfnPartitionComplete;
	m_dwPartitionCompleteKey	= dwCompletionKey;
	
	//  try forever until we successfully partition
	
	OSSYNC_FOREVER
		{
		//  read the current state of the control word as our expected before image

		const ControlWord cwBIExpected = m_cw;

		//  compute the after image of the control word

		const ControlWord cwAI = ( cwBIExpected >> 16 ) | ( cwBIExpected << 16 );
		
		//  attempt to perform the transacted state transition on the control word

		const ControlWord cwBI = AtomicCompareExchange( (long*)&m_cw, cwBIExpected, cwAI );

		//  the transaction failed

		if ( cwBI != cwBIExpected )
			{
			//  try again

			continue;
			}

		//  the transaction succeeded

		else
			{
			//  our update resulted in a partition completion

			if ( !( cwAI & 0x7FFF0000 ) )
				{
				//  execute the completion function

				m_pfnPartitionComplete( m_dwPartitionCompleteKey );
				}
				
			//  we're done

			break;
			}
		}
	}

//  partition completion function used for sync partition requests

inline void CMeteredSection::_PartitionSyncComplete( CAutoResetSignal* const pasig )
	{
	//  set the signal

	pasig->Set();
	}


//  S / X / W Latch Performance Information

class CSXWLatchPerfInfo
	:	public CSyncPerfWait,
		public CSyncPerfAcquire,
		public CLockPerfHold
	{
	public:

		//  member functions
	
		//    ctors / dtors

		CSXWLatchPerfInfo()
			{
			}
		
		//    debugging support

		void Dump( CDumpContext& dc ) const;
	};


//  S / X / W Latch Group Information

class CSXWLatchGroupInfo
	{
	public:

		//  member functions
	
		//    ctors / dtors

		CSXWLatchGroupInfo() {}
		~CSXWLatchGroupInfo() {}

		//    manipulators

		void StartWait( const int iGroup ) { m_rginfo[iGroup].StartWait(); }
		void StopWait( const int iGroup ) { m_rginfo[iGroup].StopWait(); }

		void SetAcquire( const int iGroup ) { m_rginfo[iGroup].SetAcquire(); }
		void SetContend( const int iGroup ) { m_rginfo[iGroup].SetContend(); }

		void StartHold( const int iGroup ) { m_rginfo[iGroup].StartHold(); }
		void StopHold( const int iGroup ) { m_rginfo[iGroup].StopHold(); }
		
		//    accessors

#ifdef SYNC_ANALYZE_PERFORMANCE

		QWORD	CWaitTotal( const int iGroup ) const		{ return m_rginfo[iGroup].CWaitTotal(); }
		double	CsecWaitElapsed( const int iGroup ) const	{ return m_rginfo[iGroup].CsecWaitElapsed(); }
		
		QWORD	CAcquireTotal( const int iGroup ) const		{ return m_rginfo[iGroup].CAcquireTotal(); }
		QWORD	CContendTotal( const int iGroup ) const		{ return m_rginfo[iGroup].CContendTotal(); }
		
		QWORD	CHoldTotal( const int iGroup ) const		{ return m_rginfo[iGroup].CHoldTotal(); }
		double	CsecHoldElapsed( const int iGroup ) const	{ return m_rginfo[iGroup].CsecHoldElapsed(); }

#endif  //  SYNC_ANALYZE_PERFORMANCE
		
		//    debugging support

		void Dump( CDumpContext& dc ) const;

	private:

		//  member functions

		//    operators

		CSXWLatchGroupInfo& operator=( CSXWLatchGroupInfo& );  //  disallowed

		//  data members

		//    performance info for each group

		CSXWLatchPerfInfo m_rginfo[3];
	};


//  S / X / W Latch Information

class CSXWLatchInfo
	:	public CLockBasicInfo,
		public CSXWLatchGroupInfo,
		public CLockDeadlockDetectionInfo
	{
	public:

		//  member functions
	
		//    ctors / dtors

		CSXWLatchInfo( const CLockBasicInfo& lbi )
			:	CLockBasicInfo( lbi ),
				CLockDeadlockDetectionInfo( (CLockBasicInfo&) *this )
			{
			}
		
		//    debugging support

		void Dump( CDumpContext& dc ) const;
	};


//  S / X / W Latch State

class CSXWLatchState
	{
	public:
	
		//  types

		//    control word

		typedef DWORD ControlWord;

		//  member functions

		//    ctors / dtors
		
		CSXWLatchState( const CSyncBasicInfo& sbi );
		~CSXWLatchState();
		
		//    debugging support

		void Dump( CDumpContext& dc ) const;

		//  data members

		//    control word

		union
			{
			volatile ControlWord	m_cw;
			
			struct
				{
				volatile DWORD			m_cOOWS:15;
				volatile DWORD			m_fQS:1;
				volatile DWORD			m_cOAWX:16;
				};
			};

		//    quiesced share latch count
		
		volatile DWORD			m_cQS;

		//    sempahore used to wait for the shared latch
		
		CSemaphore				m_semS;

		//    sempahore used to wait for the exclusive latch
		
		CSemaphore				m_semX;

		//    sempahore used to wait for the write latch
		
		CSemaphore				m_semW;

	private:

		//  member functions

		//    operators
		
		CSXWLatchState& operator=( CSXWLatchState& );  //  disallowed
	};


//  S / X / W Latch

class CSXWLatch
	:	private CLockObject,
		private CEnhancedStateContainer< CSXWLatchState, CSyncBasicInfo, CSXWLatchInfo, CLockBasicInfo >
	{
	public:

		//  types

		//    control word

		typedef CSXWLatchState::ControlWord ControlWord;

		//    API Error Codes

		enum ERR
			{
			errSuccess,
			errWaitForSharedLatch,
			errWaitForExclusiveLatch,
			errWaitForWriteLatch,
			errLatchConflict
			};

		//  member functions

		//    ctors / dtors

		CSXWLatch( const CLockBasicInfo& lbi );
		~CSXWLatch();

		//    manipulators

		ERR ErrAcquireSharedLatch();
		ERR ErrTryAcquireSharedLatch();
		ERR ErrAcquireExclusiveLatch();
		ERR ErrTryAcquireExclusiveLatch();
		ERR ErrTryAcquireWriteLatch();
		
		ERR ErrUpgradeSharedLatchToExclusiveLatch();
		ERR ErrUpgradeSharedLatchToWriteLatch();
		ERR ErrUpgradeExclusiveLatchToWriteLatch();

		void DowngradeWriteLatchToExclusiveLatch();
		void DowngradeWriteLatchToSharedLatch();
		void DowngradeExclusiveLatchToSharedLatch();
		
		void ReleaseWriteLatch();
		void ReleaseExclusiveLatch();
		void ReleaseSharedLatch();

		void WaitForSharedLatch();
		void WaitForExclusiveLatch();
		void WaitForWriteLatch();

		void ClaimOwnership( const DWORD group );
		void ReleaseOwnership( const DWORD group );

		//    accessors

		BOOL FOwnSharedLatch()			{ return State().FOwner( 0 ); }
		BOOL FNotOwnSharedLatch()		{ return State().FNotOwner( 0 ); }
		BOOL FOwnExclusiveLatch()		{ return State().FOwner( 1 ); }
		BOOL FNotOwnExclusiveLatch()	{ return State().FNotOwner( 1 ); }
		BOOL FOwnWriteLatch()			{ return State().FOwner( 2 ); }
		BOOL FNotOwnWriteLatch()		{ return State().FNotOwner( 2 ); }

		//    debugging support

		void Dump( CDumpContext& dc ) const;

	private:

		//  member functions

		//    operators
		
		CSXWLatch& operator=( CSXWLatch& );  //  disallowed

		//    manipulators

		void _UpdateQuiescedSharedLatchCount( const DWORD cQSDelta );
	};

//  declares the current context as an owner or waiter of a shared latch.  if
//  the shared latch is acquired immediately, errSuccess will be returned.  if
//  the shared latch is not acquired immediately, errWaitForSharedLatch will be
//  returned and WaitForSharedLatch() must be called to gain ownership of the
//  shared latch

inline CSXWLatch::ERR CSXWLatch::ErrAcquireSharedLatch()
	{
	//  we had better not already have a shared, exclusive, or write latch

	OSSYNCAssert( FNotOwnSharedLatch() );
	OSSYNCAssert( FNotOwnExclusiveLatch() );
	OSSYNCAssert( FNotOwnWriteLatch() );

	//  add ourself as an owner or waiter for the shared latch

	const ControlWord cwDelta = 0x00000001;
	const ControlWord cwBI = AtomicExchangeAdd( (long*)&State().m_cw, cwDelta );

	//  shared latches are quiesced

	if ( cwBI & 0x00008000 )
		{
		//  this is a contention for a shared latch

		State().SetContend( 0 );

		//  we are now a waiter for the shared latch

		State().AddAsWaiter( 0 );
		State().StartWait( 0 );
		
		//  we will need to block

		return errWaitForSharedLatch;
		}

	//  shared latches are not quiesced

	else
		{
		//  we are now an owner of a shared latch

		State().SetAcquire( 0 );
		State().AddAsOwner( 0 );
		State().StartHold( 0 );

		//  we now own the shared latch

		return errSuccess;
		}
	}

//  tries to declare the current context as an owner of a shared latch.  if
//  the shared latch is acquired immediately, errSuccess will be returned.  if
//  the shared latch is not acquired immediately, errLatchConflict will be
//  returned

inline CSXWLatch::ERR CSXWLatch::ErrTryAcquireSharedLatch()
	{
	//  we had better not already have a shared, exclusive, or write latch

	OSSYNCAssert( FNotOwnSharedLatch() );
	OSSYNCAssert( FNotOwnExclusiveLatch() );
	OSSYNCAssert( FNotOwnWriteLatch() );

	//  try forever until we successfully change the latch state

	OSSYNC_FOREVER
		{
		//  read the current state of the control word as our expected before image

		ControlWord cwBIExpected = State().m_cw;

		//  change the expected before image so that the transaction will only work if
		//  shared latches are not quiesced

		cwBIExpected = cwBIExpected & 0xFFFF7FFF;

		//  compute the after image of the control word by performing the transform
		//  that will acquire a shared latch iff shared latches are not quiesced

		const ControlWord cwAI = cwBIExpected + 0x00000001;

		//  attempt to perform the transacted state transition on the control word

		const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );

		//  the transaction failed

		if ( cwBI != cwBIExpected )
			{
			//  the transaction failed because shared latches were quiesced

			if ( cwBI & 0x00008000 )
				{
				//  this is a contention for the shared latch

				State().SetContend( 0 );

				//  this is a latch conflict

				return errLatchConflict;
				}
				
			//  the transaction failed because another context changed the control
			//  word

			else
				{
				//  try again

				continue;
				}
			}

		//  the transaction succeeded

		else
			{
			//  we are now an owner of a shared latch

			State().SetAcquire( 0 );
			State().AddAsOwner( 0 );
			State().StartHold( 0 );

			//  we now own the shared latch

			return errSuccess;
			}
		}
	}
	
//  declares the current context as an owner or waiter of the exclusive latch.
//  if the exclusive latch is acquired immediately, errSuccess will be returned.
//  if the exclusive latch is not acquired immediately, errWaitForExclusiveLatch
//  will be returned and WaitForExclusiveLatch() must be called to gain ownership
//  of the exclusive latch

inline CSXWLatch::ERR CSXWLatch::ErrAcquireExclusiveLatch()
	{
	//  we had better not already have a shared, exclusive, or write latch

	OSSYNCAssert( FNotOwnSharedLatch() );
	OSSYNCAssert( FNotOwnExclusiveLatch() );
	OSSYNCAssert( FNotOwnWriteLatch() );

	//  add ourself as an owner or waiter for the exclusive latch

	const ControlWord cwDelta = 0x00010000;
	const ControlWord cwBI = AtomicExchangeAdd( (long*)&State().m_cw, cwDelta );

	//  we are not the owner of the exclusive latch

	if ( cwBI & 0xFFFF0000 )
		{
		//  this is a contention for the exclusive latch

		State().SetContend( 1 );
		
		//  we are now a waiter for the exclusive latch

		State().AddAsWaiter( 1 );
		State().StartWait( 1 );
		
		//  we will need to block

		return errWaitForExclusiveLatch;
		}

	//  we are the owner of the exclusive latch

	else
		{
		//  we are now an owner of the exclusive latch

		State().SetAcquire( 1 );
		State().AddAsOwner( 1 );
		State().StartHold( 1 );

		//  we now own the exclusive latch

		return errSuccess;
		}
	}

//  tries to declare the current context as an owner of the exclusive latch.  if
//  the exclusive latch is acquired immediately, errSuccess will be returned.  if
//  the exclusive latch is not acquired immediately, errLatchConflict will be
//  returned

inline CSXWLatch::ERR CSXWLatch::ErrTryAcquireExclusiveLatch()
	{
	//  we had better not already have a shared, exclusive, or write latch

	OSSYNCAssert( FNotOwnSharedLatch() );
	OSSYNCAssert( FNotOwnExclusiveLatch() );
	OSSYNCAssert( FNotOwnWriteLatch() );

	//  try forever until we successfully change the latch state

	OSSYNC_FOREVER
		{
		//  read the current state of the control word as our expected before image

		ControlWord cwBIExpected = State().m_cw;

		//  change the expected before image so that the transaction will only work if
		//  the exclusive latch is not already owned

		cwBIExpected = cwBIExpected & 0x0000FFFF;

		//  compute the after image of the control word by performing the transform
		//  that will acquire the exclusive latch iff it is not already owned

		const ControlWord cwAI = cwBIExpected + 0x00010000;

		//  attempt to perform the transacted state transition on the control word

		const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );

		//  the transaction failed

		if ( cwBI != cwBIExpected )
			{
			//  the transaction failed because the exclusive latch was already
			//  owned

			if ( cwBI & 0xFFFF0000 )
				{
				//  this is a contention for the exclusive latch

				State().SetContend( 1 );

				//  this is a latch conflict

				return errLatchConflict;
				}
				
			//  the transaction failed because another context changed the control
			//  word

			else
				{
				//  try again

				continue;
				}
			}

		//  the transaction succeeded

		else
			{
			//  we are now an owner of the exclusive latch

			State().SetAcquire( 1 );
			State().AddAsOwner( 1 );
			State().StartHold( 1 );

			//  we now own the exclusive latch

			return errSuccess;
			}
		}
	}

//  tries to declare the current context as an owner of the write latch.  if
//  the write latch is acquired immediately, errSuccess will be returned.  if
//  the write latch is not acquired immediately, errLatchConflict will be
//  returned.  note that a latch conflict will effectively occur if any other
//  context currently owns or is waiting to own any type of latch

inline CSXWLatch::ERR CSXWLatch::ErrTryAcquireWriteLatch()
	{
	//  we had better not already have a shared, exclusive, or write latch

	OSSYNCAssert( FNotOwnSharedLatch() );
	OSSYNCAssert( FNotOwnExclusiveLatch() );
	OSSYNCAssert( FNotOwnWriteLatch() );

	//  try forever until we successfully change the latch state

	OSSYNC_FOREVER
		{
		//  set the expected before image so that the transaction will only work if
		//  no other context currently owns or is waiting to own any type of latch

		const ControlWord cwBIExpected = 0x00000000;

		//  set the after image of the control word to a single write latch

		const ControlWord cwAI = 0x00018000;

		//  attempt to perform the transacted state transition on the control word

		const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );

		//  the transaction failed

		if ( cwBI != cwBIExpected )
			{
			//  this is a contention for the write latch

			State().SetContend( 2 );

			//  this is a latch conflict

			return errLatchConflict;
			}

		//  the transaction succeeded

		else
			{
			//  we are now an owner of the write latch

			State().SetAcquire( 2 );
			State().AddAsOwner( 2 );
			State().StartHold( 2 );

			//  we now own the write latch

			return errSuccess;
			}
		}
	}

//  attempts to upgrade a shared latch to the exclusive latch.  if the exclusive
//  latch is not available, errLatchConflict will be returned.  if the exclusive
//  latch is available, it will be acquired and errSuccess will be returned

inline CSXWLatch::ERR CSXWLatch::ErrUpgradeSharedLatchToExclusiveLatch()
	{
	//  we had better already have only a shared latch

	OSSYNCAssert( FOwnSharedLatch() );
	OSSYNCAssert( FNotOwnExclusiveLatch() );
	OSSYNCAssert( FNotOwnWriteLatch() );
	
	//  try forever until we successfully change the latch state

	OSSYNC_FOREVER
		{
		//  read the current state of the control word as our expected before image

		ControlWord cwBIExpected = State().m_cw;

		//  change the expected before image so that the transaction will only work if
		//  the exclusive latch is not already owned

		cwBIExpected = cwBIExpected & 0x0000FFFF;

		//  compute the after image of the control word by performing the transform
		//  that will set an exclusive latch iff there is no current owner of the
		//  exclusive latch and release our shared latch

		const ControlWord cwAI = cwBIExpected + 0x0000FFFF;

		//  attempt to perform the transacted state transition on the control word

		const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );

		//  the transaction failed

		if ( cwBI != cwBIExpected )
			{
			//  the transaction failed because the exclusive latch was already owned

			if ( cwBI & 0xFFFF0000 )
				{
				//  this is a contention for the exclusive latch

				State().SetContend( 1 );

				//  this is a latch conflict

				return errLatchConflict;
				}
				
			//  the transaction failed because another context changed the control
			//  word

			else
				{
				//  try again

				continue;
				}
			}

		//  the transaction succeeded

		else
			{
			//  we are no longer an owner of a shared latch

			State().RemoveAsOwner( 0 );
			State().StopHold( 0 );
			
			//  we are now an owner of the exclusive latch

			State().SetAcquire( 1 );
			State().AddAsOwner( 1 );
			State().StartHold( 1 );

			//  we now own the exclusive latch

			return errSuccess;
			}
		}
	}

//  attempts to upgrade a shared latch to the write latch.  if the write latch
//  is not available, errLatchConflict will be returned.  if the write latch is
//  available, it will be acquired.  if the write latch is acquired immediately,
//  errSuccess will be returned.  if the write latch is not acquired immediately,
//  errWaitForWriteLatch will be returned and WaitForWriteLatch() must be called
//  to gain ownership of the write latch

inline CSXWLatch::ERR CSXWLatch::ErrUpgradeSharedLatchToWriteLatch()
	{
	//  we had better already have only a shared latch

	OSSYNCAssert( FOwnSharedLatch() );
	OSSYNCAssert( FNotOwnExclusiveLatch() );
	OSSYNCAssert( FNotOwnWriteLatch() );
	
	//  try forever until we successfully change the latch state

	OSSYNC_FOREVER
		{
		//  read the current state of the control word as our expected before image

		ControlWord cwBIExpected = State().m_cw;

		//  change the expected before image so that the transaction will only work if
		//  the exclusive latch is not already owned

		cwBIExpected = cwBIExpected & 0x0000FFFF;

		//  compute the after image of the control word by performing the transform
		//  that will set a write latch iff there is no current owner of the
		//  exclusive latch, quiescing any remaining shared latches

		const ControlWord cwAI = 0x00018000;

		//  attempt to perform the transacted state transition on the control word

		const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );

		//  the transaction failed

		if ( cwBI != cwBIExpected )
			{
			//  the transaction failed because the write latch was already owned

			if ( cwBI & 0xFFFF0000 )
				{
				//  this is a contention for the write latch

				State().SetContend( 2 );

				//  this is a latch conflict

				return errLatchConflict;
				}
				
			//  the transaction failed because another context changed the control
			//  word

			else
				{
				//  try again

				continue;
				}
			}

		//  the transaction succeeded

		else
			{
			//  shared latches were just quiesced

			if ( cwBI != 0x00000001 )
				{
				//  we are no longer an owner of a shared latch

				State().RemoveAsOwner( 0 );
				State().StopHold( 0 );
				
				//  update the quiesced shared latch count with the shared latch count
				//  that we displaced from the control word, possibly releasing waiters.
				//  we update the count as if we we had a shared latch as a write latch
				//  (namely ours) can be released.  don't forget to deduct our shared
				//  latch from this count

				_UpdateQuiescedSharedLatchCount( cwBI - 1 );
				
				//  we are now a waiter for the write latch

				State().AddAsWaiter( 2 );
				State().StartWait( 2 );
				
				//  we will need to block

				return errWaitForWriteLatch;
				}

			//  shared latches were not just quiesced

			else
				{
				//  we are no longer an owner of a shared latch

				State().RemoveAsOwner( 0 );
				State().StopHold( 0 );
				
				//  we are now an owner of the write latch

				State().SetAcquire( 2 );
				State().AddAsOwner( 2 );
				State().StartHold( 2 );

				//  we now own the write latch

				return errSuccess;
				}
			}
		}
	}

//  upgrades the exclusive latch to the write latch.  if the write latch is
//  acquired immediately, errSuccess will be returned.  if the write latch is
//  not acquired immediately, errWaitForWriteLatch is returned and
//  WaitForWriteLatch() must be called to gain ownership of the write latch

inline CSXWLatch::ERR CSXWLatch::ErrUpgradeExclusiveLatchToWriteLatch()
	{
	//  we had better already have only an exclusive latch

	OSSYNCAssert( FNotOwnSharedLatch() );
	OSSYNCAssert( FOwnExclusiveLatch() );
	OSSYNCAssert( FNotOwnWriteLatch() );
	
	//  we are no longer an owner of the exclusive latch

	State().RemoveAsOwner( 1 );
	State().StopHold( 1 );
	
	//  try forever until we successfully change the latch state

	OSSYNC_FOREVER
		{
		//  read the current state of the control word as our expected before image

		const ControlWord cwBIExpected = State().m_cw;

		//  compute the after image of the control word by performing the transform that
		//  will quiesce shared latches by setting the fQS flag and removing the current
		//  shared latch count from the control word

		const ControlWord cwAI = ( cwBIExpected & 0xFFFF0000 ) | 0x00008000;

		//  attempt to perform the transacted state transition on the control word

		const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );

		//  the transaction failed

		if ( cwBI != cwBIExpected )
			{
			//  try again

			continue;
			}

		//  the transaction succeeded

		else
			{
			//  shared latches were just quiesced

			if ( cwBI & 0x00007FFF )
				{
				//  this is a contention for the write latch

				State().SetContend( 2 );

				//  update the quiesced shared latch count with the shared latch
				//  count that we displaced from the control word, possibly
				//  releasing waiters.  we update the count as if we we had a
				//  shared latch as a write latch (namely ours) can be released

				_UpdateQuiescedSharedLatchCount( cwBI & 0x00007FFF );
				
				//  we are now a waiter for the write latch

				State().AddAsWaiter( 2 );
				State().StartWait( 2 );
				
				//  we will need to block

				return errWaitForWriteLatch;
				}

			//  shared latches were not just quiesced

			else
				{
				//  we are now an owner of the write latch

				State().SetAcquire( 2 );
				State().AddAsOwner( 2 );
				State().StartHold( 2 );

				//  we now own the write latch

				return errSuccess;
				}
			}
		}
	}

//  releases the write latch in exchange for the exclusive latch

inline void CSXWLatch::DowngradeWriteLatchToExclusiveLatch()
	{
	//  we had better already have only a write latch

	OSSYNCAssert( FNotOwnSharedLatch() );
	OSSYNCAssert( FNotOwnExclusiveLatch() );
	OSSYNCAssert( FOwnWriteLatch() );

	//  stop quiescing shared latches by resetting the fQS flag

	const ControlWord cwDelta = 0xFFFF8000;
	const ControlWord cwBI = AtomicExchangeAdd( (long*)&State().m_cw, cwDelta );

	//  transfer ownership from the write latch to the exclusive latch

	State().RemoveAsOwner( 2 );
	State().StopHold( 2 );

	State().SetAcquire( 1 );
	State().AddAsOwner( 1 );
	State().StartHold( 1 );

	//  release any quiesced shared latches

	if ( cwBI & 0x00007FFF )
		{
		State().m_semS.Release( cwBI & 0x00007FFF );
		}
	}

//  releases the write latch in exchange for a shared latch
	
inline void CSXWLatch::DowngradeWriteLatchToSharedLatch()
	{
	//  we had better already have only a write latch

	OSSYNCAssert( FNotOwnSharedLatch() );
	OSSYNCAssert( FNotOwnExclusiveLatch() );
	OSSYNCAssert( FOwnWriteLatch() );
	
	//  stop quiescing shared latches by resetting the fQS flag, release our
	//  exclusive latch, and acquire a shared latch

	const ControlWord cwDelta = 0xFFFE8001;
	const ControlWord cwBI = AtomicExchangeAdd( (long*)&State().m_cw, cwDelta );

	//  transfer ownership from the write latch to a shared latch

	State().RemoveAsOwner( 2 );
	State().StopHold( 2 );

	State().SetAcquire( 0 );
	State().AddAsOwner( 0 );
	State().StartHold( 0 );

	//  release any quiesced shared latches

	if ( cwBI & 0x00007FFF )
		{
		State().m_semS.Release( cwBI & 0x00007FFF );
		}

	//  release a waiter for the exclusive latch, if any

	if ( cwBI >= 0x00020000 )
		{
		State().m_semX.Release();
		}
	}

//  releases the exclusive latch in exchange for a shared latch

inline void CSXWLatch::DowngradeExclusiveLatchToSharedLatch()
	{
	//  we had better already have only an exclusive latch

	OSSYNCAssert( FNotOwnSharedLatch() );
	OSSYNCAssert( FOwnExclusiveLatch() );
	OSSYNCAssert( FNotOwnWriteLatch() );
	
	//  release our exclusive latch and acquire a shared latch

	const ControlWord cwDelta = 0xFFFF0001;
	const ControlWord cwBI = AtomicExchangeAdd( (long*)&State().m_cw, cwDelta );

	//  transfer ownership from the exclusive latch to a shared latch

	State().RemoveAsOwner( 1 );
	State().StopHold( 1 );

	State().SetAcquire( 0 );
	State().AddAsOwner( 0 );
	State().StartHold( 0 );

	//  release a waiter for the exclusive latch, if any

	if ( cwBI >= 0x00020000 )
		{
		State().m_semX.Release();
		}
	}

//  releases the write latch

inline void CSXWLatch::ReleaseWriteLatch()
	{
	//  we had better already have only a write latch

	OSSYNCAssert( FNotOwnSharedLatch() );
	OSSYNCAssert( FNotOwnExclusiveLatch() );
	OSSYNCAssert( FOwnWriteLatch() );
	
	//  stop quiescing shared latches by resetting the fQS flag and release our
	//  exclusive latch

	const ControlWord cwDelta = 0xFFFE8000;
	const ControlWord cwBI = AtomicExchangeAdd( (long*)&State().m_cw, cwDelta );

	//  release ownership of the write latch

	State().RemoveAsOwner( 2 );
	State().StopHold( 2 );

	//  release any quiesced shared latches

	if ( cwBI & 0x00007FFF )
		{
		State().m_semS.Release( cwBI & 0x00007FFF );
		}

	//  release a waiter for the exclusive latch, if any

	if ( cwBI >= 0x00020000 )
		{
		State().m_semX.Release();
		}
	}

//  releases the exclusive latch

inline void CSXWLatch::ReleaseExclusiveLatch()
	{
	//  we had better already have only an exclusive latch

	OSSYNCAssert( FNotOwnSharedLatch() );
	OSSYNCAssert( FOwnExclusiveLatch() );
	OSSYNCAssert( FNotOwnWriteLatch() );
	
	//  release our exclusive latch

	const ControlWord cwDelta = 0xFFFF0000;
	const ControlWord cwBI = AtomicExchangeAdd( (long*)&State().m_cw, cwDelta );

	//  release ownership of the exclusive latch

	State().RemoveAsOwner( 1 );
	State().StopHold( 1 );

	//  release a waiter for the exclusive latch, if any

	if ( cwBI >= 0x00020000 )
		{
		State().m_semX.Release();
		}
	}

//  releases a shared latch

inline void CSXWLatch::ReleaseSharedLatch()
	{
	//  we had better already have only a shared latch

	OSSYNCAssert( FOwnSharedLatch() );
	OSSYNCAssert( FNotOwnExclusiveLatch() );
	OSSYNCAssert( FNotOwnWriteLatch() );

	//  we are no longer an owner of a shared latch

	State().RemoveAsOwner( 0 );
	State().StopHold( 0 );
	
	//  try forever until we successfully change the latch state

	OSSYNC_FOREVER
		{
		//  read the current state of the control word as our expected before image

		ControlWord cwBIExpected = State().m_cw;

		//  change the expected before image so that the transaction will only work if
		//  shared latches are not quiesced

		cwBIExpected = cwBIExpected & 0xFFFF7FFF;

		//  compute the after image of the control word by performing the transform that
		//  will release our shared latch

		const ControlWord cwAI = cwBIExpected + 0xFFFFFFFF;

		//  attempt to perform the transacted state transition on the control word

		const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );

		//  the transaction failed

		if ( cwBI != cwBIExpected )
			{
			//  the transaction failed because shared latches were quiesced

			if ( cwBI & 0x00008000 )
				{
				//  leave the latch as a quiesced shared latch

				_UpdateQuiescedSharedLatchCount( 0xFFFFFFFF );

				//  we're done

				break;
				}

			//  the transaction failed because another context changed the control word

			else
				{
				//  try again

				continue;
				}
			}

		//  the transaction succeeded

		else
			{
			// we're done

			break;
			}
		}
	}

//  waits for ownership of a shared latch in response to receiving an
//  errWaitForSharedLatch from the API.  this function must not be called at any
//  other time

inline void CSXWLatch::WaitForSharedLatch()
	{
	//  check for deadlock

	OSSYNCAssertSzRTL( State().FCanBeWaiter(), "Potential Deadlock Detected (Rank Violation)");

	//  we had better already be declared a waiter

	OSSYNCAssert( State().FWaiter( 0 ) );
	
	//  wait for ownership of a shared latch on the shared latch semaphore

	State().m_semS.Acquire();

	State().StopWait( 0 );
	State().RemoveAsWaiter( 0 );

	State().SetAcquire( 0 );
	State().AddAsOwner( 0 );
	State().StartHold( 0 );
	}
	
//  waits for ownership of the exclusive latch in response to receiving an
//  errWaitForExclusiveLatch from the API.  this function must not be called at any
//  other time

inline void CSXWLatch::WaitForExclusiveLatch()
	{
	//  check for deadlock

	OSSYNCAssertSzRTL( State().FCanBeWaiter(), "Potential Deadlock Detected (Rank Violation)");

	//  we had better already be declared a waiter

	OSSYNCAssert( State().FWaiter( 1 ) );
	
	//  wait for ownership of the exclusive latch on the exclusive latch semaphore

	State().m_semX.Acquire();

	State().StopWait( 1 );
	State().RemoveAsWaiter( 1 );

	State().SetAcquire( 1 );
	State().AddAsOwner( 1 );
	State().StartHold( 1 );
	}
	
//  waits for ownership of the write latch in response to receiving an
//  errWaitForWriteLatch from the API.  this function must not be called at any
//  other time

inline void CSXWLatch::WaitForWriteLatch()
	{
	//  check for deadlock

	OSSYNCAssertSzRTL( State().FCanBeWaiter(), "Potential Deadlock Detected (Rank Violation)");

	//  we had better already be declared a waiter

	OSSYNCAssert( State().FWaiter( 2 ) );
	
	//  wait for ownership of the write latch on the write latch semaphore

	State().m_semW.Acquire();

	State().StopWait( 2 );
	State().RemoveAsWaiter( 2 );

	State().SetAcquire( 2 );
	State().AddAsOwner( 2 );
	State().StartHold( 2 );
	}

//  claims ownership of the latch for the specified group for deadlock detection

inline void CSXWLatch::ClaimOwnership( const DWORD group )
	{
	State().AddAsOwner( group );
	}

//  releases ownership of the latch for the specified group for deadlock detection

inline void CSXWLatch::ReleaseOwnership( const DWORD group )
	{
	State().RemoveAsOwner( group );
	}

//  updates the quiesced shared latch count, possibly releasing a waiter for
//  the write latch

inline void CSXWLatch::_UpdateQuiescedSharedLatchCount( const DWORD cQSDelta )
	{
	//  update the quiesced shared latch count using the provided delta

	const DWORD cQSBI = AtomicExchangeAdd( (long*)&State().m_cQS, cQSDelta );
	const DWORD cQSAI = cQSBI + cQSDelta;

	//  our update resulted in a zero quiesced shared latch count

	if ( !cQSAI )
		{
		//  release the waiter for the write latch

		State().m_semW.Release();
		}
	}


//  init sync subsystem

const BOOL OSSYNCAPI FOSSyncPreinit();

//  terminate sync subsystem

void OSSYNCAPI OSSyncPostterm();

//  attach the current context to the sync subsystem

BOOL OSSYNCAPI FOSSyncAttach();

//  detach the current context from the sync subsystem

void OSSYNCAPI OSSyncDetach();


//	special init/term API's for Enhanced State only

const BOOL OSSYNCAPI FOSSyncInitForES();
void OSSYNCAPI OSSyncTermForES();

};  //  namespace OSSYNC


using namespace OSSYNC;


#endif  //  _SYNC_HXX_INCLUDED