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.

440 lines
7.8 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. All rights reserved.
  4. Module Name:
  5. State.cxx
  6. Abstract:
  7. State abstraction and critical section
  8. Author:
  9. Albert Ting (AlbertT) 28-May-1994
  10. Revision History:
  11. --*/
  12. #include "spllibp.hxx"
  13. #pragma hdrstop
  14. #if DBG
  15. MCritSec* MRefCom::gpcsCom;
  16. #endif
  17. /********************************************************************
  18. Ref counting
  19. ********************************************************************/
  20. VOID
  21. MRefQuick::
  22. vIncRef(
  23. VOID
  24. )
  25. {
  26. #if DBG
  27. LONG cRefOld = _cRef;
  28. _BackTrace.hCapture( cRefOld, cRefOld + 1 );
  29. #endif
  30. ++_cRef;
  31. }
  32. LONG
  33. MRefQuick::
  34. cDecRef(
  35. VOID
  36. )
  37. {
  38. #if DBG
  39. LONG cRefOld = _cRef;
  40. _BackTrace.hCapture( cRefOld, cRefOld - 1 );
  41. #endif
  42. --_cRef;
  43. if( !_cRef ){
  44. vRefZeroed();
  45. return 0;
  46. }
  47. return _cRef;
  48. }
  49. VOID
  50. MRefQuick::
  51. vDecRefDelete(
  52. VOID
  53. )
  54. {
  55. #if DBG
  56. LONG cRefOld = _cRef;
  57. _BackTrace.hCapture( cRefOld, cRefOld );
  58. #endif
  59. --_cRef;
  60. if( !_cRef ){
  61. vRefZeroed();
  62. }
  63. }
  64. /********************************************************************
  65. MRefCom: Reference counting using interlocked references.
  66. This avoids creating a common critical section.
  67. vDeleteDecRef is the same as vDecRef, but it logs differently.
  68. ********************************************************************/
  69. VOID
  70. MRefCom::
  71. vIncRef(
  72. VOID
  73. )
  74. {
  75. #if DBG
  76. gpcsCom->vEnter();
  77. LONG cRefOld = _cRef;
  78. gpcsCom->vLeave();
  79. _BackTrace.hCapture( cRefOld, cRefOld+1 );
  80. #endif
  81. InterlockedIncrement( &_cRef );
  82. }
  83. LONG
  84. MRefCom::
  85. cDecRef(
  86. VOID
  87. )
  88. {
  89. #if DBG
  90. gpcsCom->vEnter();
  91. LONG cRefOld = _cRef;
  92. gpcsCom->vLeave();
  93. _BackTrace.hCapture( cRefOld, cRefOld - 1 );
  94. #endif
  95. LONG cRefReturn = InterlockedDecrement( &_cRef );
  96. if( !cRefReturn ){
  97. vRefZeroed();
  98. }
  99. return cRefReturn;
  100. }
  101. VOID
  102. MRefCom::
  103. vDecRefDelete(
  104. VOID
  105. )
  106. {
  107. #if DBG
  108. gpcsCom->vEnter();
  109. LONG cRefOld = _cRef;
  110. gpcsCom->vLeave();
  111. _BackTrace.hCapture( cRefOld, cRefOld );
  112. #endif
  113. if( !InterlockedDecrement( &_cRef )){
  114. vRefZeroed();
  115. }
  116. }
  117. VOID
  118. MRefCom::
  119. vRefZeroed(
  120. VOID
  121. )
  122. {
  123. }
  124. /********************************************************************
  125. State
  126. ********************************************************************/
  127. #if DBG
  128. TState::
  129. TState(
  130. VOID
  131. ) : _StateVar(0)
  132. {
  133. }
  134. TState::
  135. TState(
  136. STATEVAR StateVar
  137. ) : _StateVar(StateVar)
  138. {
  139. }
  140. TState::
  141. ~TState(
  142. VOID
  143. )
  144. {
  145. }
  146. STATEVAR
  147. TState::
  148. operator|=(
  149. STATEVAR StateVarOn
  150. )
  151. {
  152. SPLASSERT( bValidateSet( StateVarOn ));
  153. _BackTrace.hCapture( _StateVar, StateVarOn );
  154. _StateVar |= StateVarOn;
  155. return _StateVar;
  156. }
  157. STATEVAR
  158. TState::
  159. operator&=(
  160. STATEVAR StateVarMask
  161. )
  162. {
  163. SPLASSERT( bValidateMask( StateVarMask ));
  164. _BackTrace.hCapture( _StateVar, StateVarMask );
  165. _StateVar &= StateVarMask;
  166. return _StateVar;
  167. }
  168. #endif
  169. /********************************************************************
  170. Critical section implementation
  171. Logging:
  172. CS initialized: 00000000 00000000 00000000
  173. CS acquired: 1eeeeeee bbbbbbbb tttttttt
  174. e New entry count.
  175. b TickCount thread was blocked before acquiring CS.
  176. t Total tickcount all threads have blocked before acquiring CS
  177. CS released: 0eeeeeee iiiiiiii tttttttt
  178. e New entry count.
  179. i Time spent inside the CS, from _first_ acquisition.
  180. t Total tickcount all threads inside CS.
  181. ********************************************************************/
  182. #if DBG
  183. MCritSec::
  184. MCritSec(
  185. VOID
  186. ) : _dwThreadOwner( 0 ), _dwEntryCount( 0 ),
  187. _dwTickCountBlockedTotal( 0 ), _dwTickCountInsideTotal( 0 ),
  188. _dwEntryCountTotal( 0 )
  189. {
  190. InitializeCriticalSection( &_CritSec );
  191. _BackTrace.hCapture( 0, 0, 0 );
  192. }
  193. MCritSec::
  194. ~MCritSec(
  195. VOID
  196. )
  197. {
  198. DeleteCriticalSection( &_CritSec );
  199. }
  200. VOID
  201. MCritSec::
  202. vEnter(
  203. VOID
  204. )
  205. {
  206. DWORD dwTickCountBefore = GetTickCount();
  207. EnterCriticalSection( &_CritSec );
  208. ++_dwEntryCountTotal;
  209. DWORD dwTickCountBlocked = 0;
  210. //
  211. // Re-entrant case: only start the TickCountEntered counter
  212. // if this is the first time we've entered the cs.
  213. //
  214. if( _dwEntryCount == 0 ){
  215. //
  216. // Check how long it took us to enter the critical section.
  217. //
  218. _dwTickCountEntered = GetTickCount();
  219. dwTickCountBlocked = _dwTickCountEntered - dwTickCountBefore;
  220. //
  221. // Update the amount of time this thread blocked on this cs.
  222. //
  223. _dwTickCountBlockedTotal += dwTickCountBlocked;
  224. }
  225. //
  226. // We have entered the critical section; update the count
  227. // and the thread owner.
  228. //
  229. ++_dwEntryCount;
  230. _dwThreadOwner = GetCurrentThreadId();
  231. _BackTrace.hCapture( 0x10000000 | _dwEntryCount,
  232. dwTickCountBlocked,
  233. _dwTickCountBlockedTotal );
  234. }
  235. VOID
  236. MCritSec::
  237. vLeave(
  238. VOID
  239. )
  240. {
  241. SPLASSERT( bInside( ));
  242. DWORD dwTickCountInside = GetTickCount() - _dwTickCountEntered;
  243. --_dwEntryCount;
  244. //
  245. // Verify that we don't leave a CritSecHardLock.
  246. //
  247. TIter Iter;
  248. TCritSecHardLock *pCritSecHardLock;
  249. for( CritSecHardLock_vIterInit( Iter ), Iter.vNext();
  250. Iter.bValid();
  251. Iter.vNext( )){
  252. pCritSecHardLock = CritSecHardLock_pConvert( Iter );
  253. //
  254. // If you hit this assert, then you have created a hard
  255. // lock, but someone is trying to leave it. See header file
  256. // for more info (state.hxx).
  257. //
  258. if( _dwEntryCount < pCritSecHardLock->_dwEntryCountMarker ){
  259. DBGMSG( DBG_ERROR, ( "CritSec.vLeave: Leaving a hard lock.\n" ));
  260. }
  261. }
  262. //
  263. // If this leave frees the critical section, then capture
  264. // the total time the section was held (from the very first enter).
  265. //
  266. if( !_dwEntryCount ){
  267. _dwTickCountInsideTotal += dwTickCountInside;
  268. //
  269. // Since we are leaving the critical section for the last
  270. // time, the CS is now unowned. We set the thread owner to 0.
  271. //
  272. _dwThreadOwner = 0;
  273. }
  274. //
  275. // Note: dwTickCountInsideTotal is based on _first_ entrance
  276. // of critical section, not the most recent.
  277. //
  278. _BackTrace.hCapture( ~0x10000000 & _dwEntryCount,
  279. dwTickCountInside,
  280. _dwTickCountInsideTotal );
  281. LeaveCriticalSection( &_CritSec );
  282. }
  283. BOOL
  284. MCritSec::
  285. bInside(
  286. VOID
  287. ) const
  288. {
  289. if( !_dwEntryCount || GetCurrentThreadId() != _dwThreadOwner ){
  290. DBGMSG( DBG_ERROR, ( "CritSec: Not inside 0x%x!\n", this ));
  291. return FALSE;
  292. }
  293. return TRUE;
  294. }
  295. BOOL
  296. MCritSec::
  297. bOutside(
  298. VOID
  299. ) const
  300. {
  301. //
  302. // We are outside if dwThreadOwner is not our thread id.
  303. //
  304. DWORD dwThreadOwner = (DWORD)InterlockedCompareExchange(
  305. (PLONG)&_dwThreadOwner,
  306. 0,
  307. 0 );
  308. if( dwThreadOwner == GetCurrentThreadId( )){
  309. DBGMSG( DBG_ERROR, ( "CritSec: Not outside 0x%x!\n",this ));
  310. return FALSE;
  311. }
  312. return TRUE;
  313. }
  314. /********************************************************************
  315. TCritSecHardLock
  316. ********************************************************************/
  317. TCritSecHardLock::
  318. TCritSecHardLock(
  319. MCritSec& CritSec
  320. ) : _CritSec( CritSec )
  321. {
  322. _CritSec.vEnter();
  323. //
  324. // Add ourselves to the linked list and remember what the entry
  325. // count is. Everytime we leave the critical section, we'll look
  326. // at all the items in the list and see if the current entry count
  327. // is < all hard locks.
  328. //
  329. _CritSec.CritSecHardLock_vAdd( this );
  330. _dwEntryCountMarker = _CritSec._dwEntryCount;
  331. }
  332. TCritSecHardLock::
  333. ~TCritSecHardLock(
  334. VOID
  335. )
  336. {
  337. CritSecHardLock_vDelinkSelf();
  338. _CritSec.vLeave();
  339. }
  340. #endif