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

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