Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

7347 lines
169 KiB

  1. #ifndef _SYNC_HXX_INCLUDED
  2. #define _SYNC_HXX_INCLUDED
  3. #include "nt.h"
  4. #include "ntrtl.h"
  5. #include "nturtl.h"
  6. #include "windows.h"
  7. #pragma warning ( disable : 4786 ) // we allow huge symbol names
  8. // Build Options
  9. #define SYNC_USE_X86_ASM // use x86 assembly for atomic memory manipulation
  10. //#define SYNC_ANALYZE_PERFORMANCE // analyze performance of synchronization objects
  11. #ifdef SYNC_ANALYZE_PERFORMANCE
  12. #define SYNC_DUMP_PERF_DATA // dump performance analysis of synchronization objects
  13. #endif // SYNC_ANALYZE_PERFORMANCE
  14. //#define SYNC_DEADLOCK_DETECTION // perform deadlock detection
  15. //#define SYNC_VALIDATE_IRKSEM_USAGE // validate IRKSEM (CReferencedKernelSemaphore) usage
  16. #ifdef DEBUG
  17. #ifdef DBG
  18. #else // !DBG
  19. #define SYNC_DEADLOCK_DETECTION // always perform deadlock detection in DEBUG
  20. #define SYNC_VALIDATE_IRKSEM_USAGE // always validate IRKSEM (CReferencedKernelSemaphore) usage in DEBUG
  21. #endif // DBG
  22. #endif // DEBUG
  23. // copied from basestd.h to make LONG_PTR available.
  24. #ifdef __cplusplus
  25. extern "C" {
  26. #endif
  27. //
  28. // The following types are guaranteed to be signed and 32 bits wide.
  29. //
  30. typedef int LONG32, *PLONG32;
  31. typedef int INT32, *PINT32;
  32. //
  33. // The following types are guaranteed to be unsigned and 32 bits wide.
  34. //
  35. typedef unsigned int ULONG32, *PULONG32;
  36. typedef unsigned int DWORD32, *PDWORD32;
  37. typedef unsigned int UINT32, *PUINT32;
  38. //
  39. // The INT_PTR is guaranteed to be the same size as a pointer. Its
  40. // size with change with pointer size (32/64). It should be used
  41. // anywhere that a pointer is cast to an integer type. UINT_PTR is
  42. // the unsigned variation.
  43. //
  44. // __int3264 is intrinsic to 64b MIDL but not to old MIDL or to C compiler.
  45. //
  46. #if ( 501 < __midl )
  47. typedef __int3264 INT_PTR, *PINT_PTR;
  48. typedef unsigned __int3264 UINT_PTR, *PUINT_PTR;
  49. typedef __int3264 LONG_PTR, *PLONG_PTR;
  50. typedef unsigned __int3264 ULONG_PTR, *PULONG_PTR;
  51. #else // midl64
  52. // old midl and C++ compiler
  53. #ifdef _WIN64
  54. typedef __int64 INT_PTR, *PINT_PTR;
  55. typedef unsigned __int64 UINT_PTR, *PUINT_PTR;
  56. typedef __int64 LONG_PTR, *PLONG_PTR;
  57. typedef unsigned __int64 ULONG_PTR, *PULONG_PTR;
  58. #define __int3264 __int64
  59. #else
  60. typedef int INT_PTR, *PINT_PTR;
  61. typedef unsigned int UINT_PTR, *PUINT_PTR;
  62. typedef long LONG_PTR, *PLONG_PTR;
  63. typedef unsigned long ULONG_PTR, *PULONG_PTR;
  64. #define __int3264 __int32
  65. #endif
  66. #endif //midl64
  67. typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR;
  68. //
  69. // The following types are guaranteed to be signed and 64 bits wide.
  70. //
  71. typedef __int64 LONG64, *PLONG64;
  72. typedef __int64 INT64, *PINT64;
  73. //
  74. // The following types are guaranteed to be unsigned and 64 bits wide.
  75. //
  76. typedef unsigned __int64 ULONG64, *PULONG64;
  77. typedef unsigned __int64 DWORD64, *PDWORD64;
  78. typedef unsigned __int64 UINT64, *PUINT64;
  79. //
  80. // SIZE_T used for counts or ranges which need to span the range of
  81. // of a pointer. SSIZE_T is the signed variation.
  82. //
  83. typedef ULONG_PTR SIZE_T, *PSIZE_T;
  84. typedef LONG_PTR SSIZE_T, *PSSIZE_T;
  85. //
  86. // useful macros for both 32/64
  87. //
  88. #define OffsetOf(s,m) (SIZE_T)&(((s *)0)->m)
  89. #ifdef __cplusplus
  90. }
  91. #endif
  92. #pragma warning ( disable : 4355 )
  93. #include <limits.h>
  94. #include <new.h>
  95. #include <stdarg.h>
  96. #include <stdlib.h>
  97. // calling convention
  98. #define OSSYNCAPI __stdcall
  99. // basic types
  100. typedef int BOOL;
  101. #define fFalse BOOL( 0 )
  102. #define fTrue BOOL( !0 )
  103. typedef unsigned char BYTE;
  104. typedef unsigned short WORD;
  105. typedef unsigned long DWORD;
  106. typedef unsigned __int64 QWORD;
  107. // Assertions
  108. // Assertion Failure action
  109. //
  110. // called to indicate to the developer that an assumption is not true
  111. void OSSYNCAPI AssertFail( const char* szMessage, const char* szFilename, long lLine );
  112. // Assert Macros
  113. // asserts that the given expression is true or else fails with the specified message
  114. #define OSSYNCAssertSzRTL( exp, sz ) ( ( exp ) ? (void) 0 : AssertFail( sz, __FILE__, __LINE__ ) )
  115. #ifdef DEBUG
  116. #define OSSYNCAssertSz( exp, sz ) OSSYNCAssertSzRTL( exp, sz )
  117. #else // !DEBUG
  118. #define OSSYNCAssertSz( exp, sz )
  119. #endif // DEBUG
  120. // asserts that the given expression is true or else fails with that expression
  121. #define OSSYNCAssertRTL( exp ) OSSYNCAssertSzRTL( exp, #exp )
  122. #define OSSYNCAssert( exp ) OSSYNCAssertSz( exp, #exp )
  123. // Enforces
  124. // Enforce Failure action
  125. //
  126. // called when a strictly enforced condition has been violated
  127. void OSSYNCAPI EnforceFail( const char* szMessage, const char* szFilename, long lLine );
  128. // Enforce Macros
  129. // the given expression MUST be true or else fails with the specified message
  130. #define OSSYNCEnforceSz( exp, sz ) ( ( exp ) ? (void) 0 : EnforceFail( sz, __FILE__, __LINE__ ) )
  131. // the given expression MUST be true or else fails with that expression
  132. #define OSSYNCEnforce( exp ) OSSYNCEnforceSz( exp, #exp )
  133. #ifdef SYNC_VALIDATE_IRKSEM_USAGE
  134. #define OSSYNCEnforceIrksem( exp, sz ) OSSYNCEnforceSz( exp, sz )
  135. #else // !SYNC_VALIDATE_IRKSEM_USAGE
  136. #define OSSYNCEnforceIrksem( exp, sz )
  137. #endif // SYNC_VALIDATE_IRKSEM_USAGE
  138. // OSSYNC_FOREVER marks all convergence loops
  139. #if defined( _M_IX86 ) && defined( SYNC_USE_X86_ASM )
  140. inline void OSSyncPause() { __asm rep nop }
  141. #else // !_M_IX86 || !SYNC_USE_X86_ASM
  142. inline void OSSyncPause() {}
  143. #endif // _M_IX86 && SYNC_USE_X86_ASM
  144. #ifdef DEBUG
  145. #define OSSYNC_FOREVER for ( int cLoop = 0; ; cLoop++, OSSyncPause() )
  146. #else // !DEBUG
  147. #define OSSYNC_FOREVER for ( ; ; OSSyncPause() )
  148. #endif // DEBUG
  149. namespace OSSYNC {
  150. class CDumpContext;
  151. // Context Local Storage
  152. class COwner;
  153. class CLockDeadlockDetectionInfo;
  154. struct CLS
  155. {
  156. #ifdef SYNC_DEADLOCK_DETECTION
  157. COwner* pownerLockHead; // list of locks owned by this context
  158. DWORD cDisableOwnershipTracking; // lock ownerships are not tracked for this context
  159. BOOL fOverrideDeadlock; // next lock ownership will not be a deadlock
  160. CLockDeadlockDetectionInfo* plddiLockWait; // lock for which this context is waiting
  161. DWORD groupLockWait; // lock group for which this context is waiting
  162. #endif // SYNC_DEADLOCK_DETECTION
  163. };
  164. // returns the pointer to the current context's local storage
  165. CLS* const OSSYNCAPI Pcls();
  166. // Processor Information
  167. // returns the maximum number of processors this process can utilize
  168. int OSSYNCAPI OSSyncGetProcessorCountMax();
  169. // returns the current number of processors this process can utilize
  170. int OSSYNCAPI OSSyncGetProcessorCount();
  171. // returns the processor number that the current context _MAY_ be executing on
  172. //
  173. // NOTE: the current context may change processors at any time
  174. int OSSYNCAPI OSSyncGetCurrentProcessor();
  175. // sets the processor number returned by OSSyncGetCurrentProcessor()
  176. void OSSYNCAPI OSSyncSetCurrentProcessor( const int iProc );
  177. // Processor Local Storage
  178. // configures the size of processor local storage
  179. BOOL OSSYNCAPI FOSSyncConfigureProcessorLocalStorage( const size_t cbPLS );
  180. // retrieves a pointer to the current context's processor local storage
  181. void* OSSYNCAPI OSSyncGetProcessorLocalStorage();
  182. // retrieves a pointer to a given processor's local storage
  183. void* OSSYNCAPI OSSyncGetProcessorLocalStorage( const size_t iProc );
  184. // High Resolution Timer
  185. // returns the current HRT frequency
  186. QWORD OSSYNCAPI QwOSTimeHRTFreq();
  187. // returns the current HRT count
  188. QWORD OSSYNCAPI QwOSTimeHRTCount();
  189. // Timer
  190. // returns the current tick count where one tick is one millisecond
  191. DWORD OSSYNCAPI DwOSTimeGetTickCount();
  192. // Global Synchronization Constants
  193. // wait time used for testing the state of the kernel object
  194. extern const int cmsecTest;
  195. // wait time used for infinite wait on a kernel object
  196. extern const int cmsecInfinite;
  197. // maximum wait time on a kernel object before a deadlock is suspected
  198. extern const int cmsecDeadlock;
  199. // wait time used for infinite wait on a kernel object without deadlock
  200. extern const int cmsecInfiniteNoDeadlock;
  201. // cache line size
  202. extern const int cbCacheLine;
  203. // Atomic Memory Manipulations
  204. // returns fTrue if the given data is properly aligned for atomic modification
  205. inline const BOOL IsAtomicallyModifiable( long* plTarget )
  206. {
  207. return ULONG_PTR( plTarget ) % sizeof( long ) == 0;
  208. }
  209. inline const BOOL IsAtomicallyModifiablePointer( void*const* ppvTarget )
  210. {
  211. return ULONG_PTR( ppvTarget ) % sizeof( void* ) == 0;
  212. }
  213. #if defined( _M_IX86 ) && ( defined( SYNC_USE_X86_ASM ) || _MSC_FULL_VER > 13009037 )
  214. #if _MSC_FULL_VER <= 13009037
  215. #pragma warning( disable: 4035 )
  216. // atomically compares the current value of the target with the specified
  217. // initial value and if equal sets the target to the specified final value.
  218. // the initial value of the target is returned. the exchange is successful
  219. // if the value returned equals the specified initial value. the target
  220. // must be aligned to a four byte boundary
  221. inline long AtomicCompareExchange( long* const plTarget, const long lInitial, const long lFinal )
  222. {
  223. OSSYNCAssert( IsAtomicallyModifiable( plTarget ) );
  224. __asm mov ecx, plTarget
  225. __asm mov edx, lFinal
  226. __asm mov eax, lInitial
  227. __asm lock cmpxchg [ecx], edx
  228. }
  229. inline void* AtomicCompareExchangePointer( void** const ppvTarget, void* const pvInitial, void* const pvFinal )
  230. {
  231. OSSYNCAssert( IsAtomicallyModifiablePointer( ppvTarget ) );
  232. return (void*) AtomicCompareExchange( (long* const) ppvTarget, (const long) pvInitial, (const long) pvFinal );
  233. }
  234. // atomically sets the target to the specified value, returning the target's
  235. // initial value. the target must be aligned to a four byte boundary
  236. inline long AtomicExchange( long* const plTarget, const long lValue )
  237. {
  238. OSSYNCAssert( IsAtomicallyModifiable( plTarget ) );
  239. __asm mov ecx, plTarget
  240. __asm mov eax, lValue
  241. __asm lock xchg [ecx], eax
  242. }
  243. inline void* AtomicExchangePointer( void* const * ppvTarget, void* const pvValue )
  244. {
  245. OSSYNCAssert( IsAtomicallyModifiablePointer( ppvTarget ) );
  246. return (void*) AtomicExchange( (long* const) ppvTarget, (const long) pvValue );
  247. }
  248. // atomically adds the specified value to the target, returning the target's
  249. // initial value. the target must be aligned to a four byte boundary
  250. inline long AtomicExchangeAdd( long* const plTarget, const long lValue )
  251. {
  252. OSSYNCAssert( IsAtomicallyModifiable( plTarget ) );
  253. __asm mov ecx, plTarget
  254. __asm mov eax, lValue
  255. __asm lock xadd [ecx], eax
  256. }
  257. #pragma warning( default: 4035 )
  258. #else
  259. extern "C" {
  260. LONG
  261. __cdecl
  262. _InterlockedExchange(
  263. IN OUT LONG volatile *Target,
  264. IN LONG Value
  265. );
  266. #pragma intrinsic (_InterlockedExchange)
  267. }
  268. inline long AtomicExchange( long* const plTarget, const long lValue )
  269. {
  270. OSSYNCAssert( IsAtomicallyModifiable( plTarget ) );
  271. return _InterlockedExchange( plTarget, lValue );
  272. }
  273. extern "C" {
  274. LONG
  275. __cdecl
  276. _InterlockedExchangeAdd(
  277. IN OUT LONG volatile *Addend,
  278. IN LONG Increment
  279. );
  280. #pragma intrinsic (_InterlockedExchangeAdd)
  281. }
  282. inline long AtomicExchangeAdd( long* const plTarget, const long lValue )
  283. {
  284. OSSYNCAssert( IsAtomicallyModifiable( plTarget ) );
  285. return _InterlockedExchangeAdd( plTarget, lValue );
  286. }
  287. extern "C" {
  288. LONG
  289. __cdecl
  290. _InterlockedCompareExchange (
  291. IN OUT LONG volatile *Destination,
  292. IN LONG ExChange,
  293. IN LONG Comperand
  294. );
  295. #pragma intrinsic (_InterlockedCompareExchange)
  296. }
  297. inline long AtomicCompareExchange( long* const plTarget, const long lInitial, const long lFinal )
  298. {
  299. OSSYNCAssert( IsAtomicallyModifiable( plTarget ) );
  300. return _InterlockedCompareExchange( plTarget, lFinal, lInitial );
  301. }
  302. inline void* AtomicExchangePointer( void* const * ppvTarget, void* const pvValue )
  303. {
  304. return (void*)AtomicExchange( (long *)ppvTarget, (long)pvValue );
  305. }
  306. inline void* AtomicCompareExchangePointer( void** const ppvTarget, void* const pvInitial, void* const pvFinal )
  307. {
  308. return (void*)AtomicCompareExchange( (long *)ppvTarget, (long)pvInitial, (long)pvFinal );
  309. }
  310. #endif
  311. #elif defined( _WIN64 )
  312. inline long AtomicExchange( long* const plTarget, const long lValue )
  313. {
  314. OSSYNCAssert( IsAtomicallyModifiable( plTarget ) );
  315. return InterlockedExchange( plTarget, lValue );
  316. }
  317. inline long AtomicExchangeAdd( long* const plTarget, const long lValue )
  318. {
  319. OSSYNCAssert( IsAtomicallyModifiable( plTarget ) );
  320. return InterlockedExchangeAdd( plTarget, lValue );
  321. }
  322. inline long AtomicCompareExchange( long* const plTarget, const long lInitial, const long lFinal )
  323. {
  324. OSSYNCAssert( IsAtomicallyModifiable( plTarget ) );
  325. return InterlockedCompareExchange( plTarget, lFinal, lInitial );
  326. }
  327. inline void* AtomicExchangePointer( void* const * ppvTarget, void* const pvValue )
  328. {
  329. OSSYNCAssert( IsAtomicallyModifiablePointer( ppvTarget ) );
  330. return InterlockedExchangePointer( (void **)ppvTarget, pvValue );
  331. }
  332. inline void* AtomicCompareExchangePointer( void** const ppvTarget, void* const pvInitial, void* const pvFinal )
  333. {
  334. OSSYNCAssert( IsAtomicallyModifiablePointer( ppvTarget ) );
  335. return InterlockedCompareExchangePointer( ppvTarget, pvFinal, pvInitial );
  336. }
  337. #else
  338. long OSSYNCAPI AtomicCompareExchange( long* const plTarget, const long lInitial, const long lFinal );
  339. void* OSSYNCAPI AtomicCompareExchangePointer( void** const ppvTarget, void* const pvInitial, void* const pvFinal );
  340. long OSSYNCAPI AtomicExchange( long* const plTarget, const long lValue );
  341. void* OSSYNCAPI AtomicExchangePointer( void* const * ppvTarget, void* const pvValue );
  342. long OSSYNCAPI AtomicExchangeAdd( long* const plTarget, const long lValue );
  343. #endif
  344. // atomically adds the specified value to the target, returning the target's
  345. // initial value. the target must be aligned to a pointer boundary.
  346. inline void* AtomicExchangeAddPointer( void** const ppvTarget, void* const pvValue )
  347. {
  348. void* pvInitial;
  349. void* pvFinal;
  350. void* pvResult;
  351. OSSYNCAssert( IsAtomicallyModifiablePointer( ppvTarget ) );
  352. OSSYNC_FOREVER
  353. {
  354. pvInitial = *((void* volatile *)ppvTarget);
  355. pvFinal = (void*)( ULONG_PTR( pvInitial ) + ULONG_PTR( pvValue ) );
  356. pvResult = AtomicCompareExchangePointer( ppvTarget, pvInitial, pvFinal );
  357. if ( pvResult == pvInitial )
  358. {
  359. break;
  360. }
  361. }
  362. return pvResult;
  363. }
  364. // atomically increments the target, returning the incremented value. the
  365. // target must be aligned to a four byte boundary
  366. inline long AtomicIncrement( long* const plTarget )
  367. {
  368. return AtomicExchangeAdd( plTarget, 1 ) + 1;
  369. }
  370. // atomically decrements the target, returning the decremented value. the
  371. // target must be aligned to a four byte boundary
  372. inline long AtomicDecrement( long* const plTarget )
  373. {
  374. return AtomicExchangeAdd( plTarget, -1 ) - 1;
  375. }
  376. // atomically adds the specified value to the target. the target must be
  377. // aligned to a four byte boundary
  378. inline void AtomicAdd( QWORD* const pqwTarget, const QWORD qwValue )
  379. {
  380. #ifdef _WIN64
  381. AtomicExchangeAddPointer( (VOID **)pqwTarget, (VOID *)qwValue );
  382. #else
  383. DWORD* const pdwTargetLow = (DWORD*)pqwTarget;
  384. DWORD* const pdwTargetHigh = pdwTargetLow + 1;
  385. const DWORD dwValueLow = DWORD( qwValue );
  386. DWORD dwValueHigh = DWORD( qwValue >> 32 );
  387. if ( dwValueLow )
  388. {
  389. if ( DWORD( AtomicExchangeAdd( (long*)pdwTargetLow, dwValueLow ) ) + dwValueLow < dwValueLow )
  390. {
  391. dwValueHigh++;
  392. }
  393. }
  394. if ( dwValueHigh )
  395. {
  396. AtomicExchangeAdd( (long*)pdwTargetHigh, dwValueHigh );
  397. }
  398. #endif
  399. }
  400. // Atomically increments a DWORD counter, returning TRUE if the final
  401. // value is less than or equal to a specified maximum, or FALSE otherwise.
  402. // The pre-incremented value is returned in *pdwInitial
  403. // WARNING: to determine if the maximum value has been reached, an UNSIGNED
  404. // comparison is performed
  405. inline BOOL FAtomicIncrementMax(
  406. volatile DWORD * const pdw,
  407. DWORD * const pdwInitial,
  408. const DWORD dwMax )
  409. {
  410. OSSYNC_FOREVER
  411. {
  412. const DWORD dwInitial = *pdw;
  413. if ( dwInitial < dwMax )
  414. {
  415. const DWORD dwFinal = dwInitial + 1;
  416. if ( dwInitial == (DWORD)AtomicCompareExchange( (LONG *)pdw, (LONG)dwInitial, (LONG)dwFinal ) )
  417. {
  418. *pdwInitial = dwInitial;
  419. return fTrue;
  420. }
  421. }
  422. else
  423. return fFalse;
  424. }
  425. // should be impossible
  426. OSSYNCAssert( fFalse );
  427. return fFalse;
  428. }
  429. // Atomically increments a pointer-sized counter, returning TRUE if the final
  430. // value is less than or equal to a specified maximum, or FALSE otherwise.
  431. // The pre-incremented value is returned in *ppvInitial
  432. // WARNING: to determine if the maximum value has been reached, an UNSIGNED
  433. // comparison is performed
  434. inline BOOL FAtomicIncrementPointerMax(
  435. volatile VOID ** const ppv,
  436. VOID ** const ppvInitial,
  437. const VOID * const pvMax )
  438. {
  439. OSSYNC_FOREVER
  440. {
  441. const QWORD qwInitial = QWORD( *ppv );
  442. if ( qwInitial < (QWORD)pvMax )
  443. {
  444. const QWORD qwFinal = qwInitial + 1;
  445. if ( qwInitial == (QWORD)AtomicCompareExchangePointer( (VOID **)ppv, (VOID *)qwInitial, (VOID *)qwFinal ) )
  446. {
  447. *ppvInitial = (VOID *)qwInitial;
  448. return fTrue;
  449. }
  450. }
  451. else
  452. return fFalse;
  453. }
  454. // should be impossible
  455. OSSYNCAssert( fFalse );
  456. return fFalse;
  457. }
  458. // Enhanced Synchronization Object State Container
  459. //
  460. // This class manages a "simple" or normal state for an arbitrary sync object
  461. // and its "enhanced" counterpart. Which type is used depends on the build.
  462. // The goal is to maintain a footprint equal to the normal state so that other
  463. // classes that contain this object do not fluctuate in size depending on what
  464. // build options have been selected. For example, a performance build might
  465. // need extra storage to collect performance stats on the object. This data
  466. // will force the object to be allocated elsewhere in memory but will not change
  467. // the size of the object in its containing class.
  468. //
  469. // Template Arguments:
  470. //
  471. // CState sync object state class
  472. // CStateInit sync object state class ctor arg type
  473. // CInformation sync object information class
  474. // CInformationInit sync object information class ctor arg type
  475. void* OSSYNCAPI ESMemoryNew( size_t cb );
  476. void OSSYNCAPI ESMemoryDelete( void* pv );
  477. // determine when enhanced state is needed
  478. #if defined( SYNC_ANALYZE_PERFORMANCE ) || defined( SYNC_DEADLOCK_DETECTION )
  479. #define SYNC_ENHANCED_STATE
  480. #endif // SYNC_ANALYZE_PERFORMANCE || SYNC_DEADLOCK_DETECTION
  481. template< class CState, class CStateInit, class CInformation, class CInformationInit >
  482. class CEnhancedStateContainer
  483. {
  484. public:
  485. // types
  486. // enhanced state
  487. class CEnhancedState
  488. : public CState,
  489. public CInformation
  490. {
  491. public:
  492. CEnhancedState( const CStateInit& si, const CInformationInit& ii )
  493. : CState( si ),
  494. CInformation( ii )
  495. {
  496. }
  497. void* operator new( size_t cb ) { return ESMemoryNew( cb ); }
  498. void operator delete( void* pv ) { ESMemoryDelete( pv ); }
  499. };
  500. // member functions
  501. // ctors / dtors
  502. CEnhancedStateContainer( const CStateInit& si, const CInformationInit& ii )
  503. {
  504. #ifdef SYNC_ENHANCED_STATE
  505. m_pes = new CEnhancedState( si, ii );
  506. #else // !SYNC_ENHANCED_STATE
  507. new( (CState*) m_rgbState ) CState( si );
  508. #endif // SYNC_ENHANCED_STATE
  509. }
  510. ~CEnhancedStateContainer()
  511. {
  512. #ifdef SYNC_ENHANCED_STATE
  513. delete m_pes;
  514. #ifdef DEBUG
  515. m_pes = NULL;
  516. #endif // DEBUG
  517. #else // !SYNC_ENHANCED_STATE
  518. ( (CState*) m_rgbState )->~CState();
  519. #endif // SYNC_ENHANCED_STATE
  520. }
  521. // accessors
  522. CEnhancedState& State() const
  523. {
  524. #ifdef SYNC_ENHANCED_STATE
  525. return *m_pes;
  526. #else // !SYNC_ENHANCED_STATE
  527. // NOTE: this assumes that CInformation has no storage!
  528. return *( (CEnhancedState*) m_rgbState );
  529. #endif // SYNC_ENHANCED_STATE
  530. }
  531. // debugging support
  532. void Dump( CDumpContext& dc ) const;
  533. private:
  534. // data members
  535. // either a pointer to the enhanced state elsewhere in memory or the
  536. // actual state data, depending on the mode of the sync object
  537. union
  538. {
  539. CEnhancedState* m_pes;
  540. BYTE m_rgbState[ sizeof( CState ) ];
  541. };
  542. };
  543. // Synchronization Object Base Class
  544. //
  545. // All Synchronization Objects are derived from this class
  546. class CSyncObject
  547. {
  548. public:
  549. // member functions
  550. // ctors / dtors
  551. CSyncObject() {}
  552. ~CSyncObject() {}
  553. private:
  554. // member functions
  555. // operators
  556. CSyncObject& operator=( CSyncObject& ); // disallowed
  557. };
  558. // Synchronization Object Basic Information
  559. class CSyncBasicInfo
  560. {
  561. public:
  562. // member functions
  563. // ctors / dtors
  564. CSyncBasicInfo( const char* szInstanceName );
  565. ~CSyncBasicInfo();
  566. // manipulators
  567. void SetTypeName( const char* szTypeName );
  568. void SetInstance( const CSyncObject* const psyncobj );
  569. // accessors
  570. #ifdef SYNC_ENHANCED_STATE
  571. const char* SzInstanceName() const { return m_szInstanceName; }
  572. const char* SzTypeName() const { return m_szTypeName; }
  573. const CSyncObject* const Instance() const { return m_psyncobj; }
  574. #endif // SYNC_ENHANCED_STATE
  575. // debugging support
  576. void Dump( CDumpContext& dc ) const;
  577. private:
  578. // member functions
  579. // operators
  580. CSyncBasicInfo& operator=( CSyncBasicInfo& ); // disallowed
  581. // data members
  582. #ifdef SYNC_ENHANCED_STATE
  583. // Instance Name
  584. const char* m_szInstanceName;
  585. // Type Name
  586. const char* m_szTypeName;
  587. // Instance
  588. const CSyncObject* m_psyncobj;
  589. #endif // SYNC_ENHANCED_STATE
  590. };
  591. // sets the type name for the synchronization object
  592. inline void CSyncBasicInfo::SetTypeName( const char* szTypeName )
  593. {
  594. #ifdef SYNC_ENHANCED_STATE
  595. m_szTypeName = szTypeName;
  596. #endif // SYNC_ENHANCED_STATE
  597. }
  598. // sets the instance pointer for the synchronization object
  599. inline void CSyncBasicInfo::SetInstance( const CSyncObject* const psyncobj )
  600. {
  601. #ifdef SYNC_ENHANCED_STATE
  602. m_psyncobj = psyncobj;
  603. #endif // SYNC_ENHANCED_STATE
  604. }
  605. // Synchronization Object Performance: Wait Times
  606. class CSyncPerfWait
  607. {
  608. public:
  609. // member functions
  610. // ctors / dtors
  611. CSyncPerfWait();
  612. ~CSyncPerfWait();
  613. // member functions
  614. // manipulators
  615. void StartWait();
  616. void StopWait();
  617. // accessors
  618. #ifdef SYNC_ANALYZE_PERFORMANCE
  619. QWORD CWaitTotal() const { return m_cWait; }
  620. double CsecWaitElapsed() const { return (double)(signed __int64)m_qwHRTWaitElapsed /
  621. (double)(signed __int64)QwOSTimeHRTFreq(); }
  622. #endif // SYNC_ANALYZE_PERFORMANCE
  623. // debugging support
  624. void Dump( CDumpContext& dc ) const;
  625. private:
  626. // member functions
  627. // operators
  628. CSyncPerfWait& operator=( CSyncPerfWait& ); // disallowed
  629. // data members
  630. #ifdef SYNC_ANALYZE_PERFORMANCE
  631. // wait count
  632. volatile QWORD m_cWait;
  633. // elapsed wait time
  634. volatile QWORD m_qwHRTWaitElapsed;
  635. #endif // SYNC_ANALYZE_PERFORMANCE
  636. };
  637. // starts the wait timer for the sync object
  638. inline void CSyncPerfWait::StartWait()
  639. {
  640. #ifdef SYNC_ANALYZE_PERFORMANCE
  641. // increment the wait count
  642. AtomicAdd( (QWORD*)&m_cWait, 1 );
  643. // subtract the start wait time from the elapsed wait time. this starts
  644. // an elapsed time computation for this context. StopWait() will later
  645. // add the end wait time to the elapsed time, causing the following net
  646. // effect:
  647. //
  648. // m_qwHRTWaitElapsed += <end time> - <start time>
  649. //
  650. // we simply choose to go ahead and do the subtraction now to save storage
  651. AtomicAdd( (QWORD*)&m_qwHRTWaitElapsed, QWORD( -__int64( QwOSTimeHRTCount() ) ) );
  652. #endif // SYNC_ANALYZE_PERFORMANCE
  653. }
  654. // stops the wait timer for the sync object
  655. inline void CSyncPerfWait::StopWait()
  656. {
  657. #ifdef SYNC_ANALYZE_PERFORMANCE
  658. // add the end wait time to the elapsed wait time. this completes the
  659. // computation started in StartWait()
  660. AtomicAdd( (QWORD*)&m_qwHRTWaitElapsed, QwOSTimeHRTCount() );
  661. #endif // SYNC_ANALYZE_PERFORMANCE
  662. }
  663. // Null Synchronization Object State Initializer
  664. class CSyncStateInitNull
  665. {
  666. };
  667. extern const CSyncStateInitNull syncstateNull;
  668. // Kernel Semaphore Information
  669. class CKernelSemaphoreInfo
  670. : public CSyncBasicInfo,
  671. public CSyncPerfWait
  672. {
  673. public:
  674. // member functions
  675. // ctors / dtors
  676. CKernelSemaphoreInfo( const CSyncBasicInfo& sbi )
  677. : CSyncBasicInfo( sbi )
  678. {
  679. }
  680. // debugging support
  681. void Dump( CDumpContext& dc ) const;
  682. };
  683. // Kernel Semaphore State
  684. class CKernelSemaphoreState
  685. {
  686. public:
  687. // member functions
  688. // ctors / dtors
  689. CKernelSemaphoreState( const CSyncStateInitNull& null ) : m_handle( 0 ) {}
  690. // manipulators
  691. void SetHandle( void * handle ) { m_handle = handle; }
  692. // accessors
  693. void* Handle() { return m_handle; }
  694. // debugging support
  695. void Dump( CDumpContext& dc ) const;
  696. private:
  697. // member functions
  698. // operators
  699. CKernelSemaphoreState& operator=( CKernelSemaphoreState& ); // disallowed
  700. // data members
  701. // kernel semaphore handle
  702. void* m_handle;
  703. };
  704. // Kernel Semaphore
  705. class CKernelSemaphore
  706. : private CSyncObject,
  707. private CEnhancedStateContainer< CKernelSemaphoreState, CSyncStateInitNull, CKernelSemaphoreInfo, CSyncBasicInfo >
  708. {
  709. public:
  710. // member functions
  711. // ctors / dtors
  712. CKernelSemaphore( const CSyncBasicInfo& sbi );
  713. ~CKernelSemaphore();
  714. // init / term
  715. const BOOL FInit();
  716. void Term();
  717. // manipulators
  718. void Acquire();
  719. const BOOL FTryAcquire();
  720. const BOOL FAcquire( const int cmsecTimeout );
  721. void Release( const int cToRelease = 1 );
  722. // accessors
  723. const BOOL FReset();
  724. // debugging support
  725. void Dump( CDumpContext& dc ) const;
  726. private:
  727. // member functions
  728. // operators
  729. CKernelSemaphore& operator=( CKernelSemaphore& ); // disallowed
  730. // accessors
  731. const BOOL FInitialized();
  732. };
  733. // acquire one count of the semaphore, waiting forever if necessary
  734. inline void CKernelSemaphore::Acquire()
  735. {
  736. // semaphore should be initialized
  737. OSSYNCAssert( FInitialized() );
  738. // wait for the semaphore
  739. const BOOL fAcquire = FAcquire( cmsecInfinite );
  740. OSSYNCAssert( fAcquire );
  741. }
  742. // try to acquire one count of the semaphore without waiting. returns 0 if a
  743. // count could not be acquired
  744. inline const BOOL CKernelSemaphore::FTryAcquire()
  745. {
  746. // semaphore should be initialized
  747. OSSYNCAssert( FInitialized() );
  748. // test the semaphore
  749. return FAcquire( cmsecTest );
  750. }
  751. // returns fTrue if the semaphore has no available counts
  752. inline const BOOL CKernelSemaphore::FReset()
  753. {
  754. // semaphore should be initialized
  755. OSSYNCAssert( FInitialized() );
  756. // test the semaphore
  757. return !FTryAcquire();
  758. }
  759. // returns fTrue if the semaphore has been initialized
  760. inline const BOOL CKernelSemaphore::FInitialized()
  761. {
  762. return State().Handle() != 0;
  763. }
  764. // Kernel Semaphore Pool
  765. class CKernelSemaphorePool
  766. {
  767. public:
  768. // types
  769. // index to a ref counted kernel semaphore
  770. typedef unsigned short IRKSEM;
  771. enum { irksemAllocated = 0xFFFE, irksemNil = 0xFFFF };
  772. // member functions
  773. // ctors / dtors
  774. CKernelSemaphorePool();
  775. ~CKernelSemaphorePool();
  776. // init / term
  777. const BOOL FInit();
  778. void Term();
  779. // manipulators
  780. const IRKSEM Allocate( const CSyncObject* const psyncobj );
  781. void Reference( const IRKSEM irksem );
  782. void Unreference( const IRKSEM irksem );
  783. // accessors
  784. CKernelSemaphore& Ksem( const IRKSEM irksem, const CSyncObject* const psyncobj ) const;
  785. const BOOL FInitialized() const;
  786. long CksemAlloc() const { return m_cksem; }
  787. private:
  788. // types
  789. // reference counted kernel semaphore
  790. class CReferencedKernelSemaphore
  791. : public CKernelSemaphore
  792. {
  793. public:
  794. // member functions
  795. // ctors / dtors
  796. CReferencedKernelSemaphore();
  797. ~CReferencedKernelSemaphore();
  798. // init / term
  799. const BOOL FInit();
  800. void Term();
  801. // manipulators
  802. BOOL FAllocate();
  803. void Release();
  804. void SetUser( const CSyncObject* const psyncobj );
  805. void Reference();
  806. const BOOL FUnreference();
  807. // accessors
  808. const BOOL FInUse() const { return m_fInUse; }
  809. const int CReference() const { return m_cReference; }
  810. #ifdef SYNC_VALIDATE_IRKSEM_USAGE
  811. const CSyncObject* const PsyncobjUser() const { return m_psyncobjUser; }
  812. #endif // SYNC_VALIDATE_IRKSEM_USAGE
  813. private:
  814. // member functions
  815. // operators
  816. CReferencedKernelSemaphore& operator=( CReferencedKernelSemaphore& ); // disallowed
  817. // data members
  818. // transacted state representation
  819. union
  820. {
  821. volatile long m_l;
  822. struct
  823. {
  824. volatile unsigned short m_cReference:15; // 0 <= m_cReference <= ( 1 << 15 ) - 1
  825. volatile unsigned short m_fInUse:1; // m_fInUse = { 0, 1 }
  826. };
  827. };
  828. volatile long m_fAvailable;
  829. #ifdef SYNC_VALIDATE_IRKSEM_USAGE
  830. // sync object currently using this semaphore
  831. const CSyncObject* volatile m_psyncobjUser;
  832. #else // SYNC_VALIDATE_IRKSEM_USAGE
  833. BYTE m_rgbReserved1[4];
  834. #endif // SYNC_VALIDATE_IRKSEM_USAGE
  835. BYTE m_rgbReserved2[16];
  836. };
  837. // member functions
  838. // operators
  839. CKernelSemaphorePool& operator=( CKernelSemaphorePool& ); // disallowed
  840. // manipulators
  841. const IRKSEM AllocateNew();
  842. void Free( const IRKSEM irksem );
  843. // data members
  844. // semaphore index to semaphore map
  845. CReferencedKernelSemaphore* m_mpirksemrksem;
  846. // semaphore count
  847. volatile long m_cksem;
  848. };
  849. // allocates an IRKSEM from the pool on behalf of the specified sync object
  850. //
  851. // NOTE: the returned IRKSEM has one reference count
  852. inline const CKernelSemaphorePool::IRKSEM CKernelSemaphorePool::Allocate( const CSyncObject* const psyncobj )
  853. {
  854. // semaphore pool should be initialized
  855. OSSYNCAssert( FInitialized() );
  856. // there are semaphores in the semaphore pool
  857. IRKSEM irksem = irksemNil;
  858. if ( m_cksem )
  859. {
  860. // hash into the semaphore pool based on this context's CLS and the time
  861. IRKSEM irksemHash = IRKSEM( UINT_PTR( UINT_PTR( Pcls() ) / sizeof( CLS ) + UINT_PTR( QwOSTimeHRTCount() ) ) % m_cksem );
  862. OSSYNCAssert( irksemHash >= 0 && irksemHash < m_cksem );
  863. // try to allocate a semaphore, scanning forwards through the pool
  864. for ( long cLoop = 0;
  865. cLoop < m_cksem;
  866. cLoop++, irksemHash = IRKSEM( ++irksemHash % m_cksem ) )
  867. {
  868. if ( m_mpirksemrksem[ irksemHash ].FAllocate() )
  869. {
  870. irksem = irksemHash;
  871. break;
  872. }
  873. }
  874. }
  875. // if we do not yet have a semaphore, allocate one
  876. if ( irksem == irksemNil )
  877. {
  878. irksem = AllocateNew();
  879. }
  880. // validate irksem retrieved
  881. OSSYNCAssert( irksem != irksemNil );
  882. OSSYNCAssert( irksem >= 0 );
  883. OSSYNCAssert( irksem < m_cksem );
  884. // set the user for this semaphore
  885. m_mpirksemrksem[irksem].SetUser( psyncobj );
  886. // ensure that the semaphore we retrieved is reset
  887. OSSYNCEnforceIrksem( m_mpirksemrksem[irksem].FReset(),
  888. "Illegal allocation of a Kernel Semaphore with available counts!" );
  889. // return the allocated semaphore
  890. return irksem;
  891. }
  892. // add a reference count to an IRKSEM
  893. inline void CKernelSemaphorePool::Reference( const IRKSEM irksem )
  894. {
  895. // validate IN args
  896. OSSYNCAssert( irksem != irksemNil );
  897. OSSYNCAssert( irksem >= 0 );
  898. OSSYNCAssert( irksem < m_cksem );
  899. // semaphore pool should be initialized
  900. OSSYNCAssert( FInitialized() );
  901. // increment the reference count for this IRKSEM
  902. m_mpirksemrksem[irksem].Reference();
  903. }
  904. // remove a reference count from an IRKSEM, freeing it if the reference count
  905. // drops to zero and it is not currently in use
  906. inline void CKernelSemaphorePool::Unreference( const IRKSEM irksem )
  907. {
  908. // validate IN args
  909. OSSYNCAssert( irksem != irksemNil );
  910. OSSYNCAssert( irksem >= 0 );
  911. OSSYNCAssert( irksem < m_cksem );
  912. // semaphore pool should be initialized
  913. OSSYNCAssert( FInitialized() );
  914. // decrement the reference count for this IRKSEM
  915. const BOOL fFree = m_mpirksemrksem[irksem].FUnreference();
  916. // we need to free the semaphore
  917. if ( fFree )
  918. {
  919. // free the IRKSEM back to the allocation stack
  920. Free( irksem );
  921. }
  922. }
  923. // returns the CKernelSemaphore object associated with the given IRKSEM
  924. inline CKernelSemaphore& CKernelSemaphorePool::Ksem( const IRKSEM irksem, const CSyncObject* const psyncobj ) const
  925. {
  926. // validate IN args
  927. OSSYNCAssert( irksem != irksemNil );
  928. OSSYNCAssert( irksem >= 0 );
  929. OSSYNCAssert( irksem < m_cksem );
  930. // semaphore pool should be initialized
  931. OSSYNCAssert( FInitialized() );
  932. // we had better be retrieving this semaphore for the right sync object
  933. OSSYNCEnforceIrksem( m_mpirksemrksem[irksem].PsyncobjUser() == psyncobj,
  934. "Illegal use of a Kernel Semaphore by another Synchronization Object" );
  935. // return kernel semaphore
  936. return m_mpirksemrksem[irksem];
  937. }
  938. // returns fTrue if the semaphore pool has been initialized
  939. inline const BOOL CKernelSemaphorePool::FInitialized() const
  940. {
  941. return m_mpirksemrksem != NULL;
  942. }
  943. // allocates a new irksem and adds it to the stack's irksem pool
  944. inline const CKernelSemaphorePool::IRKSEM CKernelSemaphorePool::AllocateNew()
  945. {
  946. // atomically allocate a position in the stack's irksem pool for our new
  947. // irksem
  948. const long lDelta = 0x00000001;
  949. const long lBI = AtomicExchangeAdd( (long*) &m_cksem, lDelta );
  950. const IRKSEM irksem = IRKSEM( lBI );
  951. // initialize this irksem
  952. new ( &m_mpirksemrksem[irksem] ) CReferencedKernelSemaphore;
  953. BOOL fInitKernelSemaphore = m_mpirksemrksem[irksem].FInit();
  954. OSSYNCEnforceSz( fInitKernelSemaphore, "Could not allocate a Kernel Semaphore" );
  955. // return the irksem for use
  956. return irksem;
  957. }
  958. // frees the given IRKSEM back to the allocation stack
  959. inline void CKernelSemaphorePool::Free( const IRKSEM irksem )
  960. {
  961. // validate IN args
  962. OSSYNCAssert( irksem != irksemNil );
  963. OSSYNCAssert( irksem >= 0 );
  964. OSSYNCAssert( irksem < m_cksem );
  965. // semaphore pool should be initialized
  966. OSSYNCAssert( FInitialized() );
  967. // the semaphore to free had better not be in use
  968. OSSYNCEnforceIrksem( !m_mpirksemrksem[irksem].FInUse(),
  969. "Illegal free of a Kernel Semaphore that is still in use" );
  970. // the semaphore had better not already be freed
  971. OSSYNCEnforceIrksem( !m_mpirksemrksem[irksem].FAllocate(),
  972. "Illegal free of a Kernel Semaphore that is already free" );
  973. // ensure that the semaphore to free is reset
  974. OSSYNCEnforceIrksem( m_mpirksemrksem[irksem].FReset(),
  975. "Illegal free of a Kernel Semaphore that has available counts" );
  976. // release the semaphore to the pool
  977. m_mpirksemrksem[irksem].Release();
  978. }
  979. // Referenced Kernel Semaphore
  980. // attempts to allocate the semaphore, returning fTrue on success
  981. inline BOOL CKernelSemaphorePool::CReferencedKernelSemaphore::FAllocate()
  982. {
  983. return m_fAvailable && AtomicExchange( (long*)&m_fAvailable, 0 );
  984. }
  985. // releases the semaphore
  986. inline void CKernelSemaphorePool::CReferencedKernelSemaphore::Release()
  987. {
  988. AtomicExchange( (long*)&m_fAvailable, 1 );
  989. }
  990. // sets the user for the semaphore and gives the user an initial reference
  991. inline void CKernelSemaphorePool::CReferencedKernelSemaphore::SetUser( const CSyncObject* const psyncobj )
  992. {
  993. // this semaphore had better not already be in use
  994. OSSYNCEnforceIrksem( !m_fInUse,
  995. "Illegal allocation of a Kernel Semaphore that is already in use" );
  996. OSSYNCEnforceIrksem( !m_psyncobjUser,
  997. "Illegal allocation of a Kernel Semaphore that is already in use" );
  998. // mark this semaphore as in use and add an initial reference count for the
  999. // user
  1000. AtomicExchangeAdd( (long*) &m_l, 0x00008001 );
  1001. #ifdef SYNC_VALIDATE_IRKSEM_USAGE
  1002. m_psyncobjUser = psyncobj;
  1003. #endif // SYNC_VALIDATE_IRKSEM_USAGE
  1004. }
  1005. // add a reference count to the semaphore
  1006. inline void CKernelSemaphorePool::CReferencedKernelSemaphore::Reference()
  1007. {
  1008. // increment the reference count
  1009. AtomicIncrement( (long*) &m_l );
  1010. // there had better be at least one reference count!
  1011. OSSYNCAssert( m_cReference > 0 );
  1012. }
  1013. // remove a reference count from the semaphore, returning fTrue if the last
  1014. // reference count on the semaphore was removed and the semaphore was in use
  1015. // (this is the condition on which we can free the semaphore to the stack)
  1016. inline const BOOL CKernelSemaphorePool::CReferencedKernelSemaphore::FUnreference()
  1017. {
  1018. // there had better be at least one reference count!
  1019. OSSYNCAssert( m_cReference > 0 );
  1020. // try forever until we succeed in removing our reference count
  1021. long lBI;
  1022. OSSYNC_FOREVER
  1023. {
  1024. // read the current state of the control word as our expected before image
  1025. const long lBIExpected = m_l;
  1026. // compute the after image of the control word by decrementing the
  1027. // reference count and reseting the In Use bit if and only if we are
  1028. // removing the last reference count
  1029. const long lAI = lBIExpected +
  1030. ( lBIExpected == 0x00008001 ?
  1031. 0xFFFF7FFF :
  1032. 0xFFFFFFFF );
  1033. // attempt to perform the transacted state transition on the control word
  1034. lBI = AtomicCompareExchange( (long*)&m_l, lBIExpected, lAI );
  1035. // the transaction failed
  1036. if ( lBI != lBIExpected )
  1037. {
  1038. // try again
  1039. continue;
  1040. }
  1041. // the transaction succeeded
  1042. else
  1043. {
  1044. // we're done
  1045. break;
  1046. }
  1047. }
  1048. // return fTrue if we removed the last reference count and reset the In Use bit
  1049. if ( lBI == 0x00008001 )
  1050. {
  1051. #ifdef SYNC_VALIDATE_IRKSEM_USAGE
  1052. m_psyncobjUser = NULL;
  1053. #endif // SYNC_VALIDATE_IRKSEM_USAGE
  1054. return fTrue;
  1055. }
  1056. else
  1057. {
  1058. return fFalse;
  1059. }
  1060. }
  1061. // Global Kernel Semaphore Pool
  1062. extern CKernelSemaphorePool ksempoolGlobal;
  1063. // Synchronization Object Performance: Acquisition
  1064. class CSyncPerfAcquire
  1065. {
  1066. public:
  1067. // member functions
  1068. // ctors / dtors
  1069. CSyncPerfAcquire();
  1070. ~CSyncPerfAcquire();
  1071. // member functions
  1072. // manipulators
  1073. void SetAcquire();
  1074. void SetContend();
  1075. // accessors
  1076. #ifdef SYNC_ANALYZE_PERFORMANCE
  1077. QWORD CAcquireTotal() const { return m_cAcquire; }
  1078. QWORD CContendTotal() const { return m_cContend; }
  1079. #endif // SYNC_ANALYZE_PERFORMANCE
  1080. // debugging support
  1081. void Dump( CDumpContext& dc ) const;
  1082. private:
  1083. // member functions
  1084. // operators
  1085. CSyncPerfAcquire& operator=( CSyncPerfAcquire& ); // disallowed
  1086. // data members
  1087. #ifdef SYNC_ANALYZE_PERFORMANCE
  1088. // acquire count
  1089. volatile QWORD m_cAcquire;
  1090. // contend count
  1091. volatile QWORD m_cContend;
  1092. #endif // SYNC_ANALYZE_PERFORMANCE
  1093. };
  1094. // specifies that the sync object was acquired
  1095. inline void CSyncPerfAcquire::SetAcquire()
  1096. {
  1097. #ifdef SYNC_ANALYZE_PERFORMANCE
  1098. AtomicAdd( (QWORD*)&m_cAcquire, 1 );
  1099. #endif // SYNC_ANALYZE_PERFORMANCE
  1100. }
  1101. // specifies that a contention occurred while acquiring the sync object
  1102. inline void CSyncPerfAcquire::SetContend()
  1103. {
  1104. #ifdef SYNC_ANALYZE_PERFORMANCE
  1105. AtomicAdd( (QWORD*)&m_cContend, 1 );
  1106. #endif // SYNC_ANALYZE_PERFORMANCE
  1107. }
  1108. // Semaphore Information
  1109. class CSemaphoreInfo
  1110. : public CSyncBasicInfo,
  1111. public CSyncPerfWait,
  1112. public CSyncPerfAcquire
  1113. {
  1114. public:
  1115. // member functions
  1116. // ctors / dtors
  1117. CSemaphoreInfo( const CSyncBasicInfo& sbi )
  1118. : CSyncBasicInfo( sbi )
  1119. {
  1120. }
  1121. // debugging support
  1122. void Dump( CDumpContext& dc ) const;
  1123. };
  1124. // Semaphore State
  1125. class CSemaphoreState
  1126. {
  1127. public:
  1128. // member functions
  1129. // ctors / dtors
  1130. CSemaphoreState( const CSyncStateInitNull& null ) : m_cAvail( 0 ) {}
  1131. CSemaphoreState( const int cAvail );
  1132. CSemaphoreState( const int cWait, const int irksem );
  1133. ~CSemaphoreState() {}
  1134. // operators
  1135. CSemaphoreState& operator=( CSemaphoreState& state ) { m_cAvail = state.m_cAvail; return *this; }
  1136. // manipulators
  1137. const BOOL FChange( const CSemaphoreState& stateCur, const CSemaphoreState& stateNew );
  1138. const BOOL FIncAvail( const int cToInc );
  1139. const BOOL FDecAvail();
  1140. // accessors
  1141. const BOOL FNoWait() const { return m_cAvail >= 0; }
  1142. const BOOL FWait() const { return m_cAvail < 0; }
  1143. const BOOL FAvail() const { return m_cAvail > 0; }
  1144. const BOOL FNoWaitAndNoAvail() const { return m_cAvail == 0; }
  1145. const int CAvail() const { OSSYNCAssert( FNoWait() ); return m_cAvail; }
  1146. const int CWait() const { OSSYNCAssert( FWait() ); return -m_cWaitNeg; }
  1147. const CKernelSemaphorePool::IRKSEM Irksem() const { OSSYNCAssert( FWait() ); return CKernelSemaphorePool::IRKSEM( m_irksem ); }
  1148. // debugging support
  1149. void Dump( CDumpContext& dc ) const;
  1150. private:
  1151. // data members
  1152. // transacted state representation (switched on bit 31)
  1153. union
  1154. {
  1155. // Mode 0: no waiters
  1156. volatile long m_cAvail; // 0 <= m_cAvail <= ( 1 << 31 ) - 1
  1157. // Mode 1: waiters
  1158. struct
  1159. {
  1160. volatile unsigned short m_irksem; // 0 <= m_irksem <= ( 1 << 16 ) - 2
  1161. volatile short m_cWaitNeg; // -( ( 1 << 15 ) - 1 ) <= m_cWaitNeg <= -1
  1162. };
  1163. };
  1164. };
  1165. // ctor
  1166. inline CSemaphoreState::CSemaphoreState( const int cAvail )
  1167. {
  1168. // validate IN args
  1169. OSSYNCAssert( cAvail >= 0 );
  1170. OSSYNCAssert( cAvail <= 0x7FFFFFFF );
  1171. // set available count
  1172. m_cAvail = long( cAvail );
  1173. }
  1174. // ctor
  1175. inline CSemaphoreState::CSemaphoreState( const int cWait, const int irksem )
  1176. {
  1177. // validate IN args
  1178. OSSYNCAssert( cWait > 0 );
  1179. OSSYNCAssert( cWait <= 0x7FFF );
  1180. OSSYNCAssert( irksem >= 0 );
  1181. OSSYNCAssert( irksem <= 0xFFFE );
  1182. // set waiter count
  1183. m_cWaitNeg = short( -cWait );
  1184. // set semaphore
  1185. m_irksem = (unsigned short) irksem;
  1186. }
  1187. // changes the transacted state of the semaphore using a transacted memory
  1188. // compare/exchange operation, returning fFalse on failure
  1189. inline const BOOL CSemaphoreState::FChange( const CSemaphoreState& stateCur, const CSemaphoreState& stateNew )
  1190. {
  1191. return AtomicCompareExchange( (long*)&m_cAvail, stateCur.m_cAvail, stateNew.m_cAvail ) == stateCur.m_cAvail;
  1192. }
  1193. // tries to increase the available count on the semaphore by the count
  1194. // given using a transacted memory compare/exchange operation, returning fFalse
  1195. // on failure
  1196. __forceinline const BOOL CSemaphoreState::FIncAvail( const int cToInc )
  1197. {
  1198. // try forever to change the state of the semaphore
  1199. OSSYNC_FOREVER
  1200. {
  1201. // get current value
  1202. const long cAvail = m_cAvail;
  1203. // munge start value such that the transaction will only work if we are in
  1204. // mode 0 (we do this to save a branch)
  1205. const long cAvailStart = cAvail & 0x7FFFFFFF;
  1206. // compute end value relative to munged start value
  1207. const long cAvailEnd = cAvailStart + cToInc;
  1208. // validate transaction
  1209. OSSYNCAssert( cAvail < 0 || ( cAvailStart >= 0 && cAvailEnd <= 0x7FFFFFFF && cAvailEnd == cAvailStart + cToInc ) );
  1210. // attempt the transaction
  1211. const long cAvailOld = AtomicCompareExchange( (long*)&m_cAvail, cAvailStart, cAvailEnd );
  1212. // the transaction succeeded
  1213. if ( cAvailOld == cAvailStart )
  1214. {
  1215. // return success
  1216. return fTrue;
  1217. }
  1218. // the transaction failed
  1219. else
  1220. {
  1221. // the transaction failed because of a collision with another context
  1222. if ( cAvailOld >= 0 )
  1223. {
  1224. // try again
  1225. continue;
  1226. }
  1227. // the transaction failed because there are waiters
  1228. else
  1229. {
  1230. // return failure
  1231. return fFalse;
  1232. }
  1233. }
  1234. }
  1235. }
  1236. // tries to decrease the available count on the semaphore by one using a
  1237. // transacted memory compare/exchange operation, returning fFalse on failure
  1238. __forceinline const BOOL CSemaphoreState::FDecAvail()
  1239. {
  1240. // try forever to change the state of the semaphore
  1241. OSSYNC_FOREVER
  1242. {
  1243. // get current value
  1244. const long cAvail = m_cAvail;
  1245. // this function has no effect on 0x80000000, so this MUST be an illegal
  1246. // value!
  1247. OSSYNCAssert( cAvail != 0x80000000 );
  1248. // munge end value such that the transaction will only work if we are in
  1249. // mode 0 and we have at least one available count (we do this to save a
  1250. // branch)
  1251. const long cAvailEnd = ( cAvail - 1 ) & 0x7FFFFFFF;
  1252. // compute start value relative to munged end value
  1253. const long cAvailStart = cAvailEnd + 1;
  1254. // validate transaction
  1255. OSSYNCAssert( cAvail <= 0 || ( cAvailStart > 0 && cAvailEnd >= 0 && cAvailEnd == cAvail - 1 ) );
  1256. // attempt the transaction
  1257. const long cAvailOld = AtomicCompareExchange( (long*)&m_cAvail, cAvailStart, cAvailEnd );
  1258. // the transaction succeeded
  1259. if ( cAvailOld == cAvailStart )
  1260. {
  1261. // return success
  1262. return fTrue;
  1263. }
  1264. // the transaction failed
  1265. else
  1266. {
  1267. // the transaction failed because of a collision with another context
  1268. if ( cAvailOld > 0 )
  1269. {
  1270. // try again
  1271. continue;
  1272. }
  1273. // the transaction failed because there are no available counts
  1274. else
  1275. {
  1276. // return failure
  1277. return fFalse;
  1278. }
  1279. }
  1280. }
  1281. }
  1282. // Semaphore
  1283. class CSemaphore
  1284. : private CSyncObject,
  1285. private CEnhancedStateContainer< CSemaphoreState, CSyncStateInitNull, CSemaphoreInfo, CSyncBasicInfo >
  1286. {
  1287. public:
  1288. // member functions
  1289. // ctors / dtors
  1290. CSemaphore( const CSyncBasicInfo& sbi );
  1291. ~CSemaphore();
  1292. // manipulators
  1293. void Acquire();
  1294. const BOOL FTryAcquire();
  1295. const BOOL FAcquire( const int cmsecTimeout );
  1296. void Release( const int cToRelease = 1 );
  1297. // accessors
  1298. const int CWait() const;
  1299. const int CAvail() const;
  1300. // debugging support
  1301. void Dump( CDumpContext& dc ) const;
  1302. private:
  1303. // member functions
  1304. // operators
  1305. CSemaphore& operator=( CSemaphore& ); // disallowed
  1306. // manipulators
  1307. const BOOL _FAcquire( const int cmsecTimeout );
  1308. void _Release( const int cToRelease );
  1309. };
  1310. // acquire one count of the semaphore, waiting forever if necessary
  1311. inline void CSemaphore::Acquire()
  1312. {
  1313. // we will wait forever, so we should not timeout
  1314. int fAcquire = FAcquire( cmsecInfinite );
  1315. OSSYNCAssert( fAcquire );
  1316. }
  1317. // try to acquire one count of the semaphore without waiting or spinning.
  1318. // returns fFalse if a count could not be acquired
  1319. inline const BOOL CSemaphore::FTryAcquire()
  1320. {
  1321. // only try to perform a simple decrement of the available count
  1322. const BOOL fAcquire = State().FDecAvail();
  1323. // we did not acquire the semaphore
  1324. if ( !fAcquire )
  1325. {
  1326. // this is a contention
  1327. State().SetContend();
  1328. }
  1329. // we did acquire the semaphore
  1330. else
  1331. {
  1332. // note that we acquired a count
  1333. State().SetAcquire();
  1334. }
  1335. return fAcquire;
  1336. }
  1337. // acquire one count of the semaphore, waiting only for the specified interval.
  1338. // returns fFalse if the wait timed out before a count could be acquired
  1339. inline const BOOL CSemaphore::FAcquire( const int cmsecTimeout )
  1340. {
  1341. // first try to quickly grab an available count. if that doesn't work,
  1342. // retry acquire using the full state machine
  1343. return FTryAcquire() || _FAcquire( cmsecTimeout );
  1344. }
  1345. // releases the given number of counts to the semaphore, waking the appropriate
  1346. // number of waiters
  1347. inline void CSemaphore::Release( const int cToRelease )
  1348. {
  1349. // we failed to perform a simple increment of the available count
  1350. if ( !State().FIncAvail( cToRelease ) )
  1351. {
  1352. // retry release using the full state machine
  1353. _Release( cToRelease );
  1354. }
  1355. }
  1356. // returns the number of execution contexts waiting on the semaphore
  1357. inline const int CSemaphore::CWait() const
  1358. {
  1359. // read the current state of the semaphore
  1360. const CSemaphoreState stateCur = (CSemaphoreState&) State();
  1361. // return the waiter count
  1362. return stateCur.FWait() ? stateCur.CWait() : 0;
  1363. }
  1364. // returns the number of available counts on the semaphore
  1365. inline const int CSemaphore::CAvail() const
  1366. {
  1367. // read the current state of the semaphore
  1368. const CSemaphoreState stateCur = (CSemaphoreState&) State();
  1369. // return the available count
  1370. return stateCur.FNoWait() ? stateCur.CAvail() : 0;
  1371. }
  1372. // Auto-Reset Signal Information
  1373. class CAutoResetSignalInfo
  1374. : public CSyncBasicInfo,
  1375. public CSyncPerfWait,
  1376. public CSyncPerfAcquire
  1377. {
  1378. public:
  1379. // member functions
  1380. // ctors / dtors
  1381. CAutoResetSignalInfo( const CSyncBasicInfo& sbi )
  1382. : CSyncBasicInfo( sbi )
  1383. {
  1384. }
  1385. // debugging support
  1386. void Dump( CDumpContext& dc ) const;
  1387. };
  1388. // Auto-Reset Signal State
  1389. class CAutoResetSignalState
  1390. {
  1391. public:
  1392. // member functions
  1393. // ctors / dtors
  1394. CAutoResetSignalState( const CSyncStateInitNull& null ) : m_fSet( 0 ) {}
  1395. CAutoResetSignalState( const int fSet );
  1396. CAutoResetSignalState( const int cWait, const int irksem );
  1397. ~CAutoResetSignalState() {}
  1398. // operators
  1399. CAutoResetSignalState& operator=( CAutoResetSignalState& state ) { m_fSet = state.m_fSet; return *this; }
  1400. // manipulators
  1401. const BOOL FChange( const CAutoResetSignalState& stateCur, const CAutoResetSignalState& stateNew );
  1402. const BOOL FSimpleSet();
  1403. const BOOL FSimpleReset();
  1404. // accessors
  1405. const BOOL FNoWait() const { return m_fSet >= 0; }
  1406. const BOOL FWait() const { return m_fSet < 0; }
  1407. const BOOL FNoWaitAndSet() const { return m_fSet > 0; }
  1408. const BOOL FNoWaitAndNotSet() const { return m_fSet == 0; }
  1409. const BOOL FSet() const { OSSYNCAssert( FNoWait() ); return m_fSet; }
  1410. const int CWait() const { OSSYNCAssert( FWait() ); return -m_cWaitNeg; }
  1411. const CKernelSemaphorePool::IRKSEM Irksem() const { OSSYNCAssert( FWait() ); return CKernelSemaphorePool::IRKSEM( m_irksem ); }
  1412. // debugging support
  1413. void Dump( CDumpContext& dc ) const;
  1414. private:
  1415. // data members
  1416. // transacted state representation (switched on bit 31)
  1417. union
  1418. {
  1419. // Mode 0: no waiters
  1420. volatile long m_fSet; // m_fSet = { 0, 1 }
  1421. // Mode 1: waiters
  1422. struct
  1423. {
  1424. volatile unsigned short m_irksem; // 0 <= m_irksem <= ( 1 << 16 ) - 2
  1425. volatile short m_cWaitNeg; // -( ( 1 << 15 ) - 1 ) <= m_cWaitNeg <= -1
  1426. };
  1427. };
  1428. };
  1429. // ctor
  1430. inline CAutoResetSignalState::CAutoResetSignalState( const int fSet )
  1431. {
  1432. // validate IN args
  1433. OSSYNCAssert( fSet == 0 || fSet == 1 );
  1434. // set state
  1435. m_fSet = long( fSet );
  1436. }
  1437. // ctor
  1438. inline CAutoResetSignalState::CAutoResetSignalState( const int cWait, const int irksem )
  1439. {
  1440. // validate IN args
  1441. OSSYNCAssert( cWait > 0 );
  1442. OSSYNCAssert( cWait <= 0x7FFF );
  1443. OSSYNCAssert( irksem >= 0 );
  1444. OSSYNCAssert( irksem <= 0xFFFE );
  1445. // set waiter count
  1446. m_cWaitNeg = short( -cWait );
  1447. // set semaphore
  1448. m_irksem = (unsigned short) irksem;
  1449. }
  1450. // changes the transacted state of the signal using a transacted memory
  1451. // compare/exchange operation, returning 0 on failure
  1452. inline const BOOL CAutoResetSignalState::FChange( const CAutoResetSignalState& stateCur, const CAutoResetSignalState& stateNew )
  1453. {
  1454. return AtomicCompareExchange( (long*)&m_fSet, stateCur.m_fSet, stateNew.m_fSet ) == stateCur.m_fSet;
  1455. }
  1456. // tries to set the signal state from either the set or reset with no waiters states
  1457. // using a transacted memory compare/exchange operation, returning fFalse on failure
  1458. __forceinline const BOOL CAutoResetSignalState::FSimpleSet()
  1459. {
  1460. // try forever to change the state of the signal
  1461. OSSYNC_FOREVER
  1462. {
  1463. // get current value
  1464. const long fSet = m_fSet;
  1465. // munge start value such that the transaction will only work if we are in
  1466. // mode 0 (we do this to save a branch)
  1467. const long fSetStart = fSet & 0x7FFFFFFF;
  1468. // compute end value relative to munged start value
  1469. const long fSetEnd = 1;
  1470. // validate transaction
  1471. OSSYNCAssert( fSet < 0 || ( ( fSetStart == 0 || fSetStart == 1 ) && fSetEnd == 1 ) );
  1472. // attempt the transaction
  1473. const long fSetOld = AtomicCompareExchange( (long*)&m_fSet, fSetStart, fSetEnd );
  1474. // the transaction succeeded
  1475. if ( fSetOld == fSetStart )
  1476. {
  1477. // return success
  1478. return fTrue;
  1479. }
  1480. // the transaction failed
  1481. else
  1482. {
  1483. // the transaction failed because of a collision with another context
  1484. if ( fSetOld >= 0 )
  1485. {
  1486. // try again
  1487. continue;
  1488. }
  1489. // the transaction failed because there are waiters
  1490. else
  1491. {
  1492. // return failure
  1493. return fFalse;
  1494. }
  1495. }
  1496. }
  1497. }
  1498. // tries to reset the signal state from either the set or reset with no waiters states
  1499. // using a transacted memory compare/exchange operation, returning fFalse on failure
  1500. __forceinline const BOOL CAutoResetSignalState::FSimpleReset()
  1501. {
  1502. // try forever to change the state of the signal
  1503. OSSYNC_FOREVER
  1504. {
  1505. // get current value
  1506. const long fSet = m_fSet;
  1507. // munge start value such that the transaction will only work if we are in
  1508. // mode 0 (we do this to save a branch)
  1509. const long fSetStart = fSet & 0x7FFFFFFF;
  1510. // compute end value relative to munged start value
  1511. const long fSetEnd = 0;
  1512. // validate transaction
  1513. OSSYNCAssert( fSet < 0 || ( ( fSetStart == 0 || fSetStart == 1 ) && fSetEnd == 0 ) );
  1514. // attempt the transaction
  1515. const long fSetOld = AtomicCompareExchange( (long*)&m_fSet, fSetStart, fSetEnd );
  1516. // the transaction succeeded
  1517. if ( fSetOld == fSetStart )
  1518. {
  1519. // return success
  1520. return fTrue;
  1521. }
  1522. // the transaction failed
  1523. else
  1524. {
  1525. // the transaction failed because of a collision with another context
  1526. if ( fSetOld >= 0 )
  1527. {
  1528. // try again
  1529. continue;
  1530. }
  1531. // the transaction failed because there are waiters
  1532. else
  1533. {
  1534. // return failure
  1535. return fFalse;
  1536. }
  1537. }
  1538. }
  1539. }
  1540. // Auto-Reset Signal
  1541. class CAutoResetSignal
  1542. : private CSyncObject,
  1543. private CEnhancedStateContainer< CAutoResetSignalState, CSyncStateInitNull, CAutoResetSignalInfo, CSyncBasicInfo >
  1544. {
  1545. public:
  1546. // member functions
  1547. // ctors / dtors
  1548. CAutoResetSignal( const CSyncBasicInfo& sbi );
  1549. ~CAutoResetSignal();
  1550. // manipulators
  1551. void Wait();
  1552. const BOOL FTryWait();
  1553. const BOOL FWait( const int cmsecTimeout );
  1554. void Set();
  1555. void Reset();
  1556. void Pulse();
  1557. // debugging support
  1558. void Dump( CDumpContext& dc ) const;
  1559. private:
  1560. // member functions
  1561. // operators
  1562. CAutoResetSignal& operator=( CAutoResetSignal& ); // disallowed
  1563. // manipulators
  1564. const BOOL _FWait( const int cmsecTimeout );
  1565. void _Set();
  1566. void _Pulse();
  1567. };
  1568. // waits for the signal to be set, forever if necessary. when the wait completes,
  1569. // the signal will be reset
  1570. inline void CAutoResetSignal::Wait()
  1571. {
  1572. // we will wait forever, so we should not timeout
  1573. const BOOL fWait = FWait( cmsecInfinite );
  1574. OSSYNCAssert( fWait );
  1575. }
  1576. // tests the state of the signal without waiting or spinning, returning fFalse
  1577. // if the signal was not set. if the signal was set, the signal will be reset
  1578. inline const BOOL CAutoResetSignal::FTryWait()
  1579. {
  1580. // we can satisfy the wait if we can successfully change the state of the
  1581. // signal from set to reset with no waiters
  1582. const BOOL fSuccess = State().FChange( CAutoResetSignalState( 1 ), CAutoResetSignalState( 0 ) );
  1583. // we did not successfully wait for the signal
  1584. if ( !fSuccess )
  1585. {
  1586. // this is a contention
  1587. State().SetContend();
  1588. }
  1589. // we did successfully wait for the signal
  1590. else
  1591. {
  1592. // note that we acquired the signal
  1593. State().SetAcquire();
  1594. }
  1595. return fSuccess;
  1596. }
  1597. // wait for the signal to be set, but only for the specified interval,
  1598. // returning fFalse if the wait timed out before the signal was set. if the
  1599. // wait completes, the signal will be reset
  1600. inline const BOOL CAutoResetSignal::FWait( const int cmsecTimeout )
  1601. {
  1602. // first try to quickly pass through the signal. if that doesn't work,
  1603. // retry wait using the full state machine
  1604. return FTryWait() || _FWait( cmsecTimeout );
  1605. }
  1606. // sets the signal, releasing up to one waiter. if a waiter is released, then
  1607. // the signal will be reset. if a waiter is not released, the signal will
  1608. // remain set
  1609. inline void CAutoResetSignal::Set()
  1610. {
  1611. // we failed to change the signal state from reset with no waiters to set
  1612. // or from set to set (a nop)
  1613. if ( !State().FSimpleSet() )
  1614. {
  1615. // retry set using the full state machine
  1616. _Set();
  1617. }
  1618. }
  1619. // resets the signal
  1620. inline void CAutoResetSignal::Reset()
  1621. {
  1622. // if and only if the signal is in the set state, change it to the reset state
  1623. State().FChange( CAutoResetSignalState( 1 ), CAutoResetSignalState( 0 ) );
  1624. }
  1625. // resets the signal, releasing up to one waiter
  1626. inline void CAutoResetSignal::Pulse()
  1627. {
  1628. // wa failed to change the signal state from set to reset with no waiters
  1629. // or from reset with no waiters to reset with no waiters (a nop)
  1630. if ( !State().FSimpleReset() )
  1631. {
  1632. // retry pulse using the full state machine
  1633. _Pulse();
  1634. }
  1635. }
  1636. // Manual-Reset Signal Information
  1637. class CManualResetSignalInfo
  1638. : public CSyncBasicInfo,
  1639. public CSyncPerfWait,
  1640. public CSyncPerfAcquire
  1641. {
  1642. public:
  1643. // member functions
  1644. // ctors / dtors
  1645. CManualResetSignalInfo( const CSyncBasicInfo& sbi )
  1646. : CSyncBasicInfo( sbi )
  1647. {
  1648. }
  1649. // debugging support
  1650. void Dump( CDumpContext& dc ) const;
  1651. };
  1652. // Manual-Reset Signal State
  1653. class CManualResetSignalState
  1654. {
  1655. public:
  1656. // member functions
  1657. // ctors / dtors
  1658. CManualResetSignalState( const CSyncStateInitNull& null ) : m_fSet( 0 ) {}
  1659. CManualResetSignalState( const int fSet );
  1660. CManualResetSignalState( const int cWait, const int irksem );
  1661. ~CManualResetSignalState() {}
  1662. // operators
  1663. CManualResetSignalState& operator=( CManualResetSignalState& state ) { m_fSet = state.m_fSet; return *this; }
  1664. // manipulators
  1665. const BOOL FChange( const CManualResetSignalState& stateCur, const CManualResetSignalState& stateNew );
  1666. const CManualResetSignalState Set();
  1667. const CManualResetSignalState Reset();
  1668. // accessors
  1669. const BOOL FNoWait() const { return m_fSet >= 0; }
  1670. const BOOL FWait() const { return m_fSet < 0; }
  1671. const BOOL FNoWaitAndSet() const { return m_fSet > 0; }
  1672. const BOOL FNoWaitAndNotSet() const { return m_fSet == 0; }
  1673. const BOOL FSet() const { OSSYNCAssert( FNoWait() ); return m_fSet; }
  1674. const int CWait() const { OSSYNCAssert( FWait() ); return -m_cWaitNeg; }
  1675. const CKernelSemaphorePool::IRKSEM Irksem() const { OSSYNCAssert( FWait() ); return CKernelSemaphorePool::IRKSEM( m_irksem ); }
  1676. // debugging support
  1677. void Dump( CDumpContext& dc ) const;
  1678. private:
  1679. // data members
  1680. // transacted state representation (switched on bit 31)
  1681. union
  1682. {
  1683. // Mode 0: no waiters
  1684. volatile long m_fSet; // m_fSet = { 0, 1 }
  1685. // Mode 1: waiters
  1686. struct
  1687. {
  1688. volatile unsigned short m_irksem; // 0 <= m_irksem <= ( 1 << 16 ) - 2
  1689. volatile short m_cWaitNeg; // -( ( 1 << 15 ) - 1 ) <= m_cWaitNeg <= -1
  1690. };
  1691. };
  1692. };
  1693. // ctor
  1694. inline CManualResetSignalState::CManualResetSignalState( const int fSet )
  1695. {
  1696. // set state
  1697. m_fSet = long( fSet );
  1698. }
  1699. // ctor
  1700. inline CManualResetSignalState::CManualResetSignalState( const int cWait, const int irksem )
  1701. {
  1702. // validate IN args
  1703. OSSYNCAssert( cWait > 0 );
  1704. OSSYNCAssert( cWait <= 0x7FFF );
  1705. OSSYNCAssert( irksem >= 0 );
  1706. OSSYNCAssert( irksem <= 0xFFFE );
  1707. // set waiter count
  1708. m_cWaitNeg = short( -cWait );
  1709. // set semaphore
  1710. m_irksem = (unsigned short) irksem;
  1711. }
  1712. // changes the transacted state of the signal using a transacted memory
  1713. // compare/exchange operation, returning fFalse on failure
  1714. inline const BOOL CManualResetSignalState::FChange( const CManualResetSignalState& stateCur, const CManualResetSignalState& stateNew )
  1715. {
  1716. return AtomicCompareExchange( (long*)&m_fSet, stateCur.m_fSet, stateNew.m_fSet ) == stateCur.m_fSet;
  1717. }
  1718. // changes the transacted state of the signal to set using a transacted memory
  1719. // exchange operation and returns the original state of the signal
  1720. inline const CManualResetSignalState CManualResetSignalState::Set()
  1721. {
  1722. const CManualResetSignalState stateNew( 1 );
  1723. return CManualResetSignalState( AtomicExchange( (long*)&m_fSet, stateNew.m_fSet ) );
  1724. }
  1725. // changes the transacted state of the signal to reset using a transacted memory
  1726. // exchange operation and returns the original state of the signal
  1727. inline const CManualResetSignalState CManualResetSignalState::Reset()
  1728. {
  1729. const CManualResetSignalState stateNew( 0 );
  1730. return CManualResetSignalState( AtomicExchange( (long*)&m_fSet, stateNew.m_fSet ) );
  1731. }
  1732. // Manual-Reset Signal
  1733. class CManualResetSignal
  1734. : private CSyncObject,
  1735. private CEnhancedStateContainer< CManualResetSignalState, CSyncStateInitNull, CManualResetSignalInfo, CSyncBasicInfo >
  1736. {
  1737. public:
  1738. // member functions
  1739. // ctors / dtors
  1740. CManualResetSignal( const CSyncBasicInfo& sbi );
  1741. ~CManualResetSignal();
  1742. // manipulators
  1743. void Wait();
  1744. const BOOL FTryWait();
  1745. const BOOL FWait( const int cmsecTimeout );
  1746. void Set();
  1747. void Reset();
  1748. void Pulse();
  1749. // debugging support
  1750. void Dump( CDumpContext& dc ) const;
  1751. private:
  1752. // member functions
  1753. // operators
  1754. CManualResetSignal& operator=( CManualResetSignal& ); // disallowed
  1755. // manipulators
  1756. const BOOL _FWait( const int cmsecTimeout );
  1757. };
  1758. // waits for the signal to be set, forever if necessary
  1759. inline void CManualResetSignal::Wait()
  1760. {
  1761. // we will wait forever, so we should not timeout
  1762. int fWait = FWait( cmsecInfinite );
  1763. OSSYNCAssert( fWait );
  1764. }
  1765. // tests the state of the signal without waiting or spinning, returning fFalse
  1766. // if the signal was not set
  1767. inline const BOOL CManualResetSignal::FTryWait()
  1768. {
  1769. const BOOL fSuccess = State().FNoWaitAndSet();
  1770. // we did not successfully wait for the signal
  1771. if ( !fSuccess )
  1772. {
  1773. // this is a contention
  1774. State().SetContend();
  1775. }
  1776. // we did successfully wait for the signal
  1777. else
  1778. {
  1779. // note that we acquired the signal
  1780. State().SetAcquire();
  1781. }
  1782. return fSuccess;
  1783. }
  1784. // wait for the signal to be set, but only for the specified interval,
  1785. // returning fFalse if the wait timed out before the signal was set
  1786. inline const BOOL CManualResetSignal::FWait( const int cmsecTimeout )
  1787. {
  1788. // first try to quickly pass through the signal. if that doesn't work,
  1789. // retry wait using the full state machine
  1790. return FTryWait() || _FWait( cmsecTimeout );
  1791. }
  1792. // sets the signal, releasing any waiters
  1793. inline void CManualResetSignal::Set()
  1794. {
  1795. // change the signal state to set
  1796. const CManualResetSignalState stateOld = State().Set();
  1797. // there were waiters on the signal
  1798. if ( stateOld.FWait() )
  1799. {
  1800. // release all the waiters
  1801. ksempoolGlobal.Ksem( stateOld.Irksem(), this ).Release( stateOld.CWait() );
  1802. }
  1803. }
  1804. // resets the signal
  1805. inline void CManualResetSignal::Reset()
  1806. {
  1807. // if and only if the signal is in the set state, change it to the reset state
  1808. State().FChange( CManualResetSignalState( 1 ), CManualResetSignalState( 0 ) );
  1809. }
  1810. // resets the signal, releasing any waiters
  1811. inline void CManualResetSignal::Pulse()
  1812. {
  1813. // change the signal state to reset
  1814. const CManualResetSignalState stateOld = State().Reset();
  1815. // there were waiters on the signal
  1816. if ( stateOld.FWait() )
  1817. {
  1818. // release all the waiters
  1819. ksempoolGlobal.Ksem( stateOld.Irksem(), this ).Release( stateOld.CWait() );
  1820. }
  1821. }
  1822. // Lock Object Base Class
  1823. //
  1824. // All Lock Objects are derived from this class
  1825. class CLockObject
  1826. : public CSyncObject
  1827. {
  1828. public:
  1829. // member functions
  1830. // ctors / dtors
  1831. CLockObject() {}
  1832. ~CLockObject() {}
  1833. private:
  1834. // member functions
  1835. // operators
  1836. CLockObject& operator=( CLockObject& ); // disallowed
  1837. };
  1838. // Lock Object Basic Information
  1839. class CLockBasicInfo
  1840. : public CSyncBasicInfo
  1841. {
  1842. public:
  1843. // member functions
  1844. // ctors / dtors
  1845. CLockBasicInfo( const CSyncBasicInfo& sbi, const int rank, const int subrank );
  1846. ~CLockBasicInfo();
  1847. // accessors
  1848. #ifdef SYNC_DEADLOCK_DETECTION
  1849. const int Rank() const { return m_rank; }
  1850. const int SubRank() const { return m_subrank; }
  1851. #endif // SYNC_DEADLOCK_DETECTION
  1852. // debugging support
  1853. void Dump( CDumpContext& dc ) const;
  1854. private:
  1855. // member functions
  1856. // operators
  1857. CLockBasicInfo& operator=( CLockBasicInfo& ); // disallowed
  1858. // data members
  1859. #ifdef SYNC_DEADLOCK_DETECTION
  1860. // Rank and Subrank
  1861. int m_rank;
  1862. int m_subrank;
  1863. #endif // SYNC_DEADLOCK_DETECTION
  1864. };
  1865. // Lock Object Performance: Hold
  1866. class CLockPerfHold
  1867. {
  1868. public:
  1869. // member functions
  1870. // ctors / dtors
  1871. CLockPerfHold();
  1872. ~CLockPerfHold();
  1873. // member functions
  1874. // manipulators
  1875. void StartHold();
  1876. void StopHold();
  1877. // accessors
  1878. #ifdef SYNC_ANALYZE_PERFORMANCE
  1879. QWORD CHoldTotal() const { return m_cHold; }
  1880. double CsecHoldElapsed() const { return (double)(signed __int64)m_qwHRTHoldElapsed /
  1881. (double)(signed __int64)QwOSTimeHRTFreq(); }
  1882. #endif // SYNC_ANALYZE_PERFORMANCE
  1883. // debugging support
  1884. void Dump( CDumpContext& dc ) const;
  1885. private:
  1886. // member functions
  1887. // operators
  1888. CLockPerfHold& operator=( CLockPerfHold& ); // disallowed
  1889. // data members
  1890. #ifdef SYNC_ANALYZE_PERFORMANCE
  1891. // hold count
  1892. volatile QWORD m_cHold;
  1893. // elapsed hold time
  1894. volatile QWORD m_qwHRTHoldElapsed;
  1895. #endif // SYNC_ANALYZE_PERFORMANCE
  1896. };
  1897. // starts the hold timer for the lock object
  1898. inline void CLockPerfHold::StartHold()
  1899. {
  1900. #ifdef SYNC_ANALYZE_PERFORMANCE
  1901. // increment the hold count
  1902. AtomicAdd( (QWORD*)&m_cHold, 1 );
  1903. // subtract the start hold time from the elapsed hold time. this starts
  1904. // an elapsed time computation for this context. StopHold() will later
  1905. // add the end hold time to the elapsed time, causing the following net
  1906. // effect:
  1907. //
  1908. // m_qwHRTHoldElapsed += <end time> - <start time>
  1909. //
  1910. // we simply choose to go ahead and do the subtraction now to save storage
  1911. AtomicAdd( (QWORD*)&m_qwHRTHoldElapsed, QWORD( -__int64( QwOSTimeHRTCount() ) ) );
  1912. #endif // SYNC_ANALYZE_PERFORMANCE
  1913. }
  1914. // stops the hold timer for the lock object
  1915. inline void CLockPerfHold::StopHold()
  1916. {
  1917. #ifdef SYNC_ANALYZE_PERFORMANCE
  1918. // add the end hold time to the elapsed hold time. this completes the
  1919. // computation started in StartHold()
  1920. AtomicAdd( (QWORD*)&m_qwHRTHoldElapsed, QwOSTimeHRTCount() );
  1921. #endif // SYNC_ANALYZE_PERFORMANCE
  1922. }
  1923. // Lock Owner Record
  1924. class CLockDeadlockDetectionInfo;
  1925. class COwner
  1926. {
  1927. public:
  1928. // member functions
  1929. // ctors / dtors
  1930. COwner();
  1931. ~COwner();
  1932. void* operator new( size_t cb ) { return ESMemoryNew( cb ); }
  1933. void operator delete( void* pv ) { ESMemoryDelete( pv ); }
  1934. public:
  1935. // member functions
  1936. // operators
  1937. COwner& operator=( COwner& ); // disallowed
  1938. // data members
  1939. // owning context
  1940. CLS* m_pclsOwner;
  1941. // next context owning this lock
  1942. COwner* m_pownerContextNext;
  1943. // owned lock object
  1944. CLockDeadlockDetectionInfo* m_plddiOwned;
  1945. // next lock owned by this context
  1946. COwner* m_pownerLockNext;
  1947. // owning group for this context and lock
  1948. DWORD m_group;
  1949. };
  1950. // Lock Object Deadlock Detection Information
  1951. class CLockDeadlockDetectionInfo
  1952. {
  1953. public:
  1954. // types
  1955. // subrank used to disable deadlock detection at the subrank level
  1956. enum
  1957. {
  1958. subrankNoDeadlock = INT_MAX
  1959. };
  1960. // member functions
  1961. // ctors / dtors
  1962. CLockDeadlockDetectionInfo( const CLockBasicInfo& lbi );
  1963. ~CLockDeadlockDetectionInfo();
  1964. // member functions
  1965. // manipulators
  1966. void AddAsWaiter( const DWORD group = -1 );
  1967. void RemoveAsWaiter( const DWORD group = -1 );
  1968. void AddAsOwner( const DWORD group = -1 );
  1969. void RemoveAsOwner( const DWORD group = -1 );
  1970. static void OSSYNCAPI NextOwnershipIsNotADeadlock();
  1971. static void OSSYNCAPI DisableOwnershipTracking();
  1972. static void OSSYNCAPI EnableOwnershipTracking();
  1973. // accessors
  1974. const BOOL FOwner( const DWORD group = -1 );
  1975. const BOOL FNotOwner( const DWORD group = -1 );
  1976. const BOOL FOwned();
  1977. const BOOL FNotOwned();
  1978. const BOOL FCanBeWaiter();
  1979. const BOOL FWaiter( const DWORD group = -1 );
  1980. const BOOL FNotWaiter( const DWORD group = -1 );
  1981. #ifdef SYNC_DEADLOCK_DETECTION
  1982. const CLockBasicInfo& Info() { return *m_plbiParent; }
  1983. #endif // SYNC_DEADLOCK_DETECTION
  1984. // debugging support
  1985. void Dump( CDumpContext& dc ) const;
  1986. private:
  1987. // member functions
  1988. // operators
  1989. CLockDeadlockDetectionInfo& operator=( CLockDeadlockDetectionInfo& ); // disallowed
  1990. // data members
  1991. #ifdef SYNC_DEADLOCK_DETECTION
  1992. // parent lock object information
  1993. const CLockBasicInfo* m_plbiParent;
  1994. // semaphore protecting owner list
  1995. CSemaphore m_semOwnerList;
  1996. // owner list head
  1997. COwner m_ownerHead;
  1998. #endif // SYNC_DEADLOCK_DETECTION
  1999. };
  2000. // adds the current context as a waiter for the lock object as a member of the
  2001. // specified group
  2002. inline void CLockDeadlockDetectionInfo::AddAsWaiter( const DWORD group )
  2003. {
  2004. // this context had better not be a waiter for the lock
  2005. OSSYNCAssert( FNotWaiter( group ) );
  2006. #ifdef SYNC_DEADLOCK_DETECTION
  2007. // we had better not already be waiting for something else!
  2008. CLS* const pcls = Pcls();
  2009. OSSYNCAssert( !pcls->plddiLockWait );
  2010. OSSYNCAssert( !pcls->groupLockWait );
  2011. // add this context as a waiter for the lock
  2012. pcls->plddiLockWait = this;
  2013. pcls->groupLockWait = group;
  2014. #endif // SYNC_DEADLOCK_DETECTION
  2015. // this context had better be a waiter for the lock
  2016. OSSYNCAssert( FWaiter( group ) );
  2017. }
  2018. // removes the current context as a waiter for the lock object
  2019. inline void CLockDeadlockDetectionInfo::RemoveAsWaiter( const DWORD group )
  2020. {
  2021. // this context had better be a waiter for the lock
  2022. OSSYNCAssert( FWaiter( group ) );
  2023. #ifdef SYNC_DEADLOCK_DETECTION
  2024. // remove this context as a waiter for the lock
  2025. CLS* const pcls = Pcls();
  2026. pcls->plddiLockWait = NULL;
  2027. pcls->groupLockWait = 0;
  2028. #endif // SYNC_DEADLOCK_DETECTION
  2029. // this context had better not be a waiter for the lock anymore
  2030. OSSYNCAssert( FNotWaiter( group ) );
  2031. }
  2032. // adds the current context as an owner of the lock object as a member of the
  2033. // specified group
  2034. inline void CLockDeadlockDetectionInfo::AddAsOwner( const DWORD group )
  2035. {
  2036. // this context had better not be an owner of the lock
  2037. OSSYNCAssert( FNotOwner( group ) );
  2038. #ifdef SYNC_DEADLOCK_DETECTION
  2039. // add this context as an owner of the lock
  2040. CLS* const pcls = Pcls();
  2041. if ( !pcls->cDisableOwnershipTracking )
  2042. {
  2043. COwner* powner = &m_ownerHead;
  2044. if ( AtomicCompareExchangePointer( (void **)&powner->m_pclsOwner, NULL, pcls ) != NULL )
  2045. {
  2046. powner = new COwner;
  2047. OSSYNCEnforceSz( powner, "Failed to allocate Deadlock Detection Owner Record" );
  2048. m_semOwnerList.Acquire();
  2049. powner->m_pclsOwner = pcls;
  2050. powner->m_pownerContextNext = m_ownerHead.m_pownerContextNext;
  2051. m_ownerHead.m_pownerContextNext = powner;
  2052. m_semOwnerList.Release();
  2053. }
  2054. powner->m_plddiOwned = this;
  2055. powner->m_pownerLockNext = pcls->pownerLockHead;
  2056. pcls->pownerLockHead = powner;
  2057. powner->m_group = group;
  2058. }
  2059. // reset override
  2060. pcls->fOverrideDeadlock = fFalse;
  2061. #endif // SYNC_DEADLOCK_DETECTION
  2062. // this context had better be an owner of the lock
  2063. OSSYNCAssert( FOwner( group ) );
  2064. }
  2065. // removes the current context as an owner of the lock object
  2066. inline void CLockDeadlockDetectionInfo::RemoveAsOwner( const DWORD group )
  2067. {
  2068. // this context had better be an owner of the lock
  2069. OSSYNCAssert( FOwner( group ) );
  2070. #ifdef SYNC_DEADLOCK_DETECTION
  2071. // remove this context as an owner of the lock
  2072. CLS* const pcls = Pcls();
  2073. if ( !pcls->cDisableOwnershipTracking )
  2074. {
  2075. COwner** ppownerLock = &pcls->pownerLockHead;
  2076. while ( (*ppownerLock)->m_plddiOwned != this || (*ppownerLock)->m_group != group )
  2077. {
  2078. ppownerLock = &(*ppownerLock)->m_pownerLockNext;
  2079. }
  2080. COwner* pownerLock = *ppownerLock;
  2081. *ppownerLock = pownerLock->m_pownerLockNext;
  2082. pownerLock->m_plddiOwned = NULL;
  2083. pownerLock->m_pownerLockNext = NULL;
  2084. pownerLock->m_group = 0;
  2085. if ( AtomicCompareExchangePointer( (void**) &m_ownerHead.m_pclsOwner, pcls, NULL ) != pcls )
  2086. {
  2087. m_semOwnerList.Acquire();
  2088. COwner** ppownerContext = &m_ownerHead.m_pownerContextNext;
  2089. while ( (*ppownerContext)->m_pclsOwner != pcls )
  2090. {
  2091. ppownerContext = &(*ppownerContext)->m_pownerContextNext;
  2092. }
  2093. COwner* pownerContext = *ppownerContext;
  2094. *ppownerContext = pownerContext->m_pownerContextNext;
  2095. m_semOwnerList.Release();
  2096. delete pownerContext;
  2097. }
  2098. }
  2099. #endif // SYNC_DEADLOCK_DETECTION
  2100. // this context had better not be an owner of the lock anymore
  2101. OSSYNCAssert( FNotOwner( group ) );
  2102. }
  2103. // overrides deadlock detection using ranks for the next ownership
  2104. inline void OSSYNCAPI CLockDeadlockDetectionInfo::NextOwnershipIsNotADeadlock()
  2105. {
  2106. #ifdef SYNC_DEADLOCK_DETECTION
  2107. Pcls()->fOverrideDeadlock = fTrue;
  2108. #endif // SYNC_DEADLOCK_DETECTION
  2109. }
  2110. // disables ownership tracking for this context
  2111. inline void OSSYNCAPI CLockDeadlockDetectionInfo::DisableOwnershipTracking()
  2112. {
  2113. #ifdef SYNC_DEADLOCK_DETECTION
  2114. Pcls()->cDisableOwnershipTracking++;
  2115. #endif // SYNC_DEADLOCK_DETECTION
  2116. }
  2117. // enables ownership tracking for this context
  2118. inline void OSSYNCAPI CLockDeadlockDetectionInfo::EnableOwnershipTracking()
  2119. {
  2120. #ifdef SYNC_DEADLOCK_DETECTION
  2121. Pcls()->cDisableOwnershipTracking--;
  2122. #endif // SYNC_DEADLOCK_DETECTION
  2123. }
  2124. // returns fTrue if the current context is an owner of the lock object
  2125. //
  2126. // NOTE: if deadlock detection is disabled, this function will always return
  2127. // fTrue
  2128. inline const BOOL CLockDeadlockDetectionInfo::FOwner( const DWORD group )
  2129. {
  2130. #ifdef SYNC_DEADLOCK_DETECTION
  2131. COwner* pownerLock = Pcls()->pownerLockHead;
  2132. while ( pownerLock && ( pownerLock->m_plddiOwned != this || pownerLock->m_group != group ) )
  2133. {
  2134. pownerLock = pownerLock->m_pownerLockNext;
  2135. }
  2136. return Pcls()->cDisableOwnershipTracking != 0 ||
  2137. pownerLock && pownerLock->m_group == group;
  2138. #else // !SYNC_DEADLOCK_DETECTION
  2139. return fTrue;
  2140. #endif // SYNC_DEADLOCK_DETECTION
  2141. }
  2142. // returns fTrue if the current context is not an owner of the lock object
  2143. //
  2144. // NOTE: if deadlock detection is disabled, this function will always return
  2145. // fTrue
  2146. inline const BOOL CLockDeadlockDetectionInfo::FNotOwner( const DWORD group )
  2147. {
  2148. #ifdef SYNC_DEADLOCK_DETECTION
  2149. return Pcls()->cDisableOwnershipTracking != 0 || !FOwner( group );
  2150. #else // !SYNC_DEADLOCK_DETECTION
  2151. return fTrue;
  2152. #endif // SYNC_DEADLOCK_DETECTION
  2153. }
  2154. // returns fTrue if any context is an owner of the lock object
  2155. //
  2156. // NOTE: if deadlock detection is disabled, this function will always return
  2157. // fTrue
  2158. inline const BOOL CLockDeadlockDetectionInfo::FOwned()
  2159. {
  2160. #ifdef SYNC_DEADLOCK_DETECTION
  2161. return m_ownerHead.m_pclsOwner || m_ownerHead.m_pownerContextNext;
  2162. #else // !SYNC_DEADLOCK_DETECTION
  2163. return fTrue;
  2164. #endif // SYNC_DEADLOCK_DETECTION
  2165. }
  2166. // returns fTrue if no context is an owner of the lock object
  2167. //
  2168. // NOTE: if deadlock detection is disabled, this function will always return
  2169. // fTrue
  2170. inline const BOOL CLockDeadlockDetectionInfo::FNotOwned()
  2171. {
  2172. #ifdef SYNC_DEADLOCK_DETECTION
  2173. return !FOwned();
  2174. #else // !SYNC_DEADLOCK_DETECTION
  2175. return fTrue;
  2176. #endif // SYNC_DEADLOCK_DETECTION
  2177. }
  2178. // returns fTrue if the current context can wait for the lock object without
  2179. // violating any deadlock constraints
  2180. //
  2181. // NOTE: if deadlock detection is disabled, this function will always return
  2182. // fTrue
  2183. inline const BOOL CLockDeadlockDetectionInfo::FCanBeWaiter()
  2184. {
  2185. #ifdef SYNC_DEADLOCK_DETECTION
  2186. // find the minimum rank, subrank of all locks owned by the current context
  2187. CLS* const pcls = Pcls();
  2188. COwner* powner = pcls->pownerLockHead;
  2189. int Rank = INT_MAX;
  2190. int SubRank = INT_MAX;
  2191. while ( powner )
  2192. {
  2193. if ( powner->m_plddiOwned->Info().Rank() < Rank ||
  2194. ( powner->m_plddiOwned->Info().Rank() == Rank &&
  2195. powner->m_plddiOwned->Info().SubRank() < SubRank ) )
  2196. {
  2197. Rank = powner->m_plddiOwned->Info().Rank();
  2198. SubRank = powner->m_plddiOwned->Info().SubRank();
  2199. }
  2200. powner = powner->m_pownerLockNext;
  2201. }
  2202. // test this rank, subrank against our rank, subrank
  2203. return Rank > Info().Rank() ||
  2204. ( Rank == Info().Rank() && SubRank > Info().SubRank() ) ||
  2205. ( Rank == Info().Rank() && SubRank == Info().SubRank() &&
  2206. SubRank == subrankNoDeadlock ) ||
  2207. pcls->fOverrideDeadlock;
  2208. #else // !SYNC_DEADLOCK_DETECTION
  2209. return fTrue;
  2210. #endif // SYNC_DEADLOCK_DETECTION
  2211. }
  2212. // returns fTrue if the current context is a waiter of the lock object
  2213. //
  2214. // NOTE: if deadlock detection is disabled, this function will always return
  2215. // fTrue
  2216. inline const BOOL CLockDeadlockDetectionInfo::FWaiter( const DWORD group )
  2217. {
  2218. #ifdef SYNC_DEADLOCK_DETECTION
  2219. CLS* const pcls = Pcls();
  2220. return pcls->plddiLockWait == this && pcls->groupLockWait == group;
  2221. #else // !SYNC_DEADLOCK_DETECTION
  2222. return fTrue;
  2223. #endif // SYNC_DEADLOCK_DETECTION
  2224. }
  2225. // returns fTrue if the current context is not a waiter of the lock object
  2226. //
  2227. // NOTE: if deadlock detection is disabled, this function will always return
  2228. // fTrue
  2229. inline const BOOL CLockDeadlockDetectionInfo::FNotWaiter( const DWORD group )
  2230. {
  2231. #ifdef SYNC_DEADLOCK_DETECTION
  2232. return !FWaiter( group );
  2233. #else // !SYNC_DEADLOCK_DETECTION
  2234. return fTrue;
  2235. #endif // SYNC_DEADLOCK_DETECTION
  2236. }
  2237. // Critical Section (non-nestable) Information
  2238. class CCriticalSectionInfo
  2239. : public CLockBasicInfo,
  2240. public CLockPerfHold,
  2241. public CLockDeadlockDetectionInfo
  2242. {
  2243. public:
  2244. // member functions
  2245. // ctors / dtors
  2246. CCriticalSectionInfo( const CLockBasicInfo& lbi )
  2247. : CLockBasicInfo( lbi ),
  2248. CLockDeadlockDetectionInfo( (CLockBasicInfo&) *this )
  2249. {
  2250. }
  2251. // debugging support
  2252. void Dump( CDumpContext& dc ) const;
  2253. };
  2254. // Critical Section (non-nestable) State
  2255. class CCriticalSectionState
  2256. {
  2257. public:
  2258. // member functions
  2259. // ctors / dtors
  2260. CCriticalSectionState( const CSyncBasicInfo& sbi );
  2261. ~CCriticalSectionState();
  2262. // accessors
  2263. CSemaphore& Semaphore() { return m_sem; }
  2264. // debugging support
  2265. void Dump( CDumpContext& dc ) const;
  2266. private:
  2267. // member functions
  2268. // operators
  2269. CCriticalSectionState& operator=( CCriticalSectionState& ); // disallowed
  2270. // data members
  2271. // semaphore
  2272. CSemaphore m_sem;
  2273. };
  2274. // Critical Section (non-nestable)
  2275. class CCriticalSection
  2276. : private CLockObject,
  2277. private CEnhancedStateContainer< CCriticalSectionState, CSyncBasicInfo, CCriticalSectionInfo, CLockBasicInfo >
  2278. {
  2279. public:
  2280. // member functions
  2281. // ctors / dtors
  2282. CCriticalSection( const CLockBasicInfo& lbi );
  2283. ~CCriticalSection();
  2284. // manipulators
  2285. void Enter();
  2286. const BOOL FTryEnter();
  2287. const BOOL FEnter( const int cmsecTimeout );
  2288. void Leave();
  2289. // accessors
  2290. const int CWait() { return State().Semaphore().CWait(); }
  2291. const BOOL FOwner() { return State().FOwner(); }
  2292. const BOOL FNotOwner() { return State().FNotOwner(); }
  2293. // debugging support
  2294. void Dump( CDumpContext& dc ) const;
  2295. private:
  2296. // member functions
  2297. // operators
  2298. CCriticalSection& operator=( CCriticalSection& ); // disallowed
  2299. };
  2300. // enter the critical section, waiting forever if someone else is currently the
  2301. // owner. the critical section can not be re-entered until it has been left
  2302. inline void CCriticalSection::Enter()
  2303. {
  2304. // check for deadlock
  2305. OSSYNCAssertSzRTL( State().FCanBeWaiter(), "Potential Deadlock Detected (Rank Violation)" );
  2306. // acquire the semaphore
  2307. State().AddAsWaiter();
  2308. State().Semaphore().Acquire();
  2309. State().RemoveAsWaiter();
  2310. // there had better be no available counts on the semaphore
  2311. OSSYNCAssert( !State().Semaphore().CAvail() );
  2312. // we are now the owner of the critical section
  2313. State().AddAsOwner();
  2314. State().StartHold();
  2315. }
  2316. // try to enter the critical section without waiting or spinning, returning
  2317. // fFalse if someone else currently is the owner. the critical section can not
  2318. // be re-entered until it has been left
  2319. inline const BOOL CCriticalSection::FTryEnter()
  2320. {
  2321. // try to acquire the semaphore without waiting or spinning
  2322. //
  2323. // NOTE: there is no potential for deadlock here, so don't bother to check
  2324. BOOL fAcquire = State().Semaphore().FTryAcquire();
  2325. // we are now the owner of the critical section
  2326. if ( fAcquire )
  2327. {
  2328. // there had better be no available counts on the semaphore
  2329. OSSYNCAssert( !State().Semaphore().CAvail() );
  2330. // add ourself as the owner
  2331. State().AddAsOwner();
  2332. State().StartHold();
  2333. }
  2334. return fAcquire;
  2335. }
  2336. // try to enter the critical section waiting only for the specified interval,
  2337. // returning fFalse if the wait timed out before the critical section could be
  2338. // acquired. the critical section can not be re-entered until it has been left
  2339. inline const BOOL CCriticalSection::FEnter( const int cmsecTimeout )
  2340. {
  2341. // check for deadlock if we are waiting forever
  2342. OSSYNCAssertSzRTL( cmsecTimeout != cmsecInfinite || State().FCanBeWaiter(), "Potential Deadlock Detected (Rank Violation)" );
  2343. // try to acquire the semaphore, timing out as requested
  2344. //
  2345. // NOTE: there is still a potential for deadlock, but that will be detected
  2346. // at the OS level
  2347. State().AddAsWaiter();
  2348. BOOL fAcquire = State().Semaphore().FAcquire( cmsecTimeout );
  2349. State().RemoveAsWaiter();
  2350. // we are now the owner of the critical section
  2351. if ( fAcquire )
  2352. {
  2353. // there had better be no available counts on the semaphore
  2354. OSSYNCAssert( !State().Semaphore().CAvail() );
  2355. // add ourself as the owner
  2356. State().AddAsOwner();
  2357. State().StartHold();
  2358. }
  2359. return fAcquire;
  2360. }
  2361. // leaves the critical section, releasing it for ownership by someone else
  2362. inline void CCriticalSection::Leave()
  2363. {
  2364. // remove ourself as the owner
  2365. State().RemoveAsOwner();
  2366. // we are no longer holding the lock
  2367. State().StopHold();
  2368. // there had better be no available counts on the semaphore
  2369. OSSYNCAssert( !State().Semaphore().CAvail() );
  2370. // release the semaphore
  2371. State().Semaphore().Release();
  2372. }
  2373. // Nestable Critical Section Information
  2374. class CNestableCriticalSectionInfo
  2375. : public CLockBasicInfo,
  2376. public CLockPerfHold,
  2377. public CLockDeadlockDetectionInfo
  2378. {
  2379. public:
  2380. // member functions
  2381. // ctors / dtors
  2382. CNestableCriticalSectionInfo( const CLockBasicInfo& lbi )
  2383. : CLockBasicInfo( lbi ),
  2384. CLockDeadlockDetectionInfo( (CLockBasicInfo&) *this )
  2385. {
  2386. }
  2387. // debugging support
  2388. void Dump( CDumpContext& dc ) const;
  2389. };
  2390. // Nestable Critical Section State
  2391. class CNestableCriticalSectionState
  2392. {
  2393. public:
  2394. // member functions
  2395. // ctors / dtors
  2396. CNestableCriticalSectionState( const CSyncBasicInfo& sbi );
  2397. ~CNestableCriticalSectionState();
  2398. // manipulators
  2399. void SetOwner( CLS* const pcls );
  2400. void Enter();
  2401. void Leave();
  2402. // accessors
  2403. CSemaphore& Semaphore() { return m_sem; }
  2404. CLS* PclsOwner() { return m_pclsOwner; }
  2405. int CEntry() { return m_cEntry; }
  2406. // debugging support
  2407. void Dump( CDumpContext& dc ) const;
  2408. private:
  2409. // member functions
  2410. // operators
  2411. CNestableCriticalSectionState& operator=( CNestableCriticalSectionState& ); // disallowed
  2412. // data members
  2413. // semaphore
  2414. CSemaphore m_sem;
  2415. // owning context (protected by the semaphore)
  2416. CLS* volatile m_pclsOwner;
  2417. // entry count (only valid when the owner id is valid)
  2418. volatile int m_cEntry;
  2419. };
  2420. // set the owner
  2421. inline void CNestableCriticalSectionState::SetOwner( CLS* const pcls )
  2422. {
  2423. // we had either be clearing the owner or setting a new owner. we should
  2424. // never be overwriting another owner
  2425. OSSYNCAssert( !pcls || !m_pclsOwner );
  2426. // set the new owner
  2427. m_pclsOwner = pcls;
  2428. }
  2429. // increment the entry count
  2430. inline void CNestableCriticalSectionState::Enter()
  2431. {
  2432. // we had better have an owner already!
  2433. OSSYNCAssert( m_pclsOwner );
  2434. // we should not overflow the entry count
  2435. OSSYNCAssert( int( m_cEntry + 1 ) >= 1 );
  2436. // increment the entry count
  2437. m_cEntry++;
  2438. }
  2439. // decrement the entry count
  2440. inline void CNestableCriticalSectionState::Leave()
  2441. {
  2442. // we had better have an owner already!
  2443. OSSYNCAssert( m_pclsOwner );
  2444. // decrement the entry count
  2445. m_cEntry--;
  2446. }
  2447. // Nestable Critical Section
  2448. class CNestableCriticalSection
  2449. : private CLockObject,
  2450. private CEnhancedStateContainer< CNestableCriticalSectionState, CSyncBasicInfo, CNestableCriticalSectionInfo, CLockBasicInfo >
  2451. {
  2452. public:
  2453. // member functions
  2454. // ctors / dtors
  2455. CNestableCriticalSection( const CLockBasicInfo& lbi );
  2456. ~CNestableCriticalSection();
  2457. // manipulators
  2458. void Enter();
  2459. const BOOL FTryEnter();
  2460. const BOOL FEnter( const int cmsecTimeout );
  2461. void Leave();
  2462. // accessors
  2463. const int CWait() { return State().Semaphore().CWait(); }
  2464. const BOOL FOwner() { return State().FOwner(); }
  2465. const BOOL FNotOwner() { return State().FNotOwner(); }
  2466. // debugging support
  2467. void Dump( CDumpContext& dc ) const;
  2468. private:
  2469. // member functions
  2470. // operators
  2471. CNestableCriticalSection& operator=( CNestableCriticalSection& ); // disallowed
  2472. };
  2473. // enter the critical section, waiting forever if someone else is currently the
  2474. // owner. the critical section can be reentered without waiting or deadlocking
  2475. inline void CNestableCriticalSection::Enter()
  2476. {
  2477. // get our context
  2478. CLS* const pcls = Pcls();
  2479. // we own the critical section
  2480. if ( State().PclsOwner() == pcls )
  2481. {
  2482. // there had better be no available counts on the semaphore
  2483. OSSYNCAssert( !State().Semaphore().CAvail() );
  2484. // we should have at least one entry count
  2485. OSSYNCAssert( State().CEntry() >= 1 );
  2486. // increment our entry count
  2487. State().Enter();
  2488. }
  2489. // we do not own the critical section
  2490. else
  2491. {
  2492. OSSYNCAssert( State().PclsOwner() != pcls );
  2493. // check for deadlock
  2494. OSSYNCAssertSzRTL( State().FCanBeWaiter(), "Potential Deadlock Detected (Rank Violation)" );
  2495. // acquire the semaphore
  2496. State().AddAsWaiter();
  2497. State().Semaphore().Acquire();
  2498. State().RemoveAsWaiter();
  2499. // there had better be no available counts on the semaphore
  2500. OSSYNCAssert( !State().Semaphore().CAvail() );
  2501. // we are now the owner of the critical section
  2502. State().AddAsOwner();
  2503. State().StartHold();
  2504. // save our context as the owner
  2505. State().SetOwner( pcls );
  2506. // set initial entry count
  2507. State().Enter();
  2508. }
  2509. }
  2510. // try to enter the critical section without waiting or spinning, returning
  2511. // fFalse if someone else currently is the owner. the critical section can be
  2512. // reentered without waiting or deadlocking
  2513. inline const BOOL CNestableCriticalSection::FTryEnter()
  2514. {
  2515. // get our context
  2516. CLS* const pcls = Pcls();
  2517. // we own the critical section
  2518. if ( State().PclsOwner() == pcls )
  2519. {
  2520. // there had better be no available counts on the semaphore
  2521. OSSYNCAssert( !State().Semaphore().CAvail() );
  2522. // we should have at least one entry count
  2523. OSSYNCAssert( State().CEntry() >= 1 );
  2524. // increment our entry count
  2525. State().Enter();
  2526. // return success
  2527. return fTrue;
  2528. }
  2529. // we do not own the critical section
  2530. else
  2531. {
  2532. OSSYNCAssert( State().PclsOwner() != pcls );
  2533. // try to acquire the semaphore without waiting or spinning
  2534. //
  2535. // NOTE: there is no potential for deadlock here, so don't bother to check
  2536. const BOOL fAcquired = State().Semaphore().FTryAcquire();
  2537. // we now own the critical section
  2538. if ( fAcquired )
  2539. {
  2540. // there had better be no available counts on the semaphore
  2541. OSSYNCAssert( !State().Semaphore().CAvail() );
  2542. // add ourself as the owner
  2543. State().AddAsOwner();
  2544. State().StartHold();
  2545. // save our context as the owner
  2546. State().SetOwner( pcls );
  2547. // set initial entry count
  2548. State().Enter();
  2549. }
  2550. // return result
  2551. return fAcquired;
  2552. }
  2553. }
  2554. // try to enter the critical section waiting only for the specified interval,
  2555. // returning fFalse if the wait timed out before the critical section could be
  2556. // acquired. the critical section can be reentered without waiting or
  2557. // deadlocking
  2558. inline const BOOL CNestableCriticalSection::FEnter( const int cmsecTimeout )
  2559. {
  2560. // get our context
  2561. CLS* const pcls = Pcls();
  2562. // we own the critical section
  2563. if ( State().PclsOwner() == pcls )
  2564. {
  2565. // there had better be no available counts on the semaphore
  2566. OSSYNCAssert( !State().Semaphore().CAvail() );
  2567. // we should have at least one entry count
  2568. OSSYNCAssert( State().CEntry() >= 1 );
  2569. // increment our entry count
  2570. State().Enter();
  2571. // return success
  2572. return fTrue;
  2573. }
  2574. // we do not own the critical section
  2575. else
  2576. {
  2577. OSSYNCAssert( State().PclsOwner() != pcls );
  2578. // check for deadlock if we are waiting forever
  2579. OSSYNCAssertSzRTL( cmsecTimeout != cmsecInfinite || State().FCanBeWaiter(), "Potential Deadlock Detected (Rank Violation)" );
  2580. // try to acquire the semaphore, timing out as requested
  2581. //
  2582. // NOTE: there is still a potential for deadlock, but that will be detected
  2583. // at the OS level
  2584. State().AddAsWaiter();
  2585. const BOOL fAcquired = State().Semaphore().FAcquire( cmsecTimeout );
  2586. State().RemoveAsWaiter();
  2587. // we now own the critical section
  2588. if ( fAcquired )
  2589. {
  2590. // there had better be no available counts on the semaphore
  2591. OSSYNCAssert( !State().Semaphore().CAvail() );
  2592. // add ourself as the owner
  2593. State().AddAsOwner();
  2594. State().StartHold();
  2595. // save our context as the owner
  2596. State().SetOwner( pcls );
  2597. // set initial entry count
  2598. State().Enter();
  2599. }
  2600. // return result
  2601. return fAcquired;
  2602. }
  2603. }
  2604. // leave the critical section. if leave has been called for every enter that
  2605. // has completed successfully, the critical section is released for ownership
  2606. // by someone else
  2607. inline void CNestableCriticalSection::Leave()
  2608. {
  2609. // we had better be the current owner
  2610. OSSYNCAssert( State().PclsOwner() == Pcls() );
  2611. // there had better be no available counts on the semaphore
  2612. OSSYNCAssert( !State().Semaphore().CAvail() );
  2613. // there had better be at least one entry count
  2614. OSSYNCAssert( State().CEntry() >= 1 );
  2615. // release one entry count
  2616. State().Leave();
  2617. // we released the last entry count
  2618. if ( !State().CEntry() )
  2619. {
  2620. // reset the owner id
  2621. State().SetOwner( 0 );
  2622. // remove ourself as the owner
  2623. State().RemoveAsOwner();
  2624. // we are no longer holding the lock
  2625. State().StopHold();
  2626. // release the semaphore
  2627. State().Semaphore().Release();
  2628. }
  2629. }
  2630. // Gate Information
  2631. class CGateInfo
  2632. : public CSyncBasicInfo,
  2633. public CSyncPerfWait
  2634. {
  2635. public:
  2636. // member functions
  2637. // ctors / dtors
  2638. CGateInfo( const CSyncBasicInfo& sbi )
  2639. : CSyncBasicInfo( sbi )
  2640. {
  2641. }
  2642. // debugging support
  2643. void Dump( CDumpContext& dc ) const;
  2644. };
  2645. // Gate State
  2646. class CGateState
  2647. {
  2648. public:
  2649. // member functions
  2650. // ctors / dtors
  2651. CGateState( const CSyncStateInitNull& null ) : m_cWait( 0 ), m_irksem( CKernelSemaphorePool::irksemNil ) {}
  2652. CGateState( const int cWait, const int irksem );
  2653. ~CGateState() {}
  2654. // manipulators
  2655. void SetWaitCount( const int cWait );
  2656. void SetIrksem( const CKernelSemaphorePool::IRKSEM irksem );
  2657. // accessors
  2658. const int CWait() const { return m_cWait; }
  2659. const CKernelSemaphorePool::IRKSEM Irksem() const { return CKernelSemaphorePool::IRKSEM( m_irksem ); }
  2660. // debugging support
  2661. void Dump( CDumpContext& dc ) const;
  2662. private:
  2663. // member functions
  2664. // operators
  2665. CGateState& operator=( CGateState& ); // disallowed
  2666. // data members
  2667. // waiter count
  2668. volatile short m_cWait; // 0 <= m_cWait <= ( 1 << 15 ) - 1
  2669. // reference kernel semaphore
  2670. volatile unsigned short m_irksem; // 0 <= m_irksem <= ( 1 << 16 ) - 2
  2671. };
  2672. // sets the wait count for the gate
  2673. inline void CGateState::SetWaitCount( const int cWait )
  2674. {
  2675. // it must be a valid wait count
  2676. OSSYNCAssert( cWait >= 0 );
  2677. OSSYNCAssert( cWait <= 0x7FFF );
  2678. // set the wait count
  2679. m_cWait = (unsigned short) cWait;
  2680. }
  2681. // sets the referenced kernel semaphore for the gate
  2682. inline void CGateState::SetIrksem( const CKernelSemaphorePool::IRKSEM irksem )
  2683. {
  2684. // it must be a valid irksem
  2685. OSSYNCAssert( irksem >= 0 );
  2686. OSSYNCAssert( irksem <= 0xFFFF );
  2687. // set the irksem
  2688. m_irksem = (unsigned short) irksem;
  2689. }
  2690. // Gate
  2691. class CGate
  2692. : private CSyncObject,
  2693. private CEnhancedStateContainer< CGateState, CSyncStateInitNull, CGateInfo, CSyncBasicInfo >
  2694. {
  2695. public:
  2696. // member functions
  2697. // ctors / dtors
  2698. CGate( const CSyncBasicInfo& sbi );
  2699. ~CGate();
  2700. // manipulators
  2701. void Wait( CCriticalSection& crit );
  2702. void Release( CCriticalSection& crit, const int cToRelease = 1 );
  2703. void ReleaseAndHold( CCriticalSection& crit, const int cToRelease = 1 );
  2704. // accessors
  2705. const int CWait() const { return State().CWait(); }
  2706. // debugging support
  2707. void Dump( CDumpContext& dc ) const;
  2708. private:
  2709. // member functions
  2710. // operators
  2711. CGate& operator=( CGate& ); // disallowed
  2712. };
  2713. // Null Lock Object State Initializer
  2714. class CLockStateInitNull
  2715. {
  2716. };
  2717. extern const CLockStateInitNull lockstateNull;
  2718. // Binary Lock Performance Information
  2719. class CBinaryLockPerfInfo
  2720. : public CSyncPerfWait,
  2721. public CSyncPerfAcquire,
  2722. public CLockPerfHold
  2723. {
  2724. public:
  2725. // member functions
  2726. // ctors / dtors
  2727. CBinaryLockPerfInfo()
  2728. {
  2729. }
  2730. // debugging support
  2731. void Dump( CDumpContext& dc ) const;
  2732. };
  2733. // Binary Lock Group Information
  2734. class CBinaryLockGroupInfo
  2735. {
  2736. public:
  2737. // member functions
  2738. // ctors / dtors
  2739. CBinaryLockGroupInfo() {}
  2740. ~CBinaryLockGroupInfo() {}
  2741. // manipulators
  2742. void StartWait( const int iGroup ) { m_rginfo[iGroup].StartWait(); }
  2743. void StopWait( const int iGroup ) { m_rginfo[iGroup].StopWait(); }
  2744. void SetAcquire( const int iGroup ) { m_rginfo[iGroup].SetAcquire(); }
  2745. void SetContend( const int iGroup ) { m_rginfo[iGroup].SetContend(); }
  2746. void StartHold( const int iGroup ) { m_rginfo[iGroup].StartHold(); }
  2747. void StopHold( const int iGroup ) { m_rginfo[iGroup].StopHold(); }
  2748. // accessors
  2749. #ifdef SYNC_ANALYZE_PERFORMANCE
  2750. QWORD CWaitTotal( const int iGroup ) const { return m_rginfo[iGroup].CWaitTotal(); }
  2751. double CsecWaitElapsed( const int iGroup ) const { return m_rginfo[iGroup].CsecWaitElapsed(); }
  2752. QWORD CAcquireTotal( const int iGroup ) const { return m_rginfo[iGroup].CAcquireTotal(); }
  2753. QWORD CContendTotal( const int iGroup ) const { return m_rginfo[iGroup].CContendTotal(); }
  2754. QWORD CHoldTotal( const int iGroup ) const { return m_rginfo[iGroup].CHoldTotal(); }
  2755. double CsecHoldElapsed( const int iGroup ) const { return m_rginfo[iGroup].CsecHoldElapsed(); }
  2756. #endif // SYNC_ANALYZE_PERFORMANCE
  2757. // debugging support
  2758. void Dump( CDumpContext& dc ) const;
  2759. private:
  2760. // member functions
  2761. // operators
  2762. CBinaryLockGroupInfo& operator=( CBinaryLockGroupInfo& ); // disallowed
  2763. // data members
  2764. // performance info for each group
  2765. CBinaryLockPerfInfo m_rginfo[2];
  2766. };
  2767. // Binary Lock Information
  2768. class CBinaryLockInfo
  2769. : public CLockBasicInfo,
  2770. public CBinaryLockGroupInfo,
  2771. public CLockDeadlockDetectionInfo
  2772. {
  2773. public:
  2774. // member functions
  2775. // ctors / dtors
  2776. CBinaryLockInfo( const CLockBasicInfo& lbi )
  2777. : CLockBasicInfo( lbi ),
  2778. CLockDeadlockDetectionInfo( (CLockBasicInfo&) *this )
  2779. {
  2780. }
  2781. // debugging support
  2782. void Dump( CDumpContext& dc ) const;
  2783. };
  2784. // Binary Lock State
  2785. class CBinaryLockState
  2786. {
  2787. public:
  2788. // types
  2789. // control word
  2790. typedef DWORD ControlWord;
  2791. // member functions
  2792. // ctors / dtors
  2793. CBinaryLockState( const CSyncBasicInfo& sbi );
  2794. ~CBinaryLockState();
  2795. // debugging support
  2796. void Dump( CDumpContext& dc ) const;
  2797. // data members
  2798. // control word
  2799. union
  2800. {
  2801. volatile ControlWord m_cw;
  2802. struct
  2803. {
  2804. volatile DWORD m_cOOW1:15;
  2805. volatile DWORD m_fQ1:1;
  2806. volatile DWORD m_cOOW2:15;
  2807. volatile DWORD m_fQ2:1;
  2808. };
  2809. };
  2810. // quiesced owner count
  2811. volatile DWORD m_cOwner;
  2812. // sempahore used by Group 1 to wait for lock ownership
  2813. CSemaphore m_sem1;
  2814. // sempahore used by Group 2 to wait for lock ownership
  2815. CSemaphore m_sem2;
  2816. private:
  2817. // member functions
  2818. // operators
  2819. CBinaryLockState& operator=( CBinaryLockState& ); // disallowed
  2820. };
  2821. // Binary Lock
  2822. class CBinaryLock
  2823. : private CLockObject,
  2824. private CEnhancedStateContainer< CBinaryLockState, CSyncBasicInfo, CBinaryLockInfo, CLockBasicInfo >
  2825. {
  2826. public:
  2827. // types
  2828. // control word
  2829. typedef CBinaryLockState::ControlWord ControlWord;
  2830. // transition reasons for state machine
  2831. enum TransitionReason
  2832. {
  2833. trIllegal = 0,
  2834. trEnter1 = 1,
  2835. trLeave1 = 2,
  2836. trEnter2 = 4,
  2837. trLeave2 = 8,
  2838. };
  2839. // member functions
  2840. // ctors / dtors
  2841. CBinaryLock( const CLockBasicInfo& lbi );
  2842. ~CBinaryLock();
  2843. // manipulators
  2844. void Enter1();
  2845. const BOOL FTryEnter1();
  2846. void Leave1();
  2847. void Enter2();
  2848. const BOOL FTryEnter2();
  2849. void Leave2();
  2850. // accessors
  2851. const BOOL FGroup1Quiesced() { return State().m_cw & 0x00008000; }
  2852. const BOOL FGroup2Quiesced() { return State().m_cw & 0x80000000; }
  2853. const BOOL FMemberOfGroup1() { return State().FOwner( 0 ); }
  2854. const BOOL FNotMemberOfGroup1() { return State().FNotOwner( 0 ); }
  2855. const BOOL FMemberOfGroup2() { return State().FOwner( 1 ); }
  2856. const BOOL FNotMemberOfGroup2() { return State().FNotOwner( 1 ); }
  2857. // debugging support
  2858. void Dump( CDumpContext& dc ) const;
  2859. private:
  2860. // member functions
  2861. // operators
  2862. CBinaryLock& operator=( CBinaryLock& ); // disallowed
  2863. // verification
  2864. int _StateFromControlWord( const ControlWord cw );
  2865. BOOL _FValidStateTransition( const ControlWord cwBI,
  2866. const ControlWord cwAI,
  2867. const TransitionReason tr );
  2868. // manipulators
  2869. void _Enter1( const ControlWord cwBIOld );
  2870. void _Enter2( const ControlWord cwBIOld );
  2871. void _UpdateQuiescedOwnerCountAsGroup1( const DWORD cOwnerDelta );
  2872. void _UpdateQuiescedOwnerCountAsGroup2( const DWORD cOwnerDelta );
  2873. };
  2874. // enters the binary lock as a member of Group 1, waiting forever if necessary
  2875. //
  2876. // NOTE: trying to enter the lock as a member of Group 1 when you already own
  2877. // the lock as a member of Group 2 will cause a deadlock.
  2878. inline void CBinaryLock::Enter1()
  2879. {
  2880. // we had better not already own this lock as either group
  2881. OSSYNCAssert( State().FNotOwner( 0 ) );
  2882. OSSYNCAssert( State().FNotOwner( 1 ) );
  2883. // check for deadlock
  2884. OSSYNCAssertSzRTL( State().FCanBeWaiter(), "Potential Deadlock Detected (Rank Violation)" );
  2885. // try forever until we successfully change the lock state
  2886. OSSYNC_FOREVER
  2887. {
  2888. // read the current state of the control word as our expected before image
  2889. const ControlWord cwBIExpected = State().m_cw;
  2890. // compute the after image of the control word by performing the global
  2891. // transform for the Enter1 state transition
  2892. const ControlWord cwAI = ControlWord( ( ( cwBIExpected & ( ( LONG_PTR( long( cwBIExpected ) ) >> 31 ) |
  2893. 0x0000FFFF ) ) | 0x80000000 ) + 0x00000001 );
  2894. // validate the transaction
  2895. OSSYNCAssert( _FValidStateTransition( cwBIExpected, cwAI, trEnter1 ) );
  2896. // attempt to perform the transacted state transition on the control word
  2897. const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );
  2898. // the transaction failed or Group 1 was quiesced from ownership
  2899. if ( ( cwBI ^ cwBIExpected ) | ( cwBI & 0x00008000 ) )
  2900. {
  2901. // the transaction failed because another context changed the control word
  2902. if ( cwBI != cwBIExpected )
  2903. {
  2904. // try again
  2905. continue;
  2906. }
  2907. // the transaction succeeded but Group 1 was quiesced from ownership
  2908. else
  2909. {
  2910. // this is a contention for Group 1
  2911. State().SetContend( 0 );
  2912. // wait to own the lock as a member of Group 1
  2913. _Enter1( cwBI );
  2914. // we now own the lock, so we're done
  2915. break;
  2916. }
  2917. }
  2918. // the transaction succeeded and Group 1 was not quiesced from ownership
  2919. else
  2920. {
  2921. // we now own the lock, so we're done
  2922. break;
  2923. }
  2924. }
  2925. // we are now an owner of the lock for Group 1
  2926. State().SetAcquire( 0 );
  2927. State().AddAsOwner( 0 );
  2928. State().StartHold( 0 );
  2929. }
  2930. // tries to enter the binary lock as a member of Group 1 without waiting or
  2931. // spinning, returning fFalse if Group 1 is quiesced from ownership
  2932. //
  2933. // NOTE: trying to enter the lock as a member of Group 1 when you already own
  2934. // the lock as a member of Group 2 will cause a deadlock.
  2935. inline const BOOL CBinaryLock::FTryEnter1()
  2936. {
  2937. // we had better not already own this lock as either group
  2938. OSSYNCAssert( State().FNotOwner( 0 ) );
  2939. OSSYNCAssert( State().FNotOwner( 1 ) );
  2940. // try forever until we successfully change the lock state
  2941. OSSYNC_FOREVER
  2942. {
  2943. // read the current state of the control word as our expected before image
  2944. ControlWord cwBIExpected = State().m_cw;
  2945. // change the expected before image so that the transaction will only work if
  2946. // Group 1 ownership is not quiesced
  2947. cwBIExpected = cwBIExpected & 0xFFFF7FFF;
  2948. // compute the after image of the control word by performing the global
  2949. // transform for the Enter1 state transition
  2950. const ControlWord cwAI = ControlWord( ( ( cwBIExpected & ( ( LONG_PTR( long( cwBIExpected ) ) >> 31 ) |
  2951. 0x0000FFFF ) ) | 0x80000000 ) + 0x00000001 );
  2952. // validate the transaction
  2953. OSSYNCAssert( _StateFromControlWord( cwBIExpected ) < 0 ||
  2954. _FValidStateTransition( cwBIExpected, cwAI, trEnter1 ) );
  2955. // attempt to perform the transacted state transition on the control word
  2956. const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );
  2957. // the transaction failed
  2958. if ( cwBI != cwBIExpected )
  2959. {
  2960. // the transaction failed because Group 1 ownership is quiesced
  2961. if ( cwBI & 0x00008000 )
  2962. {
  2963. // return failure
  2964. return fFalse;
  2965. }
  2966. // the transaction failed because another context changed the control word
  2967. else
  2968. {
  2969. // try again
  2970. continue;
  2971. }
  2972. }
  2973. // the transaction succeeded
  2974. else
  2975. {
  2976. // we are now an owner of the lock for Group 1
  2977. State().SetAcquire( 0 );
  2978. State().AddAsOwner( 0 );
  2979. State().StartHold( 0 );
  2980. // return success
  2981. return fTrue;
  2982. }
  2983. }
  2984. }
  2985. // leaves the binary lock as a member of Group 1
  2986. //
  2987. // NOTE: you must leave the lock as a member of the same Group for which you entered
  2988. // the lock or deadlocks may occur
  2989. inline void CBinaryLock::Leave1()
  2990. {
  2991. // we are no longer an owner of the lock
  2992. State().RemoveAsOwner( 0 );
  2993. // we are no longer holding the lock
  2994. State().StopHold( 0 );
  2995. // try forever until we successfully change the lock state
  2996. OSSYNC_FOREVER
  2997. {
  2998. // read the current state of the control word as our expected before image
  2999. ControlWord cwBIExpected = State().m_cw;
  3000. // change the expected before image so that the transaction will only work if
  3001. // Group 1 ownership is not quiesced
  3002. cwBIExpected = cwBIExpected & 0xFFFF7FFF;
  3003. // compute the after image of the control word by performing the transform that
  3004. // will take us either from state 2 to state 0 or state 2 to state 2
  3005. ControlWord cwAI = cwBIExpected + 0xFFFFFFFF;
  3006. cwAI = cwAI - ( ( ( cwAI + 0xFFFFFFFF ) << 16 ) & 0x80000000 );
  3007. // validate the transaction
  3008. OSSYNCAssert( _StateFromControlWord( cwBIExpected ) < 0 ||
  3009. _FValidStateTransition( cwBIExpected, cwAI, trLeave1 ) );
  3010. // attempt to perform the transacted state transition on the control word
  3011. const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );
  3012. // the transaction failed
  3013. if ( cwBI != cwBIExpected )
  3014. {
  3015. // the transaction failed because Group 1 ownership is quiesced
  3016. if ( cwBI & 0x00008000 )
  3017. {
  3018. // leave the lock as a quiesced owner
  3019. _UpdateQuiescedOwnerCountAsGroup1( 0xFFFFFFFF );
  3020. // we're done
  3021. break;
  3022. }
  3023. // the transaction failed because another context changed the control word
  3024. else
  3025. {
  3026. // try again
  3027. continue;
  3028. }
  3029. }
  3030. // the transaction succeeded
  3031. else
  3032. {
  3033. // we're done
  3034. break;
  3035. }
  3036. }
  3037. }
  3038. // enters the binary lock as a member of Group 2, waiting forever if necessary
  3039. //
  3040. // NOTE: trying to enter the lock as a member of Group 2 when you already own
  3041. // the lock as a member of Group 1 will cause a deadlock.
  3042. inline void CBinaryLock::Enter2()
  3043. {
  3044. // we had better not already own this lock as either group
  3045. OSSYNCAssert( State().FNotOwner( 0 ) );
  3046. OSSYNCAssert( State().FNotOwner( 1 ) );
  3047. // check for deadlock
  3048. OSSYNCAssertSzRTL( State().FCanBeWaiter(), "Potential Deadlock Detected (Rank Violation)" );
  3049. // try forever until we successfully change the lock state
  3050. OSSYNC_FOREVER
  3051. {
  3052. // read the current state of the control word as our expected before image
  3053. const ControlWord cwBIExpected = State().m_cw;
  3054. // compute the after image of the control word by performing the global
  3055. // transform for the Enter2 state transition
  3056. const ControlWord cwAI = ControlWord( ( ( cwBIExpected & ( ( LONG_PTR( long( cwBIExpected << 16 ) ) >> 31 ) |
  3057. 0xFFFF0000 ) ) | 0x00008000 ) + 0x00010000 );
  3058. // validate the transaction
  3059. OSSYNCAssert( _FValidStateTransition( cwBIExpected, cwAI, trEnter2 ) );
  3060. // attempt to perform the transacted state transition on the control word
  3061. const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );
  3062. // the transaction failed or Group 2 was quiesced from ownership
  3063. if ( ( cwBI ^ cwBIExpected ) | ( cwBI & 0x80000000 ) )
  3064. {
  3065. // the transaction failed because another context changed the control word
  3066. if ( cwBI != cwBIExpected )
  3067. {
  3068. // try again
  3069. continue;
  3070. }
  3071. // the transaction succeeded but Group 2 was quiesced from ownership
  3072. else
  3073. {
  3074. // this is a contention for Group 2
  3075. State().SetContend( 1 );
  3076. // wait to own the lock as a member of Group 2
  3077. _Enter2( cwBI );
  3078. // we now own the lock, so we're done
  3079. break;
  3080. }
  3081. }
  3082. // the transaction succeeded and Group 2 was not quiesced from ownership
  3083. else
  3084. {
  3085. // we now own the lock, so we're done
  3086. break;
  3087. }
  3088. }
  3089. // we are now an owner of the lock for Group 2
  3090. State().SetAcquire( 1 );
  3091. State().AddAsOwner( 1 );
  3092. State().StartHold( 1 );
  3093. }
  3094. // tries to enter the binary lock as a member of Group 2 without waiting or
  3095. // spinning, returning fFalse if Group 2 is quiesced from ownership
  3096. //
  3097. // NOTE: trying to enter the lock as a member of Group 2 when you already own
  3098. // the lock as a member of Group 1 will cause a deadlock.
  3099. inline const BOOL CBinaryLock::FTryEnter2()
  3100. {
  3101. // we had better not already own this lock as either group
  3102. OSSYNCAssert( State().FNotOwner( 0 ) );
  3103. OSSYNCAssert( State().FNotOwner( 1 ) );
  3104. // try forever until we successfully change the lock state
  3105. OSSYNC_FOREVER
  3106. {
  3107. // read the current state of the control word as our expected before image
  3108. ControlWord cwBIExpected = State().m_cw;
  3109. // change the expected before image so that the transaction will only work if
  3110. // Group 2 ownership is not quiesced
  3111. cwBIExpected = cwBIExpected & 0x7FFFFFFF;
  3112. // compute the after image of the control word by performing the global
  3113. // transform for the Enter2 state transition
  3114. const ControlWord cwAI = ControlWord( ( ( cwBIExpected & ( ( LONG_PTR( long( cwBIExpected << 16 ) ) >> 31 ) |
  3115. 0xFFFF0000 ) ) | 0x00008000 ) + 0x00010000 );
  3116. // validate the transaction
  3117. OSSYNCAssert( _StateFromControlWord( cwBIExpected ) < 0 ||
  3118. _FValidStateTransition( cwBIExpected, cwAI, trEnter2 ) );
  3119. // attempt to perform the transacted state transition on the control word
  3120. const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );
  3121. // the transaction failed
  3122. if ( cwBI != cwBIExpected )
  3123. {
  3124. // the transaction failed because Group 2 ownership is quiesced
  3125. if ( cwBI & 0x80000000 )
  3126. {
  3127. // return failure
  3128. return fFalse;
  3129. }
  3130. // the transaction failed because another context changed the control word
  3131. else
  3132. {
  3133. // try again
  3134. continue;
  3135. }
  3136. }
  3137. // the transaction succeeded
  3138. else
  3139. {
  3140. // we are now an owner of the lock for Group 2
  3141. State().SetAcquire( 1 );
  3142. State().AddAsOwner( 1 );
  3143. State().StartHold( 1 );
  3144. // return success
  3145. return fTrue;
  3146. }
  3147. }
  3148. }
  3149. // leaves the binary lock as a member of Group 2
  3150. //
  3151. // NOTE: you must leave the lock as a member of the same Group for which you entered
  3152. // the lock or deadlocks may occur
  3153. inline void CBinaryLock::Leave2()
  3154. {
  3155. // we are no longer an owner of the lock
  3156. State().RemoveAsOwner( 1 );
  3157. // we are no longer holding the lock
  3158. State().StopHold( 1 );
  3159. // try forever until we successfully change the lock state
  3160. OSSYNC_FOREVER
  3161. {
  3162. // read the current state of the control word as our expected before image
  3163. ControlWord cwBIExpected = State().m_cw;
  3164. // change the expected before image so that the transaction will only work if
  3165. // Group 2 ownership is not quiesced
  3166. cwBIExpected = cwBIExpected & 0x7FFFFFFF;
  3167. // compute the after image of the control word by performing the transform that
  3168. // will take us either from state 1 to state 0 or state 1 to state 1
  3169. ControlWord cwAI = cwBIExpected + 0xFFFF0000;
  3170. cwAI = cwAI - ( ( ( cwAI + 0xFFFF0000 ) >> 16 ) & 0x00008000 );
  3171. // validate the transaction
  3172. OSSYNCAssert( _StateFromControlWord( cwBIExpected ) < 0 ||
  3173. _FValidStateTransition( cwBIExpected, cwAI, trLeave2 ) );
  3174. // attempt to perform the transacted state transition on the control word
  3175. const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );
  3176. // the transaction failed
  3177. if ( cwBI != cwBIExpected )
  3178. {
  3179. // the transaction failed because Group 2 ownership is quiesced
  3180. if ( cwBI & 0x80000000 )
  3181. {
  3182. // leave the lock as a quiesced owner
  3183. _UpdateQuiescedOwnerCountAsGroup2( 0xFFFFFFFF );
  3184. // we're done
  3185. break;
  3186. }
  3187. // the transaction failed because another context changed the control word
  3188. else
  3189. {
  3190. // try again
  3191. continue;
  3192. }
  3193. }
  3194. // the transaction succeeded
  3195. else
  3196. {
  3197. // we're done
  3198. break;
  3199. }
  3200. }
  3201. }
  3202. // Reader / Writer Lock Performance Information
  3203. class CReaderWriterLockPerfInfo
  3204. : public CSyncPerfWait,
  3205. public CSyncPerfAcquire,
  3206. public CLockPerfHold
  3207. {
  3208. public:
  3209. // member functions
  3210. // ctors / dtors
  3211. CReaderWriterLockPerfInfo()
  3212. {
  3213. }
  3214. // debugging support
  3215. void Dump( CDumpContext& dc ) const;
  3216. };
  3217. // Reader / Writer Lock Group Information
  3218. class CReaderWriterLockGroupInfo
  3219. {
  3220. public:
  3221. // member functions
  3222. // ctors / dtors
  3223. CReaderWriterLockGroupInfo() {}
  3224. ~CReaderWriterLockGroupInfo() {}
  3225. // manipulators
  3226. void StartWait( const int iGroup ) { m_rginfo[iGroup].StartWait(); }
  3227. void StopWait( const int iGroup ) { m_rginfo[iGroup].StopWait(); }
  3228. void SetAcquire( const int iGroup ) { m_rginfo[iGroup].SetAcquire(); }
  3229. void SetContend( const int iGroup ) { m_rginfo[iGroup].SetContend(); }
  3230. void StartHold( const int iGroup ) { m_rginfo[iGroup].StartHold(); }
  3231. void StopHold( const int iGroup ) { m_rginfo[iGroup].StopHold(); }
  3232. // accessors
  3233. #ifdef SYNC_ANALYZE_PERFORMANCE
  3234. QWORD CWaitTotal( const int iGroup ) const { return m_rginfo[iGroup].CWaitTotal(); }
  3235. double CsecWaitElapsed( const int iGroup ) const { return m_rginfo[iGroup].CsecWaitElapsed(); }
  3236. QWORD CAcquireTotal( const int iGroup ) const { return m_rginfo[iGroup].CAcquireTotal(); }
  3237. QWORD CContendTotal( const int iGroup ) const { return m_rginfo[iGroup].CContendTotal(); }
  3238. QWORD CHoldTotal( const int iGroup ) const { return m_rginfo[iGroup].CHoldTotal(); }
  3239. double CsecHoldElapsed( const int iGroup ) const { return m_rginfo[iGroup].CsecHoldElapsed(); }
  3240. #endif // SYNC_ANALYZE_PERFORMANCE
  3241. // debugging support
  3242. void Dump( CDumpContext& dc ) const;
  3243. private:
  3244. // member functions
  3245. // operators
  3246. CReaderWriterLockGroupInfo& operator=( CReaderWriterLockGroupInfo& ); // disallowed
  3247. // data members
  3248. // performance info for each group
  3249. CReaderWriterLockPerfInfo m_rginfo[2];
  3250. };
  3251. // Reader / Writer Lock Information
  3252. class CReaderWriterLockInfo
  3253. : public CLockBasicInfo,
  3254. public CReaderWriterLockGroupInfo,
  3255. public CLockDeadlockDetectionInfo
  3256. {
  3257. public:
  3258. // member functions
  3259. // ctors / dtors
  3260. CReaderWriterLockInfo( const CLockBasicInfo& lbi )
  3261. : CLockBasicInfo( lbi ),
  3262. CLockDeadlockDetectionInfo( (CLockBasicInfo&) *this )
  3263. {
  3264. }
  3265. // debugging support
  3266. void Dump( CDumpContext& dc ) const;
  3267. };
  3268. // Reader / Writer Lock State
  3269. class CReaderWriterLockState
  3270. {
  3271. public:
  3272. // types
  3273. // control word
  3274. typedef DWORD ControlWord;
  3275. // member functions
  3276. // ctors / dtors
  3277. CReaderWriterLockState( const CSyncBasicInfo& sbi );
  3278. ~CReaderWriterLockState();
  3279. // debugging support
  3280. void Dump( CDumpContext& dc ) const;
  3281. // data members
  3282. // control word
  3283. union
  3284. {
  3285. volatile ControlWord m_cw;
  3286. struct
  3287. {
  3288. volatile DWORD m_cOAOWW:15;
  3289. volatile DWORD m_fQW:1;
  3290. volatile DWORD m_cOOWR:15;
  3291. volatile DWORD m_fQR:1;
  3292. };
  3293. };
  3294. // quiesced owner count
  3295. volatile DWORD m_cOwner;
  3296. // sempahore used by writers to wait for lock ownership
  3297. CSemaphore m_semWriter;
  3298. // sempahore used by readers to wait for lock ownership
  3299. CSemaphore m_semReader;
  3300. private:
  3301. // member functions
  3302. // operators
  3303. CReaderWriterLockState& operator=( CReaderWriterLockState& ); // disallowed
  3304. };
  3305. // Reader / Writer Lock
  3306. class CReaderWriterLock
  3307. : private CLockObject,
  3308. private CEnhancedStateContainer< CReaderWriterLockState, CSyncBasicInfo, CReaderWriterLockInfo, CLockBasicInfo >
  3309. {
  3310. public:
  3311. // types
  3312. // control word
  3313. typedef CReaderWriterLockState::ControlWord ControlWord;
  3314. // transition reasons for state machine
  3315. enum TransitionReason
  3316. {
  3317. trIllegal = 0,
  3318. trEnterAsWriter = 1,
  3319. trLeaveAsWriter = 2,
  3320. trEnterAsReader = 4,
  3321. trLeaveAsReader = 8,
  3322. };
  3323. // member functions
  3324. // ctors / dtors
  3325. CReaderWriterLock( const CLockBasicInfo& lbi );
  3326. ~CReaderWriterLock();
  3327. // manipulators
  3328. void EnterAsWriter();
  3329. const BOOL FTryEnterAsWriter();
  3330. void LeaveAsWriter();
  3331. void EnterAsReader();
  3332. const BOOL FTryEnterAsReader();
  3333. void LeaveAsReader();
  3334. // accessors
  3335. const BOOL FWritersQuiesced() { return State().m_cw & 0x00008000; }
  3336. const BOOL FReadersQuiesced() { return State().m_cw & 0x80000000; }
  3337. const BOOL FWriter() { return State().FOwner( 0 ); }
  3338. const BOOL FNotWriter() { return State().FNotOwner( 0 ); }
  3339. const BOOL FReader() { return State().FOwner( 1 ); }
  3340. const BOOL FNotReader() { return State().FNotOwner( 1 ); }
  3341. // debugging support
  3342. void Dump( CDumpContext& dc ) const;
  3343. private:
  3344. // member functions
  3345. // operators
  3346. CReaderWriterLock& operator=( CReaderWriterLock& ); // disallowed
  3347. // verification
  3348. int _StateFromControlWord( const ControlWord cw );
  3349. BOOL _FValidStateTransition( const ControlWord cwBI,
  3350. const ControlWord cwAI,
  3351. const TransitionReason tr );
  3352. // manipulators
  3353. void _EnterAsWriter( const ControlWord cwBIOld );
  3354. void _EnterAsReader( const ControlWord cwBIOld );
  3355. void _UpdateQuiescedOwnerCountAsWriter( const DWORD cOwnerDelta );
  3356. void _UpdateQuiescedOwnerCountAsReader( const DWORD cOwnerDelta );
  3357. };
  3358. // enters the reader / writer lock as a writer, waiting forever if necessary
  3359. //
  3360. // NOTE: trying to enter the lock as a writer when you already own the lock
  3361. // as a reader will cause a deadlock.
  3362. inline void CReaderWriterLock::EnterAsWriter()
  3363. {
  3364. // we had better not already own this lock as either a reader or a writer
  3365. OSSYNCAssert( State().FNotOwner( 0 ) );
  3366. OSSYNCAssert( State().FNotOwner( 1 ) );
  3367. // check for deadlock
  3368. OSSYNCAssertSzRTL( State().FCanBeWaiter(), "Potential Deadlock Detected (Rank Violation)");
  3369. // try forever until we successfully change the lock state
  3370. OSSYNC_FOREVER
  3371. {
  3372. // read the current state of the control word as our expected before image
  3373. const ControlWord cwBIExpected = State().m_cw;
  3374. // compute the after image of the control word by performing the global
  3375. // transform for the EnterAsWriter state transition
  3376. const ControlWord cwAI = ControlWord( ( ( cwBIExpected & ( ( LONG_PTR( long( cwBIExpected ) ) >> 31 ) |
  3377. 0x0000FFFF ) ) | 0x80000000 ) + 0x00000001 );
  3378. // validate the transaction
  3379. OSSYNCAssert( _FValidStateTransition( cwBIExpected, cwAI, trEnterAsWriter ) );
  3380. // attempt to perform the transacted state transition on the control word
  3381. const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );
  3382. // the transaction failed or writers are quiesced from ownership or a
  3383. // writer already owns the lock
  3384. if ( ( cwBI ^ cwBIExpected ) | ( cwBI & 0x0000FFFF ) )
  3385. {
  3386. // the transaction failed because another context changed the control word
  3387. if ( cwBI != cwBIExpected )
  3388. {
  3389. // try again
  3390. continue;
  3391. }
  3392. // the transaction succeeded but writers are quiesced from ownership
  3393. // or a writer already owns the lock
  3394. else
  3395. {
  3396. // this is a contention for writers
  3397. State().SetContend( 0 );
  3398. // wait to own the lock as a writer
  3399. _EnterAsWriter( cwBI );
  3400. // we now own the lock, so we're done
  3401. break;
  3402. }
  3403. }
  3404. // the transaction succeeded and writers were not quiesced from ownership
  3405. // and a writer did not already own the lock
  3406. else
  3407. {
  3408. // we now own the lock, so we're done
  3409. break;
  3410. }
  3411. }
  3412. // we are now an owner of the lock for writers
  3413. State().SetAcquire( 0 );
  3414. State().AddAsOwner( 0 );
  3415. State().StartHold( 0 );
  3416. }
  3417. // tries to enter the reader / writer lock as a writer without waiting or
  3418. // spinning, returning fFalse if writers are quiesced from ownership or
  3419. // another writer already owns the lock
  3420. //
  3421. // NOTE: trying to enter the lock as a writer when you already own the lock
  3422. // as a reader will cause a deadlock.
  3423. inline const BOOL CReaderWriterLock::FTryEnterAsWriter()
  3424. {
  3425. // we had better not already own this lock as either a reader or a writer
  3426. OSSYNCAssert( State().FNotOwner( 0 ) );
  3427. OSSYNCAssert( State().FNotOwner( 1 ) );
  3428. // try forever until we successfully change the lock state
  3429. OSSYNC_FOREVER
  3430. {
  3431. // read the current state of the control word as our expected before image
  3432. ControlWord cwBIExpected = State().m_cw;
  3433. // change the expected before image so that the transaction will only work if
  3434. // writers were not quiesced from ownership and another writer doesn't already
  3435. // own the lock
  3436. cwBIExpected = cwBIExpected & 0xFFFF0000;
  3437. // compute the after image of the control word by performing the global
  3438. // transform for the EnterAsWriter state transition
  3439. const ControlWord cwAI = ControlWord( ( ( cwBIExpected & ( ( LONG_PTR( long( cwBIExpected ) ) >> 31 ) |
  3440. 0x0000FFFF ) ) | 0x80000000 ) + 0x00000001 );
  3441. // validate the transaction
  3442. OSSYNCAssert( _StateFromControlWord( cwBIExpected ) < 0 ||
  3443. _FValidStateTransition( cwBIExpected, cwAI, trEnterAsWriter ) );
  3444. // attempt to perform the transacted state transition on the control word
  3445. const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );
  3446. // the transaction failed
  3447. if ( cwBI != cwBIExpected )
  3448. {
  3449. // the transaction failed because writers were quiesced from ownership
  3450. // or another writer already owns the lock
  3451. if ( cwBI & 0x0000FFFF )
  3452. {
  3453. // return failure
  3454. return fFalse;
  3455. }
  3456. // the transaction failed because another context changed the control word
  3457. else
  3458. {
  3459. // try again
  3460. continue;
  3461. }
  3462. }
  3463. // the transaction succeeded
  3464. else
  3465. {
  3466. // we are now an owner of the lock for writers
  3467. State().SetAcquire( 0 );
  3468. State().AddAsOwner( 0 );
  3469. State().StartHold( 0 );
  3470. // return success
  3471. return fTrue;
  3472. }
  3473. }
  3474. }
  3475. // leaves the reader / writer lock as a writer
  3476. //
  3477. // NOTE: you must leave the lock as a member of the same group for which you entered
  3478. // the lock or deadlocks may occur
  3479. inline void CReaderWriterLock::LeaveAsWriter()
  3480. {
  3481. // we are no longer an owner of the lock
  3482. State().RemoveAsOwner( 0 );
  3483. // we are no longer holding the lock
  3484. State().StopHold( 0 );
  3485. // try forever until we successfully change the lock state
  3486. OSSYNC_FOREVER
  3487. {
  3488. // read the current state of the control word as our expected before image
  3489. ControlWord cwBIExpected = State().m_cw;
  3490. // change the expected before image so that the transaction will only work if
  3491. // writers were not quiesced from ownership
  3492. cwBIExpected = cwBIExpected & 0xFFFF7FFF;
  3493. // compute the after image of the control word by performing the transform that
  3494. // will take us either from state 2 to state 0 or state 2 to state 2
  3495. ControlWord cwAI = cwBIExpected + 0xFFFFFFFF;
  3496. cwAI = cwAI - ( ( ( cwAI + 0xFFFFFFFF ) << 16 ) & 0x80000000 );
  3497. // validate the transaction
  3498. OSSYNCAssert( _StateFromControlWord( cwBIExpected ) < 0 ||
  3499. _FValidStateTransition( cwBIExpected, cwAI, trLeaveAsWriter ) );
  3500. // attempt to perform the transacted state transition on the control word
  3501. const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );
  3502. // the transaction failed
  3503. if ( cwBI != cwBIExpected )
  3504. {
  3505. // the transaction failed because writers were quiesced from ownership
  3506. if ( cwBI & 0x00008000 )
  3507. {
  3508. // leave the lock as a quiesced owner
  3509. _UpdateQuiescedOwnerCountAsWriter( 0xFFFFFFFF );
  3510. // we're done
  3511. break;
  3512. }
  3513. // the transaction failed because another context changed the control word
  3514. else
  3515. {
  3516. // try again
  3517. continue;
  3518. }
  3519. }
  3520. // the transaction succeeded
  3521. else
  3522. {
  3523. // there were other writers waiting for ownership of the lock
  3524. if ( cwAI & 0x00007FFF )
  3525. {
  3526. // release the next writer into ownership of the lock
  3527. State().m_semWriter.Release();
  3528. }
  3529. // we're done
  3530. break;
  3531. }
  3532. }
  3533. }
  3534. // enters the reader / writer lock as a reader, waiting forever if necessary
  3535. //
  3536. // NOTE: trying to enter the lock as a reader when you already own the lock
  3537. // as a writer will cause a deadlock.
  3538. inline void CReaderWriterLock::EnterAsReader()
  3539. {
  3540. // we had better not already own this lock as either a reader or a writer
  3541. OSSYNCAssert( State().FNotOwner( 0 ) );
  3542. OSSYNCAssert( State().FNotOwner( 1 ) );
  3543. // check for deadlock
  3544. OSSYNCAssertSzRTL( State().FCanBeWaiter(), "Potential Deadlock Detected (Rank Violation)" );
  3545. // try forever until we successfully change the lock state
  3546. OSSYNC_FOREVER
  3547. {
  3548. // read the current state of the control word as our expected before image
  3549. const ControlWord cwBIExpected = State().m_cw;
  3550. // compute the after image of the control word by performing the global
  3551. // transform for the EnterAsReader state transition
  3552. const ControlWord cwAI = ( cwBIExpected & 0xFFFF7FFF ) +
  3553. ( ( cwBIExpected & 0x80008000 ) == 0x80000000 ?
  3554. 0x00017FFF :
  3555. 0x00018000 );
  3556. // validate the transaction
  3557. OSSYNCAssert( _FValidStateTransition( cwBIExpected, cwAI, trEnterAsReader ) );
  3558. // attempt to perform the transacted state transition on the control word
  3559. const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );
  3560. // the transaction failed or readers were quiesced from ownership
  3561. if ( ( cwBI ^ cwBIExpected ) | ( cwBI & 0x80000000 ) )
  3562. {
  3563. // the transaction failed because another context changed the control word
  3564. if ( cwBI != cwBIExpected )
  3565. {
  3566. // try again
  3567. continue;
  3568. }
  3569. // the transaction succeeded but readers were quiesced from ownership
  3570. else
  3571. {
  3572. // this is a contention for readers
  3573. State().SetContend( 1 );
  3574. // wait to own the lock as a reader
  3575. _EnterAsReader( cwBI );
  3576. // we now own the lock, so we're done
  3577. break;
  3578. }
  3579. }
  3580. // the transaction succeeded and readers were not quiesced from ownership
  3581. else
  3582. {
  3583. // we now own the lock, so we're done
  3584. break;
  3585. }
  3586. }
  3587. // we are now an owner of the lock for readers
  3588. State().SetAcquire( 1 );
  3589. State().AddAsOwner( 1 );
  3590. State().StartHold( 1 );
  3591. }
  3592. // tries to enter the reader / writer lock as a reader without waiting or
  3593. // spinning, returning fFalse if readers are quiesced from ownership
  3594. //
  3595. // NOTE: trying to enter the lock as a reader when you already own the lock
  3596. // as a writer will cause a deadlock.
  3597. inline const BOOL CReaderWriterLock::FTryEnterAsReader()
  3598. {
  3599. // we had better not already own this lock as either a reader or a writer
  3600. OSSYNCAssert( State().FNotOwner( 0 ) );
  3601. OSSYNCAssert( State().FNotOwner( 1 ) );
  3602. // try forever until we successfully change the lock state
  3603. OSSYNC_FOREVER
  3604. {
  3605. // read the current state of the control word as our expected before image
  3606. ControlWord cwBIExpected = State().m_cw;
  3607. // change the expected before image so that the transaction will only work if
  3608. // readers were not quiesced from ownership
  3609. cwBIExpected = cwBIExpected & 0x7FFFFFFF;
  3610. // compute the after image of the control word by performing the global
  3611. // transform for the EnterAsReader state transition
  3612. const ControlWord cwAI = ( cwBIExpected & 0xFFFF7FFF ) +
  3613. ( ( cwBIExpected & 0x80008000 ) == 0x80000000 ?
  3614. 0x00017FFF :
  3615. 0x00018000 );
  3616. // validate the transaction
  3617. OSSYNCAssert( _StateFromControlWord( cwBIExpected ) < 0 ||
  3618. _FValidStateTransition( cwBIExpected, cwAI, trEnterAsReader ) );
  3619. // attempt to perform the transacted state transition on the control word
  3620. const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );
  3621. // the transaction failed
  3622. if ( cwBI != cwBIExpected )
  3623. {
  3624. // the transaction failed because readers were quiesced from ownership
  3625. if ( cwBI & 0x80000000 )
  3626. {
  3627. // return failure
  3628. return fFalse;
  3629. }
  3630. // the transaction failed because another context changed the control word
  3631. else
  3632. {
  3633. // try again
  3634. continue;
  3635. }
  3636. }
  3637. // the transaction succeeded
  3638. else
  3639. {
  3640. // we are now an owner of the lock for readers
  3641. State().SetAcquire( 1 );
  3642. State().AddAsOwner( 1 );
  3643. State().StartHold( 1 );
  3644. // return success
  3645. return fTrue;
  3646. }
  3647. }
  3648. }
  3649. // leaves the reader / writer lock as a reader
  3650. //
  3651. // NOTE: you must leave the lock as a member of the same group for which you entered
  3652. // the lock or deadlocks may occur
  3653. inline void CReaderWriterLock::LeaveAsReader()
  3654. {
  3655. // we are no longer an owner of the lock
  3656. State().RemoveAsOwner( 1 );
  3657. // we are no longer holding the lock
  3658. State().StopHold( 1 );
  3659. // try forever until we successfully change the lock state
  3660. OSSYNC_FOREVER
  3661. {
  3662. // read the current state of the control word as our expected before image
  3663. ControlWord cwBIExpected = State().m_cw;
  3664. // change the expected before image so that the transaction will only work if
  3665. // readers were not quiesced from ownership
  3666. cwBIExpected = cwBIExpected & 0x7FFFFFFF;
  3667. // compute the after image of the control word by performing the transform that
  3668. // will take us either from state 1 to state 0 or state 1 to state 1
  3669. const ControlWord cwAI = ControlWord( cwBIExpected + 0xFFFF0000 +
  3670. ( ( LONG_PTR( long( cwBIExpected + 0xFFFE0000 ) ) >> 31 ) & 0xFFFF8000 ) );
  3671. // validate the transaction
  3672. OSSYNCAssert( _StateFromControlWord( cwBIExpected ) < 0 ||
  3673. _FValidStateTransition( cwBIExpected, cwAI, trLeaveAsReader ) );
  3674. // attempt to perform the transacted state transition on the control word
  3675. const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );
  3676. // the transaction failed
  3677. if ( cwBI != cwBIExpected )
  3678. {
  3679. // the transaction failed because readers were quiesced from ownership
  3680. if ( cwBI & 0x80000000 )
  3681. {
  3682. // leave the lock as a quiesced owner
  3683. _UpdateQuiescedOwnerCountAsReader( 0xFFFFFFFF );
  3684. // we're done
  3685. break;
  3686. }
  3687. // the transaction failed because another context changed the control word
  3688. else
  3689. {
  3690. // try again
  3691. continue;
  3692. }
  3693. }
  3694. // the transaction succeeded
  3695. else
  3696. {
  3697. // we're done
  3698. break;
  3699. }
  3700. }
  3701. }
  3702. // Metered Section
  3703. class CMeteredSection
  3704. : private CSyncObject
  3705. {
  3706. public:
  3707. // types
  3708. // control word
  3709. typedef DWORD ControlWord;
  3710. // callback used to notify the user when a partition of the current
  3711. // group has been completed
  3712. typedef void (*PFNPARTITIONCOMPLETE)( const DWORD_PTR dwCompletionKey );
  3713. // member functions
  3714. // ctors / dtors
  3715. CMeteredSection();
  3716. ~CMeteredSection();
  3717. // manipulators
  3718. int Enter();
  3719. void Leave( const int group );
  3720. void Partition( const PFNPARTITIONCOMPLETE pfnPartitionComplete = NULL,
  3721. const DWORD_PTR dwCompletionKey = NULL );
  3722. // accessors
  3723. int ActiveGroup() { return int( m_groupCurrent ); }
  3724. // debugging support
  3725. void Dump( CDumpContext& dc ) const;
  3726. private:
  3727. // data members
  3728. // partition complete callback
  3729. PFNPARTITIONCOMPLETE m_pfnPartitionComplete;
  3730. DWORD_PTR m_dwPartitionCompleteKey;
  3731. // control word
  3732. union
  3733. {
  3734. volatile ControlWord m_cw;
  3735. struct
  3736. {
  3737. volatile DWORD m_cCurrent:15;
  3738. volatile DWORD m_groupCurrent:1;
  3739. volatile DWORD m_cQuiesced:15;
  3740. volatile DWORD m_groupQuiesced:1;
  3741. };
  3742. };
  3743. // member functions
  3744. // operators
  3745. CMeteredSection& operator=( CMeteredSection& ); // disallowed
  3746. // manipulators
  3747. void _PartitionAsync( const PFNPARTITIONCOMPLETE pfnPartitionComplete,
  3748. const DWORD_PTR dwCompletionKey );
  3749. static void _PartitionSyncComplete( CAutoResetSignal* const pasig );
  3750. };
  3751. // ctor
  3752. inline CMeteredSection::CMeteredSection()
  3753. : m_cw( 0x80000000 ),
  3754. m_pfnPartitionComplete( NULL ),
  3755. m_dwPartitionCompleteKey( NULL )
  3756. {
  3757. }
  3758. // dtor
  3759. inline CMeteredSection::~CMeteredSection()
  3760. {
  3761. }
  3762. // enter the metered section, returning the group id for which the current
  3763. // context has acquired the metered section
  3764. inline int CMeteredSection::Enter()
  3765. {
  3766. // increment the count for the current group
  3767. const DWORD cwDelta = 0x00000001;
  3768. const DWORD cwBI = AtomicExchangeAdd( (long*) &m_cw, (long) cwDelta );
  3769. // there had better not be any overflow!
  3770. OSSYNCAssert( ( cwBI & 0x80008000 ) == ( ( cwBI + cwDelta ) & 0x80008000 ) );
  3771. // return the group we referenced
  3772. return int( ( cwBI >> 15 ) & 1 );
  3773. }
  3774. // leave the metered section using the specified group id. this group id must
  3775. // be the group id returned by the corresponding call to Enter()
  3776. inline void CMeteredSection::Leave( const int group )
  3777. {
  3778. // try forever until we successfully leave
  3779. OSSYNC_FOREVER
  3780. {
  3781. // read the current state of the control word as our expected before image
  3782. const ControlWord cwBIExpected = m_cw;
  3783. // compute the after image of the control word
  3784. const ControlWord cwAI = cwBIExpected - ( ( ( ( cwBIExpected & 0x80008000 ) ^ 0x80008000 ) >> 15 ) ^ ( ( group << 16 ) | group ) );
  3785. // there had better not be any underflow!
  3786. OSSYNCAssert( ( cwBIExpected & 0x80008000 ) == ( cwAI & 0x80008000 ) );
  3787. // attempt to perform the transacted state transition on the control word
  3788. const ControlWord cwBI = AtomicCompareExchange( (long*)&m_cw, cwBIExpected, cwAI );
  3789. // the transaction failed
  3790. if ( cwBI != cwBIExpected )
  3791. {
  3792. // try again
  3793. continue;
  3794. }
  3795. // the transaction succeeded
  3796. else
  3797. {
  3798. // our update resulted in a partition completion
  3799. if ( ( cwBI & 0x7FFF0000 ) + ( cwAI & 0x7FFF0000 ) == 0x00010000 )
  3800. {
  3801. // execute the completion function
  3802. m_pfnPartitionComplete( m_dwPartitionCompleteKey );
  3803. }
  3804. // we're done
  3805. break;
  3806. }
  3807. }
  3808. }
  3809. // partitions all execution contexts entering the metered section into two groups.
  3810. // all contexts entering the section after this call are in a different group than
  3811. // all the contexts that entered the section before this call. when all contexts
  3812. // in the old group have left the metered section, the partition will be completed
  3813. //
  3814. // there are two ways to complete a partition: asynchronously and synchronously.
  3815. // asynchronous operation is selected if a completion function and key are provided.
  3816. // the last thread to leave the metered section for the previous group will
  3817. // execute asynchronous completions
  3818. //
  3819. // NOTE: it is illegal to have multiple concurrent partition requests. any attempt
  3820. // to do so will result in undefined behavior
  3821. inline void CMeteredSection::Partition( const PFNPARTITIONCOMPLETE pfnPartitionComplete,
  3822. const DWORD_PTR dwCompletionKey )
  3823. {
  3824. // this is an async partition request
  3825. if ( pfnPartitionComplete )
  3826. {
  3827. // execute the parititon request
  3828. _PartitionAsync( pfnPartitionComplete, dwCompletionKey );
  3829. }
  3830. // this is a sync partition request
  3831. else
  3832. {
  3833. // create a signal to wait for completion
  3834. CAutoResetSignal asig( CSyncBasicInfo( "CMeteredSection::Partition()::asig" ) );
  3835. // issue an async partition request
  3836. _PartitionAsync( PFNPARTITIONCOMPLETE( _PartitionSyncComplete ),
  3837. DWORD_PTR( &asig ) );
  3838. // wait for the partition to complete
  3839. asig.Wait();
  3840. }
  3841. }
  3842. // performs an async partition request
  3843. inline void CMeteredSection::_PartitionAsync( const PFNPARTITIONCOMPLETE pfnPartitionComplete,
  3844. const DWORD_PTR dwCompletionKey )
  3845. {
  3846. // we should not be calling this if there is already a partition pending
  3847. OSSYNCAssertSz( !( m_cw & 0x7FFF0000 ), "Illegal concurrent use of Partitioning" );
  3848. // save the callback and key for the future completion
  3849. m_pfnPartitionComplete = pfnPartitionComplete;
  3850. m_dwPartitionCompleteKey = dwCompletionKey;
  3851. // try forever until we successfully partition
  3852. OSSYNC_FOREVER
  3853. {
  3854. // read the current state of the control word as our expected before image
  3855. const ControlWord cwBIExpected = m_cw;
  3856. // compute the after image of the control word
  3857. const ControlWord cwAI = ( cwBIExpected >> 16 ) | ( cwBIExpected << 16 );
  3858. // attempt to perform the transacted state transition on the control word
  3859. const ControlWord cwBI = AtomicCompareExchange( (long*)&m_cw, cwBIExpected, cwAI );
  3860. // the transaction failed
  3861. if ( cwBI != cwBIExpected )
  3862. {
  3863. // try again
  3864. continue;
  3865. }
  3866. // the transaction succeeded
  3867. else
  3868. {
  3869. // our update resulted in a partition completion
  3870. if ( !( cwAI & 0x7FFF0000 ) )
  3871. {
  3872. // execute the completion function
  3873. m_pfnPartitionComplete( m_dwPartitionCompleteKey );
  3874. }
  3875. // we're done
  3876. break;
  3877. }
  3878. }
  3879. }
  3880. // partition completion function used for sync partition requests
  3881. inline void CMeteredSection::_PartitionSyncComplete( CAutoResetSignal* const pasig )
  3882. {
  3883. // set the signal
  3884. pasig->Set();
  3885. }
  3886. // S / X / W Latch Performance Information
  3887. class CSXWLatchPerfInfo
  3888. : public CSyncPerfWait,
  3889. public CSyncPerfAcquire,
  3890. public CLockPerfHold
  3891. {
  3892. public:
  3893. // member functions
  3894. // ctors / dtors
  3895. CSXWLatchPerfInfo()
  3896. {
  3897. }
  3898. // debugging support
  3899. void Dump( CDumpContext& dc ) const;
  3900. };
  3901. // S / X / W Latch Group Information
  3902. class CSXWLatchGroupInfo
  3903. {
  3904. public:
  3905. // member functions
  3906. // ctors / dtors
  3907. CSXWLatchGroupInfo() {}
  3908. ~CSXWLatchGroupInfo() {}
  3909. // manipulators
  3910. void StartWait( const int iGroup ) { m_rginfo[iGroup].StartWait(); }
  3911. void StopWait( const int iGroup ) { m_rginfo[iGroup].StopWait(); }
  3912. void SetAcquire( const int iGroup ) { m_rginfo[iGroup].SetAcquire(); }
  3913. void SetContend( const int iGroup ) { m_rginfo[iGroup].SetContend(); }
  3914. void StartHold( const int iGroup ) { m_rginfo[iGroup].StartHold(); }
  3915. void StopHold( const int iGroup ) { m_rginfo[iGroup].StopHold(); }
  3916. // accessors
  3917. #ifdef SYNC_ANALYZE_PERFORMANCE
  3918. QWORD CWaitTotal( const int iGroup ) const { return m_rginfo[iGroup].CWaitTotal(); }
  3919. double CsecWaitElapsed( const int iGroup ) const { return m_rginfo[iGroup].CsecWaitElapsed(); }
  3920. QWORD CAcquireTotal( const int iGroup ) const { return m_rginfo[iGroup].CAcquireTotal(); }
  3921. QWORD CContendTotal( const int iGroup ) const { return m_rginfo[iGroup].CContendTotal(); }
  3922. QWORD CHoldTotal( const int iGroup ) const { return m_rginfo[iGroup].CHoldTotal(); }
  3923. double CsecHoldElapsed( const int iGroup ) const { return m_rginfo[iGroup].CsecHoldElapsed(); }
  3924. #endif // SYNC_ANALYZE_PERFORMANCE
  3925. // debugging support
  3926. void Dump( CDumpContext& dc ) const;
  3927. private:
  3928. // member functions
  3929. // operators
  3930. CSXWLatchGroupInfo& operator=( CSXWLatchGroupInfo& ); // disallowed
  3931. // data members
  3932. // performance info for each group
  3933. CSXWLatchPerfInfo m_rginfo[3];
  3934. };
  3935. // S / X / W Latch Information
  3936. class CSXWLatchInfo
  3937. : public CLockBasicInfo,
  3938. public CSXWLatchGroupInfo,
  3939. public CLockDeadlockDetectionInfo
  3940. {
  3941. public:
  3942. // member functions
  3943. // ctors / dtors
  3944. CSXWLatchInfo( const CLockBasicInfo& lbi )
  3945. : CLockBasicInfo( lbi ),
  3946. CLockDeadlockDetectionInfo( (CLockBasicInfo&) *this )
  3947. {
  3948. }
  3949. // debugging support
  3950. void Dump( CDumpContext& dc ) const;
  3951. };
  3952. // S / X / W Latch State
  3953. class CSXWLatchState
  3954. {
  3955. public:
  3956. // types
  3957. // control word
  3958. typedef DWORD ControlWord;
  3959. // member functions
  3960. // ctors / dtors
  3961. CSXWLatchState( const CSyncBasicInfo& sbi );
  3962. ~CSXWLatchState();
  3963. // debugging support
  3964. void Dump( CDumpContext& dc ) const;
  3965. // data members
  3966. // control word
  3967. union
  3968. {
  3969. volatile ControlWord m_cw;
  3970. struct
  3971. {
  3972. volatile DWORD m_cOOWS:15;
  3973. volatile DWORD m_fQS:1;
  3974. volatile DWORD m_cOAWX:16;
  3975. };
  3976. };
  3977. // quiesced share latch count
  3978. volatile DWORD m_cQS;
  3979. // sempahore used to wait for the shared latch
  3980. CSemaphore m_semS;
  3981. // sempahore used to wait for the exclusive latch
  3982. CSemaphore m_semX;
  3983. // sempahore used to wait for the write latch
  3984. CSemaphore m_semW;
  3985. private:
  3986. // member functions
  3987. // operators
  3988. CSXWLatchState& operator=( CSXWLatchState& ); // disallowed
  3989. };
  3990. // S / X / W Latch
  3991. class CSXWLatch
  3992. : private CLockObject,
  3993. private CEnhancedStateContainer< CSXWLatchState, CSyncBasicInfo, CSXWLatchInfo, CLockBasicInfo >
  3994. {
  3995. public:
  3996. // types
  3997. // control word
  3998. typedef CSXWLatchState::ControlWord ControlWord;
  3999. // API Error Codes
  4000. enum ERR
  4001. {
  4002. errSuccess,
  4003. errWaitForSharedLatch,
  4004. errWaitForExclusiveLatch,
  4005. errWaitForWriteLatch,
  4006. errLatchConflict
  4007. };
  4008. // member functions
  4009. // ctors / dtors
  4010. CSXWLatch( const CLockBasicInfo& lbi );
  4011. ~CSXWLatch();
  4012. // manipulators
  4013. ERR ErrAcquireSharedLatch();
  4014. ERR ErrTryAcquireSharedLatch();
  4015. ERR ErrAcquireExclusiveLatch();
  4016. ERR ErrTryAcquireExclusiveLatch();
  4017. ERR ErrTryAcquireWriteLatch();
  4018. ERR ErrUpgradeSharedLatchToExclusiveLatch();
  4019. ERR ErrUpgradeSharedLatchToWriteLatch();
  4020. ERR ErrUpgradeExclusiveLatchToWriteLatch();
  4021. ERR ErrTryUpgradeSharedLatchToWriteLatch();
  4022. void DowngradeWriteLatchToExclusiveLatch();
  4023. void DowngradeWriteLatchToSharedLatch();
  4024. void DowngradeExclusiveLatchToSharedLatch();
  4025. void ReleaseWriteLatch();
  4026. void ReleaseExclusiveLatch();
  4027. void ReleaseSharedLatch();
  4028. void WaitForSharedLatch();
  4029. void WaitForExclusiveLatch();
  4030. void WaitForWriteLatch();
  4031. void ClaimOwnership( const DWORD group );
  4032. void ReleaseOwnership( const DWORD group );
  4033. // accessors
  4034. BOOL FOwnSharedLatch() { return State().FOwner( 0 ); }
  4035. BOOL FNotOwnSharedLatch() { return State().FNotOwner( 0 ); }
  4036. BOOL FOwnExclusiveLatch() { return State().FOwner( 1 ); }
  4037. BOOL FNotOwnExclusiveLatch() { return State().FNotOwner( 1 ); }
  4038. BOOL FOwnWriteLatch() { return State().FOwner( 2 ); }
  4039. BOOL FNotOwnWriteLatch() { return State().FNotOwner( 2 ); }
  4040. // debugging support
  4041. void Dump( CDumpContext& dc ) const;
  4042. private:
  4043. // member functions
  4044. // operators
  4045. CSXWLatch& operator=( CSXWLatch& ); // disallowed
  4046. // manipulators
  4047. void _UpdateQuiescedSharedLatchCount( const DWORD cQSDelta );
  4048. };
  4049. // declares the current context as an owner or waiter of a shared latch. if
  4050. // the shared latch is acquired immediately, errSuccess will be returned. if
  4051. // the shared latch is not acquired immediately, errWaitForSharedLatch will be
  4052. // returned and WaitForSharedLatch() must be called to gain ownership of the
  4053. // shared latch
  4054. inline CSXWLatch::ERR CSXWLatch::ErrAcquireSharedLatch()
  4055. {
  4056. // we had better not already have a shared, exclusive, or write latch
  4057. OSSYNCAssert( FNotOwnSharedLatch() );
  4058. OSSYNCAssert( FNotOwnExclusiveLatch() );
  4059. OSSYNCAssert( FNotOwnWriteLatch() );
  4060. // add ourself as an owner or waiter for the shared latch
  4061. const ControlWord cwDelta = 0x00000001;
  4062. const ControlWord cwBI = AtomicExchangeAdd( (long*)&State().m_cw, cwDelta );
  4063. // shared latches are quiesced
  4064. if ( cwBI & 0x00008000 )
  4065. {
  4066. // this is a contention for a shared latch
  4067. State().SetContend( 0 );
  4068. // we are now a waiter for the shared latch
  4069. State().AddAsWaiter( 0 );
  4070. State().StartWait( 0 );
  4071. // we will need to block
  4072. return errWaitForSharedLatch;
  4073. }
  4074. // shared latches are not quiesced
  4075. else
  4076. {
  4077. // we are now an owner of a shared latch
  4078. State().SetAcquire( 0 );
  4079. State().AddAsOwner( 0 );
  4080. State().StartHold( 0 );
  4081. // we now own the shared latch
  4082. return errSuccess;
  4083. }
  4084. }
  4085. // tries to declare the current context as an owner of a shared latch. if
  4086. // the shared latch is acquired immediately, errSuccess will be returned. if
  4087. // the shared latch is not acquired immediately, errLatchConflict will be
  4088. // returned
  4089. inline CSXWLatch::ERR CSXWLatch::ErrTryAcquireSharedLatch()
  4090. {
  4091. // we had better not already have a shared, exclusive, or write latch
  4092. OSSYNCAssert( FNotOwnSharedLatch() );
  4093. OSSYNCAssert( FNotOwnExclusiveLatch() );
  4094. OSSYNCAssert( FNotOwnWriteLatch() );
  4095. // try forever until we successfully change the latch state
  4096. OSSYNC_FOREVER
  4097. {
  4098. // read the current state of the control word as our expected before image
  4099. ControlWord cwBIExpected = State().m_cw;
  4100. // change the expected before image so that the transaction will only work if
  4101. // shared latches are not quiesced
  4102. cwBIExpected = cwBIExpected & 0xFFFF7FFF;
  4103. // compute the after image of the control word by performing the transform
  4104. // that will acquire a shared latch iff shared latches are not quiesced
  4105. const ControlWord cwAI = cwBIExpected + 0x00000001;
  4106. // attempt to perform the transacted state transition on the control word
  4107. const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );
  4108. // the transaction failed
  4109. if ( cwBI != cwBIExpected )
  4110. {
  4111. // the transaction failed because shared latches were quiesced
  4112. if ( cwBI & 0x00008000 )
  4113. {
  4114. // this is a contention for the shared latch
  4115. State().SetContend( 0 );
  4116. // this is a latch conflict
  4117. return errLatchConflict;
  4118. }
  4119. // the transaction failed because another context changed the control
  4120. // word
  4121. else
  4122. {
  4123. // try again
  4124. continue;
  4125. }
  4126. }
  4127. // the transaction succeeded
  4128. else
  4129. {
  4130. // we are now an owner of a shared latch
  4131. State().SetAcquire( 0 );
  4132. State().AddAsOwner( 0 );
  4133. State().StartHold( 0 );
  4134. // we now own the shared latch
  4135. return errSuccess;
  4136. }
  4137. }
  4138. }
  4139. // declares the current context as an owner or waiter of the exclusive latch.
  4140. // if the exclusive latch is acquired immediately, errSuccess will be returned.
  4141. // if the exclusive latch is not acquired immediately, errWaitForExclusiveLatch
  4142. // will be returned and WaitForExclusiveLatch() must be called to gain ownership
  4143. // of the exclusive latch
  4144. inline CSXWLatch::ERR CSXWLatch::ErrAcquireExclusiveLatch()
  4145. {
  4146. // we had better not already have a shared, exclusive, or write latch
  4147. OSSYNCAssert( FNotOwnSharedLatch() );
  4148. OSSYNCAssert( FNotOwnExclusiveLatch() );
  4149. OSSYNCAssert( FNotOwnWriteLatch() );
  4150. // add ourself as an owner or waiter for the exclusive latch
  4151. const ControlWord cwDelta = 0x00010000;
  4152. const ControlWord cwBI = AtomicExchangeAdd( (long*)&State().m_cw, cwDelta );
  4153. // we are not the owner of the exclusive latch
  4154. if ( cwBI & 0xFFFF0000 )
  4155. {
  4156. // this is a contention for the exclusive latch
  4157. State().SetContend( 1 );
  4158. // we are now a waiter for the exclusive latch
  4159. State().AddAsWaiter( 1 );
  4160. State().StartWait( 1 );
  4161. // we will need to block
  4162. return errWaitForExclusiveLatch;
  4163. }
  4164. // we are the owner of the exclusive latch
  4165. else
  4166. {
  4167. // we are now an owner of the exclusive latch
  4168. State().SetAcquire( 1 );
  4169. State().AddAsOwner( 1 );
  4170. State().StartHold( 1 );
  4171. // we now own the exclusive latch
  4172. return errSuccess;
  4173. }
  4174. }
  4175. // tries to declare the current context as an owner of the exclusive latch. if
  4176. // the exclusive latch is acquired immediately, errSuccess will be returned. if
  4177. // the exclusive latch is not acquired immediately, errLatchConflict will be
  4178. // returned
  4179. inline CSXWLatch::ERR CSXWLatch::ErrTryAcquireExclusiveLatch()
  4180. {
  4181. // we had better not already have a shared, exclusive, or write latch
  4182. OSSYNCAssert( FNotOwnSharedLatch() );
  4183. OSSYNCAssert( FNotOwnExclusiveLatch() );
  4184. OSSYNCAssert( FNotOwnWriteLatch() );
  4185. // try forever until we successfully change the latch state
  4186. OSSYNC_FOREVER
  4187. {
  4188. // read the current state of the control word as our expected before image
  4189. ControlWord cwBIExpected = State().m_cw;
  4190. // change the expected before image so that the transaction will only work if
  4191. // the exclusive latch is not already owned
  4192. cwBIExpected = cwBIExpected & 0x0000FFFF;
  4193. // compute the after image of the control word by performing the transform
  4194. // that will acquire the exclusive latch iff it is not already owned
  4195. const ControlWord cwAI = cwBIExpected + 0x00010000;
  4196. // attempt to perform the transacted state transition on the control word
  4197. const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );
  4198. // the transaction failed
  4199. if ( cwBI != cwBIExpected )
  4200. {
  4201. // the transaction failed because the exclusive latch was already
  4202. // owned
  4203. if ( cwBI & 0xFFFF0000 )
  4204. {
  4205. // this is a contention for the exclusive latch
  4206. State().SetContend( 1 );
  4207. // this is a latch conflict
  4208. return errLatchConflict;
  4209. }
  4210. // the transaction failed because another context changed the control
  4211. // word
  4212. else
  4213. {
  4214. // try again
  4215. continue;
  4216. }
  4217. }
  4218. // the transaction succeeded
  4219. else
  4220. {
  4221. // we are now an owner of the exclusive latch
  4222. State().SetAcquire( 1 );
  4223. State().AddAsOwner( 1 );
  4224. State().StartHold( 1 );
  4225. // we now own the exclusive latch
  4226. return errSuccess;
  4227. }
  4228. }
  4229. }
  4230. // tries to declare the current context as an owner of the write latch. if
  4231. // the write latch is acquired immediately, errSuccess will be returned. if
  4232. // the write latch is not acquired immediately, errLatchConflict will be
  4233. // returned. note that a latch conflict will effectively occur if any other
  4234. // context currently owns or is waiting to own any type of latch
  4235. inline CSXWLatch::ERR CSXWLatch::ErrTryAcquireWriteLatch()
  4236. {
  4237. // we had better not already have a shared, exclusive, or write latch
  4238. OSSYNCAssert( FNotOwnSharedLatch() );
  4239. OSSYNCAssert( FNotOwnExclusiveLatch() );
  4240. OSSYNCAssert( FNotOwnWriteLatch() );
  4241. // try forever until we successfully change the latch state
  4242. OSSYNC_FOREVER
  4243. {
  4244. // set the expected before image so that the transaction will only work if
  4245. // no other context currently owns or is waiting to own any type of latch
  4246. const ControlWord cwBIExpected = 0x00000000;
  4247. // set the after image of the control word to a single write latch
  4248. const ControlWord cwAI = 0x00018000;
  4249. // attempt to perform the transacted state transition on the control word
  4250. const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );
  4251. // the transaction failed
  4252. if ( cwBI != cwBIExpected )
  4253. {
  4254. // this is a contention for the write latch
  4255. State().SetContend( 2 );
  4256. // this is a latch conflict
  4257. return errLatchConflict;
  4258. }
  4259. // the transaction succeeded
  4260. else
  4261. {
  4262. // we are now an owner of the write latch
  4263. State().SetAcquire( 2 );
  4264. State().AddAsOwner( 2 );
  4265. State().StartHold( 2 );
  4266. // we now own the write latch
  4267. return errSuccess;
  4268. }
  4269. }
  4270. }
  4271. // attempts to upgrade a shared latch to the exclusive latch. if the exclusive
  4272. // latch is not available, errLatchConflict will be returned. if the exclusive
  4273. // latch is available, it will be acquired and errSuccess will be returned
  4274. inline CSXWLatch::ERR CSXWLatch::ErrUpgradeSharedLatchToExclusiveLatch()
  4275. {
  4276. // we had better already have only a shared latch
  4277. OSSYNCAssert( FOwnSharedLatch() );
  4278. OSSYNCAssert( FNotOwnExclusiveLatch() );
  4279. OSSYNCAssert( FNotOwnWriteLatch() );
  4280. // try forever until we successfully change the latch state
  4281. OSSYNC_FOREVER
  4282. {
  4283. // read the current state of the control word as our expected before image
  4284. ControlWord cwBIExpected = State().m_cw;
  4285. // change the expected before image so that the transaction will only work if
  4286. // the exclusive latch is not already owned
  4287. cwBIExpected = cwBIExpected & 0x0000FFFF;
  4288. // compute the after image of the control word by performing the transform
  4289. // that will set an exclusive latch iff there is no current owner of the
  4290. // exclusive latch and release our shared latch
  4291. const ControlWord cwAI = cwBIExpected + 0x0000FFFF;
  4292. // attempt to perform the transacted state transition on the control word
  4293. const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );
  4294. // the transaction failed
  4295. if ( cwBI != cwBIExpected )
  4296. {
  4297. // the transaction failed because the exclusive latch was already owned
  4298. if ( cwBI & 0xFFFF0000 )
  4299. {
  4300. // this is a contention for the exclusive latch
  4301. State().SetContend( 1 );
  4302. // this is a latch conflict
  4303. return errLatchConflict;
  4304. }
  4305. // the transaction failed because another context changed the control
  4306. // word
  4307. else
  4308. {
  4309. // try again
  4310. continue;
  4311. }
  4312. }
  4313. // the transaction succeeded
  4314. else
  4315. {
  4316. // we are no longer an owner of a shared latch
  4317. State().RemoveAsOwner( 0 );
  4318. State().StopHold( 0 );
  4319. // we are now an owner of the exclusive latch
  4320. State().SetAcquire( 1 );
  4321. State().AddAsOwner( 1 );
  4322. State().StartHold( 1 );
  4323. // we now own the exclusive latch
  4324. return errSuccess;
  4325. }
  4326. }
  4327. }
  4328. // attempts to upgrade a shared latch to the write latch. if the write latch
  4329. // is not available, errLatchConflict will be returned. if the write latch is
  4330. // available, it will be acquired. if the write latch is acquired immediately,
  4331. // errSuccess will be returned. if the write latch is not acquired immediately,
  4332. // errWaitForWriteLatch will be returned and WaitForWriteLatch() must be called
  4333. // to gain ownership of the write latch
  4334. inline CSXWLatch::ERR CSXWLatch::ErrUpgradeSharedLatchToWriteLatch()
  4335. {
  4336. // we had better already have only a shared latch
  4337. OSSYNCAssert( FOwnSharedLatch() );
  4338. OSSYNCAssert( FNotOwnExclusiveLatch() );
  4339. OSSYNCAssert( FNotOwnWriteLatch() );
  4340. // try forever until we successfully change the latch state
  4341. OSSYNC_FOREVER
  4342. {
  4343. // read the current state of the control word as our expected before image
  4344. ControlWord cwBIExpected = State().m_cw;
  4345. // change the expected before image so that the transaction will only work if
  4346. // the exclusive latch is not already owned
  4347. cwBIExpected = cwBIExpected & 0x0000FFFF;
  4348. // compute the after image of the control word by performing the transform
  4349. // that will set a write latch iff there is no current owner of the
  4350. // exclusive latch, quiescing any remaining shared latches
  4351. const ControlWord cwAI = 0x00018000;
  4352. // attempt to perform the transacted state transition on the control word
  4353. const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );
  4354. // the transaction failed
  4355. if ( cwBI != cwBIExpected )
  4356. {
  4357. // the transaction failed because the write latch was already owned
  4358. if ( cwBI & 0xFFFF0000 )
  4359. {
  4360. // this is a contention for the write latch
  4361. State().SetContend( 2 );
  4362. // this is a latch conflict
  4363. return errLatchConflict;
  4364. }
  4365. // the transaction failed because another context changed the control
  4366. // word
  4367. else
  4368. {
  4369. // try again
  4370. continue;
  4371. }
  4372. }
  4373. // the transaction succeeded
  4374. else
  4375. {
  4376. // shared latches were just quiesced
  4377. if ( cwBI != 0x00000001 )
  4378. {
  4379. // we are no longer an owner of a shared latch
  4380. State().RemoveAsOwner( 0 );
  4381. State().StopHold( 0 );
  4382. // update the quiesced shared latch count with the shared latch count
  4383. // that we displaced from the control word, possibly releasing waiters.
  4384. // we update the count as if we we had a shared latch as a write latch
  4385. // (namely ours) can be released. don't forget to deduct our shared
  4386. // latch from this count
  4387. _UpdateQuiescedSharedLatchCount( cwBI - 1 );
  4388. // we are now a waiter for the write latch
  4389. State().AddAsWaiter( 2 );
  4390. State().StartWait( 2 );
  4391. // we will need to block
  4392. return errWaitForWriteLatch;
  4393. }
  4394. // shared latches were not just quiesced
  4395. else
  4396. {
  4397. // we are no longer an owner of a shared latch
  4398. State().RemoveAsOwner( 0 );
  4399. State().StopHold( 0 );
  4400. // we are now an owner of the write latch
  4401. State().SetAcquire( 2 );
  4402. State().AddAsOwner( 2 );
  4403. State().StartHold( 2 );
  4404. // we now own the write latch
  4405. return errSuccess;
  4406. }
  4407. }
  4408. }
  4409. }
  4410. // upgrades the exclusive latch to the write latch. if the write latch is
  4411. // acquired immediately, errSuccess will be returned. if the write latch is
  4412. // not acquired immediately, errWaitForWriteLatch is returned and
  4413. // WaitForWriteLatch() must be called to gain ownership of the write latch
  4414. inline CSXWLatch::ERR CSXWLatch::ErrUpgradeExclusiveLatchToWriteLatch()
  4415. {
  4416. // we had better already have only an exclusive latch
  4417. OSSYNCAssert( FNotOwnSharedLatch() );
  4418. OSSYNCAssert( FOwnExclusiveLatch() );
  4419. OSSYNCAssert( FNotOwnWriteLatch() );
  4420. // we are no longer an owner of the exclusive latch
  4421. State().RemoveAsOwner( 1 );
  4422. State().StopHold( 1 );
  4423. // try forever until we successfully change the latch state
  4424. OSSYNC_FOREVER
  4425. {
  4426. // read the current state of the control word as our expected before image
  4427. const ControlWord cwBIExpected = State().m_cw;
  4428. // compute the after image of the control word by performing the transform that
  4429. // will quiesce shared latches by setting the fQS flag and removing the current
  4430. // shared latch count from the control word
  4431. const ControlWord cwAI = ( cwBIExpected & 0xFFFF0000 ) | 0x00008000;
  4432. // attempt to perform the transacted state transition on the control word
  4433. const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );
  4434. // the transaction failed
  4435. if ( cwBI != cwBIExpected )
  4436. {
  4437. // try again
  4438. continue;
  4439. }
  4440. // the transaction succeeded
  4441. else
  4442. {
  4443. // shared latches were just quiesced
  4444. if ( cwBI & 0x00007FFF )
  4445. {
  4446. // this is a contention for the write latch
  4447. State().SetContend( 2 );
  4448. // update the quiesced shared latch count with the shared latch
  4449. // count that we displaced from the control word, possibly
  4450. // releasing waiters. we update the count as if we we had a
  4451. // shared latch as a write latch (namely ours) can be released
  4452. _UpdateQuiescedSharedLatchCount( cwBI & 0x00007FFF );
  4453. // we are now a waiter for the write latch
  4454. State().AddAsWaiter( 2 );
  4455. State().StartWait( 2 );
  4456. // we will need to block
  4457. return errWaitForWriteLatch;
  4458. }
  4459. // shared latches were not just quiesced
  4460. else
  4461. {
  4462. // we are now an owner of the write latch
  4463. State().SetAcquire( 2 );
  4464. State().AddAsOwner( 2 );
  4465. State().StartHold( 2 );
  4466. // we now own the write latch
  4467. return errSuccess;
  4468. }
  4469. }
  4470. }
  4471. }
  4472. // tries to upgrade a shared latch owned by this context to the write latch.
  4473. // if the write latch is acquired immediately, errSuccess will be returned.
  4474. // if the write latch is not acquired immediately, errLatchConflict will be
  4475. // returned. note that a latch conflict will effectively occur if any other
  4476. // context currently owns or is waiting to own any type of latch
  4477. inline CSXWLatch::ERR CSXWLatch::ErrTryUpgradeSharedLatchToWriteLatch()
  4478. {
  4479. // we had better already have only a shared latch
  4480. OSSYNCAssert( FOwnSharedLatch() );
  4481. OSSYNCAssert( FNotOwnExclusiveLatch() );
  4482. OSSYNCAssert( FNotOwnWriteLatch() );
  4483. // try forever until we successfully change the latch state
  4484. OSSYNC_FOREVER
  4485. {
  4486. // set the expected before image so that the transaction will only work if
  4487. // we are the only owner of a latch and it is a share latch
  4488. const ControlWord cwBIExpected = 0x00000001;
  4489. // set the after image of the control word to a single write latch
  4490. const ControlWord cwAI = 0x00018000;
  4491. // attempt to perform the transacted state transition on the control word
  4492. const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );
  4493. // the transaction failed
  4494. if ( cwBI != cwBIExpected )
  4495. {
  4496. // this is a contention for the write latch
  4497. State().SetContend( 2 );
  4498. // this is a latch conflict
  4499. return errLatchConflict;
  4500. }
  4501. // the transaction succeeded
  4502. else
  4503. {
  4504. // we are no longer an owner of a shared latch
  4505. State().RemoveAsOwner( 0 );
  4506. State().StopHold( 0 );
  4507. // we are now an owner of the write latch
  4508. State().SetAcquire( 2 );
  4509. State().AddAsOwner( 2 );
  4510. State().StartHold( 2 );
  4511. // we now own the write latch
  4512. return errSuccess;
  4513. }
  4514. }
  4515. }
  4516. // releases the write latch in exchange for the exclusive latch
  4517. inline void CSXWLatch::DowngradeWriteLatchToExclusiveLatch()
  4518. {
  4519. // we had better already have only a write latch
  4520. OSSYNCAssert( FNotOwnSharedLatch() );
  4521. OSSYNCAssert( FNotOwnExclusiveLatch() );
  4522. OSSYNCAssert( FOwnWriteLatch() );
  4523. // stop quiescing shared latches by resetting the fQS flag
  4524. const ControlWord cwDelta = 0xFFFF8000;
  4525. const ControlWord cwBI = AtomicExchangeAdd( (long*)&State().m_cw, cwDelta );
  4526. // transfer ownership from the write latch to the exclusive latch
  4527. State().RemoveAsOwner( 2 );
  4528. State().StopHold( 2 );
  4529. State().SetAcquire( 1 );
  4530. State().AddAsOwner( 1 );
  4531. State().StartHold( 1 );
  4532. // release any quiesced shared latches
  4533. if ( cwBI & 0x00007FFF )
  4534. {
  4535. State().m_semS.Release( cwBI & 0x00007FFF );
  4536. }
  4537. }
  4538. // releases the write latch in exchange for a shared latch
  4539. inline void CSXWLatch::DowngradeWriteLatchToSharedLatch()
  4540. {
  4541. // we had better already have only a write latch
  4542. OSSYNCAssert( FNotOwnSharedLatch() );
  4543. OSSYNCAssert( FNotOwnExclusiveLatch() );
  4544. OSSYNCAssert( FOwnWriteLatch() );
  4545. // stop quiescing shared latches by resetting the fQS flag, release our
  4546. // exclusive latch, and acquire a shared latch
  4547. const ControlWord cwDelta = 0xFFFE8001;
  4548. const ControlWord cwBI = AtomicExchangeAdd( (long*)&State().m_cw, cwDelta );
  4549. // transfer ownership from the write latch to a shared latch
  4550. State().RemoveAsOwner( 2 );
  4551. State().StopHold( 2 );
  4552. State().SetAcquire( 0 );
  4553. State().AddAsOwner( 0 );
  4554. State().StartHold( 0 );
  4555. // release any quiesced shared latches
  4556. if ( cwBI & 0x00007FFF )
  4557. {
  4558. State().m_semS.Release( cwBI & 0x00007FFF );
  4559. }
  4560. // release a waiter for the exclusive latch, if any
  4561. if ( cwBI >= 0x00020000 )
  4562. {
  4563. State().m_semX.Release();
  4564. }
  4565. }
  4566. // releases the exclusive latch in exchange for a shared latch
  4567. inline void CSXWLatch::DowngradeExclusiveLatchToSharedLatch()
  4568. {
  4569. // we had better already have only an exclusive latch
  4570. OSSYNCAssert( FNotOwnSharedLatch() );
  4571. OSSYNCAssert( FOwnExclusiveLatch() );
  4572. OSSYNCAssert( FNotOwnWriteLatch() );
  4573. // release our exclusive latch and acquire a shared latch
  4574. const ControlWord cwDelta = 0xFFFF0001;
  4575. const ControlWord cwBI = AtomicExchangeAdd( (long*)&State().m_cw, cwDelta );
  4576. // transfer ownership from the exclusive latch to a shared latch
  4577. State().RemoveAsOwner( 1 );
  4578. State().StopHold( 1 );
  4579. State().SetAcquire( 0 );
  4580. State().AddAsOwner( 0 );
  4581. State().StartHold( 0 );
  4582. // release a waiter for the exclusive latch, if any
  4583. if ( cwBI >= 0x00020000 )
  4584. {
  4585. State().m_semX.Release();
  4586. }
  4587. }
  4588. // releases the write latch
  4589. inline void CSXWLatch::ReleaseWriteLatch()
  4590. {
  4591. // we had better already have only a write latch
  4592. OSSYNCAssert( FNotOwnSharedLatch() );
  4593. OSSYNCAssert( FNotOwnExclusiveLatch() );
  4594. OSSYNCAssert( FOwnWriteLatch() );
  4595. // stop quiescing shared latches by resetting the fQS flag and release our
  4596. // exclusive latch
  4597. const ControlWord cwDelta = 0xFFFE8000;
  4598. const ControlWord cwBI = AtomicExchangeAdd( (long*)&State().m_cw, cwDelta );
  4599. // release ownership of the write latch
  4600. State().RemoveAsOwner( 2 );
  4601. State().StopHold( 2 );
  4602. // release any quiesced shared latches
  4603. if ( cwBI & 0x00007FFF )
  4604. {
  4605. State().m_semS.Release( cwBI & 0x00007FFF );
  4606. }
  4607. // release a waiter for the exclusive latch, if any
  4608. if ( cwBI >= 0x00020000 )
  4609. {
  4610. State().m_semX.Release();
  4611. }
  4612. }
  4613. // releases the exclusive latch
  4614. inline void CSXWLatch::ReleaseExclusiveLatch()
  4615. {
  4616. // we had better already have only an exclusive latch
  4617. OSSYNCAssert( FNotOwnSharedLatch() );
  4618. OSSYNCAssert( FOwnExclusiveLatch() );
  4619. OSSYNCAssert( FNotOwnWriteLatch() );
  4620. // release our exclusive latch
  4621. const ControlWord cwDelta = 0xFFFF0000;
  4622. const ControlWord cwBI = AtomicExchangeAdd( (long*)&State().m_cw, cwDelta );
  4623. // release ownership of the exclusive latch
  4624. State().RemoveAsOwner( 1 );
  4625. State().StopHold( 1 );
  4626. // release a waiter for the exclusive latch, if any
  4627. if ( cwBI >= 0x00020000 )
  4628. {
  4629. State().m_semX.Release();
  4630. }
  4631. }
  4632. // releases a shared latch
  4633. inline void CSXWLatch::ReleaseSharedLatch()
  4634. {
  4635. // we had better already have only a shared latch
  4636. OSSYNCAssert( FOwnSharedLatch() );
  4637. OSSYNCAssert( FNotOwnExclusiveLatch() );
  4638. OSSYNCAssert( FNotOwnWriteLatch() );
  4639. // we are no longer an owner of a shared latch
  4640. State().RemoveAsOwner( 0 );
  4641. State().StopHold( 0 );
  4642. // try forever until we successfully change the latch state
  4643. OSSYNC_FOREVER
  4644. {
  4645. // read the current state of the control word as our expected before image
  4646. ControlWord cwBIExpected = State().m_cw;
  4647. // change the expected before image so that the transaction will only work if
  4648. // shared latches are not quiesced
  4649. cwBIExpected = cwBIExpected & 0xFFFF7FFF;
  4650. // compute the after image of the control word by performing the transform that
  4651. // will release our shared latch
  4652. const ControlWord cwAI = cwBIExpected + 0xFFFFFFFF;
  4653. // attempt to perform the transacted state transition on the control word
  4654. const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );
  4655. // the transaction failed
  4656. if ( cwBI != cwBIExpected )
  4657. {
  4658. // the transaction failed because shared latches were quiesced
  4659. if ( cwBI & 0x00008000 )
  4660. {
  4661. // leave the latch as a quiesced shared latch
  4662. _UpdateQuiescedSharedLatchCount( 0xFFFFFFFF );
  4663. // we're done
  4664. break;
  4665. }
  4666. // the transaction failed because another context changed the control word
  4667. else
  4668. {
  4669. // try again
  4670. continue;
  4671. }
  4672. }
  4673. // the transaction succeeded
  4674. else
  4675. {
  4676. // we're done
  4677. break;
  4678. }
  4679. }
  4680. }
  4681. // waits for ownership of a shared latch in response to receiving an
  4682. // errWaitForSharedLatch from the API. this function must not be called at any
  4683. // other time
  4684. inline void CSXWLatch::WaitForSharedLatch()
  4685. {
  4686. // check for deadlock
  4687. OSSYNCAssertSzRTL( State().FCanBeWaiter(), "Potential Deadlock Detected (Rank Violation)");
  4688. // we had better already be declared a waiter
  4689. OSSYNCAssert( State().FWaiter( 0 ) );
  4690. // wait for ownership of a shared latch on the shared latch semaphore
  4691. State().m_semS.Acquire();
  4692. State().StopWait( 0 );
  4693. State().RemoveAsWaiter( 0 );
  4694. State().SetAcquire( 0 );
  4695. State().AddAsOwner( 0 );
  4696. State().StartHold( 0 );
  4697. }
  4698. // waits for ownership of the exclusive latch in response to receiving an
  4699. // errWaitForExclusiveLatch from the API. this function must not be called at any
  4700. // other time
  4701. inline void CSXWLatch::WaitForExclusiveLatch()
  4702. {
  4703. // check for deadlock
  4704. OSSYNCAssertSzRTL( State().FCanBeWaiter(), "Potential Deadlock Detected (Rank Violation)");
  4705. // we had better already be declared a waiter
  4706. OSSYNCAssert( State().FWaiter( 1 ) );
  4707. // wait for ownership of the exclusive latch on the exclusive latch semaphore
  4708. State().m_semX.Acquire();
  4709. State().StopWait( 1 );
  4710. State().RemoveAsWaiter( 1 );
  4711. State().SetAcquire( 1 );
  4712. State().AddAsOwner( 1 );
  4713. State().StartHold( 1 );
  4714. }
  4715. // waits for ownership of the write latch in response to receiving an
  4716. // errWaitForWriteLatch from the API. this function must not be called at any
  4717. // other time
  4718. inline void CSXWLatch::WaitForWriteLatch()
  4719. {
  4720. // check for deadlock
  4721. OSSYNCAssertSzRTL( State().FCanBeWaiter(), "Potential Deadlock Detected (Rank Violation)");
  4722. // we had better already be declared a waiter
  4723. OSSYNCAssert( State().FWaiter( 2 ) );
  4724. // wait for ownership of the write latch on the write latch semaphore
  4725. State().m_semW.Acquire();
  4726. State().StopWait( 2 );
  4727. State().RemoveAsWaiter( 2 );
  4728. State().SetAcquire( 2 );
  4729. State().AddAsOwner( 2 );
  4730. State().StartHold( 2 );
  4731. }
  4732. // claims ownership of the latch for the specified group for deadlock detection
  4733. inline void CSXWLatch::ClaimOwnership( const DWORD group )
  4734. {
  4735. State().AddAsOwner( group );
  4736. }
  4737. // releases ownership of the latch for the specified group for deadlock detection
  4738. inline void CSXWLatch::ReleaseOwnership( const DWORD group )
  4739. {
  4740. State().RemoveAsOwner( group );
  4741. }
  4742. // updates the quiesced shared latch count, possibly releasing a waiter for
  4743. // the write latch
  4744. inline void CSXWLatch::_UpdateQuiescedSharedLatchCount( const DWORD cQSDelta )
  4745. {
  4746. // update the quiesced shared latch count using the provided delta
  4747. const DWORD cQSBI = AtomicExchangeAdd( (long*)&State().m_cQS, cQSDelta );
  4748. const DWORD cQSAI = cQSBI + cQSDelta;
  4749. // our update resulted in a zero quiesced shared latch count
  4750. if ( !cQSAI )
  4751. {
  4752. // release the waiter for the write latch
  4753. State().m_semW.Release();
  4754. }
  4755. }
  4756. // init sync subsystem
  4757. const BOOL OSSYNCAPI FOSSyncPreinit();
  4758. #define FOSSyncInit FOSSyncPreinit
  4759. // terminate sync subsystem
  4760. void OSSYNCAPI OSSyncPostterm();
  4761. #define OSSyncTerm OSSyncPostterm
  4762. // attach the current context to the sync subsystem
  4763. BOOL OSSYNCAPI FOSSyncAttach();
  4764. // detach the current context from the sync subsystem
  4765. void OSSYNCAPI OSSyncDetach();
  4766. // special init/term API's for Enhanced State only
  4767. const BOOL OSSYNCAPI FOSSyncInitForES();
  4768. void OSSYNCAPI OSSyncTermForES();
  4769. }; // namespace OSSYNC
  4770. using namespace OSSYNC;
  4771. #endif // _SYNC_HXX_INCLUDED