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.

468 lines
11 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. lock.c
  5. Abstract:
  6. This module implements debugging function for locks.
  7. Author:
  8. Manny Weiser (mannyw) 17-Jan-1992
  9. This is essentially a copy of the LAN Manager server lock
  10. debugging
  11. Revision History:
  12. --*/
  13. #if MUPDBG
  14. #include "mup.h"
  15. #define HAS_TEB(_teb) ((BOOLEAN)(((ULONG)(_teb) <= MM_HIGHEST_USER_ADDRESS) ? FALSE : MmIsNonPagedSystemAddressValid(_teb)))
  16. #define MupCurrentTeb( ) ((PTEB)(KeGetCurrentThread( )->Teb))
  17. #define MupTebLockList( ) \
  18. ((PLIST_ENTRY)&(MupCurrentTeb( )->UserReserved[MUP_TEB_LOCK_LIST]))
  19. #define MupThreadLockAddress( ) \
  20. ( IsListEmpty( MupTebLockList( ) ) ? 0 : CONTAINING_RECORD( \
  21. MupTebLockList( )->Flink, \
  22. MUP_LOCK, \
  23. Header.ThreadListEntry \
  24. ) )
  25. #define MupThreadLockLevel( ) \
  26. ( IsListEmpty( MupTebLockList( ) ) ? 0 : CONTAINING_RECORD( \
  27. MupTebLockList( )->Flink, \
  28. MUP_LOCK, \
  29. Header.ThreadListEntry \
  30. )->Header.LockLevel )
  31. #define MupThreadLockName( ) \
  32. ( IsListEmpty( MupTebLockList( ) ) ? "none" : CONTAINING_RECORD( \
  33. MupTebLockList( )->Flink, \
  34. MUP_LOCK, \
  35. Header.ThreadListEntry \
  36. )->Header.LockName )
  37. KSPIN_LOCK LockSpinLock = {0};
  38. BOOLEAN LockSpinLockInitialized = FALSE;
  39. #define MAX_LOCKS_HELD 15
  40. #ifdef ALLOC_PRAGMA
  41. #pragma alloc_text( PAGE, MupInitializeLock )
  42. #pragma alloc_text( PAGE, MupDeleteLock )
  43. #pragma alloc_text( PAGE, MupReleaseLock )
  44. #pragma alloc_text( PAGE, MupCheckListIntegrity )
  45. #endif
  46. #if 0
  47. NOT PAGEABLE - MupAcquireLock
  48. #endif
  49. VOID
  50. MupInitializeLock(
  51. IN PMUP_LOCK Lock,
  52. IN ULONG LockLevel,
  53. IN PSZ LockName
  54. )
  55. /*++
  56. Routine Description:
  57. This routine initializes the input lock variable.
  58. Arguments:
  59. Lock - Supplies the lock variable being initialized
  60. LockLevel - Supplies the level of the lock
  61. LockName - Supplies the name of the lock
  62. Return Value:
  63. None.
  64. --*/
  65. {
  66. PAGED_CODE( );
  67. if ( !LockSpinLockInitialized ) {
  68. LockSpinLockInitialized = TRUE;
  69. KeInitializeSpinLock( &LockSpinLock );
  70. }
  71. //
  72. // Initialize the executive resource.
  73. //
  74. ExInitializeResourceLite( &Lock->Resource );
  75. //
  76. // Initialize the lock level. This is used to determine whether a
  77. // thread may acquire the lock. Save the lock name.
  78. //
  79. LOCK_LEVEL( Lock ) = LockLevel;
  80. LOCK_NAME( Lock ) = LockName;
  81. return;
  82. } // MupInitializeLock
  83. VOID
  84. MupDeleteLock (
  85. IN PMUP_LOCK Lock
  86. )
  87. /*++
  88. Routine Description:
  89. This routine deletes (i.e., uninitializes) a lock variable.
  90. Arguments:
  91. Lock - Supplies the lock variable being deleted
  92. Return Value:
  93. None.
  94. --*/
  95. {
  96. PAGED_CODE( );
  97. //
  98. // Make sure the lock is unowned.
  99. //
  100. if ( LOCK_NUMBER_OF_ACTIVE( Lock ) != 0 ) {
  101. DbgPrint( "MupDeleteLock: Thread %d\n", KeGetCurrentThread( ) );
  102. DbgPrint( "MupDeleteLock: Attempt to delete owned lock %s(%lx)",
  103. LOCK_NAME( Lock ),
  104. Lock
  105. );
  106. DbgBreakPoint();
  107. }
  108. //
  109. // Delete the resource.
  110. //
  111. ExDeleteResourceLite( &Lock->Resource );
  112. return;
  113. } // MupDeleteLock
  114. VOID
  115. MupAcquireLock(
  116. IN PMUP_LOCK Lock
  117. )
  118. /*++
  119. Routine Description:
  120. The routine acquires a lock.
  121. Arguments:
  122. Lock - Supplies the lock to acquire
  123. Return Value:
  124. BOOLEAN - Indicates whether the lock was acquired.
  125. --*/
  126. {
  127. PKTHREAD currentThread;
  128. PTEB currentTeb;
  129. BOOLEAN hasTeb;
  130. ULONG threadLockLevel;
  131. KIRQL oldIrql;
  132. currentThread = (PKTHREAD)ExGetCurrentResourceThread( );
  133. currentTeb = MupCurrentTeb( );
  134. hasTeb = HAS_TEB(currentTeb);
  135. //
  136. // If this thread does not have a nonpaged TEB, do not do lock-level
  137. // debugging. (We might be at DPC level, so we can't take page
  138. // faults.)
  139. //
  140. if ( hasTeb ) {
  141. //
  142. // Make sure that this thread has been initialized for lock
  143. // debugging. If not, initialize it.
  144. //
  145. KeAcquireSpinLock( &LockSpinLock, &oldIrql );
  146. if ( (ULONG)currentTeb->UserReserved[MUP_TEB_LOCK_INIT] !=
  147. 0xbabababa ) {
  148. PLIST_ENTRY tebLockList = MupTebLockList( );
  149. InitializeListHead( tebLockList );
  150. currentTeb->UserReserved[MUP_TEB_LOCK_INIT] = (PVOID)0xbabababa;
  151. }
  152. KeReleaseSpinLock( &LockSpinLock, oldIrql );
  153. //
  154. // Make sure that the list of locks in the TEB is consistent.
  155. //
  156. MupCheckListIntegrity( MupTebLockList( ), MAX_LOCKS_HELD );
  157. //
  158. // The "lock level" of this thread is the highest level of the
  159. // locks currently held exclusively. If this thread holds no
  160. // locks, the lock level of the thread is 0 and it can acquire
  161. // any lock.
  162. //
  163. threadLockLevel = MupThreadLockLevel( );
  164. //
  165. // Make sure that the lock the thread is attempting to acquire
  166. // has a higher level than the last-acquired exclusive lock.
  167. // Note that a recursive exclusive acquisition of a lock should
  168. // succeed, even if a different, higher-level lock has been
  169. // acquired since the lock was originally acquired. Shared
  170. // acquisition of a lock that is already held exclusively must
  171. // fail.
  172. //
  173. if ( LOCK_LEVEL( Lock ) <= threadLockLevel ) {
  174. DbgPrint( "Thread %lx, last lock %s(%lx, L%lx) attempted to ",
  175. currentThread,
  176. MupThreadLockName( ), MupThreadLockAddress( ),
  177. threadLockLevel );
  178. DbgPrint( "acquire %s(%lx, L%lx) for %s access.\n",
  179. LOCK_NAME( Lock ), Lock, LOCK_LEVEL( Lock ),
  180. "exclusive" );
  181. DbgBreakPoint( );
  182. }
  183. }
  184. //
  185. // Acquire the lock.
  186. //
  187. ExAcquireResourceExclusiveLite( &Lock->Resource, TRUE );
  188. //
  189. // The thread acquired the lock for exlusive access.
  190. //
  191. if ( LOCK_NUMBER_OF_ACTIVE( Lock ) == -1 ) {
  192. if ( hasTeb ) {
  193. //
  194. // Insert the lock on the thread's list of locks.
  195. //
  196. ExInterlockedInsertHeadList(
  197. MupTebLockList( ),
  198. LOCK_THREAD_LIST( Lock ),
  199. &LockSpinLock
  200. );
  201. }
  202. }
  203. return;
  204. } // MupAcquireLock
  205. VOID
  206. MupReleaseLock(
  207. IN PMUP_LOCK Lock
  208. )
  209. /*++
  210. Routine Description:
  211. This routine releases a lock.
  212. Arguments:
  213. Lock - Supplies the lock to release
  214. Return Value:
  215. None.
  216. --*/
  217. {
  218. PKTHREAD currentThread;
  219. PTEB currentTeb;
  220. BOOLEAN hasTeb;
  221. PAGED_CODE( );
  222. currentThread = (PKTHREAD)ExGetCurrentResourceThread( );
  223. currentTeb = MupCurrentTeb( );
  224. hasTeb = HAS_TEB(currentTeb);
  225. //
  226. // Make sure the lock is really owned by the current thread.
  227. //
  228. if ( LOCK_NUMBER_OF_ACTIVE( Lock ) == 0 ) {
  229. // !!! Should crash server on internal error here.
  230. DbgPrint( "Thread %lx releasing unowned lock %s(%lx)\n",
  231. currentThread, LOCK_NAME( Lock ), Lock );
  232. DbgBreakPoint( );
  233. } else if ( (LOCK_NUMBER_OF_ACTIVE( Lock ) < 0) &&
  234. (LOCK_EXCLUSIVE_OWNER( Lock ) != (ULONG)currentThread) ) {
  235. // !!! Should crash server on internal error here.
  236. DbgPrint( "Thread %lx releasing lock %s(%lx) owned by "
  237. "thread %lx\n",
  238. currentThread, LOCK_NAME( Lock ), Lock,
  239. LOCK_EXCLUSIVE_OWNER( Lock ) );
  240. DbgBreakPoint( );
  241. } else if ( LOCK_NUMBER_OF_ACTIVE( Lock ) == -1 ) {
  242. //
  243. // The thread is fully releasing exclusive access to the lock.
  244. //
  245. if ( hasTeb ) {
  246. //
  247. // Remove the lock from the list of locks held by this
  248. // thread.
  249. //
  250. ExInterlockedRemoveHeadList(
  251. LOCK_THREAD_LIST( Lock )->Blink,
  252. &LockSpinLock
  253. );
  254. LOCK_THREAD_LIST( Lock )->Flink = NULL;
  255. LOCK_THREAD_LIST( Lock )->Blink = NULL;
  256. //
  257. // Make sure that the list of locks in the TEB is consistent.
  258. //
  259. MupCheckListIntegrity( MupTebLockList( ), MAX_LOCKS_HELD );
  260. }
  261. }
  262. //
  263. // Now actually do the release.
  264. //
  265. ExReleaseResourceLite( &Lock->Resource );
  266. return;
  267. } // MupReleaseLock
  268. ULONG
  269. MupCheckListIntegrity (
  270. IN PLIST_ENTRY ListHead,
  271. IN ULONG MaxEntries
  272. )
  273. /*++
  274. Routine Description:
  275. This debug routine checks the integrity of a doubly-linked list by
  276. walking the list forward and backward. If the number of elements is
  277. different in either direction, or there are too many entries in the
  278. list, execution is stopped.
  279. *** It is the responsibility of the calling routine to do any
  280. necessary synchronization.
  281. Arguments:
  282. ListHead - a pointer to the head of the list.
  283. MaxEntries - if the number of entries in the list exceeds this
  284. number, breakpoint.
  285. Return Value:
  286. ULONG - the number of entries in the list.
  287. --*/
  288. {
  289. PLIST_ENTRY current;
  290. ULONG entriesSoFar;
  291. ULONG flinkEntries;
  292. for ( current = ListHead->Flink, entriesSoFar = 0;
  293. current != ListHead;
  294. current = current->Flink ) {
  295. if ( ++entriesSoFar >= MaxEntries ) {
  296. DbgPrint( "Seen %ld entries in list at %lx\n",
  297. entriesSoFar, ListHead );
  298. DbgBreakPoint( );
  299. }
  300. }
  301. flinkEntries = entriesSoFar;
  302. for ( current = ListHead->Blink, entriesSoFar = 0;
  303. current != ListHead;
  304. current = current->Blink ) {
  305. if ( ++entriesSoFar >= MaxEntries ) {
  306. DbgPrint( "Seen %ld entries in list at %lx\n",
  307. entriesSoFar, ListHead );
  308. DbgBreakPoint( );
  309. }
  310. }
  311. if ( flinkEntries != entriesSoFar ) {
  312. DbgPrint( "In list %lx, Flink entries: %ld, Blink entries: %lx\n",
  313. ListHead, flinkEntries, entriesSoFar );
  314. DbgBreakPoint( );
  315. }
  316. return entriesSoFar;
  317. } // MupCheckListIntegrity
  318. #endif // MUPDBG