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.

393 lines
7.6 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. Critical section implementation
  126. Logging:
  127. CS initialized: 00000000 00000000 00000000
  128. CS acquired: 1eeeeeee bbbbbbbb tttttttt
  129. e New entry count.
  130. b TickCount thread was blocked before acquiring CS.
  131. t Total tickcount all threads have blocked before acquiring CS
  132. CS released: 0eeeeeee iiiiiiii tttttttt
  133. e New entry count.
  134. i Time spent inside the CS, from _first_ acquisition.
  135. t Total tickcount all threads inside CS.
  136. ********************************************************************/
  137. #if DBG
  138. MCritSec::
  139. MCritSec(
  140. VOID
  141. ) : _dwThreadOwner( 0 ), _dwEntryCount( 0 ),
  142. _dwTickCountBlockedTotal( 0 ), _dwTickCountInsideTotal( 0 ),
  143. _dwEntryCountTotal( 0 )
  144. {
  145. InitializeCriticalSectionAndSpinCount( &_CritSec, 0x80000000 );
  146. _BackTrace.hCapture( 0, 0, 0 );
  147. }
  148. MCritSec::
  149. ~MCritSec(
  150. VOID
  151. )
  152. {
  153. DeleteCriticalSection( &_CritSec );
  154. }
  155. VOID
  156. MCritSec::
  157. vEnter(
  158. VOID
  159. )
  160. {
  161. DWORD dwTickCountBefore = GetTickCount();
  162. EnterCriticalSection( &_CritSec );
  163. ++_dwEntryCountTotal;
  164. DWORD dwTickCountBlocked = 0;
  165. //
  166. // Re-entrant case: only start the TickCountEntered counter
  167. // if this is the first time we've entered the cs.
  168. //
  169. if( _dwEntryCount == 0 ){
  170. //
  171. // Check how long it took us to enter the critical section.
  172. //
  173. _dwTickCountEntered = GetTickCount();
  174. dwTickCountBlocked = _dwTickCountEntered - dwTickCountBefore;
  175. //
  176. // Update the amount of time this thread blocked on this cs.
  177. //
  178. _dwTickCountBlockedTotal += dwTickCountBlocked;
  179. }
  180. //
  181. // We have entered the critical section; update the count
  182. // and the thread owner.
  183. //
  184. ++_dwEntryCount;
  185. _dwThreadOwner = GetCurrentThreadId();
  186. _BackTrace.hCapture( 0x10000000 | _dwEntryCount,
  187. dwTickCountBlocked,
  188. _dwTickCountBlockedTotal );
  189. }
  190. VOID
  191. MCritSec::
  192. vLeave(
  193. VOID
  194. )
  195. {
  196. SPLASSERT( bInside( ));
  197. DWORD dwTickCountInside = GetTickCount() - _dwTickCountEntered;
  198. --_dwEntryCount;
  199. //
  200. // Verify that we don't leave a CritSecHardLock.
  201. //
  202. TIter Iter;
  203. TCritSecHardLock *pCritSecHardLock;
  204. for( CritSecHardLock_vIterInit( Iter ), Iter.vNext();
  205. Iter.bValid();
  206. Iter.vNext( )){
  207. pCritSecHardLock = CritSecHardLock_pConvert( Iter );
  208. //
  209. // If you hit this assert, then you have created a hard
  210. // lock, but someone is trying to leave it. See header file
  211. // for more info (state.hxx).
  212. //
  213. if( _dwEntryCount < pCritSecHardLock->_dwEntryCountMarker ){
  214. DBGMSG( DBG_ERROR, ( "CritSec.vLeave: Leaving a hard lock.\n" ));
  215. }
  216. }
  217. //
  218. // If this leave frees the critical section, then capture
  219. // the total time the section was held (from the very first enter).
  220. //
  221. if( !_dwEntryCount ){
  222. _dwTickCountInsideTotal += dwTickCountInside;
  223. //
  224. // Since we are leaving the critical section for the last
  225. // time, the CS is now unowned. We set the thread owner to 0.
  226. //
  227. _dwThreadOwner = 0;
  228. }
  229. //
  230. // Note: dwTickCountInsideTotal is based on _first_ entrance
  231. // of critical section, not the most recent.
  232. //
  233. _BackTrace.hCapture( ~0x10000000 & _dwEntryCount,
  234. dwTickCountInside,
  235. _dwTickCountInsideTotal );
  236. LeaveCriticalSection( &_CritSec );
  237. }
  238. BOOL
  239. MCritSec::
  240. bInside(
  241. VOID
  242. ) const
  243. {
  244. if( !_dwEntryCount || GetCurrentThreadId() != _dwThreadOwner ){
  245. DBGMSG( DBG_NONE, ( "CritSec: Not inside 0x%x!\n", this ));
  246. return FALSE;
  247. }
  248. return TRUE;
  249. }
  250. BOOL
  251. MCritSec::
  252. bOutside(
  253. VOID
  254. ) const
  255. {
  256. //
  257. // We are outside if dwThreadOwner is not our thread id.
  258. //
  259. DWORD dwThreadOwner = (DWORD)InterlockedCompareExchange(
  260. (PLONG)&_dwThreadOwner,
  261. 0,
  262. 0 );
  263. if( dwThreadOwner == GetCurrentThreadId( )){
  264. DBGMSG( DBG_NONE, ( "CritSec: Not outside 0x%x!\n",this ));
  265. return FALSE;
  266. }
  267. return TRUE;
  268. }
  269. #else // !DBG
  270. MCritSec::
  271. MCritSec() {
  272. InitializeCriticalSectionAndSpinCount(&_CritSec, 0);
  273. }
  274. #endif
  275. /********************************************************************
  276. TCritSecHardLock
  277. ********************************************************************/
  278. #if DBG
  279. TCritSecHardLock::
  280. TCritSecHardLock(
  281. MCritSec& CritSec
  282. ) : _CritSec( CritSec )
  283. {
  284. _CritSec.vEnter();
  285. //
  286. // Add ourselves to the linked list and remember what the entry
  287. // count is. Everytime we leave the critical section, we'll look
  288. // at all the items in the list and see if the current entry count
  289. // is < all hard locks.
  290. //
  291. _CritSec.CritSecHardLock_vAdd( this );
  292. _dwEntryCountMarker = _CritSec._dwEntryCount;
  293. }
  294. TCritSecHardLock::
  295. ~TCritSecHardLock(
  296. VOID
  297. )
  298. {
  299. CritSecHardLock_vDelinkSelf();
  300. _CritSec.vLeave();
  301. }
  302. #endif