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.

395 lines
10 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 2002 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: MemoryTracking.cpp
  6. * Content: Debug memory tracking for detecting leaks, overruns, etc.
  7. *
  8. * History:
  9. * Date By Reason
  10. * ==== == ======
  11. * 1/10/2002 masonb Created
  12. *
  13. ***************************************************************************/
  14. #include "dncmni.h"
  15. #ifndef DPNBUILD_ONLYONETHREAD
  16. #ifdef DBG
  17. //
  18. // Uncomment this line to turn critical section internal structure validation on.
  19. //
  20. //#define DNCS_VALIDATE
  21. #define DN_INVALID_THREAD_ID -1
  22. CBilink g_blAllCritSecs;
  23. CBilink g_blGlobalCritSecsHeldGroup;
  24. CRITICAL_SECTION g_CSLock;
  25. DWORD g_dwNumCritSecsAllocated = 0;
  26. DWORD g_dwNumCritSecsEntered = 0;
  27. #ifdef DNCS_VALIDATE
  28. void DNCSTrackInternalValidate();
  29. #else // ! DNCS_VALIDATE
  30. #define DNCSTrackInternalValidate()
  31. #endif // DNCS_VALIDATE
  32. #undef DPF_MODNAME
  33. #define DPF_MODNAME "DNCSTrackInitialize"
  34. BOOL DNCSTrackInitialize()
  35. {
  36. g_blAllCritSecs.Initialize();
  37. g_blGlobalCritSecsHeldGroup.Initialize();
  38. if ( DNOSInitializeCriticalSection(&g_CSLock) == FALSE )
  39. {
  40. DPFX(DPFPREP, 0, "Failed to initialize critical section tracking code!" );
  41. DNASSERT( FALSE );
  42. return FALSE;
  43. }
  44. return TRUE;
  45. }
  46. #undef DPF_MODNAME
  47. #define DPF_MODNAME "DNCSTrackDeinitialize"
  48. void DNCSTrackDeinitialize()
  49. {
  50. DeleteCriticalSection(&g_CSLock);
  51. }
  52. #undef DPF_MODNAME
  53. #define DPF_MODNAME "DNCSTrackDumpLeaks"
  54. BOOL DNCSTrackDumpLeaks()
  55. {
  56. DNCRITICAL_SECTION* pCS;
  57. TCHAR CallStackBuffer[CALLSTACK_BUFFER_SIZE];
  58. BOOL fLeaked = FALSE;
  59. EnterCriticalSection(&g_CSLock);
  60. while (!g_blAllCritSecs.IsEmpty())
  61. {
  62. pCS = CONTAINING_OBJECT(g_blAllCritSecs.GetNext(), DNCRITICAL_SECTION, blAllCritSecs);
  63. pCS->AllocCallStack.GetCallStackString(CallStackBuffer);
  64. DPFX(DPFPREP, 0, "Critical Section leaked at address 0x%p\n%s", pCS, CallStackBuffer );
  65. pCS->blAllCritSecs.RemoveFromList();
  66. DeleteCriticalSection(&pCS->CriticalSection);
  67. fLeaked = TRUE;
  68. }
  69. LeaveCriticalSection(&g_CSLock);
  70. return fLeaked;
  71. }
  72. #undef DPF_MODNAME
  73. #define DPF_MODNAME "DNCSTrackInitializeCriticalSection"
  74. BOOL DNCSTrackInitializeCriticalSection( DNCRITICAL_SECTION *const pCriticalSection )
  75. {
  76. BOOL fReturn;
  77. DNASSERT( pCriticalSection != NULL );
  78. memset( pCriticalSection, 0x00, sizeof( *pCriticalSection ) );
  79. pCriticalSection->OwningThreadID = DN_INVALID_THREAD_ID;
  80. pCriticalSection->MaxLockCount = -1;
  81. pCriticalSection->blCritSecsHeld.Initialize();
  82. pCriticalSection->blAllCritSecs.Initialize();
  83. pCriticalSection->pblCritSecsHeldGroup = &g_blGlobalCritSecsHeldGroup;
  84. fReturn = DNOSInitializeCriticalSection(&pCriticalSection->CriticalSection);
  85. if ( fReturn != FALSE )
  86. {
  87. pCriticalSection->AllocCallStack.NoteCurrentCallStack();
  88. EnterCriticalSection(&g_CSLock);
  89. pCriticalSection->blAllCritSecs.InsertBefore(&g_blAllCritSecs);
  90. g_dwNumCritSecsAllocated++;
  91. DNCSTrackInternalValidate();
  92. LeaveCriticalSection(&g_CSLock);
  93. }
  94. return fReturn;
  95. }
  96. #undef DPF_MODNAME
  97. #define DPF_MODNAME "DNCSTrackDeleteCriticalSection"
  98. void DNCSTrackDeleteCriticalSection( DNCRITICAL_SECTION *const pCriticalSection )
  99. {
  100. DNASSERT( pCriticalSection != NULL );
  101. DNASSERT( pCriticalSection->LockCount == 0 );
  102. EnterCriticalSection(&g_CSLock);
  103. pCriticalSection->blAllCritSecs.RemoveFromList();
  104. g_dwNumCritSecsAllocated--;
  105. // NOTE: If they delete the CS without leaving it, still remove it from the held list.
  106. // If asserts are on, this will have asserted above at LockCount == 0.
  107. // Calling this is safe whether it is on the list or not.
  108. pCriticalSection->blCritSecsHeld.RemoveFromList();
  109. DNCSTrackInternalValidate();
  110. LeaveCriticalSection(&g_CSLock);
  111. DeleteCriticalSection( &pCriticalSection->CriticalSection );
  112. memset( &pCriticalSection->CriticalSection, 0x00, sizeof( pCriticalSection->CriticalSection ) );
  113. }
  114. #undef DPF_MODNAME
  115. #define DPF_MODNAME "DNCSTrackSetCriticalRecursionCount"
  116. void DNCSTrackSetCriticalSectionRecursionCount( DNCRITICAL_SECTION *const pCriticalSection, const UINT_PTR RecursionCount )
  117. {
  118. DNASSERT( pCriticalSection != NULL );
  119. pCriticalSection->MaxLockCount = RecursionCount + 1;
  120. DNASSERT( pCriticalSection->MaxLockCount != 0 );
  121. }
  122. #undef DPF_MODNAME
  123. #define DPF_MODNAME "DNCSTrackSetCriticalSectionGroup"
  124. void DNCSTrackSetCriticalSectionGroup( DNCRITICAL_SECTION *const pCriticalSection, CBilink * const pblGroup )
  125. {
  126. DNASSERT( pCriticalSection != NULL );
  127. DNASSERT( pblGroup != NULL );
  128. pCriticalSection->pblCritSecsHeldGroup = pblGroup;
  129. }
  130. #undef DPF_MODNAME
  131. #define DPF_MODNAME "DNCSTrackSetCriticalSectionLockOrder"
  132. void DNCSTrackSetCriticalSectionLockOrder( DNCRITICAL_SECTION *const pCriticalSection, const DWORD dwLockOrder )
  133. {
  134. DNASSERT( pCriticalSection != NULL );
  135. DNASSERT( dwLockOrder > 0 );
  136. pCriticalSection->dwLockOrder = dwLockOrder;
  137. }
  138. #undef DPF_MODNAME
  139. #define DPF_MODNAME "DNCSTrackEnterCriticalSection"
  140. void DNCSTrackEnterCriticalSection( DNCRITICAL_SECTION *const pCriticalSection )
  141. {
  142. UINT_PTR ThisThreadID;
  143. DNASSERT( pCriticalSection != NULL );
  144. EnterCriticalSection( &pCriticalSection->CriticalSection );
  145. ThisThreadID = GetCurrentThreadId();
  146. if ( pCriticalSection->OwningThreadID != ThisThreadID )
  147. {
  148. DNASSERT( pCriticalSection->OwningThreadID == DN_INVALID_THREAD_ID );
  149. DNASSERT( pCriticalSection->LockCount == 0 );
  150. pCriticalSection->OwningThreadID = ThisThreadID;
  151. }
  152. else
  153. {
  154. DNASSERT( pCriticalSection->LockCount != 0 );
  155. }
  156. if ( pCriticalSection->LockCount == 0 )
  157. {
  158. pCriticalSection->CallStack.NoteCurrentCallStack();
  159. // Track this critical section that was just entered for the first time.
  160. EnterCriticalSection(&g_CSLock);
  161. pCriticalSection->LockCount++;
  162. //
  163. // If this critical section has a lock order, assert that we're not
  164. // violating it.
  165. //
  166. if (pCriticalSection->dwLockOrder != 0)
  167. {
  168. CBilink * pBilink;
  169. DNCRITICAL_SECTION * pCS;
  170. pBilink = pCriticalSection->pblCritSecsHeldGroup->GetNext();
  171. while (pBilink != pCriticalSection->pblCritSecsHeldGroup)
  172. {
  173. pCS = CONTAINING_OBJECT(pBilink, DNCRITICAL_SECTION, blCritSecsHeld);
  174. if (pCS->dwLockOrder != 0)
  175. {
  176. DNASSERT( pCS->dwLockOrder <= pCriticalSection->dwLockOrder );
  177. }
  178. pBilink = pBilink->GetNext();
  179. }
  180. }
  181. pCriticalSection->blCritSecsHeld.InsertBefore(pCriticalSection->pblCritSecsHeldGroup);
  182. DNASSERT(g_dwNumCritSecsEntered < g_dwNumCritSecsAllocated);
  183. g_dwNumCritSecsEntered++;
  184. DNCSTrackInternalValidate();
  185. LeaveCriticalSection(&g_CSLock);
  186. }
  187. else
  188. {
  189. pCriticalSection->LockCount++;
  190. }
  191. if ( pCriticalSection->LockCount > pCriticalSection->MaxLockCount )
  192. {
  193. if ( pCriticalSection->MaxLockCount == 1 )
  194. {
  195. TCHAR CallStackBuffer[ CALLSTACK_BUFFER_SIZE ];
  196. //
  197. // Exceeded recursion depth of 1, display stack of call originally
  198. // holding the lock.
  199. //
  200. pCriticalSection->CallStack.GetCallStackString( CallStackBuffer );
  201. DPFX(DPFPREP, 0, "Critical section 0x%p has been reentered!\nOriginal Holder's Stack:\n%s", pCriticalSection, CallStackBuffer);
  202. DNASSERT(FALSE);
  203. }
  204. else
  205. {
  206. //
  207. // exceeded recursion depth, check your code!!
  208. //
  209. DNASSERT(FALSE);
  210. }
  211. }
  212. }
  213. #undef DPF_MODNAME
  214. #define DPF_MODNAME "DNCSTrackLeaveCriticalSection"
  215. void DNCSTrackLeaveCriticalSection( DNCRITICAL_SECTION *const pCriticalSection )
  216. {
  217. DNASSERT( pCriticalSection != NULL );
  218. DNASSERT( pCriticalSection->OwningThreadID == GetCurrentThreadId() );
  219. DNASSERT( pCriticalSection->LockCount <= pCriticalSection->MaxLockCount );
  220. DNASSERT( pCriticalSection->LockCount != 0 );
  221. if ( pCriticalSection->LockCount == 1 )
  222. {
  223. memset( &pCriticalSection->CallStack, 0x00, sizeof( pCriticalSection->CallStack ) );
  224. pCriticalSection->OwningThreadID = DN_INVALID_THREAD_ID;
  225. // Track this critical section being left for the last time.
  226. EnterCriticalSection(&g_CSLock);
  227. pCriticalSection->LockCount--;
  228. pCriticalSection->blCritSecsHeld.RemoveFromList();
  229. DNASSERT(g_dwNumCritSecsEntered > 0);
  230. g_dwNumCritSecsEntered--;
  231. DNCSTrackInternalValidate();
  232. LeaveCriticalSection(&g_CSLock);
  233. }
  234. else
  235. {
  236. pCriticalSection->LockCount--;
  237. }
  238. LeaveCriticalSection( &pCriticalSection->CriticalSection );
  239. }
  240. #undef DPF_MODNAME
  241. #define DPF_MODNAME "DNCSTrackCriticalSectionIsTakenByThisThread"
  242. void DNCSTrackCriticalSectionIsTakenByThisThread( const DNCRITICAL_SECTION *const pCriticalSection, const BOOL fFlag )
  243. {
  244. DNASSERT( fFlag == ( pCriticalSection->OwningThreadID == GetCurrentThreadId() ) );
  245. }
  246. #undef DPF_MODNAME
  247. #define DPF_MODNAME "DNCSTrackNoCriticalSectionsTakenByThisThread"
  248. void DNCSTrackNoCriticalSectionsTakenByThisThread( CBilink * pblGroup )
  249. {
  250. CBilink* pBilink;
  251. DNCRITICAL_SECTION* pCS;
  252. if (pblGroup == NULL)
  253. {
  254. pblGroup = &g_blGlobalCritSecsHeldGroup;
  255. }
  256. EnterCriticalSection(&g_CSLock);
  257. pBilink = pblGroup->GetNext();
  258. while (pBilink != pblGroup)
  259. {
  260. pCS = CONTAINING_OBJECT(pBilink, DNCRITICAL_SECTION, blCritSecsHeld);
  261. DNASSERT( pCS->OwningThreadID != GetCurrentThreadId() );
  262. pBilink = pBilink->GetNext();
  263. }
  264. DNCSTrackInternalValidate();
  265. LeaveCriticalSection(&g_CSLock);
  266. }
  267. #ifdef DNCS_VALIDATE
  268. #undef DPF_MODNAME
  269. #define DPF_MODNAME "DNCSTrackInternalValidate"
  270. void DNCSTrackInternalValidate()
  271. {
  272. CBilink* pBilink;
  273. DNCRITICAL_SECTION* pCS;
  274. DWORD dwNumAllocated = 0;
  275. DWORD dwNumEntered = 0;
  276. //
  277. // The global critical section lock must be held!
  278. //
  279. DNASSERT(g_dwNumCritSecsEntered <= g_dwNumCritSecsAllocated);
  280. pBilink = g_blAllCritSecs.GetNext();
  281. while (pBilink != &g_blAllCritSecs)
  282. {
  283. DNASSERT(pBilink->GetNext() != pBilink);
  284. DNASSERT(pBilink->GetPrev() != pBilink);
  285. DNASSERT(pBilink->IsListMember(&g_blAllCritSecs));
  286. pCS = CONTAINING_OBJECT(pBilink, DNCRITICAL_SECTION, blAllCritSecs);
  287. dwNumAllocated++;
  288. if (pCS->blCritSecsHeld.IsEmpty())
  289. {
  290. DNASSERT(pCS->LockCount == 0);
  291. }
  292. else
  293. {
  294. DNASSERT(pCS->LockCount > 0);
  295. dwNumEntered++;
  296. }
  297. pBilink = pBilink->GetNext();
  298. }
  299. DNASSERT(dwNumAllocated == g_dwNumCritSecsAllocated);
  300. DNASSERT(dwNumEntered == g_dwNumCritSecsEntered);
  301. }
  302. #endif // DNCS_VALIDATE
  303. #endif // DBG
  304. #endif // !DPNBUILD_ONLYONETHREAD