Source code of Windows XP (NT5)
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.

4898 lines
104 KiB

  1. #ifndef _OS_SYNC_HXX_INCLUDED
  2. #define _OS_SYNC_HXX_INCLUDED
  3. // Build Options
  4. #define SYNC_USE_X86_ASM // use x86 assembly for atomic memory manipulation
  5. //#define SYNC_ANALYZE_PERFORMANCE // analyze usage of synchronization objects
  6. //#define SYNC_DEADLOCK_DETECTION // perform deadlock detection
  7. #define SYNC_VALIDATE_IRKSEM_USAGE // validate IRKSEM (CReferencedKernelSemaphore) usage
  8. #ifdef DEBUG
  9. #define SYNC_DEADLOCK_DETECTION // always perform deadlock detection in DEBUG
  10. #define SYNC_VALIDATE_IRKSEM_USAGE // always validate IRKSEM (CReferencedKernelSemaphore) usage in DEBUG
  11. #endif // DEBUG
  12. #pragma warning ( disable : 4355 )
  13. #include <tchar.h>
  14. #include <new.h>
  15. #include <stdarg.h>
  16. typedef int BOOL;
  17. #define fFalse 0
  18. #define fTrue (!0)
  19. typedef unsigned char BYTE;
  20. typedef unsigned short WORD;
  21. typedef unsigned long DWORD;
  22. typedef unsigned __int64 QWORD;
  23. #ifdef DEBUG
  24. #define SYNC_FOREVER for ( int cLoop = 0; ; cLoop++ )
  25. #else // !DEBUG
  26. #define SYNC_FOREVER for ( ; ; )
  27. #endif // DEBUG
  28. class CPRINTFSYNC
  29. {
  30. public:
  31. CPRINTFSYNC() {}
  32. virtual ~CPRINTFSYNC() {}
  33. public:
  34. virtual void __cdecl operator()( const _TCHAR* szFormat, ... ) const = 0;
  35. };
  36. // Context Local Storage
  37. class COwner;
  38. struct CLS
  39. {
  40. COwner* pownerLockHead; // list of locks owned by this context
  41. DWORD dwContextId; // context ID
  42. CLS* pclsNext; // next CLS in global list
  43. CLS** ppclsNext; // pointer to the pointer to this CLS
  44. };
  45. // returns the pointer to the current context's local storage
  46. CLS* const Pcls();
  47. // Assertions
  48. // Assertion Failure action
  49. //
  50. // called to indicate to the developer that an assumption is not true
  51. void AssertFail( const _TCHAR* szMessage, const _TCHAR* szFilename, long lLine );
  52. #ifdef Assert
  53. #else // !Assert
  54. // Assert Macros
  55. // asserts that the given expression is true or else fails with the specified message
  56. #define AssertRTLSz( exp, sz ) ( ( exp ) ? (void) 0 : AssertFail( _T( sz ), _T( __FILE__ ), __LINE__ ) )
  57. #ifdef DEBUG
  58. #define AssertSz( exp, sz ) AssertRTLSz( exp, sz )
  59. #else // !DEBUG
  60. #define AssertSz( exp, sz )
  61. #endif // DEBUG
  62. // asserts that the given expression is true or else fails with that expression
  63. #define AssertRTL( exp ) AssertRTLSz( exp, #exp )
  64. #define Assert( exp ) AssertSz( exp, #exp )
  65. #endif // Assert
  66. // Enforces
  67. // Enforce Failure action
  68. //
  69. // called when a strictly enforced condition has been violated
  70. void EnforceFail( const _TCHAR* szMessage, const _TCHAR* szFilename, long lLine );
  71. #ifdef Enforce
  72. #else // !Enforce
  73. // Enforce Macros
  74. // the given expression MUST be true or else fails with the specified message
  75. #define EnforceSz( exp, sz ) ( ( exp ) ? (void) 0 : EnforceFail( _T( sz ), _T ( __FILE__ ), __LINE__ ) )
  76. // the given expression MUST be true or else fails with that expression
  77. #define Enforce( exp ) EnforceSz( exp, #exp )
  78. #endif // Enforce
  79. #ifdef SYNC_VALIDATE_IRKSEM_USAGE
  80. #define Enforce1Sz( exp, sz ) EnforceSz( exp, sz )
  81. #else // !SYNC_VALIDATE_IRKSEM_USAGE
  82. #define Enforce1Sz( exp, sz )
  83. #endif // SYNC_VALIDATE_IRKSEM_USAGE
  84. // High Resolution Timer
  85. // returns the current HRT count
  86. QWORD QwOSTimeHRTCount();
  87. // Global Synchronization Constants
  88. // wait time used for testing the state of the kernel object
  89. extern const int cmsecTest;
  90. // wait time used for infinite wait on a kernel object
  91. extern const int cmsecInfinite;
  92. // maximum wait time on a kernel object before a deadlock is suspected
  93. extern const int cmsecDeadlock;
  94. // wait time used for infinite wait on a kernel object without deadlock
  95. extern const int cmsecInfiniteNoDeadlock;
  96. // Atomic Memory Manipulations
  97. #if defined( _M_IX86 ) && defined( SYNC_USE_X86_ASM )
  98. // returns fTrue if the given data is properly aligned for atomic modification
  99. inline const BOOL IsAtomicallyModifiable( long* plTarget )
  100. {
  101. return long( plTarget ) % sizeof( long ) == 0;
  102. }
  103. #pragma warning( disable: 4035 )
  104. // atomically compares the current value of the target with the specified
  105. // initial value and if equal sets the target to the specified final value.
  106. // the initial value of the target is returned. the exchange is successful
  107. // if the value returned equals the specified initial value. the target
  108. // must be aligned to a four byte boundary
  109. inline const long AtomicCompareExchange( long* plTarget, const long lInitial, const long lFinal )
  110. {
  111. Assert( IsAtomicallyModifiable( plTarget ) );
  112. __asm mov ecx, plTarget
  113. __asm mov edx, lFinal
  114. __asm mov eax, lInitial
  115. __asm lock cmpxchg [ecx], edx
  116. }
  117. // atomically sets the target to the specified value, returning the target's
  118. // initial value. the target must be aligned to a four byte boundary
  119. inline const long AtomicExchange( long* plTarget, const long lValue )
  120. {
  121. Assert( IsAtomicallyModifiable( plTarget ) );
  122. __asm mov ecx, plTarget
  123. __asm mov eax, lValue
  124. __asm lock xchg [ecx], eax
  125. }
  126. // atomically adds the specified value to the target, returning the target's
  127. // initial value. the target must be aligned to a four byte boundary
  128. inline const long AtomicExchangeAdd( long* plTarget, const long lValue )
  129. {
  130. Assert( IsAtomicallyModifiable( plTarget ) );
  131. __asm mov ecx, plTarget
  132. __asm mov eax, lValue
  133. __asm lock xadd [ecx], eax
  134. }
  135. #pragma warning( default: 4035 )
  136. #elif defined( _M_AMD64) || defined(_M_IA64)
  137. // returns fTrue if the given data is properly aligned for atomic modification
  138. inline const BOOL IsAtomicallyModifiable( long* plTarget )
  139. {
  140. return (ULONG_PTR) plTarget % sizeof( long ) == 0;
  141. }
  142. inline const long AtomicCompareExchange( long* plTarget, const long lInitial, const long lFinal )
  143. {
  144. Assert( IsAtomicallyModifiable( plTarget ) );
  145. return InterlockedCompareExchange( plTarget, lFinal, lInitial );
  146. }
  147. inline const long AtomicExchange( long* plTarget, const long lValue )
  148. {
  149. Assert( IsAtomicallyModifiable( plTarget ) );
  150. return InterlockedExchange( plTarget, lValue );
  151. }
  152. inline const long AtomicExchangeAdd( long* plTarget, const long lValue )
  153. {
  154. Assert( IsAtomicallyModifiable( plTarget ) );
  155. return InterlockedExchangeAdd( plTarget, lValue );
  156. }
  157. #else
  158. const BOOL IsAtomicallyModifiable( long* plTarget );
  159. const long AtomicCompareExchange( long* plTarget, const long lInitial, const long lFinal );
  160. const long AtomicExchange( long* plTarget, const long lValue );
  161. const long AtomicExchangeAdd( long* plTarget, const long lValue );
  162. #endif
  163. // atomically increments the target, returning the incremented value. the
  164. // target must be aligned to a four byte boundary
  165. inline const long AtomicIncrement( long* plTarget )
  166. {
  167. return AtomicExchangeAdd( plTarget, 1 ) + 1;
  168. }
  169. // atomically decrements the target, returning the decremented value. the
  170. // target must be aligned to a four byte boundary
  171. inline const long AtomicDecrement( long* plTarget )
  172. {
  173. return AtomicExchangeAdd( plTarget, -1 ) - 1;
  174. }
  175. // atomically adds the specified value to the target. the target must be
  176. // aligned to a four byte boundary
  177. inline void AtomicAdd( QWORD* pqwTarget, QWORD qwValue )
  178. {
  179. DWORD* const pdwTargetLow = (DWORD*)pqwTarget;
  180. DWORD* const pdwTargetHigh = pdwTargetLow + 1;
  181. const DWORD dwValueLow = DWORD( qwValue );
  182. DWORD dwValueHigh = DWORD( qwValue >> 32 );
  183. if ( dwValueLow )
  184. {
  185. if ( DWORD( AtomicExchangeAdd( (long*)pdwTargetLow, dwValueLow ) ) + dwValueLow < dwValueLow )
  186. {
  187. dwValueHigh++;
  188. }
  189. }
  190. if ( dwValueHigh )
  191. {
  192. AtomicExchangeAdd( (long*)pdwTargetHigh, dwValueHigh );
  193. }
  194. }
  195. // Enhanced Synchronization Object State Container
  196. //
  197. // This class manages a "simple" or normal state for an arbitrary sync object
  198. // and its "enhanced" counterpart. Which type is used depends on the build.
  199. // The goal is to maintain a footprint equal to the normal state so that other
  200. // classes that contain this object do not fluctuate in size depending on what
  201. // build options have been selected. For example, a performance build might
  202. // need extra storage to collect performance stats on the object. This data
  203. // will force the object to be allocated elsewhere in memory but will not change
  204. // the size of the object in its containing class.
  205. //
  206. // Template Arguments:
  207. //
  208. // CState sync object state class
  209. // CStateInit sync object state class ctor arg type
  210. // CInformation sync object information class
  211. // CInformationInit sync object information class ctor arg type
  212. void* ESMemoryNew( size_t cb );
  213. void ESMemoryDelete( void* pv );
  214. // determine when enhanced state is needed
  215. #if defined( SYNC_ANALYZE_PERFORMANCE ) || defined( SYNC_DEADLOCK_DETECTION )
  216. #define SYNC_ENHANCED_STATE
  217. #endif // SYNC_ANALYZE_PERFORMANCE || SYNC_DEADLOCK_DETECTION
  218. template< class CState, class CStateInit, class CInformation, class CInformationInit >
  219. class CEnhancedStateContainer
  220. {
  221. public:
  222. // types
  223. // enhanced state
  224. class CEnhancedState
  225. : public CState,
  226. public CInformation
  227. {
  228. public:
  229. CEnhancedState( const CStateInit& si, const CInformationInit& ii )
  230. : CState( si ),
  231. CInformation( ii )
  232. {
  233. }
  234. void* operator new( size_t cb ) { return ESMemoryNew( cb ); }
  235. void operator delete( void* pv ) { ESMemoryDelete( pv ); }
  236. };
  237. // member functions
  238. // ctors / dtors
  239. #ifdef SYNC_ENHANCED_STATE
  240. CEnhancedStateContainer( const CStateInit& si, const CInformationInit& ii )
  241. {
  242. m_pes = new CEnhancedState( si, ii );
  243. }
  244. #else // !SYNC_ENHANCED_STATE
  245. CEnhancedStateContainer( const CStateInit& si, const CInformationInit& ii )
  246. : m_state( si )
  247. {
  248. }
  249. #endif // SYNC_ENHANCED_STATE
  250. ~CEnhancedStateContainer()
  251. {
  252. #ifdef SYNC_ENHANCED_STATE
  253. delete m_pes;
  254. #ifdef DEBUG
  255. m_pes = NULL;
  256. #endif // DEBUG
  257. #endif // SYNC_ENHANCED_STATE
  258. }
  259. // accessors
  260. CEnhancedState& State() const
  261. {
  262. #ifdef SYNC_ENHANCED_STATE
  263. return *m_pes;
  264. #else // !SYNC_ENHANCED_STATE
  265. // NOTE: this assumes that CInformation has no storage!
  266. return (CEnhancedState&) m_state;
  267. #endif // SYNC_ENHANCED_STATE
  268. }
  269. size_t CbState() const
  270. {
  271. #ifdef SYNC_ENHANCED_STATE
  272. return sizeof( CEnhancedState );
  273. #else // !SYNC_ENHANCED_STATE
  274. // NOTE: this assumes that CInformation has no storage!
  275. return sizeof( CState );
  276. #endif // SYNC_ENHANCED_STATE
  277. }
  278. private:
  279. // data members
  280. // either a pointer to the enhanced state elsewhere in memory or the
  281. // actual state data, depending on the mode of the sync object
  282. #ifdef SYNC_ENHANCED_STATE
  283. union
  284. {
  285. CEnhancedState* m_pes;
  286. BYTE m_rgbSize[ sizeof( CState ) ];
  287. };
  288. #else // !SYNC_ENHANCED_STATE
  289. CState m_state;
  290. #endif // SYNC_ENHANCED_STATE
  291. };
  292. // Synchronization Object Base Class
  293. //
  294. // All Synchronization Objects are derived from this class
  295. class CSyncObject
  296. {
  297. public:
  298. // member functions
  299. // ctors / dtors
  300. CSyncObject() {}
  301. ~CSyncObject() {}
  302. private:
  303. // member functions
  304. // operators
  305. CSyncObject& operator=( CSyncObject& ); // disallowed
  306. };
  307. // Synchronization Object Basic Information
  308. class CSyncBasicInfo
  309. {
  310. public:
  311. // member functions
  312. // ctors / dtors
  313. CSyncBasicInfo( const _TCHAR* szInstanceName );
  314. ~CSyncBasicInfo();
  315. // manipulators
  316. #ifdef SYNC_ENHANCED_STATE
  317. void SetTypeName( const _TCHAR* szTypeName ) { m_szTypeName = szTypeName; }
  318. void SetInstance( const CSyncObject* const psyncobj ) { m_psyncobj = psyncobj; }
  319. #endif // SYNC_ENHANCED_STATE
  320. // accessors
  321. #ifdef SYNC_ENHANCED_STATE
  322. const _TCHAR* SzInstanceName() const { return m_szInstanceName; }
  323. const _TCHAR* SzTypeName() const { return m_szTypeName; }
  324. const CSyncObject* const Instance() const { return m_psyncobj; }
  325. #endif // SYNC_ENHANCED_STATE
  326. // debugging support
  327. void Dump( CPRINTFSYNC* pcprintf, DWORD dwOffset );
  328. private:
  329. // member functions
  330. // operators
  331. CSyncBasicInfo& operator=( CSyncBasicInfo& ); // disallowed
  332. // data members
  333. #ifdef SYNC_ENHANCED_STATE
  334. // Instance Name
  335. const _TCHAR* m_szInstanceName;
  336. // Type Name
  337. const _TCHAR* m_szTypeName;
  338. // Instance
  339. const CSyncObject* m_psyncobj;
  340. #endif // SYNC_ENHANCED_STATE
  341. };
  342. // Synchronization Object Performance: Wait Times
  343. class CSyncPerfWait
  344. {
  345. public:
  346. // member functions
  347. // ctors / dtors
  348. CSyncPerfWait();
  349. ~CSyncPerfWait();
  350. // member functions
  351. // manipulators
  352. void StartWait();
  353. void StopWait();
  354. // debugging support
  355. void Dump( CPRINTFSYNC* pcprintf, DWORD dwOffset );
  356. private:
  357. // member functions
  358. // operators
  359. CSyncPerfWait& operator=( CSyncPerfWait& ); // disallowed
  360. // data members
  361. #ifdef SYNC_ANALYZE_PERFORMANCE
  362. // wait count
  363. volatile QWORD m_cWait;
  364. // elapsed wait time
  365. volatile QWORD m_qwHRTWaitElapsed;
  366. #endif // SYNC_ANALYZE_PERFORMANCE
  367. };
  368. // starts the wait timer for the sync object
  369. inline void CSyncPerfWait::StartWait()
  370. {
  371. #ifdef SYNC_ANALYZE_PERFORMANCE
  372. // increment the wait count
  373. AtomicAdd( (QWORD*)&m_cWait, 1 );
  374. // subtract the start wait time from the elapsed wait time. this starts
  375. // an elapsed time computation for this context. StopWait() will later
  376. // add the end wait time to the elapsed time, causing the following net
  377. // effect:
  378. //
  379. // m_qwHRTWaitElapsed += <end time> - <start time>
  380. //
  381. // we simply choose to go ahead and do the subtraction now to save storage
  382. AtomicAdd( (QWORD*)&m_qwHRTWaitElapsed, QWORD( -__int64( QwOSTimeHRTCount() ) ) );
  383. #endif // SYNC_ANALYZE_PERFORMANCE
  384. }
  385. // stops the wait timer for the sync object
  386. inline void CSyncPerfWait::StopWait()
  387. {
  388. #ifdef SYNC_ANALYZE_PERFORMANCE
  389. // add the end wait time to the elapsed wait time. this completes the
  390. // computation started in StartWait()
  391. AtomicAdd( (QWORD*)&m_qwHRTWaitElapsed, QwOSTimeHRTCount() );
  392. #endif // SYNC_ANALYZE_PERFORMANCE
  393. }
  394. // Simple Synchronization Object Performance Information
  395. class CSyncSimplePerfInfo
  396. : public CSyncBasicInfo,
  397. public CSyncPerfWait
  398. {
  399. public:
  400. // member functions
  401. // ctors / dtors
  402. CSyncSimplePerfInfo( const CSyncBasicInfo& sbi )
  403. : CSyncBasicInfo( sbi )
  404. {
  405. }
  406. // debugging support
  407. void Dump( CPRINTFSYNC* pcprintf, DWORD dwOffset )
  408. {
  409. CSyncBasicInfo::Dump( pcprintf, dwOffset );
  410. CSyncPerfWait::Dump( pcprintf, dwOffset );
  411. }
  412. };
  413. // Null Synchronization Object State Initializer
  414. class CSyncStateInitNull
  415. {
  416. };
  417. extern CSyncStateInitNull syncstateNull;
  418. // Kernel Semaphore State
  419. class CKernelSemaphoreState
  420. {
  421. public:
  422. // member functions
  423. // ctors / dtors
  424. CKernelSemaphoreState( const CSyncStateInitNull& null ) : m_handle( 0 ) {}
  425. // manipulators
  426. void SetHandle( LONG_PTR handle ) { m_handle = handle; }
  427. // accessors
  428. LONG_PTR Handle() { return m_handle; }
  429. // debugging support
  430. void Dump( CPRINTFSYNC* pcprintf, DWORD dwOffset );
  431. private:
  432. // member functions
  433. // operators
  434. CKernelSemaphoreState& operator=( CKernelSemaphoreState& ); // disallowed
  435. // data members
  436. // kernel semaphore handle
  437. LONG_PTR m_handle;
  438. };
  439. // Kernel Semaphore
  440. class CKernelSemaphore
  441. : private CSyncObject,
  442. private CEnhancedStateContainer< CKernelSemaphoreState, CSyncStateInitNull, CSyncSimplePerfInfo, CSyncBasicInfo >
  443. {
  444. public:
  445. // member functions
  446. // ctors / dtors
  447. CKernelSemaphore( const CSyncBasicInfo& sbi );
  448. ~CKernelSemaphore();
  449. // init / term
  450. const BOOL FInit();
  451. void Term();
  452. // manipulators
  453. void Acquire();
  454. const BOOL FTryAcquire();
  455. const BOOL FAcquire( const int cmsecTimeout );
  456. void Release( const int cToRelease = 1 );
  457. // accessors
  458. const BOOL FReset();
  459. // debugging support
  460. void Dump( CPRINTFSYNC* pcprintf, DWORD dwOffset = 0 );
  461. size_t CbEnhancedState() { return CbState(); }
  462. private:
  463. // member functions
  464. // operators
  465. CKernelSemaphore& operator=( CKernelSemaphore& ); // disallowed
  466. // accessors
  467. const BOOL FInitialized();
  468. };
  469. // acquire one count of the semaphore, waiting forever if necessary
  470. inline void CKernelSemaphore::Acquire()
  471. {
  472. // semaphore should be initialized
  473. Assert( FInitialized() );
  474. // wait for the semaphore
  475. const BOOL fAcquire = FAcquire( cmsecInfinite );
  476. Assert( fAcquire );
  477. }
  478. // try to acquire one count of the semaphore without waiting. returns 0 if a
  479. // count could not be acquired
  480. inline const BOOL CKernelSemaphore::FTryAcquire()
  481. {
  482. // semaphore should be initialized
  483. Assert( FInitialized() );
  484. // test the semaphore
  485. return FAcquire( cmsecTest );
  486. }
  487. // returns fTrue if the semaphore has no available counts
  488. inline const BOOL CKernelSemaphore::FReset()
  489. {
  490. // semaphore should be initialized
  491. Assert( FInitialized() );
  492. // test the semaphore
  493. return !FTryAcquire();
  494. }
  495. // returns fTrue if the semaphore has been initialized
  496. inline const BOOL CKernelSemaphore::FInitialized()
  497. {
  498. return State().Handle() != 0;
  499. }
  500. // Kernel Semaphore Pool
  501. class CKernelSemaphorePool
  502. {
  503. public:
  504. // types
  505. // index to a ref counted kernel semaphore
  506. typedef unsigned short IRKSEM;
  507. enum { irksemUnknown = 0xFFFE, irksemNil = 0xFFFF };
  508. // member functions
  509. // ctors / dtors
  510. CKernelSemaphorePool();
  511. ~CKernelSemaphorePool();
  512. // init / term
  513. const BOOL FInit();
  514. void Term();
  515. // manipulators
  516. const IRKSEM Allocate( const CSyncObject* const psyncobj );
  517. void Reference( const IRKSEM irksem );
  518. void Unreference( const IRKSEM irksem );
  519. // accessors
  520. CKernelSemaphore& Ksem( const IRKSEM irksem, const CSyncObject* const psyncobj ) const;
  521. const BOOL FInitialized() const;
  522. private:
  523. // types
  524. // reference counted kernel semaphore
  525. class CReferencedKernelSemaphore
  526. : public CKernelSemaphore
  527. {
  528. public:
  529. // member functions
  530. // ctors / dtors
  531. CReferencedKernelSemaphore();
  532. ~CReferencedKernelSemaphore();
  533. // init / term
  534. const BOOL FInit();
  535. void Term();
  536. // manipulators
  537. void SetUser( const CSyncObject* const psyncobj );
  538. void Reference();
  539. const BOOL FUnreference();
  540. void SetNextIrksem( const IRKSEM irksem );
  541. // accessors
  542. const IRKSEM IrksemNext() const { return m_irksemNext; }
  543. const BOOL FInUse() const { return m_fInUse; }
  544. const int CReference() const { return m_cReference; }
  545. #ifdef SYNC_VALIDATE_IRKSEM_USAGE
  546. const CSyncObject* const PsyncobjUser() const { return m_psyncobjUser; }
  547. #endif // SYNC_VALIDATE_IRKSEM_USAGE
  548. private:
  549. // member functions
  550. // operators
  551. CReferencedKernelSemaphore& operator=( CReferencedKernelSemaphore& ); // disallowed
  552. // data members
  553. // transacted state representation
  554. union
  555. {
  556. volatile long m_l;
  557. struct
  558. {
  559. volatile unsigned short m_cReference:15; // 0 <= m_cReference <= ( 1 << 15 ) - 1
  560. volatile unsigned short m_fInUse:1; // m_fInUse = { 0, 1 }
  561. volatile unsigned short m_irksemNext; // 0 <= m_irksemNext <= ( 1 << 16 ) - 1
  562. };
  563. };
  564. #ifdef SYNC_VALIDATE_IRKSEM_USAGE
  565. // sync object currently using this semaphore
  566. const CSyncObject* volatile m_psyncobjUser;
  567. #endif // SYNC_VALIDATE_IRKSEM_USAGE
  568. };
  569. // member functions
  570. // operators
  571. CKernelSemaphorePool& operator=( CKernelSemaphorePool& ); // disallowed
  572. // manipulators
  573. const IRKSEM AllocateNew();
  574. void RefreshNextPointer();
  575. void Free( const IRKSEM irksem );
  576. // data members
  577. // semaphore count
  578. volatile long m_cksem;
  579. // semaphore index to semaphore map
  580. CReferencedKernelSemaphore* m_mpirksemrksem;
  581. // transacted state representation
  582. union
  583. {
  584. volatile long m_l;
  585. struct
  586. {
  587. volatile unsigned short m_irksemTop; // 0 <= m_irksemTop <= ( 1 << 16 ) - 1
  588. volatile unsigned short m_irksemNext; // 0 <= m_irksemNext <= ( 1 << 16 ) - 1
  589. };
  590. };
  591. };
  592. // allocates an IRKSEM from the pool on behalf of the specified sync object
  593. //
  594. // NOTE: the returned IRKSEM has one reference count
  595. inline const CKernelSemaphorePool::IRKSEM CKernelSemaphorePool::Allocate( const CSyncObject* const psyncobj )
  596. {
  597. // semaphore pool should be initialized
  598. Assert( FInitialized() );
  599. // try forever until we succeed in popping an IRKSEM off of the stack
  600. IRKSEM irksem;
  601. SYNC_FOREVER
  602. {
  603. // read the current state of the control word as our expected before image
  604. long lBIExpected = m_l;
  605. // change the expected before image so that the transaction will only
  606. // work if the next pointer is not unknown
  607. lBIExpected = IRKSEM( lBIExpected >> 16 ) == irksemUnknown ? 0 : lBIExpected;
  608. // compute the after image of the control word by moving the previous next
  609. // pointer to the top pointer and marking the next pointer as unknown
  610. const long lAI = long( irksemUnknown << 16 ) | IRKSEM( lBIExpected >> 16 );
  611. // attempt to perform the transacted state transition on the control word
  612. const long lBI = AtomicCompareExchange( (long*)&m_l, lBIExpected, lAI );
  613. // the transaction failed
  614. if ( lBI != lBIExpected )
  615. {
  616. // the transaction failed because the next pointer was unknown
  617. if ( IRKSEM( lBI >> 16 ) == irksemUnknown )
  618. {
  619. // the transaction failed because the stack is empty
  620. if ( IRKSEM( lBI & 0x0000FFFF ) == irksemNil )
  621. {
  622. // allocate a new semaphore
  623. irksem = AllocateNew();
  624. // we're done
  625. break;
  626. }
  627. // the transaction failed because the next pointer needs to be refreshed
  628. else
  629. {
  630. // refresh next pointer
  631. RefreshNextPointer();
  632. // try again
  633. continue;
  634. }
  635. }
  636. // the transaction failed because another context changed the control word
  637. else
  638. {
  639. // try again
  640. continue;
  641. }
  642. }
  643. // the transaction succeeded
  644. else
  645. {
  646. // extract the irksem from the before image
  647. irksem = IRKSEM( lBI & 0x0000FFFF );
  648. // we're done
  649. break;
  650. }
  651. }
  652. // validate irksem retrieved
  653. Assert( irksem != irksemNil );
  654. Assert( irksem >= 0 );
  655. Assert( irksem < m_cksem );
  656. // set the user for this semaphore
  657. m_mpirksemrksem[irksem].SetUser( psyncobj );
  658. // ensure that the semaphore we retrieved is reset
  659. Enforce1Sz( Ksem( irksem, psyncobj ).FReset(),
  660. _T( "Illegal allocation of a Kernel Semaphore with available counts!" ) );
  661. // return the allocated semaphore
  662. return irksem;
  663. }
  664. // add a reference count to an IRKSEM
  665. inline void CKernelSemaphorePool::Reference( const IRKSEM irksem )
  666. {
  667. // validate IN args
  668. Assert( irksem != irksemNil );
  669. Assert( irksem >= 0 );
  670. Assert( irksem < m_cksem );
  671. // semaphore pool should be initialized
  672. Assert( FInitialized() );
  673. // increment the reference count for this IRKSEM
  674. m_mpirksemrksem[irksem].Reference();
  675. }
  676. // remove a reference count from an IRKSEM, freeing it if the reference count
  677. // drops to zero and it is not currently in use
  678. inline void CKernelSemaphorePool::Unreference( const IRKSEM irksem )
  679. {
  680. // validate IN args
  681. Assert( irksem != irksemNil );
  682. Assert( irksem >= 0 );
  683. Assert( irksem < m_cksem );
  684. // semaphore pool should be initialized
  685. Assert( FInitialized() );
  686. // decrement the reference count for this IRKSEM
  687. const BOOL fFree = m_mpirksemrksem[irksem].FUnreference();
  688. // we need to free the semaphore
  689. if ( fFree )
  690. {
  691. // free the IRKSEM back to the allocation stack
  692. Free( irksem );
  693. }
  694. }
  695. // returns the CKernelSemaphore object associated with the given IRKSEM
  696. inline CKernelSemaphore& CKernelSemaphorePool::Ksem( const IRKSEM irksem, const CSyncObject* const psyncobj ) const
  697. {
  698. // validate IN args
  699. Assert( irksem != irksemNil );
  700. Assert( irksem >= 0 );
  701. Assert( irksem < m_cksem );
  702. // semaphore pool should be initialized
  703. Assert( FInitialized() );
  704. // we had better be retrieving this semaphore for the right sync object
  705. Enforce1Sz( m_mpirksemrksem[irksem].PsyncobjUser() == psyncobj,
  706. _T( "Illegal use of a Kernel Semaphore by another Synchronization Object" ) );
  707. // return kernel semaphore
  708. return m_mpirksemrksem[irksem];
  709. }
  710. // returns fTrue if the semaphore pool has been initialized
  711. inline const BOOL CKernelSemaphorePool::FInitialized() const
  712. {
  713. return m_mpirksemrksem != NULL;
  714. }
  715. // allocates a new irksem and adds it to the stack's irksem pool
  716. inline const CKernelSemaphorePool::IRKSEM CKernelSemaphorePool::AllocateNew()
  717. {
  718. // atomically allocate a position in the stack's irksem pool for our new
  719. // irksem
  720. const long lDelta = 0x00000001;
  721. const long lBI = AtomicExchangeAdd( (long*) &m_cksem, lDelta );
  722. const IRKSEM irksem = IRKSEM( lBI );
  723. // initialize this irksem
  724. new ( &m_mpirksemrksem[irksem] ) CReferencedKernelSemaphore;
  725. BOOL fInitKernelSemaphore = m_mpirksemrksem[irksem].FInit();
  726. EnforceSz( fInitKernelSemaphore, "Could not allocate a Kernel Semaphore" );
  727. // return the irksem for use
  728. return irksem;
  729. }
  730. // refreshes the next pointer in the stack control word to permit allocation.
  731. // this is only necessary if the next pointer is marked as unknown. this can
  732. // happen if there is more than one allocation from the stack in a row
  733. inline void CKernelSemaphorePool::RefreshNextPointer()
  734. {
  735. // try forever until we succeed in restoring the next pointer
  736. SYNC_FOREVER
  737. {
  738. // read the current state of the control word as our expected before image
  739. long lBIExpected = m_l;
  740. // change the expected before image so that the transaction will only
  741. // work if the stack is not empty
  742. lBIExpected = lBIExpected == ( ( irksemUnknown << 16 ) | irksemNil ) ? 0 : lBIExpected;
  743. // compute the after image of the control word by setting the next pointer
  744. // to the next pointer of the irksem at the top of the stack
  745. const long lAI = long( m_mpirksemrksem[ lBIExpected & 0x0000FFFF ].IrksemNext() << 16 ) | ( lBIExpected & 0x0000FFFF );
  746. // attempt to perform the transacted state transition on the control word
  747. const long lBI = AtomicCompareExchange( (long*)&m_l, lBIExpected, lAI );
  748. // the transaction failed
  749. if ( lBI != lBIExpected )
  750. {
  751. // the transaction failed because the stack was empty
  752. if ( lBI == ( ( irksemUnknown << 16 ) | irksemNil ) )
  753. {
  754. // we're done
  755. break;
  756. }
  757. // the transaction failed because another context changed the control word
  758. else
  759. {
  760. // try again
  761. continue;
  762. }
  763. }
  764. // the transaction succeeded
  765. else
  766. {
  767. // we're done
  768. break;
  769. }
  770. }
  771. }
  772. // frees the given IRKSEM back to the allocation stack
  773. inline void CKernelSemaphorePool::Free( const IRKSEM irksem )
  774. {
  775. // validate IN args
  776. Assert( irksem != irksemNil );
  777. Assert( irksem >= 0 );
  778. Assert( irksem < m_cksem );
  779. // semaphore pool should be initialized
  780. Assert( FInitialized() );
  781. // the semaphore to free had better not be in use
  782. Enforce1Sz( !m_mpirksemrksem[irksem].FInUse(),
  783. _T( "Illegal free of a Kernel Semaphore that is still in use" ) );
  784. // ensure that the semaphore to free is reset
  785. Enforce1Sz( m_mpirksemrksem[irksem].FReset(),
  786. _T( "Illegal free of a Kernel Semaphore that has available counts" ) );
  787. // try forever until we succeed in pushing an IRKSEM onto the stack
  788. SYNC_FOREVER
  789. {
  790. // read the current state of the control word as our expected before image
  791. const long lBIExpected = m_l;
  792. // compute the after image of the control word by setting the next pointer
  793. // to the top pointer and the top pointer to the irksem to push
  794. const long lAI = ( lBIExpected << 16 ) | irksem;
  795. // set the irksem's next irksem to point to the irksem at the TOS
  796. m_mpirksemrksem[irksem].SetNextIrksem( IRKSEM( lBIExpected & 0x0000FFFF ) );
  797. // attempt to perform the transacted state transition on the control word
  798. const long lBI = AtomicCompareExchange( (long*)&m_l, lBIExpected, lAI );
  799. // the transaction failed
  800. if ( lBI != lBIExpected )
  801. {
  802. // try again
  803. continue;
  804. }
  805. // the transaction succeeded
  806. else
  807. {
  808. // we're done
  809. break;
  810. }
  811. }
  812. }
  813. // Referenced Kernel Semaphore
  814. // sets the user for the semaphore and gives the user an initial reference
  815. inline void CKernelSemaphorePool::CReferencedKernelSemaphore::SetUser( const CSyncObject* const psyncobj )
  816. {
  817. // this semaphore had better not already be in use
  818. Enforce1Sz( !m_fInUse,
  819. _T( "Illegal allocation of a Kernel Semaphore that is already in use" ) );
  820. Enforce1Sz( !m_psyncobjUser,
  821. _T( "Illegal allocation of a Kernel Semaphore that is already in use" ) );
  822. // mark this semaphore as in use and add an initial reference count for the
  823. // user
  824. AtomicExchangeAdd( (long*) &m_l, 0x00008001 );
  825. #ifdef SYNC_VALIDATE_IRKSEM_USAGE
  826. m_psyncobjUser = psyncobj;
  827. #endif // SYNC_VALIDATE_IRKSEM_USAGE
  828. }
  829. // add a reference count to the semaphore
  830. inline void CKernelSemaphorePool::CReferencedKernelSemaphore::Reference()
  831. {
  832. // increment the reference count
  833. AtomicIncrement( (long*) &m_l );
  834. // there had better be at least one reference count!
  835. Assert( m_cReference > 0 );
  836. }
  837. // remove a reference count from the semaphore, returning fTrue if the last
  838. // reference count on the semaphore was removed and the semaphore was in use
  839. // (this is the condition on which we can free the semaphore to the stack)
  840. inline const BOOL CKernelSemaphorePool::CReferencedKernelSemaphore::FUnreference()
  841. {
  842. // there had better be at least one reference count!
  843. Assert( m_cReference > 0 );
  844. // decrement the reference count
  845. const long lOld = AtomicDecrement( (long*) &m_l );
  846. // we removed the last reference count and the semaphore is in use
  847. if ( ( lOld & 0x0000FFFF ) == 0x00008000 )
  848. {
  849. // try forever to reset the in use flag
  850. long lCurrent;
  851. long lOld;
  852. do
  853. {
  854. lCurrent = m_l;
  855. const long lNew = lCurrent & 0xFFFF7FFF;
  856. lOld = AtomicCompareExchange( (long*) &m_l, lCurrent, lNew );
  857. }
  858. while ( ( lOld & 0x00008000 ) && lOld != lCurrent );
  859. // we were the context to reset the in use flag
  860. if ( lOld == lCurrent )
  861. {
  862. // we need to free the semaphore, so clear the user and return fTrue
  863. #ifdef SYNC_VALIDATE_IRKSEM_USAGE
  864. m_psyncobjUser = 0;
  865. #endif // SYNC_VALIDATE_IRKSEM_USAGE
  866. return fTrue;
  867. }
  868. // we were not the context to reset the in use flag
  869. else
  870. {
  871. // we do not need to free the semaphore
  872. return fFalse;
  873. }
  874. }
  875. // we either didn't remove the last reference count or the semaphore was
  876. // not in use
  877. else
  878. {
  879. // we do not need to free the semaphore
  880. return fFalse;
  881. }
  882. }
  883. // sets the next irksem pointer
  884. //
  885. // NOTE: this code assumes only one context can modify the next irksem at once
  886. inline void CKernelSemaphorePool::CReferencedKernelSemaphore::SetNextIrksem( const IRKSEM irksem )
  887. {
  888. const IRKSEM irksemOld = m_irksemNext;
  889. AtomicExchangeAdd( (long*) &m_l, ( irksem - irksemOld ) << 16 );
  890. }
  891. // Global Kernel Semaphore Pool
  892. extern CKernelSemaphorePool ksempoolGlobal;
  893. // Synchronization Object Performance: Acquisition
  894. class CSyncPerfAcquire
  895. {
  896. public:
  897. // member functions
  898. // ctors / dtors
  899. CSyncPerfAcquire();
  900. ~CSyncPerfAcquire();
  901. // member functions
  902. // manipulators
  903. void SetAcquire();
  904. void SetContend();
  905. // debugging support
  906. void Dump( CPRINTFSYNC* pcprintf, DWORD dwOffset );
  907. private:
  908. // member functions
  909. // operators
  910. CSyncPerfAcquire& operator=( CSyncPerfAcquire& ); // disallowed
  911. // data members
  912. #ifdef SYNC_ANALYZE_PERFORMANCE
  913. // acquire count
  914. volatile QWORD m_cAcquire;
  915. // contend count
  916. volatile QWORD m_cContend;
  917. #endif // SYNC_ANALYZE_PERFORMANCE
  918. };
  919. // specifies that the sync object was acquired
  920. inline void CSyncPerfAcquire::SetAcquire()
  921. {
  922. #ifdef SYNC_ANALYZE_PERFORMANCE
  923. AtomicAdd( (QWORD*)&m_cAcquire, 1 );
  924. #endif // SYNC_ANALYZE_PERFORMANCE
  925. }
  926. // specifies that a contention occurred while acquiring the sync object
  927. inline void CSyncPerfAcquire::SetContend()
  928. {
  929. #ifdef SYNC_ANALYZE_PERFORMANCE
  930. AtomicAdd( (QWORD*)&m_cContend, 1 );
  931. #endif // SYNC_ANALYZE_PERFORMANCE
  932. }
  933. // Complex Synchronization Object Performance Information
  934. class CSyncComplexPerfInfo
  935. : public CSyncSimplePerfInfo,
  936. public CSyncPerfAcquire
  937. {
  938. public:
  939. // member functions
  940. // ctors / dtors
  941. CSyncComplexPerfInfo( const CSyncBasicInfo& sbi )
  942. : CSyncSimplePerfInfo( sbi )
  943. {
  944. }
  945. // debugging support
  946. void Dump( CPRINTFSYNC* pcprintf, DWORD dwOffset )
  947. {
  948. CSyncSimplePerfInfo::Dump( pcprintf, dwOffset );
  949. CSyncPerfAcquire::Dump( pcprintf, dwOffset );
  950. }
  951. };
  952. // Semaphore State
  953. #pragma pack( 1 )
  954. class CSemaphoreState
  955. {
  956. public:
  957. // member functions
  958. // ctors / dtors
  959. CSemaphoreState( const CSyncStateInitNull& null ) : m_cAvail( 0 ) {}
  960. CSemaphoreState( const int cAvail );
  961. CSemaphoreState( const int cWait, const int irksem );
  962. ~CSemaphoreState() {}
  963. // operators
  964. CSemaphoreState& operator=( CSemaphoreState& state ) { m_cAvail = state.m_cAvail; return *this; }
  965. // manipulators
  966. const BOOL FChange( const CSemaphoreState& stateCur, const CSemaphoreState& stateNew );
  967. const BOOL FIncAvail( const int cToInc );
  968. const BOOL FDecAvail();
  969. // accessors
  970. const BOOL FNoWait() const { return m_cAvail >= 0; }
  971. const BOOL FWait() const { return m_cAvail < 0; }
  972. const BOOL FAvail() const { return m_cAvail > 0; }
  973. const BOOL FNoWaitAndNoAvail() const { return m_cAvail == 0; }
  974. const int CAvail() const { Assert( FNoWait() ); return m_cAvail; }
  975. const int CWait() const { Assert( FWait() ); return -m_cWaitNeg; }
  976. const CKernelSemaphorePool::IRKSEM Irksem() const { Assert( FWait() ); return CKernelSemaphorePool::IRKSEM( m_irksem ); }
  977. // debugging support
  978. void Dump( CPRINTFSYNC* pcprintf, DWORD dwOffset );
  979. private:
  980. // data members
  981. // transacted state representation (switched on bit 31)
  982. union
  983. {
  984. // Mode 0: no waiters
  985. volatile long m_cAvail; // 0 <= m_cAvail <= ( 1 << 31 ) - 1
  986. // Mode 1: waiters
  987. struct
  988. {
  989. volatile unsigned short m_irksem; // 0 <= m_irksem <= ( 1 << 16 ) - 2
  990. volatile short m_cWaitNeg; // -( ( 1 << 15 ) - 1 ) <= m_cWaitNeg <= -1
  991. };
  992. };
  993. };
  994. #pragma pack()
  995. // ctor
  996. inline CSemaphoreState::CSemaphoreState( const int cAvail )
  997. {
  998. // validate IN args
  999. Assert( cAvail >= 0 );
  1000. Assert( cAvail <= 0x7FFFFFFF );
  1001. // set available count
  1002. m_cAvail = long( cAvail );
  1003. }
  1004. // ctor
  1005. inline CSemaphoreState::CSemaphoreState( const int cWait, const int irksem )
  1006. {
  1007. // validate IN args
  1008. Assert( cWait > 0 );
  1009. Assert( cWait <= 0x7FFF );
  1010. Assert( irksem >= 0 );
  1011. Assert( irksem <= 0xFFFE );
  1012. // set waiter count
  1013. m_cWaitNeg = short( -cWait );
  1014. // set semaphore
  1015. m_irksem = (unsigned short) irksem;
  1016. }
  1017. // changes the transacted state of the semaphore using a transacted memory
  1018. // compare/exchange operation, returning fFalse on failure
  1019. inline const BOOL CSemaphoreState::FChange( const CSemaphoreState& stateCur, const CSemaphoreState& stateNew )
  1020. {
  1021. return AtomicCompareExchange( (long*)&m_cAvail, stateCur.m_cAvail, stateNew.m_cAvail ) == stateCur.m_cAvail;
  1022. }
  1023. // tries to increase the available count on the semaphore by the count
  1024. // given using a transacted memory compare/exchange operation, returning fFalse
  1025. // on failure
  1026. inline const BOOL CSemaphoreState::FIncAvail( const int cToInc )
  1027. {
  1028. // try forever to change the state of the semaphore
  1029. SYNC_FOREVER
  1030. {
  1031. // get current value
  1032. const long cAvail = m_cAvail;
  1033. // munge start value such that the transaction will only work if we are in
  1034. // mode 0 (we do this to save a branch)
  1035. const long cAvailStart = cAvail & 0x7FFFFFFF;
  1036. // compute end value relative to munged start value
  1037. const long cAvailEnd = cAvailStart + cToInc;
  1038. // validate transaction
  1039. Assert( cAvail < 0 || ( cAvailStart >= 0 && cAvailEnd <= 0x7FFFFFFF && cAvailEnd == cAvailStart + cToInc ) );
  1040. // attempt the transaction
  1041. const long cAvailOld = AtomicCompareExchange( (long*)&m_cAvail, cAvailStart, cAvailEnd );
  1042. // the transaction succeeded
  1043. if ( cAvailOld == cAvailStart )
  1044. {
  1045. // return success
  1046. return fTrue;
  1047. }
  1048. // the transaction failed
  1049. else
  1050. {
  1051. // the transaction failed because of a collision with another context
  1052. if ( cAvailOld >= 0 )
  1053. {
  1054. // try again
  1055. continue;
  1056. }
  1057. // the transaction failed because there are waiters
  1058. else
  1059. {
  1060. // return failure
  1061. return fFalse;
  1062. }
  1063. }
  1064. }
  1065. }
  1066. // tries to decrease the available count on the semaphore by one using a
  1067. // transacted memory compare/exchange operation, returning fFalse on failure
  1068. inline const BOOL CSemaphoreState::FDecAvail()
  1069. {
  1070. // try forever to change the state of the semaphore
  1071. SYNC_FOREVER
  1072. {
  1073. // get current value
  1074. const long cAvail = m_cAvail;
  1075. // this function has no effect on 0x80000000, so this MUST be an illegal
  1076. // value!
  1077. Assert( cAvail != 0x80000000 );
  1078. // munge end value such that the transaction will only work if we are in
  1079. // mode 0 and we have at least one available count (we do this to save a
  1080. // branch)
  1081. const long cAvailEnd = ( cAvail - 1 ) & 0x7FFFFFFF;
  1082. // compute start value relative to munged end value
  1083. const long cAvailStart = cAvailEnd + 1;
  1084. // validate transaction
  1085. Assert( cAvail <= 0 || ( cAvailStart > 0 && cAvailEnd >= 0 && cAvailEnd == cAvail - 1 ) );
  1086. // attempt the transaction
  1087. const long cAvailOld = AtomicCompareExchange( (long*)&m_cAvail, cAvailStart, cAvailEnd );
  1088. // the transaction succeeded
  1089. if ( cAvailOld == cAvailStart )
  1090. {
  1091. // return success
  1092. return fTrue;
  1093. }
  1094. // the transaction failed
  1095. else
  1096. {
  1097. // the transaction failed because of a collision with another context
  1098. if ( cAvailOld > 0 )
  1099. {
  1100. // try again
  1101. continue;
  1102. }
  1103. // the transaction failed because there are no available counts
  1104. else
  1105. {
  1106. // return failure
  1107. return fFalse;
  1108. }
  1109. }
  1110. }
  1111. }
  1112. // Semaphore
  1113. class CSemaphore
  1114. : private CSyncObject,
  1115. private CEnhancedStateContainer< CSemaphoreState, CSyncStateInitNull, CSyncComplexPerfInfo, CSyncBasicInfo >
  1116. {
  1117. public:
  1118. // member functions
  1119. // ctors / dtors
  1120. CSemaphore( const CSyncBasicInfo& sbi );
  1121. ~CSemaphore();
  1122. // manipulators
  1123. void Acquire();
  1124. const BOOL FTryAcquire();
  1125. const BOOL FAcquire( const int cmsecTimeout );
  1126. void Release( const int cToRelease = 1 );
  1127. // accessors
  1128. const int CWait() const;
  1129. const int CAvail() const;
  1130. // debugging support
  1131. void Dump( CPRINTFSYNC* pcprintf, DWORD dwOffset = 0 );
  1132. size_t CbEnhancedState() { return CbState(); }
  1133. private:
  1134. // member functions
  1135. // operators
  1136. CSemaphore& operator=( CSemaphore& ); // disallowed
  1137. // manipulators
  1138. const BOOL _FAcquire( const int cmsecTimeout );
  1139. void _Release( const int cToRelease );
  1140. };
  1141. // acquire one count of the semaphore, waiting forever if necessary
  1142. inline void CSemaphore::Acquire()
  1143. {
  1144. // we will wait forever, so we should not timeout
  1145. int fAcquire = FAcquire( cmsecInfinite );
  1146. Assert( fAcquire );
  1147. }
  1148. // try to acquire one count of the semaphore without waiting or spinning.
  1149. // returns fFalse if a count could not be acquired
  1150. inline const BOOL CSemaphore::FTryAcquire()
  1151. {
  1152. // only try to perform a simple decrement of the available count
  1153. const BOOL fAcquire = State().FDecAvail();
  1154. // we did not acquire the semaphore
  1155. if ( !fAcquire )
  1156. {
  1157. // this is a contention
  1158. State().SetContend();
  1159. }
  1160. // we did acquire the semaphore
  1161. else
  1162. {
  1163. // note that we acquired a count
  1164. State().SetAcquire();
  1165. }
  1166. return fAcquire;
  1167. }
  1168. // acquire one count of the semaphore, waiting only for the specified interval.
  1169. // returns fFalse if the wait timed out before a count could be acquired
  1170. inline const BOOL CSemaphore::FAcquire( const int cmsecTimeout )
  1171. {
  1172. // first try to quickly grab an available count. if that doesn't work,
  1173. // retry acquire using the full state machine
  1174. return FTryAcquire() || _FAcquire( cmsecTimeout );
  1175. }
  1176. // releases the given number of counts to the semaphore, waking the appropriate
  1177. // number of waiters
  1178. inline void CSemaphore::Release( const int cToRelease )
  1179. {
  1180. // we failed to perform a simple increment of the available count
  1181. if ( !State().FIncAvail( cToRelease ) )
  1182. {
  1183. // retry release using the full state machine
  1184. _Release( cToRelease );
  1185. }
  1186. }
  1187. // returns the number of execution contexts waiting on the semaphore
  1188. inline const int CSemaphore::CWait() const
  1189. {
  1190. // read the current state of the semaphore
  1191. const CSemaphoreState stateCur = (CSemaphoreState&) State();
  1192. // return the waiter count
  1193. return stateCur.FWait() ? stateCur.CWait() : 0;
  1194. }
  1195. // returns the number of available counts on the semaphore
  1196. inline const int CSemaphore::CAvail() const
  1197. {
  1198. // read the current state of the semaphore
  1199. const CSemaphoreState stateCur = (CSemaphoreState&) State();
  1200. // return the available count
  1201. return stateCur.FNoWait() ? stateCur.CAvail() : 0;
  1202. }
  1203. // Auto-Reset Signal State
  1204. #pragma pack( 1 )
  1205. class CAutoResetSignalState
  1206. {
  1207. public:
  1208. // member functions
  1209. // ctors / dtors
  1210. CAutoResetSignalState( const CSyncStateInitNull& null ) : m_fSet( 0 ) {}
  1211. CAutoResetSignalState( const int fSet );
  1212. CAutoResetSignalState( const int cWait, const int irksem );
  1213. ~CAutoResetSignalState() {}
  1214. // operators
  1215. CAutoResetSignalState& operator=( CAutoResetSignalState& state ) { m_fSet = state.m_fSet; return *this; }
  1216. // manipulators
  1217. const BOOL FChange( const CAutoResetSignalState& stateCur, const CAutoResetSignalState& stateNew );
  1218. const BOOL FSimpleSet();
  1219. const BOOL FSimpleReset();
  1220. // accessors
  1221. const BOOL FNoWait() const { return m_fSet >= 0; }
  1222. const BOOL FWait() const { return m_fSet < 0; }
  1223. const BOOL FNoWaitAndSet() const { return m_fSet > 0; }
  1224. const BOOL FNoWaitAndNotSet() const { return m_fSet == 0; }
  1225. const BOOL FSet() const { Assert( FNoWait() ); return m_fSet; }
  1226. const int CWait() const { Assert( FWait() ); return -m_cWaitNeg; }
  1227. const CKernelSemaphorePool::IRKSEM Irksem() const { Assert( FWait() ); return CKernelSemaphorePool::IRKSEM( m_irksem ); }
  1228. // debugging support
  1229. void Dump( CPRINTFSYNC* pcprintf, DWORD dwOffset );
  1230. private:
  1231. // data members
  1232. // transacted state representation (switched on bit 31)
  1233. union
  1234. {
  1235. // Mode 0: no waiters
  1236. volatile long m_fSet; // m_fSet = { 0, 1 }
  1237. // Mode 1: waiters
  1238. struct
  1239. {
  1240. volatile unsigned short m_irksem; // 0 <= m_irksem <= ( 1 << 16 ) - 2
  1241. volatile short m_cWaitNeg; // -( ( 1 << 15 ) - 1 ) <= m_cWaitNeg <= -1
  1242. };
  1243. };
  1244. };
  1245. #pragma pack()
  1246. // ctor
  1247. inline CAutoResetSignalState::CAutoResetSignalState( const int fSet )
  1248. {
  1249. // validate IN args
  1250. Assert( fSet == 0 || fSet == 1 );
  1251. // set state
  1252. m_fSet = long( fSet );
  1253. }
  1254. // ctor
  1255. inline CAutoResetSignalState::CAutoResetSignalState( const int cWait, const int irksem )
  1256. {
  1257. // validate IN args
  1258. Assert( cWait > 0 );
  1259. Assert( cWait <= 0x7FFF );
  1260. Assert( irksem >= 0 );
  1261. Assert( irksem <= 0xFFFE );
  1262. // set waiter count
  1263. m_cWaitNeg = short( -cWait );
  1264. // set semaphore
  1265. m_irksem = (unsigned short) irksem;
  1266. }
  1267. // changes the transacted state of the signal using a transacted memory
  1268. // compare/exchange operation, returning 0 on failure
  1269. inline const BOOL CAutoResetSignalState::FChange( const CAutoResetSignalState& stateCur, const CAutoResetSignalState& stateNew )
  1270. {
  1271. return AtomicCompareExchange( (long*)&m_fSet, stateCur.m_fSet, stateNew.m_fSet ) == stateCur.m_fSet;
  1272. }
  1273. // tries to set the signal state from either the set or reset with no waiters states
  1274. // using a transacted memory compare/exchange operation, returning fFalse on failure
  1275. inline const BOOL CAutoResetSignalState::FSimpleSet()
  1276. {
  1277. // try forever to change the state of the signal
  1278. SYNC_FOREVER
  1279. {
  1280. // get current value
  1281. const long fSet = m_fSet;
  1282. // munge start value such that the transaction will only work if we are in
  1283. // mode 0 (we do this to save a branch)
  1284. const long fSetStart = fSet & 0x7FFFFFFF;
  1285. // compute end value relative to munged start value
  1286. const long fSetEnd = 1;
  1287. // validate transaction
  1288. Assert( fSet < 0 || ( ( fSetStart == 0 || fSetStart == 1 ) && fSetEnd == 1 ) );
  1289. // attempt the transaction
  1290. const long fSetOld = AtomicCompareExchange( (long*)&m_fSet, fSetStart, fSetEnd );
  1291. // the transaction succeeded
  1292. if ( fSetOld == fSetStart )
  1293. {
  1294. // return success
  1295. return fTrue;
  1296. }
  1297. // the transaction failed
  1298. else
  1299. {
  1300. // the transaction failed because of a collision with another context
  1301. if ( fSetOld >= 0 )
  1302. {
  1303. // try again
  1304. continue;
  1305. }
  1306. // the transaction failed because there are waiters
  1307. else
  1308. {
  1309. // return failure
  1310. return fFalse;
  1311. }
  1312. }
  1313. }
  1314. }
  1315. // tries to reset the signal state from either the set or reset with no waiters states
  1316. // using a transacted memory compare/exchange operation, returning fFalse on failure
  1317. inline const BOOL CAutoResetSignalState::FSimpleReset()
  1318. {
  1319. // try forever to change the state of the signal
  1320. SYNC_FOREVER
  1321. {
  1322. // get current value
  1323. const long fSet = m_fSet;
  1324. // munge start value such that the transaction will only work if we are in
  1325. // mode 0 (we do this to save a branch)
  1326. const long fSetStart = fSet & 0x7FFFFFFF;
  1327. // compute end value relative to munged start value
  1328. const long fSetEnd = 0;
  1329. // validate transaction
  1330. Assert( fSet < 0 || ( ( fSetStart == 0 || fSetStart == 1 ) && fSetEnd == 0 ) );
  1331. // attempt the transaction
  1332. const long fSetOld = AtomicCompareExchange( (long*)&m_fSet, fSetStart, fSetEnd );
  1333. // the transaction succeeded
  1334. if ( fSetOld == fSetStart )
  1335. {
  1336. // return success
  1337. return fTrue;
  1338. }
  1339. // the transaction failed
  1340. else
  1341. {
  1342. // the transaction failed because of a collision with another context
  1343. if ( fSetOld >= 0 )
  1344. {
  1345. // try again
  1346. continue;
  1347. }
  1348. // the transaction failed because there are waiters
  1349. else
  1350. {
  1351. // return failure
  1352. return fFalse;
  1353. }
  1354. }
  1355. }
  1356. }
  1357. // Auto-Reset Signal
  1358. class CAutoResetSignal
  1359. : private CSyncObject,
  1360. private CEnhancedStateContainer< CAutoResetSignalState, CSyncStateInitNull, CSyncComplexPerfInfo, CSyncBasicInfo >
  1361. {
  1362. public:
  1363. // member functions
  1364. // ctors / dtors
  1365. CAutoResetSignal( const CSyncBasicInfo& sbi );
  1366. ~CAutoResetSignal();
  1367. // manipulators
  1368. void Wait();
  1369. const BOOL FTryWait();
  1370. const BOOL FWait( const int cmsecTimeout );
  1371. void Set();
  1372. void Reset();
  1373. void Pulse();
  1374. // debugging support
  1375. void Dump( CPRINTFSYNC* pcprintf, DWORD dwOffset = 0 );
  1376. size_t CbEnhancedState() { return CbState(); }
  1377. private:
  1378. // member functions
  1379. // operators
  1380. CAutoResetSignal& operator=( CAutoResetSignal& ); // disallowed
  1381. // manipulators
  1382. const BOOL _FWait( const int cmsecTimeout );
  1383. void _Set();
  1384. void _Pulse();
  1385. };
  1386. // waits for the signal to be set, forever if necessary. when the wait completes,
  1387. // the signal will be reset
  1388. inline void CAutoResetSignal::Wait()
  1389. {
  1390. // we will wait forever, so we should not timeout
  1391. const BOOL fWait = FWait( cmsecInfinite );
  1392. Assert( fWait );
  1393. }
  1394. // tests the state of the signal without waiting or spinning, returning fFalse
  1395. // if the signal was not set. if the signal was set, the signal will be reset
  1396. inline const BOOL CAutoResetSignal::FTryWait()
  1397. {
  1398. // we can satisfy the wait if we can successfully change the state of the
  1399. // signal from set to reset with no waiters
  1400. const BOOL fSuccess = State().FChange( CAutoResetSignalState( 1 ), CAutoResetSignalState( 0 ) );
  1401. // we did not successfully wait for the signal
  1402. if ( !fSuccess )
  1403. {
  1404. // this is a contention
  1405. State().SetContend();
  1406. }
  1407. // we did successfully wait for the signal
  1408. else
  1409. {
  1410. // note that we acquired the signal
  1411. State().SetAcquire();
  1412. }
  1413. return fSuccess;
  1414. }
  1415. // wait for the signal to be set, but only for the specified interval,
  1416. // returning fFalse if the wait timed out before the signal was set. if the
  1417. // wait completes, the signal will be reset
  1418. inline const BOOL CAutoResetSignal::FWait( const int cmsecTimeout )
  1419. {
  1420. // first try to quickly pass through the signal. if that doesn't work,
  1421. // retry wait using the full state machine
  1422. return FTryWait() || _FWait( cmsecTimeout );
  1423. }
  1424. // sets the signal, releasing up to one waiter. if a waiter is released, then
  1425. // the signal will be reset. if a waiter is not released, the signal will
  1426. // remain set
  1427. inline void CAutoResetSignal::Set()
  1428. {
  1429. // we failed to change the signal state from reset with no waiters to set
  1430. // or from set to set (a nop)
  1431. if ( !State().FSimpleSet() )
  1432. {
  1433. // retry set using the full state machine
  1434. _Set();
  1435. }
  1436. }
  1437. // resets the signal
  1438. inline void CAutoResetSignal::Reset()
  1439. {
  1440. // if and only if the signal is in the set state, change it to the reset state
  1441. State().FChange( CAutoResetSignalState( 1 ), CAutoResetSignalState( 0 ) );
  1442. }
  1443. // resets the signal, releasing up to one waiter
  1444. inline void CAutoResetSignal::Pulse()
  1445. {
  1446. // wa failed to change the signal state from set to reset with no waiters
  1447. // or from reset with no waiters to reset with no waiters (a nop)
  1448. if ( !State().FSimpleReset() )
  1449. {
  1450. // retry pulse using the full state machine
  1451. _Pulse();
  1452. }
  1453. }
  1454. // Manual-Reset Signal State
  1455. #pragma pack( 1 )
  1456. class CManualResetSignalState
  1457. {
  1458. public:
  1459. // member functions
  1460. // ctors / dtors
  1461. CManualResetSignalState( const CSyncStateInitNull& null ) : m_fSet( 0 ) {}
  1462. CManualResetSignalState( const int fSet );
  1463. CManualResetSignalState( const int cWait, const int irksem );
  1464. ~CManualResetSignalState() {}
  1465. // operators
  1466. CManualResetSignalState& operator=( CManualResetSignalState& state ) { m_fSet = state.m_fSet; return *this; }
  1467. // manipulators
  1468. const BOOL FChange( const CManualResetSignalState& stateCur, const CManualResetSignalState& stateNew );
  1469. const CManualResetSignalState Set();
  1470. const CManualResetSignalState Reset();
  1471. // accessors
  1472. const BOOL FNoWait() const { return m_fSet >= 0; }
  1473. const BOOL FWait() const { return m_fSet < 0; }
  1474. const BOOL FNoWaitAndSet() const { return m_fSet > 0; }
  1475. const BOOL FNoWaitAndNotSet() const { return m_fSet == 0; }
  1476. const BOOL FSet() const { Assert( FNoWait() ); return m_fSet; }
  1477. const int CWait() const { Assert( FWait() ); return -m_cWaitNeg; }
  1478. const CKernelSemaphorePool::IRKSEM Irksem() const { Assert( FWait() ); return CKernelSemaphorePool::IRKSEM( m_irksem ); }
  1479. // debugging support
  1480. void Dump( CPRINTFSYNC* pcprintf, DWORD dwOffset );
  1481. private:
  1482. // data members
  1483. // transacted state representation (switched on bit 31)
  1484. union
  1485. {
  1486. // Mode 0: no waiters
  1487. volatile long m_fSet; // m_fSet = { 0, 1 }
  1488. // Mode 1: waiters
  1489. struct
  1490. {
  1491. volatile unsigned short m_irksem; // 0 <= m_irksem <= ( 1 << 16 ) - 2
  1492. volatile short m_cWaitNeg; // -( ( 1 << 15 ) - 1 ) <= m_cWaitNeg <= -1
  1493. };
  1494. };
  1495. };
  1496. #pragma pack()
  1497. // ctor
  1498. inline CManualResetSignalState::CManualResetSignalState( const int fSet )
  1499. {
  1500. // set state
  1501. m_fSet = long( fSet );
  1502. }
  1503. // ctor
  1504. inline CManualResetSignalState::CManualResetSignalState( const int cWait, const int irksem )
  1505. {
  1506. // validate IN args
  1507. Assert( cWait > 0 );
  1508. Assert( cWait <= 0x7FFF );
  1509. Assert( irksem >= 0 );
  1510. Assert( irksem <= 0xFFFE );
  1511. // set waiter count
  1512. m_cWaitNeg = short( -cWait );
  1513. // set semaphore
  1514. m_irksem = (unsigned short) irksem;
  1515. }
  1516. // changes the transacted state of the signal using a transacted memory
  1517. // compare/exchange operation, returning fFalse on failure
  1518. inline const BOOL CManualResetSignalState::FChange( const CManualResetSignalState& stateCur, const CManualResetSignalState& stateNew )
  1519. {
  1520. return AtomicCompareExchange( (long*)&m_fSet, stateCur.m_fSet, stateNew.m_fSet ) == stateCur.m_fSet;
  1521. }
  1522. // changes the transacted state of the signal to set using a transacted memory
  1523. // exchange operation and returns the original state of the signal
  1524. inline const CManualResetSignalState CManualResetSignalState::Set()
  1525. {
  1526. const CManualResetSignalState stateNew( 1 );
  1527. return CManualResetSignalState( AtomicExchange( (long*)&m_fSet, stateNew.m_fSet ) );
  1528. }
  1529. // changes the transacted state of the signal to reset using a transacted memory
  1530. // exchange operation and returns the original state of the signal
  1531. inline const CManualResetSignalState CManualResetSignalState::Reset()
  1532. {
  1533. const CManualResetSignalState stateNew( 0 );
  1534. return CManualResetSignalState( AtomicExchange( (long*)&m_fSet, stateNew.m_fSet ) );
  1535. }
  1536. // Manual-Reset Signal
  1537. class CManualResetSignal
  1538. : private CSyncObject,
  1539. private CEnhancedStateContainer< CManualResetSignalState, CSyncStateInitNull, CSyncComplexPerfInfo, CSyncBasicInfo >
  1540. {
  1541. public:
  1542. // member functions
  1543. // ctors / dtors
  1544. CManualResetSignal( const CSyncBasicInfo& sbi );
  1545. ~CManualResetSignal();
  1546. // manipulators
  1547. void Wait();
  1548. const BOOL FTryWait();
  1549. const BOOL FWait( const int cmsecTimeout );
  1550. void Set();
  1551. void Reset();
  1552. void Pulse();
  1553. // debugging support
  1554. void Dump( CPRINTFSYNC* pcprintf, DWORD dwOffset = 0 );
  1555. size_t CbEnhancedState() { return CbState(); }
  1556. private:
  1557. // member functions
  1558. // operators
  1559. CManualResetSignal& operator=( CManualResetSignal& ); // disallowed
  1560. // manipulators
  1561. const BOOL _FWait( const int cmsecTimeout );
  1562. };
  1563. // waits for the signal to be set, forever if necessary
  1564. inline void CManualResetSignal::Wait()
  1565. {
  1566. // we will wait forever, so we should not timeout
  1567. int fWait = FWait( cmsecInfinite );
  1568. Assert( fWait );
  1569. }
  1570. // tests the state of the signal without waiting or spinning, returning fFalse
  1571. // if the signal was not set
  1572. inline const BOOL CManualResetSignal::FTryWait()
  1573. {
  1574. const BOOL fSuccess = State().FSet();
  1575. // we did not successfully wait for the signal
  1576. if ( !fSuccess )
  1577. {
  1578. // this is a contention
  1579. State().SetContend();
  1580. }
  1581. // we did successfully wait for the signal
  1582. else
  1583. {
  1584. // note that we acquired the signal
  1585. State().SetAcquire();
  1586. }
  1587. return fSuccess;
  1588. }
  1589. // wait for the signal to be set, but only for the specified interval,
  1590. // returning fFalse if the wait timed out before the signal was set
  1591. inline const BOOL CManualResetSignal::FWait( const int cmsecTimeout )
  1592. {
  1593. // first try to quickly pass through the signal. if that doesn't work,
  1594. // retry wait using the full state machine
  1595. return FTryWait() || _FWait( cmsecTimeout );
  1596. }
  1597. // sets the signal, releasing any waiters
  1598. inline void CManualResetSignal::Set()
  1599. {
  1600. // change the signal state to set
  1601. const CManualResetSignalState stateOld = State().Set();
  1602. // there were waiters on the signal
  1603. if ( stateOld.FWait() )
  1604. {
  1605. // release all the waiters
  1606. ksempoolGlobal.Ksem( stateOld.Irksem(), this ).Release( stateOld.CWait() );
  1607. }
  1608. }
  1609. // resets the signal
  1610. inline void CManualResetSignal::Reset()
  1611. {
  1612. // if and only if the signal is in the set state, change it to the reset state
  1613. State().FChange( CManualResetSignalState( 1 ), CManualResetSignalState( 0 ) );
  1614. }
  1615. // resets the signal, releasing any waiters
  1616. inline void CManualResetSignal::Pulse()
  1617. {
  1618. // change the signal state to reset
  1619. const CManualResetSignalState stateOld = State().Reset();
  1620. // there were waiters on the signal
  1621. if ( stateOld.FWait() )
  1622. {
  1623. // release all the waiters
  1624. ksempoolGlobal.Ksem( stateOld.Irksem(), this ).Release( stateOld.CWait() );
  1625. }
  1626. }
  1627. // Lock Object Base Class
  1628. //
  1629. // All Lock Objects are derived from this class
  1630. class CLockObject
  1631. : public CSyncObject
  1632. {
  1633. public:
  1634. // member functions
  1635. // ctors / dtors
  1636. CLockObject() {}
  1637. ~CLockObject() {}
  1638. private:
  1639. // member functions
  1640. // operators
  1641. CLockObject& operator=( CLockObject& ); // disallowed
  1642. };
  1643. // Lock Object Basic Information
  1644. class CLockBasicInfo
  1645. : public CSyncBasicInfo
  1646. {
  1647. public:
  1648. // member functions
  1649. // ctors / dtors
  1650. CLockBasicInfo( const CSyncBasicInfo& sbi, const int rank, const int subrank );
  1651. ~CLockBasicInfo();
  1652. // accessors
  1653. #ifdef SYNC_DEADLOCK_DETECTION
  1654. const int Rank() const { return m_rank; }
  1655. const int SubRank() const { return m_subrank; }
  1656. #endif // SYNC_DEADLOCK_DETECTION
  1657. // debugging support
  1658. void Dump( CPRINTFSYNC* pcprintf, DWORD dwOffset );
  1659. private:
  1660. // member functions
  1661. // operators
  1662. CLockBasicInfo& operator=( CLockBasicInfo& ); // disallowed
  1663. // data members
  1664. #ifdef SYNC_DEADLOCK_DETECTION
  1665. // Rank and Subrank
  1666. int m_rank;
  1667. int m_subrank;
  1668. #endif // SYNC_DEADLOCK_DETECTION
  1669. };
  1670. // Lock Object Performance: Hold
  1671. class CLockPerfHold
  1672. {
  1673. public:
  1674. // member functions
  1675. // ctors / dtors
  1676. CLockPerfHold();
  1677. ~CLockPerfHold();
  1678. // member functions
  1679. // manipulators
  1680. void StartHold();
  1681. void StopHold();
  1682. // debugging support
  1683. void Dump( CPRINTFSYNC* pcprintf, DWORD dwOffset );
  1684. private:
  1685. // member functions
  1686. // operators
  1687. CLockPerfHold& operator=( CLockPerfHold& ); // disallowed
  1688. // data members
  1689. #ifdef SYNC_ANALYZE_PERFORMANCE
  1690. // hold count
  1691. volatile QWORD m_cHold;
  1692. // elapsed hold time
  1693. volatile QWORD m_qwHRTHoldElapsed;
  1694. #endif // SYNC_ANALYZE_PERFORMANCE
  1695. };
  1696. // starts the hold timer for the lock object
  1697. inline void CLockPerfHold::StartHold()
  1698. {
  1699. #ifdef SYNC_ANALYZE_PERFORMANCE
  1700. // increment the hold count
  1701. AtomicAdd( (QWORD*)&m_cHold, 1 );
  1702. // subtract the start hold time from the elapsed hold time. this starts
  1703. // an elapsed time computation for this context. StopHold() will later
  1704. // add the end hold time to the elapsed time, causing the following net
  1705. // effect:
  1706. //
  1707. // m_qwHRTHoldElapsed += <end time> - <start time>
  1708. //
  1709. // we simply choose to go ahead and do the subtraction now to save storage
  1710. AtomicAdd( (QWORD*)&m_qwHRTHoldElapsed, QWORD( -__int64( QwOSTimeHRTCount() ) ) );
  1711. #endif // SYNC_ANALYZE_PERFORMANCE
  1712. }
  1713. // stops the hold timer for the lock object
  1714. inline void CLockPerfHold::StopHold()
  1715. {
  1716. #ifdef SYNC_ANALYZE_PERFORMANCE
  1717. // add the end hold time to the elapsed hold time. this completes the
  1718. // computation started in StartHold()
  1719. AtomicAdd( (QWORD*)&m_qwHRTHoldElapsed, QwOSTimeHRTCount() );
  1720. #endif // SYNC_ANALYZE_PERFORMANCE
  1721. }
  1722. // Lock Owner Record
  1723. class CLockDeadlockDetectionInfo;
  1724. class COwner
  1725. {
  1726. public:
  1727. // member functions
  1728. // ctors / dtors
  1729. COwner();
  1730. ~COwner();
  1731. public:
  1732. // member functions
  1733. // operators
  1734. COwner& operator=( COwner& ); // disallowed
  1735. // data members
  1736. // owning context
  1737. CLS* m_pclsOwner;
  1738. // next context owning this lock
  1739. COwner* m_pownerContextNext;
  1740. // owned lock object
  1741. CLockDeadlockDetectionInfo* m_plddiOwned;
  1742. // next lock owned by this context
  1743. COwner* m_pownerLockNext;
  1744. // owning group for this context and lock
  1745. DWORD m_group;
  1746. };
  1747. // Lock Object Deadlock Detection Information
  1748. class CLockDeadlockDetectionInfo
  1749. {
  1750. public:
  1751. // member functions
  1752. // ctors / dtors
  1753. CLockDeadlockDetectionInfo( const CLockBasicInfo& lbi );
  1754. ~CLockDeadlockDetectionInfo();
  1755. // member functions
  1756. // manipulators
  1757. void AddAsOwner( const DWORD group = -1 );
  1758. void RemoveAsOwner( const DWORD group = -1 );
  1759. // accessors
  1760. const BOOL FCanBeOwner();
  1761. const BOOL FOwner( const DWORD group = -1 );
  1762. const BOOL FOwned();
  1763. const BOOL FNotOwner( const DWORD group = -1 );
  1764. const BOOL FNotOwned();
  1765. #ifdef SYNC_DEADLOCK_DETECTION
  1766. const CLockBasicInfo& Info() { return *m_plbiParent; }
  1767. #endif // SYNC_DEADLOCK_DETECTION
  1768. // debugging support
  1769. void Dump( CPRINTFSYNC* pcprintf, DWORD dwOffset );
  1770. private:
  1771. // member functions
  1772. // operators
  1773. CLockDeadlockDetectionInfo& operator=( CLockDeadlockDetectionInfo& ); // disallowed
  1774. // data members
  1775. #ifdef SYNC_DEADLOCK_DETECTION
  1776. // parent lock object information
  1777. const CLockBasicInfo* m_plbiParent;
  1778. // semaphore protecting owner list
  1779. CSemaphore m_semOwnerList;
  1780. // owner list head
  1781. COwner m_ownerHead;
  1782. #endif // SYNC_DEADLOCK_DETECTION
  1783. };
  1784. // adds the current context as an owner of the lock object as a member of the
  1785. // specified group
  1786. inline void CLockDeadlockDetectionInfo::AddAsOwner( const DWORD group )
  1787. {
  1788. // this context had better not be an owner of the lock, but it certainly
  1789. // should be able to own it
  1790. Assert( FNotOwner( group ) );
  1791. Assert( FCanBeOwner() );
  1792. #ifdef SYNC_DEADLOCK_DETECTION
  1793. // add this context as an owner of the lock
  1794. CLS* const pcls = Pcls();
  1795. COwner* powner = &m_ownerHead;
  1796. if ( InterlockedCompareExchangePointer( (PVOID *) &powner->m_pclsOwner, pcls, NULL ) )
  1797. {
  1798. powner = new COwner;
  1799. EnforceSz( powner, _T( "Failed to allocate Deadlock Detection Owner Record" ) );
  1800. m_semOwnerList.Acquire();
  1801. powner->m_pclsOwner = pcls;
  1802. powner->m_pownerContextNext = m_ownerHead.m_pownerContextNext;
  1803. m_ownerHead.m_pownerContextNext = powner;
  1804. m_semOwnerList.Release();
  1805. }
  1806. powner->m_plddiOwned = this;
  1807. powner->m_pownerLockNext = pcls->pownerLockHead;
  1808. pcls->pownerLockHead = powner;
  1809. powner->m_group = group;
  1810. #endif // SYNC_DEADLOCK_DETECTION
  1811. // this context had better be an owner of the lock
  1812. Assert( FOwner( group ) );
  1813. }
  1814. // removes the current context as an owner of the lock object
  1815. inline void CLockDeadlockDetectionInfo::RemoveAsOwner( const DWORD group )
  1816. {
  1817. // this context had better be an owner of the lock
  1818. Assert( FOwner( group ) );
  1819. #ifdef SYNC_DEADLOCK_DETECTION
  1820. // remove this context as an owner of the lock
  1821. CLS* const pcls = Pcls();
  1822. COwner** ppownerLock = &pcls->pownerLockHead;
  1823. while ( (*ppownerLock)->m_plddiOwned != this )
  1824. {
  1825. ppownerLock = &(*ppownerLock)->m_pownerLockNext;
  1826. }
  1827. COwner* pownerLock = *ppownerLock;
  1828. *ppownerLock = pownerLock->m_pownerLockNext;
  1829. pownerLock->m_plddiOwned = NULL;
  1830. pownerLock->m_pownerLockNext = NULL;
  1831. pownerLock->m_group = 0;
  1832. if ( m_ownerHead.m_pclsOwner == pcls )
  1833. {
  1834. m_ownerHead.m_pclsOwner = NULL;
  1835. }
  1836. else
  1837. {
  1838. m_semOwnerList.Acquire();
  1839. COwner** ppownerContext = &m_ownerHead.m_pownerContextNext;
  1840. while ( (*ppownerContext)->m_pclsOwner != pcls )
  1841. {
  1842. ppownerContext = &(*ppownerContext)->m_pownerContextNext;
  1843. }
  1844. COwner* pownerContext = *ppownerContext;
  1845. *ppownerContext = pownerContext->m_pownerContextNext;
  1846. m_semOwnerList.Release();
  1847. delete pownerContext;
  1848. }
  1849. #endif // SYNC_DEADLOCK_DETECTION
  1850. // this context had better not be an owner of the lock anymore
  1851. Assert( FNotOwner( group ) );
  1852. }
  1853. // returns fTrue if the current context can own the lock object without
  1854. // violating any deadlock constraints
  1855. //
  1856. // NOTE: if deadlock detection is disabled, this function will always return
  1857. // fTrue
  1858. inline const BOOL CLockDeadlockDetectionInfo::FCanBeOwner()
  1859. {
  1860. #ifdef SYNC_DEADLOCK_DETECTION
  1861. COwner* const powner = Pcls()->pownerLockHead;
  1862. // UNDONE: remove instance name comparison (hack for ESE)
  1863. return !powner ||
  1864. powner->m_plddiOwned->Info().Rank() > Info().Rank() ||
  1865. powner->m_plddiOwned->Info().SubRank() > Info().SubRank() ||
  1866. powner->m_plddiOwned->Info().SzInstanceName() == Info().SzInstanceName() ||
  1867. !_tcscmp( powner->m_plddiOwned->Info().SzInstanceName(), Info().SzInstanceName() );
  1868. #else // !SYNC_DEADLOCK_DETECTION
  1869. return fTrue;
  1870. #endif // SYNC_DEADLOCK_DETECTION
  1871. }
  1872. // returns fTrue if the current context is an owner of the lock object
  1873. //
  1874. // NOTE: if deadlock detection is disabled, this function will always return
  1875. // fTrue
  1876. inline const BOOL CLockDeadlockDetectionInfo::FOwner( const DWORD group )
  1877. {
  1878. #ifdef SYNC_DEADLOCK_DETECTION
  1879. COwner* pownerLock = Pcls()->pownerLockHead;
  1880. while ( pownerLock && pownerLock->m_plddiOwned != this )
  1881. {
  1882. pownerLock = pownerLock->m_pownerLockNext;
  1883. }
  1884. return pownerLock && pownerLock->m_group == group;
  1885. #else // !SYNC_DEADLOCK_DETECTION
  1886. return fTrue;
  1887. #endif // SYNC_DEADLOCK_DETECTION
  1888. }
  1889. // returns fTrue if any context is an owner of the lock object
  1890. //
  1891. // NOTE: if deadlock detection is disabled, this function will always return
  1892. // fTrue
  1893. inline const BOOL CLockDeadlockDetectionInfo::FOwned()
  1894. {
  1895. #ifdef SYNC_DEADLOCK_DETECTION
  1896. return m_ownerHead.m_pclsOwner || m_ownerHead.m_pownerContextNext;
  1897. #else // !SYNC_DEADLOCK_DETECTION
  1898. return fTrue;
  1899. #endif // SYNC_DEADLOCK_DETECTION
  1900. }
  1901. // returns fTrue if the current context is not an owner of the lock object
  1902. //
  1903. // NOTE: if deadlock detection is disabled, this function will always return
  1904. // fTrue
  1905. inline const BOOL CLockDeadlockDetectionInfo::FNotOwner( const DWORD group )
  1906. {
  1907. #ifdef SYNC_DEADLOCK_DETECTION
  1908. return !FOwner( group );
  1909. #else // !SYNC_DEADLOCK_DETECTION
  1910. return fTrue;
  1911. #endif // SYNC_DEADLOCK_DETECTION
  1912. }
  1913. // returns fTrue if no context is an owner of the lock object
  1914. //
  1915. // NOTE: if deadlock detection is disabled, this function will always return
  1916. // fTrue
  1917. inline const BOOL CLockDeadlockDetectionInfo::FNotOwned()
  1918. {
  1919. #ifdef SYNC_DEADLOCK_DETECTION
  1920. return !FOwned();
  1921. #else // !SYNC_DEADLOCK_DETECTION
  1922. return fTrue;
  1923. #endif // SYNC_DEADLOCK_DETECTION
  1924. }
  1925. // Simple Lock Object Group Performance Information
  1926. class CLockGroupSimplePerfInfo
  1927. : public CLockPerfHold
  1928. {
  1929. public:
  1930. // member functions
  1931. // ctors / dtors
  1932. CLockGroupSimplePerfInfo()
  1933. {
  1934. }
  1935. // debugging support
  1936. void Dump( CPRINTFSYNC* pcprintf, DWORD dwOffset )
  1937. {
  1938. CLockPerfHold::Dump( pcprintf, dwOffset );
  1939. }
  1940. };
  1941. // Simple Lock Object Information
  1942. class CLockSimpleInfo
  1943. : public CLockBasicInfo,
  1944. public CLockGroupSimplePerfInfo,
  1945. public CLockDeadlockDetectionInfo
  1946. {
  1947. public:
  1948. // member functions
  1949. // ctors / dtors
  1950. CLockSimpleInfo( const CLockBasicInfo& lbi )
  1951. : CLockDeadlockDetectionInfo( (CLockBasicInfo&) *this ),
  1952. CLockBasicInfo( lbi )
  1953. {
  1954. }
  1955. // debugging support
  1956. void Dump( CPRINTFSYNC* pcprintf, DWORD dwOffset )
  1957. {
  1958. CLockBasicInfo::Dump( pcprintf, dwOffset );
  1959. CLockGroupSimplePerfInfo::Dump( pcprintf, dwOffset );
  1960. CLockDeadlockDetectionInfo::Dump( pcprintf, dwOffset );
  1961. }
  1962. };
  1963. // Critical Section (non-nestable) State
  1964. #pragma pack( 1 )
  1965. class CCriticalSectionState
  1966. {
  1967. public:
  1968. // member functions
  1969. // ctors / dtors
  1970. CCriticalSectionState( const CSyncBasicInfo& sbi );
  1971. ~CCriticalSectionState();
  1972. // accessors
  1973. CSemaphore& Semaphore() { return m_sem; }
  1974. // debugging support
  1975. void Dump( CPRINTFSYNC* pcprintf, DWORD dwOffset );
  1976. private:
  1977. // member functions
  1978. // operators
  1979. CCriticalSectionState& operator=( CCriticalSectionState& ); // disallowed
  1980. // data members
  1981. // semaphore
  1982. CSemaphore m_sem;
  1983. };
  1984. #pragma pack()
  1985. // Critical Section (non-nestable)
  1986. class CCriticalSection
  1987. : private CLockObject,
  1988. private CEnhancedStateContainer< CCriticalSectionState, CSyncBasicInfo, CLockSimpleInfo, CLockBasicInfo >
  1989. {
  1990. public:
  1991. // member functions
  1992. // ctors / dtors
  1993. CCriticalSection( const CLockBasicInfo& lbi );
  1994. ~CCriticalSection();
  1995. // manipulators
  1996. void Enter();
  1997. const BOOL FTryEnter();
  1998. const BOOL FEnter( const int cmsecTimeout );
  1999. void Leave();
  2000. // accessors
  2001. const int CWait() { return State().Semaphore().CWait(); }
  2002. const BOOL FOwner() { return State().FOwner(); }
  2003. const BOOL FNotOwner() { return State().FNotOwner(); }
  2004. // debugging support
  2005. void Dump( CPRINTFSYNC* pcprintf, DWORD dwOffset = 0 );
  2006. size_t CbEnhancedState() { return CbState(); }
  2007. private:
  2008. // member functions
  2009. // operators
  2010. CCriticalSection& operator=( CCriticalSection& ); // disallowed
  2011. // debugging support
  2012. static void Dump( CLockObject* plockobj, CPRINTFSYNC* pcprintf, DWORD dwOffset = 0 ) { ( (CCriticalSection*) plockobj )->Dump( pcprintf, dwOffset ); }
  2013. };
  2014. // enter the critical section, waiting forever if someone else is currently the
  2015. // owner. the critical section can not be re-entered until it has been left
  2016. inline void CCriticalSection::Enter()
  2017. {
  2018. // check for deadlock
  2019. AssertRTLSz( State().FCanBeOwner(), _T( "Potential Deadlock Detected" ) );
  2020. // acquire the semaphore
  2021. State().Semaphore().Acquire();
  2022. // there had better be no available counts on the semaphore
  2023. Assert( !State().Semaphore().CAvail() );
  2024. // we are now holding the lock
  2025. State().StartHold();
  2026. // we are now the owner of the critical section
  2027. State().AddAsOwner();
  2028. }
  2029. // try to enter the critical section without waiting or spinning, returning
  2030. // fFalse if someone else currently is the owner. the critical section can not
  2031. // be re-entered until it has been left
  2032. inline const BOOL CCriticalSection::FTryEnter()
  2033. {
  2034. // try to acquire the semaphore without waiting or spinning
  2035. //
  2036. // NOTE: there is no potential for deadlock here, so don't bother to check
  2037. BOOL fAcquire = State().Semaphore().FTryAcquire();
  2038. // we are now the owner of the critical section
  2039. if ( fAcquire )
  2040. {
  2041. // there had better be no available counts on the semaphore
  2042. Assert( !State().Semaphore().CAvail() );
  2043. // we are now holding the lock
  2044. State().StartHold();
  2045. // add ourself as the owner
  2046. State().AddAsOwner();
  2047. }
  2048. return fAcquire;
  2049. }
  2050. // try to enter the critical section waiting only for the specified interval,
  2051. // returning fFalse if the wait timed out before the critical section could be
  2052. // acquired. the critical section can not be re-entered until it has been left
  2053. inline const BOOL CCriticalSection::FEnter( const int cmsecTimeout )
  2054. {
  2055. // check for deadlock if we are waiting forever
  2056. AssertRTLSz( cmsecTimeout != cmsecInfinite || State().FCanBeOwner(), _T( "Potential Deadlock Detected" ) );
  2057. // try to acquire the semaphore, timing out as requested
  2058. //
  2059. // NOTE: there is still a potential for deadlock, but that will be detected
  2060. // at the OS level
  2061. BOOL fAcquire = State().Semaphore().FAcquire( cmsecTimeout );
  2062. // we are now the owner of the critical section
  2063. if ( fAcquire )
  2064. {
  2065. // there had better be no available counts on the semaphore
  2066. Assert( !State().Semaphore().CAvail() );
  2067. // we are now holding the lock
  2068. State().StartHold();
  2069. // add ourself as the owner
  2070. State().AddAsOwner();
  2071. }
  2072. return fAcquire;
  2073. }
  2074. // leaves the critical section, releasing it for ownership by someone else
  2075. inline void CCriticalSection::Leave()
  2076. {
  2077. // remove ourself as the owner
  2078. State().RemoveAsOwner();
  2079. // there had better be no available counts on the semaphore
  2080. Assert( !State().Semaphore().CAvail() );
  2081. // release the semaphore
  2082. State().Semaphore().Release();
  2083. // we are no longer holding the lock
  2084. State().StopHold();
  2085. }
  2086. // Nestable Critical Section State
  2087. #pragma pack( 1 )
  2088. class CNestableCriticalSectionState
  2089. {
  2090. public:
  2091. // member functions
  2092. // ctors / dtors
  2093. CNestableCriticalSectionState( const CSyncBasicInfo& sbi );
  2094. ~CNestableCriticalSectionState();
  2095. // manipulators
  2096. void SetOwner( CLS* const pcls );
  2097. void Enter();
  2098. void Leave();
  2099. // accessors
  2100. CSemaphore& Semaphore() { return m_sem; }
  2101. CLS* PclsOwner() { return m_pclsOwner; }
  2102. int CEntry() { return m_cEntry; }
  2103. // debugging support
  2104. void Dump( CPRINTFSYNC* pcprintf, DWORD dwOffset );
  2105. private:
  2106. // member functions
  2107. // operators
  2108. CNestableCriticalSectionState& operator=( CNestableCriticalSectionState& ); // disallowed
  2109. // data members
  2110. // semaphore
  2111. CSemaphore m_sem;
  2112. // owning context (protected by the semaphore)
  2113. CLS* volatile m_pclsOwner;
  2114. // entry count (only valid when the owner id is valid)
  2115. volatile int m_cEntry;
  2116. };
  2117. #pragma pack()
  2118. // set the owner
  2119. inline void CNestableCriticalSectionState::SetOwner( CLS* const pcls )
  2120. {
  2121. // we had either be clearing the owner or setting a new owner. we should
  2122. // never be overwriting another owner
  2123. Assert( !pcls || !m_pclsOwner );
  2124. // set the new owner
  2125. m_pclsOwner = pcls;
  2126. }
  2127. // increment the entry count
  2128. inline void CNestableCriticalSectionState::Enter()
  2129. {
  2130. // we had better have an owner already!
  2131. Assert( m_pclsOwner );
  2132. // we should not overflow the entry count
  2133. Assert( int( m_cEntry + 1 ) >= 1 );
  2134. // increment the entry count
  2135. m_cEntry++;
  2136. }
  2137. // decrement the entry count
  2138. inline void CNestableCriticalSectionState::Leave()
  2139. {
  2140. // we had better have an owner already!
  2141. Assert( m_pclsOwner );
  2142. // decrement the entry count
  2143. m_cEntry--;
  2144. }
  2145. // Nestable Critical Section
  2146. class CNestableCriticalSection
  2147. : private CLockObject,
  2148. private CEnhancedStateContainer< CNestableCriticalSectionState, CSyncBasicInfo, CLockSimpleInfo, CLockBasicInfo >
  2149. {
  2150. public:
  2151. // member functions
  2152. // ctors / dtors
  2153. CNestableCriticalSection( const CLockBasicInfo& lbi );
  2154. ~CNestableCriticalSection();
  2155. // manipulators
  2156. void Enter();
  2157. const BOOL FTryEnter();
  2158. const BOOL FEnter( const int cmsecTimeout );
  2159. void Leave();
  2160. // accessors
  2161. const int CWait() { return State().Semaphore().CWait(); }
  2162. const BOOL FOwner() { return State().FOwner(); }
  2163. const BOOL FNotOwner() { return State().FNotOwner(); }
  2164. // debugging support
  2165. void Dump( CPRINTFSYNC* pcprintf, DWORD dwOffset = 0 );
  2166. size_t CbEnhancedState() { return CbState(); }
  2167. private:
  2168. // member functions
  2169. // operators
  2170. CNestableCriticalSection& operator=( CNestableCriticalSection& ); // disallowed
  2171. // debugging support
  2172. static void Dump( CLockObject* plockobj, CPRINTFSYNC* pcprintf, DWORD dwOffset = 0 ) { ( (CNestableCriticalSection*) plockobj )->Dump( pcprintf, dwOffset ); }
  2173. };
  2174. // enter the critical section, waiting forever if someone else is currently the
  2175. // owner. the critical section can be reentered without waiting or deadlocking
  2176. inline void CNestableCriticalSection::Enter()
  2177. {
  2178. // get our context
  2179. CLS* const pcls = Pcls();
  2180. // we own the critical section
  2181. if ( State().PclsOwner() == pcls )
  2182. {
  2183. // there had better be no available counts on the semaphore
  2184. Assert( !State().Semaphore().CAvail() );
  2185. // we should have at least one entry count
  2186. Assert( State().CEntry() >= 1 );
  2187. // increment our entry count
  2188. State().Enter();
  2189. }
  2190. // we do not own the critical section
  2191. else
  2192. {
  2193. Assert( State().PclsOwner() != pcls );
  2194. // check for deadlock
  2195. AssertRTLSz( State().FCanBeOwner(), _T( "Potential Deadlock Detected" ) );
  2196. // acquire the semaphore
  2197. State().Semaphore().Acquire();
  2198. // there had better be no available counts on the semaphore
  2199. Assert( !State().Semaphore().CAvail() );
  2200. // we are now holding the lock
  2201. State().StartHold();
  2202. // we are now the owner of the critical section
  2203. State().AddAsOwner();
  2204. // save our context as the owner
  2205. State().SetOwner( pcls );
  2206. // set initial entry count
  2207. State().Enter();
  2208. }
  2209. }
  2210. // try to enter the critical section without waiting or spinning, returning
  2211. // fFalse if someone else currently is the owner. the critical section can be
  2212. // reentered without waiting or deadlocking
  2213. inline const BOOL CNestableCriticalSection::FTryEnter()
  2214. {
  2215. // get our context
  2216. CLS* const pcls = Pcls();
  2217. // we own the critical section
  2218. if ( State().PclsOwner() == pcls )
  2219. {
  2220. // there had better be no available counts on the semaphore
  2221. Assert( !State().Semaphore().CAvail() );
  2222. // we should have at least one entry count
  2223. Assert( State().CEntry() >= 1 );
  2224. // increment our entry count
  2225. State().Enter();
  2226. // return success
  2227. return fTrue;
  2228. }
  2229. // we do not own the critical section
  2230. else
  2231. {
  2232. Assert( State().PclsOwner() != pcls );
  2233. // try to acquire the semaphore without waiting or spinning
  2234. //
  2235. // NOTE: there is no potential for deadlock here, so don't bother to check
  2236. const BOOL fAcquired = State().Semaphore().FTryAcquire();
  2237. // we now own the critical section
  2238. if ( fAcquired )
  2239. {
  2240. // there had better be no available counts on the semaphore
  2241. Assert( !State().Semaphore().CAvail() );
  2242. // we are now holding the lock
  2243. State().StartHold();
  2244. // add ourself as the owner
  2245. State().AddAsOwner();
  2246. // save our context as the owner
  2247. State().SetOwner( pcls );
  2248. // set initial entry count
  2249. State().Enter();
  2250. }
  2251. // return result
  2252. return fAcquired;
  2253. }
  2254. }
  2255. // try to enter the critical section waiting only for the specified interval,
  2256. // returning fFalse if the wait timed out before the critical section could be
  2257. // acquired. the critical section can be reentered without waiting or
  2258. // deadlocking
  2259. inline const BOOL CNestableCriticalSection::FEnter( const int cmsecTimeout )
  2260. {
  2261. // get our context
  2262. CLS* const pcls = Pcls();
  2263. // we own the critical section
  2264. if ( State().PclsOwner() == pcls )
  2265. {
  2266. // there had better be no available counts on the semaphore
  2267. Assert( !State().Semaphore().CAvail() );
  2268. // we should have at least one entry count
  2269. Assert( State().CEntry() >= 1 );
  2270. // increment our entry count
  2271. State().Enter();
  2272. // return success
  2273. return fTrue;
  2274. }
  2275. // we do not own the critical section
  2276. else
  2277. {
  2278. Assert( State().PclsOwner() != pcls );
  2279. // check for deadlock if we are waiting forever
  2280. AssertRTLSz( cmsecTimeout != cmsecInfinite || State().FCanBeOwner(), _T( "Potential Deadlock Detected" ) );
  2281. // try to acquire the semaphore, timing out as requested
  2282. //
  2283. // NOTE: there is still a potential for deadlock, but that will be detected
  2284. // at the OS level
  2285. const BOOL fAcquired = State().Semaphore().FAcquire( cmsecTimeout );
  2286. // we now own the critical section
  2287. if ( fAcquired )
  2288. {
  2289. // there had better be no available counts on the semaphore
  2290. Assert( !State().Semaphore().CAvail() );
  2291. // we are now holding the lock
  2292. State().StartHold();
  2293. // add ourself as the owner
  2294. State().AddAsOwner();
  2295. // save our context as the owner
  2296. State().SetOwner( pcls );
  2297. // set initial entry count
  2298. State().Enter();
  2299. }
  2300. // return result
  2301. return fAcquired;
  2302. }
  2303. }
  2304. // leave the critical section. if leave has been called for every enter that
  2305. // has completed successfully, the critical section is released for ownership
  2306. // by someone else
  2307. inline void CNestableCriticalSection::Leave()
  2308. {
  2309. // we had better be the current owner
  2310. Assert( State().PclsOwner() == Pcls() );
  2311. // there had better be no available counts on the semaphore
  2312. Assert( !State().Semaphore().CAvail() );
  2313. // there had better be at least one entry count
  2314. Assert( State().CEntry() >= 1 );
  2315. // release one entry count
  2316. State().Leave();
  2317. // we released the last entry count
  2318. if ( !State().CEntry() )
  2319. {
  2320. // reset the owner id
  2321. State().SetOwner( 0 );
  2322. // remove ourself as the owner
  2323. State().RemoveAsOwner();
  2324. // release the semaphore
  2325. State().Semaphore().Release();
  2326. // we are no longer holding the lock
  2327. State().StopHold();
  2328. }
  2329. }
  2330. // Gate State
  2331. #pragma pack( 1 )
  2332. class CGateState
  2333. {
  2334. public:
  2335. // member functions
  2336. // ctors / dtors
  2337. CGateState( const CSyncStateInitNull& null ) : m_cWait( 0 ), m_irksem( CKernelSemaphorePool::irksemNil ) {}
  2338. CGateState( const int cWait, const int irksem );
  2339. ~CGateState() {}
  2340. // manipulators
  2341. void SetWaitCount( const int cWait );
  2342. void SetIrksem( const CKernelSemaphorePool::IRKSEM irksem );
  2343. // accessors
  2344. const int CWait() const { return m_cWait; }
  2345. const CKernelSemaphorePool::IRKSEM Irksem() const { return CKernelSemaphorePool::IRKSEM( m_irksem ); }
  2346. // debugging support
  2347. void Dump( CPRINTFSYNC* pcprintf, DWORD dwOffset );
  2348. private:
  2349. // member functions
  2350. // operators
  2351. CGateState& operator=( CGateState& ); // disallowed
  2352. // data members
  2353. // waiter count
  2354. volatile short m_cWait; // 0 <= m_cWait <= ( 1 << 15 ) - 1
  2355. // reference kernel semaphore
  2356. volatile unsigned short m_irksem; // 0 <= m_irksem <= ( 1 << 16 ) - 2
  2357. };
  2358. #pragma pack()
  2359. // sets the wait count for the gate
  2360. inline void CGateState::SetWaitCount( const int cWait )
  2361. {
  2362. // it must be a valid wait count
  2363. Assert( cWait >= 0 );
  2364. Assert( cWait <= 0x7FFF );
  2365. // set the wait count
  2366. m_cWait = (unsigned short) cWait;
  2367. }
  2368. // sets the referenced kernel semaphore for the gate
  2369. inline void CGateState::SetIrksem( const CKernelSemaphorePool::IRKSEM irksem )
  2370. {
  2371. // it must be a valid irksem
  2372. Assert( irksem >= 0 );
  2373. Assert( irksem <= 0xFFFF );
  2374. // set the irksem
  2375. m_irksem = (unsigned short) irksem;
  2376. }
  2377. // Gate
  2378. class CGate
  2379. : private CSyncObject,
  2380. private CEnhancedStateContainer< CGateState, CSyncStateInitNull, CSyncSimplePerfInfo, CSyncBasicInfo >
  2381. {
  2382. public:
  2383. // member functions
  2384. // ctors / dtors
  2385. CGate( const CSyncBasicInfo& sbi );
  2386. ~CGate();
  2387. // manipulators
  2388. void Wait( CCriticalSection& crit );
  2389. void Release( CCriticalSection& crit, const int cToRelease = 1 );
  2390. void ReleaseAndHold( CCriticalSection& crit, const int cToRelease = 1 );
  2391. // accessors
  2392. const int CWait() const { return State().CWait(); }
  2393. // debugging support
  2394. void Dump( CPRINTFSYNC* pcprintf, DWORD dwOffset = 0 );
  2395. size_t CbEnhancedState() { return CbState(); }
  2396. private:
  2397. // member functions
  2398. // operators
  2399. CGate& operator=( CGate& ); // disallowed
  2400. };
  2401. // Null Lock Object State Initializer
  2402. class CLockStateInitNull
  2403. {
  2404. };
  2405. extern CLockStateInitNull lockstateNull;
  2406. // Complex Lock Object Group Performance Information
  2407. class CLockGroupComplexPerfInfo
  2408. : public CSyncPerfWait,
  2409. public CSyncPerfAcquire,
  2410. public CLockGroupSimplePerfInfo
  2411. {
  2412. public:
  2413. // member functions
  2414. // ctors / dtors
  2415. CLockGroupComplexPerfInfo()
  2416. {
  2417. }
  2418. // debugging support
  2419. void Dump( CPRINTFSYNC* pcprintf, DWORD dwOffset )
  2420. {
  2421. CSyncPerfWait::Dump( pcprintf, dwOffset );
  2422. CSyncPerfAcquire::Dump( pcprintf, dwOffset );
  2423. CLockGroupSimplePerfInfo::Dump( pcprintf, dwOffset );
  2424. }
  2425. };
  2426. // Complex Group Lock Object Performance Information
  2427. template< const int m_cGroup >
  2428. class CGroupLockComplexPerfInfo
  2429. {
  2430. public:
  2431. // member functions
  2432. // ctors / dtors
  2433. CGroupLockComplexPerfInfo() {}
  2434. ~CGroupLockComplexPerfInfo() {}
  2435. // manipulators
  2436. void StartWait( const int iGroup ) { Assert( iGroup < m_cGroup ); m_rginfo[iGroup].StartWait(); }
  2437. void StopWait( const int iGroup ) { Assert( iGroup < m_cGroup ); m_rginfo[iGroup].StopWait(); }
  2438. void SetAcquire( const int iGroup ) { Assert( iGroup < m_cGroup ); m_rginfo[iGroup].SetAcquire(); }
  2439. void SetContend( const int iGroup ) { Assert( iGroup < m_cGroup ); m_rginfo[iGroup].SetContend(); }
  2440. void StartHold( const int iGroup ) { Assert( iGroup < m_cGroup ); m_rginfo[iGroup].StartHold(); }
  2441. void StopHold( const int iGroup ) { Assert( iGroup < m_cGroup ); m_rginfo[iGroup].StopHold(); }
  2442. // debugging support
  2443. void Dump( CPRINTFSYNC* pcprintf, DWORD dwOffset )
  2444. {
  2445. for ( int iGroup = 0; iGroup < m_cGroup; iGroup++ )
  2446. {
  2447. m_rginfo[iGroup].Dump( pcprintf, dwOffset );
  2448. }
  2449. }
  2450. private:
  2451. // member functions
  2452. // operators
  2453. CGroupLockComplexPerfInfo& operator=( CGroupLockComplexPerfInfo& ); // disallowed
  2454. // data members
  2455. // performance info for each group
  2456. CLockGroupComplexPerfInfo m_rginfo[m_cGroup];
  2457. };
  2458. // Complex Group Lock Object Information
  2459. template< const int m_cGroup >
  2460. class CGroupLockComplexInfo
  2461. : public CLockBasicInfo,
  2462. public CGroupLockComplexPerfInfo< m_cGroup >,
  2463. public CLockDeadlockDetectionInfo
  2464. {
  2465. public:
  2466. // member functions
  2467. // ctors / dtors
  2468. CGroupLockComplexInfo( const CLockBasicInfo& lbi )
  2469. : CLockDeadlockDetectionInfo( (CLockBasicInfo&) *this ),
  2470. CLockBasicInfo( lbi )
  2471. {
  2472. }
  2473. // debugging support
  2474. void Dump( CPRINTFSYNC* pcprintf, DWORD dwOffset )
  2475. {
  2476. CLockBasicInfo::Dump( pcprintf, dwOffset );
  2477. CGroupLockComplexPerfInfo< m_cGroup >::Dump( pcprintf, dwOffset );
  2478. CLockDeadlockDetectionInfo::Dump( pcprintf, dwOffset );
  2479. }
  2480. };
  2481. // Binary Lock State
  2482. #pragma pack( 1 )
  2483. class CBinaryLockState
  2484. {
  2485. public:
  2486. // types
  2487. // control word
  2488. typedef DWORD ControlWord;
  2489. // member functions
  2490. // ctors / dtors
  2491. CBinaryLockState( const CSyncBasicInfo& sbi );
  2492. ~CBinaryLockState();
  2493. // debugging support
  2494. void Dump( CPRINTFSYNC* pcprintf, DWORD dwOffset );
  2495. // data members
  2496. // control word
  2497. union
  2498. {
  2499. volatile ControlWord m_cw;
  2500. struct
  2501. {
  2502. volatile DWORD m_cOOW1:15;
  2503. volatile DWORD m_fQ1:1;
  2504. volatile DWORD m_cOOW2:15;
  2505. volatile DWORD m_fQ2:1;
  2506. };
  2507. };
  2508. // quiesced owner count
  2509. volatile DWORD m_cOwner;
  2510. // sempahore used by Group 1 to wait for lock ownership
  2511. CSemaphore m_sem1;
  2512. // sempahore used by Group 2 to wait for lock ownership
  2513. CSemaphore m_sem2;
  2514. private:
  2515. // member functions
  2516. // operators
  2517. CBinaryLockState& operator=( CBinaryLockState& ); // disallowed
  2518. };
  2519. #pragma pack()
  2520. // Binary Lock
  2521. class CBinaryLock
  2522. : private CLockObject,
  2523. private CEnhancedStateContainer< CBinaryLockState, CSyncBasicInfo, CGroupLockComplexInfo< 2 >, CLockBasicInfo >
  2524. {
  2525. public:
  2526. // types
  2527. // control word
  2528. typedef CBinaryLockState::ControlWord ControlWord;
  2529. // transition reasons for state machine
  2530. enum TransitionReason
  2531. {
  2532. trIllegal = 0,
  2533. trEnter1 = 1,
  2534. trLeave1 = 2,
  2535. trEnter2 = 4,
  2536. trLeave2 = 8,
  2537. };
  2538. // member functions
  2539. // ctors / dtors
  2540. CBinaryLock( const CLockBasicInfo& lbi );
  2541. ~CBinaryLock();
  2542. // manipulators
  2543. void Enter1();
  2544. void Leave1();
  2545. void Enter2();
  2546. void Leave2();
  2547. // accessors
  2548. const BOOL FMemberOfGroup1() { return State().FOwner( 0 ); }
  2549. const BOOL FNotMemberOfGroup1() { return State().FNotOwner( 0 ); }
  2550. const BOOL FMemberOfGroup2() { return State().FOwner( 1 ); }
  2551. const BOOL FNotMemberOfGroup2() { return State().FNotOwner( 1 ); }
  2552. // debugging support
  2553. void Dump( CPRINTFSYNC* pcprintf, DWORD dwOffset = 0 );
  2554. size_t CbEnhancedState() { return CbState(); }
  2555. private:
  2556. // member functions
  2557. // operators
  2558. CBinaryLock& operator=( CBinaryLock& ); // disallowed
  2559. // verification
  2560. int _StateFromControlWord( const ControlWord cw );
  2561. BOOL _FValidStateTransition( const ControlWord cwBI,
  2562. const ControlWord cwAI,
  2563. const TransitionReason tr );
  2564. // manipulators
  2565. void _Enter1( const ControlWord cwBIOld );
  2566. void _Enter2( const ControlWord cwBIOld );
  2567. void _UpdateQuiescedOwnerCountAsGroup1( const DWORD cOwnerDelta );
  2568. void _UpdateQuiescedOwnerCountAsGroup2( const DWORD cOwnerDelta );
  2569. // debugging support
  2570. static void Dump( CLockObject* plockobj, CPRINTFSYNC* pcprintf, DWORD dwOffset = 0 ) { ( (CBinaryLock*) plockobj )->Dump( pcprintf, dwOffset ); }
  2571. };
  2572. // enters the binary lock as a member of Group 1, waiting forever if necessary
  2573. //
  2574. // NOTE: trying to enter the lock as a member of Group 1 when you already own
  2575. // the lock as a member of Group 2 will cause a deadlock.
  2576. inline void CBinaryLock::Enter1()
  2577. {
  2578. // we had better not already own this lock as either group
  2579. Assert( State().FNotOwner( 0 ) );
  2580. Assert( State().FNotOwner( 1 ) );
  2581. // check for deadlock
  2582. AssertRTLSz( State().FCanBeOwner(), _T( "Potential Deadlock Detected" ) );
  2583. // try forever until we successfully change the lock state
  2584. SYNC_FOREVER
  2585. {
  2586. // read the current state of the control word as our expected before image
  2587. const ControlWord cwBIExpected = State().m_cw;
  2588. // compute the after image of the control word by performing the global
  2589. // transform for the Enter1 state transition
  2590. const ControlWord cwAI = ( ( cwBIExpected & ( ( long( cwBIExpected ) >> 15 ) |
  2591. 0x0000FFFF ) ) | 0x80000000 ) + 0x00000001;
  2592. // validate the transaction
  2593. Assert( _FValidStateTransition( cwBIExpected, cwAI, trEnter1 ) );
  2594. // attempt to perform the transacted state transition on the control word
  2595. const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );
  2596. // the transaction failed or Group 1 was quiesced from ownership
  2597. if ( ( cwBI ^ cwBIExpected ) | ( cwBI & 0x00008000 ) )
  2598. {
  2599. // the transaction failed because another context changed the control word
  2600. if ( cwBI != cwBIExpected )
  2601. {
  2602. // try again
  2603. continue;
  2604. }
  2605. // the transaction succeeded but Group 1 was quiesced from ownership
  2606. else
  2607. {
  2608. // this is a contention for Group 1
  2609. State().SetContend( 0 );
  2610. // wait to own the lock as a member of Group 1
  2611. _Enter1( cwBI );
  2612. // we now own the lock, so we're done
  2613. break;
  2614. }
  2615. }
  2616. // the transaction succeeded and Group 1 was not quiesced from ownership
  2617. else
  2618. {
  2619. // we now own the lock, so we're done
  2620. break;
  2621. }
  2622. }
  2623. // note that we acquired the lock for Group 1
  2624. State().SetAcquire( 0 );
  2625. // we are now holding the lock
  2626. State().StartHold( 0 );
  2627. // we are now an owner of the lock
  2628. State().AddAsOwner( 0 );
  2629. }
  2630. // leaves the binary lock as a member of Group 1
  2631. //
  2632. // NOTE: you must leave the lock as a member of the same Group for which you entered
  2633. // the lock or deadlocks may occur
  2634. inline void CBinaryLock::Leave1()
  2635. {
  2636. // we are no longer an owner of the lock
  2637. State().RemoveAsOwner( 0 );
  2638. // try forever until we successfully change the lock state
  2639. SYNC_FOREVER
  2640. {
  2641. // read the current state of the control word as our expected before image
  2642. ControlWord cwBIExpected = State().m_cw;
  2643. // change the expected before image so that the transaction will only work if
  2644. // Group 1 ownership is not quiesced
  2645. cwBIExpected = cwBIExpected & 0xFFFF7FFF;
  2646. // compute the after image of the control word by performing the transform that
  2647. // will take us either from state 2 to state 0 or state 2 to state 2
  2648. ControlWord cwAI = cwBIExpected + 0xFFFFFFFF;
  2649. cwAI = cwAI - ( ( ( cwAI + 0xFFFFFFFF ) << 16 ) & 0x80000000 );
  2650. // validate the transaction
  2651. Assert( _StateFromControlWord( cwBIExpected ) < 0 ||
  2652. _FValidStateTransition( cwBIExpected, cwAI, trLeave1 ) );
  2653. // attempt to perform the transacted state transition on the control word
  2654. const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );
  2655. // the transaction failed
  2656. if ( cwBI != cwBIExpected )
  2657. {
  2658. // the transaction failed because Group 1 ownership is quiesced
  2659. if ( cwBI & 0x00008000 )
  2660. {
  2661. // leave the lock as a quiesced owner
  2662. _UpdateQuiescedOwnerCountAsGroup1( 0xFFFFFFFF );
  2663. // we're done
  2664. break;
  2665. }
  2666. // the transaction failed because another context changed the control word
  2667. else
  2668. {
  2669. // try again
  2670. continue;
  2671. }
  2672. }
  2673. // the transaction succeeded
  2674. else
  2675. {
  2676. // we're done
  2677. break;
  2678. }
  2679. }
  2680. // we are no longer holding the lock
  2681. State().StopHold( 0 );
  2682. }
  2683. // enters the binary lock as a member of Group 2, waiting forever if necessary
  2684. //
  2685. // NOTE: trying to enter the lock as a member of Group 2 when you already own
  2686. // the lock as a member of Group 1 will cause a deadlock.
  2687. inline void CBinaryLock::Enter2()
  2688. {
  2689. // we had better not already own this lock as either group
  2690. Assert( State().FNotOwner( 0 ) );
  2691. Assert( State().FNotOwner( 1 ) );
  2692. // check for deadlock
  2693. AssertRTLSz( State().FCanBeOwner(), _T( "Potential Deadlock Detected" ) );
  2694. // try forever until we successfully change the lock state
  2695. SYNC_FOREVER
  2696. {
  2697. // read the current state of the control word as our expected before image
  2698. const ControlWord cwBIExpected = State().m_cw;
  2699. // compute the after image of the control word by performing the global
  2700. // transform for the Enter2 state transition
  2701. const ControlWord cwAI = ( ( cwBIExpected & ( ( long( cwBIExpected << 16 ) >> 31 ) |
  2702. 0xFFFF0000 ) ) | 0x00008000 ) + 0x00010000;
  2703. // validate the transaction
  2704. Assert( _FValidStateTransition( cwBIExpected, cwAI, trEnter2 ) );
  2705. // attempt to perform the transacted state transition on the control word
  2706. const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );
  2707. // the transaction failed or Group 2 was quiesced from ownership
  2708. if ( ( cwBI ^ cwBIExpected ) | ( cwBI & 0x80000000 ) )
  2709. {
  2710. // the transaction failed because another context changed the control word
  2711. if ( cwBI != cwBIExpected )
  2712. {
  2713. // try again
  2714. continue;
  2715. }
  2716. // the transaction succeeded but Group 2 was quiesced from ownership
  2717. else
  2718. {
  2719. // this is a contention for Group 2
  2720. State().SetContend( 1 );
  2721. // wait to own the lock as a member of Group 2
  2722. _Enter2( cwBI );
  2723. // we now own the lock, so we're done
  2724. break;
  2725. }
  2726. }
  2727. // the transaction succeeded and Group 2 was not quiesced from ownership
  2728. else
  2729. {
  2730. // we now own the lock, so we're done
  2731. break;
  2732. }
  2733. }
  2734. // note that we acquired the lock for Group 2
  2735. State().SetAcquire( 1 );
  2736. // we are now holding the lock
  2737. State().StartHold( 1 );
  2738. // we are now an owner of the lock
  2739. State().AddAsOwner( 1 );
  2740. }
  2741. // leaves the binary lock as a member of Group 2
  2742. //
  2743. // NOTE: you must leave the lock as a member of the same Group for which you entered
  2744. // the lock or deadlocks may occur
  2745. inline void CBinaryLock::Leave2()
  2746. {
  2747. // we are no longer an owner of the lock
  2748. State().RemoveAsOwner( 1 );
  2749. // try forever until we successfully change the lock state
  2750. SYNC_FOREVER
  2751. {
  2752. // read the current state of the control word as our expected before image
  2753. ControlWord cwBIExpected = State().m_cw;
  2754. // change the expected before image so that the transaction will only work if
  2755. // Group 2 ownership is not quiesced
  2756. cwBIExpected = cwBIExpected & 0x7FFFFFFF;
  2757. // compute the after image of the control word by performing the transform that
  2758. // will take us either from state 1 to state 0 or state 1 to state 1
  2759. ControlWord cwAI = cwBIExpected + 0xFFFF0000;
  2760. cwAI = cwAI - ( ( ( cwAI + 0xFFFF0000 ) >> 16 ) & 0x00008000 );
  2761. // validate the transaction
  2762. Assert( _StateFromControlWord( cwBIExpected ) < 0 ||
  2763. _FValidStateTransition( cwBIExpected, cwAI, trLeave2 ) );
  2764. // attempt to perform the transacted state transition on the control word
  2765. const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );
  2766. // the transaction failed
  2767. if ( cwBI != cwBIExpected )
  2768. {
  2769. // the transaction failed because Group 2 ownership is quiesced
  2770. if ( cwBI & 0x80000000 )
  2771. {
  2772. // leave the lock as a quiesced owner
  2773. _UpdateQuiescedOwnerCountAsGroup2( 0xFFFFFFFF );
  2774. // we're done
  2775. break;
  2776. }
  2777. // the transaction failed because another context changed the control word
  2778. else
  2779. {
  2780. // try again
  2781. continue;
  2782. }
  2783. }
  2784. // the transaction succeeded
  2785. else
  2786. {
  2787. // we're done
  2788. break;
  2789. }
  2790. }
  2791. // we are no longer holding the lock
  2792. State().StopHold( 1 );
  2793. }
  2794. // Reader / Writer Lock State
  2795. class CReaderWriterLockState
  2796. {
  2797. public:
  2798. // types
  2799. // control word
  2800. typedef DWORD ControlWord;
  2801. // member functions
  2802. // ctors / dtors
  2803. CReaderWriterLockState( const CSyncBasicInfo& sbi );
  2804. ~CReaderWriterLockState();
  2805. // debugging support
  2806. void Dump( CPRINTFSYNC* pcprintf, DWORD dwOffset );
  2807. // data members
  2808. // control word
  2809. union
  2810. {
  2811. volatile ControlWord m_cw;
  2812. struct
  2813. {
  2814. volatile DWORD m_cOAOWW:15;
  2815. volatile DWORD m_fQW:1;
  2816. volatile DWORD m_cOOWR:15;
  2817. volatile DWORD m_fQR:1;
  2818. };
  2819. };
  2820. // quiesced owner count
  2821. volatile DWORD m_cOwner;
  2822. // sempahore used by writers to wait for lock ownership
  2823. CSemaphore m_semWriter;
  2824. // sempahore used by readers to wait for lock ownership
  2825. CSemaphore m_semReader;
  2826. private:
  2827. // member functions
  2828. // operators
  2829. CReaderWriterLockState& operator=( CReaderWriterLockState& ); // disallowed
  2830. };
  2831. // Reader / Writer Lock
  2832. class CReaderWriterLock
  2833. : private CLockObject,
  2834. private CEnhancedStateContainer< CReaderWriterLockState, CSyncBasicInfo, CGroupLockComplexInfo< 2 >, CLockBasicInfo >
  2835. {
  2836. public:
  2837. // types
  2838. // control word
  2839. typedef CBinaryLockState::ControlWord ControlWord;
  2840. // transition reasons for state machine
  2841. enum TransitionReason
  2842. {
  2843. trIllegal = 0,
  2844. trEnterAsWriter = 1,
  2845. trLeaveAsWriter = 2,
  2846. trEnterAsReader = 4,
  2847. trLeaveAsReader = 8,
  2848. };
  2849. // member functions
  2850. // ctors / dtors
  2851. CReaderWriterLock( const CLockBasicInfo& lbi );
  2852. ~CReaderWriterLock();
  2853. // manipulators
  2854. void EnterAsWriter();
  2855. void LeaveAsWriter();
  2856. void EnterAsReader();
  2857. void LeaveAsReader();
  2858. // accessors
  2859. const BOOL FWriter() { return State().FOwner( 0 ); }
  2860. const BOOL FNotWriter() { return State().FNotOwner( 0 ); }
  2861. const BOOL FReader() { return State().FOwner( 1 ); }
  2862. const BOOL FNotReader() { return State().FNotOwner( 1 ); }
  2863. // debugging support
  2864. void Dump( CPRINTFSYNC* pcprintf, DWORD dwOffset = 0 );
  2865. size_t CbEnhancedState() { return CbState(); }
  2866. private:
  2867. // member functions
  2868. // operators
  2869. CReaderWriterLock& operator=( CReaderWriterLock& ); // disallowed
  2870. // verification
  2871. int _StateFromControlWord( const ControlWord cw );
  2872. BOOL _FValidStateTransition( const ControlWord cwBI,
  2873. const ControlWord cwAI,
  2874. const TransitionReason tr );
  2875. // manipulators
  2876. void _EnterAsWriter( const ControlWord cwBIOld );
  2877. void _EnterAsReader( const ControlWord cwBIOld );
  2878. void _UpdateQuiescedOwnerCountAsWriter( const DWORD cOwnerDelta );
  2879. void _UpdateQuiescedOwnerCountAsReader( const DWORD cOwnerDelta );
  2880. // debugging support
  2881. static void Dump( CLockObject* plockobj, CPRINTFSYNC* pcprintf, DWORD dwOffset = 0 ) { ( (CReaderWriterLock*) plockobj )->Dump( pcprintf, dwOffset ); }
  2882. };
  2883. // enters the reader / writer lock as a writer, waiting forever if necessary
  2884. //
  2885. // NOTE: trying to enter the lock as a writer when you already own the lock
  2886. // as a reader will cause a deadlock.
  2887. inline void CReaderWriterLock::EnterAsWriter()
  2888. {
  2889. // we had better not already own this lock as either a reader or a writer
  2890. Assert( State().FNotOwner( 0 ) );
  2891. Assert( State().FNotOwner( 1 ) );
  2892. // check for deadlock
  2893. AssertRTLSz( State().FCanBeOwner(), _T( "Potential Deadlock Detected" ) );
  2894. // try forever until we successfully change the lock state
  2895. SYNC_FOREVER
  2896. {
  2897. // read the current state of the control word as our expected before image
  2898. const ControlWord cwBIExpected = State().m_cw;
  2899. // compute the after image of the control word by performing the global
  2900. // transform for the EnterAsWriter state transition
  2901. const ControlWord cwAI = ( ( cwBIExpected & ( ( long( cwBIExpected ) >> 15 ) |
  2902. 0x0000FFFF ) ) | 0x80000000 ) + 0x00000001;
  2903. // validate the transaction
  2904. Assert( _FValidStateTransition( cwBIExpected, cwAI, trEnterAsWriter ) );
  2905. // attempt to perform the transacted state transition on the control word
  2906. const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );
  2907. // the transaction failed or writers are quiesced from ownership or a
  2908. // writer already owns the lock
  2909. if ( ( cwBI ^ cwBIExpected ) | ( cwBI & 0x0000FFFF ) )
  2910. {
  2911. // the transaction failed because another context changed the control word
  2912. if ( cwBI != cwBIExpected )
  2913. {
  2914. // try again
  2915. continue;
  2916. }
  2917. // the transaction succeeded but writers are quiesced from ownership
  2918. // or a writer already owns the lock
  2919. else
  2920. {
  2921. // this is a contention for writers
  2922. State().SetContend( 0 );
  2923. // wait to own the lock as a writer
  2924. _EnterAsWriter( cwBI );
  2925. // we now own the lock, so we're done
  2926. break;
  2927. }
  2928. }
  2929. // the transaction succeeded and writers were not quiesced from ownership
  2930. // and a writer did not already own the lock
  2931. else
  2932. {
  2933. // we now own the lock, so we're done
  2934. break;
  2935. }
  2936. }
  2937. // note that we acquired the lock for writers
  2938. State().SetAcquire( 0 );
  2939. // we are now holding the lock
  2940. State().StartHold( 0 );
  2941. // we are now an owner of the lock
  2942. State().AddAsOwner( 0 );
  2943. }
  2944. // leaves the reader / writer lock as a writer
  2945. //
  2946. // NOTE: you must leave the lock as a member of the same group for which you entered
  2947. // the lock or deadlocks may occur
  2948. inline void CReaderWriterLock::LeaveAsWriter()
  2949. {
  2950. // we are no longer an owner of the lock
  2951. State().RemoveAsOwner( 0 );
  2952. // try forever until we successfully change the lock state
  2953. SYNC_FOREVER
  2954. {
  2955. // read the current state of the control word as our expected before image
  2956. ControlWord cwBIExpected = State().m_cw;
  2957. // change the expected before image so that the transaction will only work if
  2958. // writers were not quiesced from ownership
  2959. cwBIExpected = cwBIExpected & 0xFFFF7FFF;
  2960. // compute the after image of the control word by performing the transform that
  2961. // will take us either from state 2 to state 0 or state 2 to state 2
  2962. ControlWord cwAI = cwBIExpected + 0xFFFFFFFF;
  2963. cwAI = cwAI - ( ( ( cwAI + 0xFFFFFFFF ) << 16 ) & 0x80000000 );
  2964. // validate the transaction
  2965. Assert( _StateFromControlWord( cwBIExpected ) < 0 ||
  2966. _FValidStateTransition( cwBIExpected, cwAI, trLeaveAsWriter ) );
  2967. // attempt to perform the transacted state transition on the control word
  2968. const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );
  2969. // the transaction failed
  2970. if ( cwBI != cwBIExpected )
  2971. {
  2972. // the transaction failed because writers were quiesced from ownership
  2973. if ( cwBI & 0x00008000 )
  2974. {
  2975. // leave the lock as a quiesced owner
  2976. _UpdateQuiescedOwnerCountAsWriter( 0xFFFFFFFF );
  2977. // we're done
  2978. break;
  2979. }
  2980. // the transaction failed because another context changed the control word
  2981. else
  2982. {
  2983. // try again
  2984. continue;
  2985. }
  2986. }
  2987. // the transaction succeeded
  2988. else
  2989. {
  2990. // there were other writers waiting for ownership of the lock
  2991. if ( cwAI & 0x00007FFF )
  2992. {
  2993. // release the next writer into ownership of the lock
  2994. State().m_semWriter.Release();
  2995. }
  2996. // we're done
  2997. break;
  2998. }
  2999. }
  3000. // we are no longer holding the lock
  3001. State().StopHold( 0 );
  3002. }
  3003. // enters the reader / writer lock as a reader, waiting forever if necessary
  3004. //
  3005. // NOTE: trying to enter the lock as a reader when you already own the lock
  3006. // as a writer will cause a deadlock.
  3007. inline void CReaderWriterLock::EnterAsReader()
  3008. {
  3009. // we had better not already own this lock as either a reader or a writer
  3010. Assert( State().FNotOwner( 0 ) );
  3011. Assert( State().FNotOwner( 1 ) );
  3012. // check for deadlock
  3013. AssertRTLSz( State().FCanBeOwner(), _T( "Potential Deadlock Detected" ) );
  3014. // try forever until we successfully change the lock state
  3015. SYNC_FOREVER
  3016. {
  3017. // read the current state of the control word as our expected before image
  3018. const ControlWord cwBIExpected = State().m_cw;
  3019. // compute the after image of the control word by performing the global
  3020. // transform for the EnterAsReader state transition
  3021. const ControlWord cwAI = ( cwBIExpected & 0xFFFF7FFF ) +
  3022. ( ( cwBIExpected & 0x80008000 ) == 0x80000000 ?
  3023. 0x00017FFF :
  3024. 0x00018000 );
  3025. // validate the transaction
  3026. Assert( _FValidStateTransition( cwBIExpected, cwAI, trEnterAsReader ) );
  3027. // attempt to perform the transacted state transition on the control word
  3028. const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );
  3029. // the transaction failed or readers were quiesced from ownership
  3030. if ( ( cwBI ^ cwBIExpected ) | ( cwBI & 0x80000000 ) )
  3031. {
  3032. // the transaction failed because another context changed the control word
  3033. if ( cwBI != cwBIExpected )
  3034. {
  3035. // try again
  3036. continue;
  3037. }
  3038. // the transaction succeeded but readers were quiesced from ownership
  3039. else
  3040. {
  3041. // this is a contention for readers
  3042. State().SetContend( 1 );
  3043. // wait to own the lock as a reader
  3044. _EnterAsReader( cwBI );
  3045. // we now own the lock, so we're done
  3046. break;
  3047. }
  3048. }
  3049. // the transaction succeeded and readers were not quiesced from ownership
  3050. else
  3051. {
  3052. // we now own the lock, so we're done
  3053. break;
  3054. }
  3055. }
  3056. // note that we acquired the lock for readers
  3057. State().SetAcquire( 1 );
  3058. // we are now holding the lock
  3059. State().StartHold( 1 );
  3060. // we are now an owner of the lock
  3061. State().AddAsOwner( 1 );
  3062. }
  3063. // leaves the reader / writer lock as a reader
  3064. //
  3065. // NOTE: you must leave the lock as a member of the same group for which you entered
  3066. // the lock or deadlocks may occur
  3067. inline void CReaderWriterLock::LeaveAsReader()
  3068. {
  3069. // we are no longer an owner of the lock
  3070. State().RemoveAsOwner( 1 );
  3071. // try forever until we successfully change the lock state
  3072. SYNC_FOREVER
  3073. {
  3074. // read the current state of the control word as our expected before image
  3075. ControlWord cwBIExpected = State().m_cw;
  3076. // change the expected before image so that the transaction will only work if
  3077. // readers were not quiesced from ownership
  3078. cwBIExpected = cwBIExpected & 0x7FFFFFFF;
  3079. // compute the after image of the control word by performing the transform that
  3080. // will take us either from state 1 to state 0 or state 1 to state 1
  3081. const ControlWord cwAI = cwBIExpected +
  3082. 0xFFFF0000 +
  3083. ( ( long( cwBIExpected + 0xFFFE0000 ) >> 31 ) & 0xFFFF8000 );
  3084. // validate the transaction
  3085. Assert( _StateFromControlWord( cwBIExpected ) < 0 ||
  3086. _FValidStateTransition( cwBIExpected, cwAI, trLeaveAsReader ) );
  3087. // attempt to perform the transacted state transition on the control word
  3088. const ControlWord cwBI = AtomicCompareExchange( (long*)&State().m_cw, cwBIExpected, cwAI );
  3089. // the transaction failed
  3090. if ( cwBI != cwBIExpected )
  3091. {
  3092. // the transaction failed because readers were quiesced from ownership
  3093. if ( cwBI & 0x80000000 )
  3094. {
  3095. // leave the lock as a quiesced owner
  3096. _UpdateQuiescedOwnerCountAsReader( 0xFFFFFFFF );
  3097. // we're done
  3098. break;
  3099. }
  3100. // the transaction failed because another context changed the control word
  3101. else
  3102. {
  3103. // try again
  3104. continue;
  3105. }
  3106. }
  3107. // the transaction succeeded
  3108. else
  3109. {
  3110. // we're done
  3111. break;
  3112. }
  3113. }
  3114. // we are no longer holding the lock
  3115. State().StopHold( 1 );
  3116. }
  3117. // init sync subsystem
  3118. const BOOL FOSSyncInit();
  3119. // terminate sync subsystem
  3120. void OSSyncTerm();
  3121. #endif // _OS_SYNC_HXX_INCLUDED