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.

694 lines
12 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. All rights reserved.
  4. Module Name:
  5. State.hxx
  6. Abstract:
  7. Handles state objects and critical sections.
  8. Author:
  9. Albert Ting (AlbertT) 28-May-1994
  10. Revision History:
  11. --*/
  12. #ifndef _STATE_HXX
  13. #define _STATE_HXX
  14. typedef DWORD STATEVAR;
  15. /********************************************************************
  16. State object (DWORD) for bitfields.
  17. ********************************************************************/
  18. class TState {
  19. SIGNATURE( 'stat' )
  20. ALWAYS_VALID
  21. SAFE_NEW
  22. public:
  23. #if DBG
  24. TState( VOID );
  25. TState( STATEVAR StateVar );
  26. ~TState( VOID );
  27. STATEVAR operator|=( STATEVAR StateVarOn );
  28. STATEVAR operator&=( STATEVAR StateVarMask );
  29. STATEVAR operator|=( INT iStateVarOn )
  30. { return operator|=( (STATEVAR)iStateVarOn ); }
  31. STATEVAR operator&=( INT iStateVarMask )
  32. { return operator&=( (STATEVAR)iStateVarMask ); }
  33. #else
  34. TState(VOID) : _StateVar(0)
  35. { }
  36. TState(STATEVAR StateVar) : _StateVar( StateVar )
  37. { }
  38. ~TState(VOID)
  39. { }
  40. STATEVAR operator|=( STATEVAR StateVarOn )
  41. { return _StateVar |= StateVarOn; }
  42. STATEVAR operator&=( STATEVAR StateVarMask )
  43. { return _StateVar &= StateVarMask; }
  44. STATEVAR operator|=( INT iStateVarOn )
  45. { return operator|=( (STATEVAR)iStateVarOn ); }
  46. STATEVAR operator&=( INT iStateVarMask )
  47. { return operator&=( (STATEVAR)iStateVarMask ); }
  48. #endif
  49. BOOL bBit( STATEVAR StateVarBit )
  50. { return _StateVar & StateVarBit ? TRUE : FALSE; }
  51. STATEVAR operator&( TState& State )
  52. { return _StateVar & State._StateVar; }
  53. STATEVAR operator=( STATEVAR StateVarNew )
  54. { return _StateVar = StateVarNew; }
  55. TState& operator=( const TState& StateNew )
  56. {
  57. _StateVar = StateNew._StateVar;
  58. return *this;
  59. }
  60. operator STATEVAR() const
  61. { return _StateVar; }
  62. private:
  63. STATEVAR _StateVar;
  64. #if DBG
  65. TBackTraceMem _BackTrace;
  66. virtual BOOL bValidateState() const
  67. { return TRUE; }
  68. virtual BOOL bValidateSet(STATEVAR StateVarOn) const
  69. {
  70. UNREFERENCED_PARAMETER( StateVarOn );
  71. return TRUE;
  72. }
  73. virtual BOOL bValidateMask(STATEVAR StateVarMask) const
  74. {
  75. UNREFERENCED_PARAMETER( StateVarMask );
  76. return TRUE;
  77. }
  78. #endif
  79. };
  80. /********************************************************************
  81. Critical section implementation
  82. Avoid using vEnter and vLeave, since there may be a codepath
  83. that forgets to call one or the other. Instead, use
  84. TCritSec{Hard}Lock and TCritSecUnlock.
  85. MCritSec:
  86. This is the basic critical section. It has vEnter and vLeave,
  87. but these should be used sparingly--use TCritSec*Lock instead.
  88. TCritSecLock:
  89. Used to acquire a critical section for the lifetime of the
  90. TCritSecLock object.
  91. {
  92. foo();
  93. {
  94. TCritSecLock CSL( CritSec ); // CritSec acquired here.
  95. bar();
  96. } // CritSec released here since
  97. // CSL is destroyed.
  98. }
  99. -----------------------------------------------------------------
  100. TCritSecUnlock:
  101. Used to release an acquired critical section for the lifetime of
  102. the TCritSecUnlock object.
  103. Note: The critical section _must_ already be acquired.
  104. {
  105. TCritSecLock CSL( CritSec );
  106. while( bDoIt ){
  107. {
  108. TCritSecLock CSU( CritSec );
  109. Sleep( 10000 );
  110. }
  111. vTouchProtectedData();
  112. }
  113. }
  114. -----------------------------------------------------------------
  115. TCritSecHardLock:
  116. ** Acts same as TCritSecLock on free builds, but on CHK builds it
  117. ** asserts if lock is freed while lock is held.
  118. {
  119. TCritSecLock CSL( CritSec ); // <- *** (A)
  120. TBar *pBar = gData.pBar;
  121. foo();
  122. pBar->UseMe();
  123. }
  124. In the above snippet, the author wants the entire block to be
  125. within the CritSec. However, he/she didn't realize foo leaves
  126. CritSec because it needs to hit the net--and in doing so, gData.pBar
  127. may have been deleted/changed by another thread. For example,
  128. foo() may do the following:
  129. VOID
  130. foo(
  131. VOID
  132. )
  133. {
  134. {
  135. TCritSecUnlock( CritSec );
  136. vLongOperationOverNet(); // <- BUG! Callee assumes
  137. // CritSec _not_ left!
  138. }
  139. //
  140. // Back inside CritSec.
  141. //
  142. }
  143. To catch this in debug builds, (A) above should use TCritSecHardLock.
  144. This will assert when we try and leave CritSec. Care must still
  145. be taken, however, since leaving CritSec may be a rare codepath
  146. and not hit during testing.
  147. Note that foo() is a dangerous function in any case, since
  148. it assumes that the CS is only onwed once.
  149. -----------------------------------------------------------------
  150. Note: TCrit*Lock uses space to store the critical section. In
  151. cases where this is known or already stored somewhere, this is
  152. wasted space. We should change this to use templates to avoid
  153. this extra reference.
  154. ********************************************************************/
  155. class MCritSec;
  156. class TCritSecLock {
  157. SIGNATURE( 'cslk' )
  158. ALWAYS_VALID
  159. SAFE_NEW
  160. public:
  161. TCritSecLock(
  162. MCritSec& CritSec
  163. );
  164. ~TCritSecLock(
  165. VOID
  166. );
  167. private:
  168. //
  169. // Copying and assignement not defined.
  170. //
  171. TCritSecLock( const TCritSecLock & );
  172. TCritSecLock & operator =(const TCritSecLock &);
  173. MCritSec& _CritSec;
  174. };
  175. class TCritSecUnlock {
  176. SIGNATURE( 'csul' )
  177. ALWAYS_VALID
  178. SAFE_NEW
  179. public:
  180. TCritSecUnlock(
  181. MCritSec& CritSec
  182. );
  183. ~TCritSecUnlock(
  184. VOID
  185. );
  186. private:
  187. //
  188. // Copying and assignement not defined.
  189. //
  190. TCritSecUnlock( const TCritSecUnlock & );
  191. TCritSecUnlock & operator =(const TCritSecUnlock &);
  192. MCritSec& _CritSec;
  193. };
  194. class TCritSecHardLock {
  195. friend MCritSec;
  196. SIGNATURE( 'cshl' )
  197. ALWAYS_VALID
  198. SAFE_NEW
  199. public:
  200. TCritSecHardLock(
  201. MCritSec& CritSec
  202. );
  203. ~TCritSecHardLock(
  204. VOID
  205. );
  206. private:
  207. //
  208. // Copying and assignement not defined.
  209. //
  210. TCritSecHardLock( const TCritSecHardLock & );
  211. TCritSecHardLock & operator =(const TCritSecHardLock &);
  212. MCritSec& _CritSec;
  213. #if DBG
  214. DWORD _dwEntryCountMarker;
  215. DLINK( TCritSecHardLock, CritSecHardLock );
  216. #endif
  217. };
  218. /********************************************************************
  219. MCritSec
  220. ********************************************************************/
  221. class MCritSec {
  222. friend TDebugExt;
  223. friend TCritSecHardLock;
  224. SIGNATURE( 'crsc' )
  225. ALWAYS_VALID
  226. SAFE_NEW
  227. public:
  228. #if DBG
  229. MCritSec();
  230. ~MCritSec();
  231. VOID vEnter();
  232. VOID vLeave();
  233. BOOL bInside() const;
  234. BOOL bOutside() const;
  235. #else
  236. MCritSec()
  237. { InitializeCriticalSection(&_CritSec); }
  238. ~MCritSec()
  239. { DeleteCriticalSection(&_CritSec); }
  240. VOID vEnter()
  241. { EnterCriticalSection(&_CritSec); }
  242. VOID vLeave()
  243. { LeaveCriticalSection(&_CritSec); }
  244. #endif
  245. private:
  246. CRITICAL_SECTION _CritSec;
  247. #if DBG
  248. //
  249. // Current owner, entry count, and tickcount at entry time. These
  250. // values change for each entrance.
  251. //
  252. DWORD _dwThreadOwner;
  253. DWORD _dwEntryCount;
  254. DWORD _dwTickCountEntered;
  255. //
  256. // Statistics gathering.
  257. //
  258. DWORD _dwTickCountBlockedTotal;
  259. DWORD _dwTickCountInsideTotal;
  260. DWORD _dwEntryCountTotal;
  261. DLINK_BASE( TCritSecHardLock, CritSecHardLock, CritSecHardLock );
  262. TBackTraceMem _BackTrace;
  263. #endif
  264. };
  265. /********************************************************************
  266. MRef and TRefLock: Locking objects used for ref counting.
  267. class TFoo : public MRef, public MGenWin {
  268. ...
  269. };
  270. class TUserOfFoo {
  271. private:
  272. REF_LOCK( TFoo, Foo );
  273. ...
  274. };
  275. //
  276. // Acquires lock on foo by initialization.
  277. //
  278. TUserOfFoo( TFoo* pFoo ) : RL_Foo( pFoo ) {}
  279. //
  280. // During destruction of TUserOfFoo, the reference count
  281. // of pFoo is automatically decremented.
  282. //
  283. //
  284. // Acquires lock on foo after initialization.
  285. //
  286. vGetLock()
  287. {
  288. Foo.vAcquire( pFoo1 );
  289. ...
  290. //
  291. // Get the pFoo pointer from RLFoo.
  292. //
  293. pFoo1 = pFoo();
  294. Foo.vRelease( pFoo1 );
  295. }
  296. ********************************************************************/
  297. inline
  298. TCritSecLock::
  299. TCritSecLock(
  300. MCritSec& CritSec
  301. ) : _CritSec( CritSec )
  302. {
  303. _CritSec.vEnter();
  304. }
  305. inline
  306. TCritSecLock::
  307. ~TCritSecLock(
  308. VOID
  309. )
  310. {
  311. _CritSec.vLeave();
  312. }
  313. inline
  314. TCritSecUnlock::
  315. TCritSecUnlock(
  316. MCritSec& CritSec
  317. ) : _CritSec( CritSec )
  318. {
  319. _CritSec.vLeave();
  320. SPLASSERT( _CritSec.bOutside( ));
  321. }
  322. inline
  323. TCritSecUnlock::
  324. ~TCritSecUnlock( VOID )
  325. {
  326. _CritSec.vEnter();
  327. }
  328. #if !DBG
  329. inline
  330. TCritSecHardLock::
  331. TCritSecHardLock(
  332. MCritSec& CritSec
  333. ) : _CritSec( CritSec )
  334. {
  335. _CritSec.vEnter();
  336. }
  337. inline
  338. TCritSecHardLock::
  339. ~TCritSecHardLock(
  340. VOID
  341. )
  342. {
  343. _CritSec.vLeave();
  344. }
  345. #endif
  346. /************************************************************
  347. VRef: virtual base class for all ref counting.
  348. ************************************************************/
  349. class VRef {
  350. SAFE_NEW
  351. public:
  352. virtual ~VRef()
  353. { }
  354. //
  355. // Virtuals that must be overwritten by the reference classes.
  356. //
  357. virtual VOID vIncRef() = 0;
  358. virtual LONG cDecRef() = 0;
  359. virtual VOID vDecRefDelete() = 0;
  360. protected:
  361. //
  362. // Clients of the reference class should override this class
  363. // to perform cleanup. Generally clients will implement vRefZeroed
  364. // to delete themselves.
  365. //
  366. virtual VOID vRefZeroed() = 0;
  367. };
  368. /************************************************************
  369. MRefNone: quick ref counter, no sync done.
  370. ************************************************************/
  371. class MRefQuick : public VRef {
  372. SIGNATURE( 'refq' )
  373. ALWAYS_VALID
  374. protected:
  375. VAR( LONG, cRef );
  376. public:
  377. #if DBG
  378. TBackTraceMem _BackTrace;
  379. MRefQuick( VOID ) : _cRef( 0 )
  380. { }
  381. ~MRefQuick( VOID )
  382. {
  383. SPLASSERT( !_cRef );
  384. }
  385. #else
  386. MRefQuick( VOID ) : _cRef( 0 )
  387. { }
  388. #endif
  389. VOID vIncRef();
  390. LONG cDecRef();
  391. VOID vDecRefDelete();
  392. };
  393. /************************************************************
  394. MRefCom: Refcount with interlocks
  395. ************************************************************/
  396. class MRefCom : public VRef {
  397. SIGNATURE( 'refc' )
  398. ALWAYS_VALID
  399. public:
  400. #if DBG
  401. TBackTraceMem _BackTrace;
  402. MRefCom( VOID ) : _cRef( 0 )
  403. { }
  404. ~MRefCom( VOID )
  405. {
  406. SPLASSERT( !_cRef );
  407. }
  408. #else
  409. MRefCom( VOID ) : _cRef( 0 )
  410. { }
  411. #endif
  412. VOID vIncRef();
  413. LONG cDecRef();
  414. VOID vDecRefDelete();
  415. protected:
  416. //
  417. // Must be LONG, not REFCOUNT for Interlocked* apis.
  418. //
  419. VAR( LONG, cRef );
  420. virtual VOID vRefZeroed();
  421. private:
  422. #if DBG
  423. public:
  424. static MCritSec* gpcsCom;
  425. #endif
  426. };
  427. /************************************************************
  428. TRefLock: used to lock a VRef.
  429. ************************************************************/
  430. template<class T>
  431. class TRefLock {
  432. SIGNATURE( 'refl' )
  433. ALWAYS_VALID
  434. SAFE_NEW
  435. public:
  436. TRefLock(
  437. VOID
  438. ) : _pRef( NULL )
  439. { }
  440. TRefLock(
  441. T* pRef
  442. )
  443. {
  444. _pRef = pRef;
  445. _pRef->vIncRef( );
  446. }
  447. ~TRefLock( )
  448. {
  449. if( _pRef )
  450. _pRef->cDecRef( );
  451. }
  452. VOID vAcquire( T* pRef )
  453. {
  454. SPLASSERT( !_pRef );
  455. _pRef = pRef;
  456. _pRef->vIncRef( );
  457. }
  458. VOID vRelease( VOID )
  459. {
  460. SPLASSERT( _pRef );
  461. _pRef->cDecRef( );
  462. _pRef = NULL;
  463. }
  464. T*
  465. pGet(
  466. VOID
  467. ) const
  468. {
  469. return _pRef;
  470. }
  471. T*
  472. operator->(
  473. VOID
  474. ) const
  475. {
  476. return _pRef;
  477. }
  478. private:
  479. //
  480. // Copying and assignement not defined.
  481. //
  482. TRefLock( const TRefLock & );
  483. TRefLock & operator =(const TRefLock &);
  484. T *_pRef;
  485. };
  486. #endif // ndef _STATE_HXX