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.

874 lines
28 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. locks.c
  5. Abstract:
  6. WinDbg Extension Api
  7. Author:
  8. Ramon J San Andres (ramonsa) 5-Nov-1993
  9. Environment:
  10. User Mode.
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. BOOLEAN
  16. FindQWord(
  17. IN ULONG64 Value,
  18. IN ULONG64 Array[],
  19. IN ULONG EntriesToSearch
  20. )
  21. {
  22. // clear low few bits which are sometimes used as flag bits :(
  23. Value &= ~(ULONG64)3;
  24. while (EntriesToSearch) {
  25. if (Array[--EntriesToSearch] == Value) {
  26. return TRUE;
  27. }
  28. }
  29. return FALSE;
  30. }
  31. BOOLEAN
  32. GetWaitListFromDispatcherHeader(
  33. IN ULONG64 ShWaitListArray[],
  34. IN ULONG ArrayByteSize,
  35. IN ULONG64 DispatcherHeaderAddress,
  36. OUT PULONG EntriesFilledIn
  37. )
  38. {
  39. ULONG KThreadWaitListOffset;
  40. ULONG64 TerminationAddress = 0;
  41. ULONG64 CurrListEntry;
  42. ULONG MaxEntries = ArrayByteSize / sizeof( ULONG64);
  43. ULONG64 NextListEntry;
  44. ULONG64 ThreadAddr;
  45. ULONG64 Mask = IsPtr64() ? ~(ULONG64)0 : 0xffffffff;
  46. *EntriesFilledIn = 0;
  47. GetFieldOffset("nt!_KTHREAD", "WaitBlock", &KThreadWaitListOffset);
  48. GetFieldOffset("nt!_DISPATCHER_HEADER", "WaitListHead", &(ULONG)TerminationAddress);
  49. TerminationAddress += DispatcherHeaderAddress;
  50. CurrListEntry = TerminationAddress;
  51. // note: does not process initial (pased in) list entry as an object.
  52. do {
  53. GetFieldValue( CurrListEntry, "nt!_LIST_ENTRY", "Flink", NextListEntry);
  54. CurrListEntry = NextListEntry;
  55. if (CurrListEntry != TerminationAddress) {
  56. ThreadAddr = CurrListEntry - KThreadWaitListOffset;
  57. ShWaitListArray[ *EntriesFilledIn] = ThreadAddr & Mask;
  58. *EntriesFilledIn += 1;
  59. }
  60. // better check CTRL+C here in case we're walking trash memory
  61. if ((0 == (*EntriesFilledIn % 10)) && CheckControlC() ) {
  62. *EntriesFilledIn = -1;
  63. return FALSE;
  64. }
  65. } while ((CurrListEntry != TerminationAddress) &&
  66. (*EntriesFilledIn < MaxEntries));
  67. // edge case here (entries == maxentries) but..
  68. if (*EntriesFilledIn == MaxEntries) {
  69. *EntriesFilledIn = -1;
  70. }
  71. return TRUE;
  72. }
  73. void
  74. ShowThread(
  75. ULONG dwProcessor,
  76. ULONG64 Thread,
  77. ULONG ThreadCount,
  78. ULONG Verbose,
  79. PULONG Count,
  80. BOOLEAN IsOwner)
  81. {
  82. ULONG ThreadType;
  83. ULONG64 ActualThread;
  84. if (Thread != 0) {
  85. (*Count)++;
  86. dprintf("%08p-%02x%s ", Thread, ThreadCount, IsOwner ? "<*>" : " ");
  87. ActualThread = (Thread | 3) - 3;
  88. if (GetFieldValue(ActualThread, "nt!_ETHREAD", "Tcb.Header.Type", ThreadType) ||
  89. (ThreadType != ThreadObject)) {
  90. dprintf("*** Unknown owner, possibly FileSystem");
  91. *Count=4;
  92. } else if (Thread & 3) {
  93. dprintf("*** Actual Thread %p", ActualThread);
  94. *Count=4;
  95. }
  96. if (Verbose) {
  97. dprintf("\n\n");
  98. DumpThread(dwProcessor, " ", ActualThread, 0xf );
  99. }
  100. }
  101. }
  102. DECLARE_API( locks )
  103. /*++
  104. Routine Description:
  105. Dump kernel mode resource locks
  106. Arguments:
  107. arg - [-V] [-P] [Address]
  108. Return Value:
  109. None
  110. --*/
  111. {
  112. UCHAR Buffer[256];
  113. LONG ActiveCount;
  114. ULONG ContentionCount;
  115. ULONG64 Displacement;
  116. BOOLEAN DisplayZero;
  117. ULONG64 End;
  118. USHORT Flag;
  119. ULONG Index;
  120. USHORT NumberOfExclusiveWaiters;
  121. USHORT NumberOfSharedWaiters;
  122. BOOLEAN Performance;
  123. ULONG64 PerformanceData;
  124. ULONG TableSize;
  125. ULONG64 ResourceHead;
  126. ULONG64 Next;
  127. ULONG Result;
  128. ULONG64 ResourceToDump;
  129. ULONG64 Resource;
  130. ULONG64 DdkResource;
  131. ULONG64 ShWaitListArray[1024];
  132. BOOLEAN Owner;
  133. ULONG i;
  134. ULONG j;
  135. ULONG64 Thread;
  136. ULONG64 SharedWaitersSmpAdr;
  137. ULONG64 ExclusiveWaitersEvAdr;
  138. BOOLEAN DetermineSharedOwners;
  139. BOOLEAN AllSharedOwners;
  140. ULONG SharedWaiterCount;
  141. LONG ThreadCount;
  142. UCHAR DdkThreadCount;
  143. BOOLEAN Verbose;
  144. PUCHAR s;
  145. ULONG TotalLocks;
  146. ULONG TotalUsedLocks;
  147. ULONG SkippedLocks;
  148. ULONG SizeOfListEntry, SizeofOwnerEntry;
  149. ULONG InitialOwnerThreadsOffset, OwnerThreadsOffset;
  150. ULONG dwProcessor=0;
  151. HRESULT hr = S_OK;
  152. ULONG64 Link;
  153. ULONG64 FlinkBlink;
  154. ULONG64 BlinkFlink;
  155. ULONG ResourceListOffset;
  156. INIT_API();
  157. GetCurrentProcessor(Client, &dwProcessor, NULL);
  158. ResourceToDump = 0;
  159. GetFieldOffset("nt!_ERESOURCE", "SystemResourcesList", &ResourceListOffset);
  160. DisplayZero = FALSE;
  161. Performance = FALSE;
  162. Verbose = FALSE;
  163. s = (PSTR)args;
  164. while ( s != NULL && *s ) {
  165. if (*s == '-' || *s == '/') {
  166. while (*++s) {
  167. switch (*s) {
  168. case 'D':
  169. case 'd':
  170. DisplayZero = TRUE;
  171. break;
  172. case 'P':
  173. case 'p':
  174. Performance = TRUE;
  175. break;
  176. case 'V':
  177. case 'v':
  178. Verbose = TRUE;
  179. break;
  180. case ' ':
  181. goto gotBlank;
  182. default:
  183. dprintf( "KD: !locks invalid option flag '-%c'\n", *s );
  184. break;
  185. }
  186. }
  187. } else if (*s != ' ') {
  188. ResourceToDump = GetExpression(s);
  189. s = strpbrk( s, " " );
  190. } else {
  191. gotBlank:
  192. s++;
  193. }
  194. }
  195. //
  196. // Dump performance data if requested.
  197. //
  198. if (Performance != FALSE) {
  199. UCHAR ResPerf[]="nt!_RESOURCE_PERFORMANCE_DATA";
  200. ULONG TotalResourceCount, ActiveResourceCount, ExclusiveAcquire;
  201. ULONG SharedFirstLevel, SharedSecondLevel, StarveFirstLevel, StarveSecondLevel;
  202. ULONG WaitForExclusive, OwnerTableExpands, MaximumTableExpand;
  203. ULONG HashTableOffset;
  204. dprintf("**** Dump Resource Performance Data ****\n\n");
  205. PerformanceData = GetExpression("nt!ExpResourcePerformanceData");
  206. if ((PerformanceData == 0) ||
  207. GetFieldValue(PerformanceData, ResPerf,"TotalResourceCount",TotalResourceCount)) {
  208. //
  209. // The target build does not support resource performance data.
  210. //
  211. dprintf("%08p: No resource performance data available\n", PerformanceData);
  212. } else {
  213. GetFieldOffset(ResPerf, "HashTable", &HashTableOffset);
  214. GetFieldValue(PerformanceData, ResPerf, "ActiveResourceCount", ActiveResourceCount);
  215. GetFieldValue(PerformanceData, ResPerf,"ExclusiveAcquire", ExclusiveAcquire);
  216. GetFieldValue(PerformanceData, ResPerf, "SharedFirstLevel", SharedFirstLevel);
  217. GetFieldValue(PerformanceData, ResPerf,"SharedSecondLevel", SharedSecondLevel);
  218. GetFieldValue(PerformanceData, ResPerf, "StarveFirstLevel", StarveFirstLevel);
  219. GetFieldValue(PerformanceData, ResPerf, "StarveSecondLevel", StarveSecondLevel);
  220. GetFieldValue(PerformanceData, ResPerf, "WaitForExclusive", WaitForExclusive);
  221. GetFieldValue(PerformanceData, ResPerf, "OwnerTableExpands", OwnerTableExpands);
  222. GetFieldValue(PerformanceData, ResPerf, "MaximumTableExpand", MaximumTableExpand);
  223. //
  224. // Output the summary statistics.
  225. //
  226. dprintf("Total resources initialized : %u\n",
  227. TotalResourceCount);
  228. dprintf("Currently active resources : %u\n",
  229. ActiveResourceCount);
  230. dprintf("Exclusive resource acquires : %u\n",
  231. ExclusiveAcquire);
  232. dprintf("Shared resource acquires (fl) : %u\n",
  233. SharedFirstLevel);
  234. dprintf("Shared resource acquires (sl) : %u\n",
  235. SharedSecondLevel);
  236. dprintf("Starve resource acquires (fl) : %u\n",
  237. StarveFirstLevel);
  238. dprintf("Starve resource acquires (sl) : %u\n",
  239. StarveSecondLevel);
  240. dprintf("Shared wait resource acquires : %u\n",
  241. WaitForExclusive);
  242. dprintf("Owner table expansions : %u\n",
  243. OwnerTableExpands);
  244. dprintf("Maximum table expansion : %u\n\n",
  245. MaximumTableExpand);
  246. //
  247. // Dump the inactive resource statistics.
  248. //
  249. dprintf(" Inactive Resource Statistics\n");
  250. dprintf("Contention Number Initialization Address\n\n");
  251. SizeOfListEntry = GetTypeSize("nt!_LIST_ENTRY");
  252. for (Index = 0; Index < RESOURCE_HASH_TABLE_SIZE; Index += 1) {
  253. End = HashTableOffset + PerformanceData + SizeOfListEntry * Index;
  254. GetFieldValue(End,"nt!_LIST_ENTRY","Flink",Next);
  255. while (Next != End) {
  256. ULONG64 Address;
  257. ULONG Number;
  258. if (CheckControlC()) {
  259. break;
  260. }
  261. if (!GetFieldValue(Next,
  262. "nt!_RESOURCE_HASH_ENTRY",
  263. "Address",
  264. Address)) {
  265. GetSymbol(Address, Buffer, &Displacement);
  266. GetFieldValue(Next,"nt!_RESOURCE_HASH_ENTRY","Number",Number);
  267. GetFieldValue(Next,"nt!_RESOURCE_HASH_ENTRY","ContentionCount",ContentionCount);
  268. dprintf("%10d %6d %s",
  269. ContentionCount,
  270. Number,
  271. Buffer);
  272. if (Displacement != 0) {
  273. dprintf("+0x%x", Displacement);
  274. }
  275. dprintf("\n");
  276. }
  277. GetFieldValue(Next,"nt!_RESOURCE_HASH_ENTRY","ListEntry.Flink", Next);
  278. }
  279. }
  280. //
  281. // Dump the active resource statistics.
  282. //
  283. dprintf("\n Active Resource Statistics\n");
  284. dprintf("Resource Contention Initialization Address\n\n");
  285. //
  286. // Read the resource listhead and check if it is empty.
  287. //
  288. ResourceHead = GetNtDebuggerData( ExpSystemResourcesList );
  289. if ((ResourceHead == 0) ||
  290. (!GetFieldValue(ResourceHead,
  291. "nt!_LIST_ENTRY",
  292. "Flink",
  293. Next) == FALSE)) {
  294. dprintf("%08p: Unable to get value of ExpSystemResourcesList\n", ResourceHead );
  295. hr = E_INVALIDARG;
  296. goto exitBangLocks;
  297. }
  298. if (Next == 0) {
  299. dprintf("ExpSystemResourcesList is NULL!\n");
  300. hr = E_INVALIDARG;
  301. goto exitBangLocks;
  302. }
  303. //
  304. // Scan the resource list and dump the resource information.
  305. //
  306. while(Next != ResourceHead) {
  307. ULONG64 Address;
  308. if (CheckControlC()) {
  309. break;
  310. }
  311. Resource = Next; // SystemResourcesList is the first element in struct
  312. // CONTAINING_RECORD(Next, ERESOURCE, SystemResourcesList);
  313. if (!GetFieldValue(Resource,
  314. "nt!_ERESOURCE",
  315. "ContentionCount",
  316. ContentionCount) == FALSE) {
  317. dprintf("%08p: Unable to read _ERESOURCE\n", Resource);
  318. continue;
  319. } else {
  320. GetFieldValue(Resource,"nt!_ERESOURCE","Address",Address);
  321. GetFieldValue(Resource,"nt!_ERESOURCE","ContentionCount",ContentionCount);
  322. if ((ContentionCount != 0) ||
  323. (DisplayZero != FALSE)) {
  324. GetSymbol(Address,
  325. Buffer,
  326. &Displacement);
  327. dprintf("%08p %10d %s",
  328. Resource,
  329. ContentionCount,
  330. Buffer);
  331. if (Displacement != 0) {
  332. dprintf("+0x%x", Displacement);
  333. }
  334. dprintf("\n");
  335. }
  336. }
  337. GetFieldValue(Resource,"nt!_ERESOURCE","SystemResourcesList.Flink",Next);
  338. }
  339. dprintf("\n");
  340. //
  341. // Dump the active fast mutex statistics.
  342. //
  343. dprintf("\n Active Fast Mutex Statistics\n");
  344. dprintf("Address Contention Fast Mutex Name\n\n");
  345. //
  346. // Dump statistics for static fast/guarded mutexes.
  347. //
  348. DumpStaticFastMutex("FsRtlCreateLockInfo");
  349. DumpStaticFastMutex("PspActiveProcessMutex");
  350. dprintf("\n");
  351. }
  352. hr = E_INVALIDARG;
  353. goto exitBangLocks;
  354. }
  355. //
  356. // Dump remaining lock data.
  357. //
  358. if (ResourceToDump == 0) {
  359. dprintf("**** DUMP OF ALL RESOURCE OBJECTS ****\n");
  360. ResourceHead = GetNtDebuggerData( ExpSystemResourcesList );
  361. if ( !ResourceHead ||
  362. (GetFieldValue(ResourceHead,
  363. "nt!_LIST_ENTRY",
  364. "Flink",
  365. Next) != FALSE)) {
  366. dprintf("%08p: Unable to get value of ExpSystemResourcesList\n", ResourceHead );
  367. hr = E_INVALIDARG;
  368. goto exitBangLocks;
  369. }
  370. if (Next == 0) {
  371. dprintf("ExpSystemResourcesList is NULL!\n");
  372. hr = E_INVALIDARG;
  373. goto exitBangLocks;
  374. }
  375. } else {
  376. Next = 0;
  377. ResourceHead = 1;
  378. }
  379. TotalLocks = 0;
  380. TotalUsedLocks = 0;
  381. SkippedLocks = 0;
  382. // Get the offset of OwnerThreads in ERESOURCE
  383. if (GetFieldOffset("nt!_ERESOURCE", "OwnerThreads", &OwnerThreadsOffset)) {
  384. dprintf("Cannot get _ERESOURCE type\n");
  385. hr = E_INVALIDARG;
  386. goto exitBangLocks;
  387. }
  388. if (!(SizeofOwnerEntry = GetTypeSize("nt!_OWNER_ENTRY"))) {
  389. dprintf("Cannot get nt!_OWNER_ENTRY type\n");
  390. hr = E_INVALIDARG;
  391. goto exitBangLocks;
  392. }
  393. while(Next != ResourceHead) {
  394. ULONG64 OwnerThreads, OwnerCounts, OwnerTable;
  395. if (Next != 0) {
  396. Resource = Next;// SystemResourcesList is the first element of struct ERESOURCE
  397. // CONTAINING_RECORD(Next,ERESOURCE,SystemResourcesList);
  398. } else {
  399. Resource = ResourceToDump;
  400. }
  401. /*
  402. if ( GetFieldValue( Resource,
  403. "NTDDK_ERESOURCE",
  404. "OwnerThreads",
  405. OwnerThreads) ) {
  406. dprintf("%08lx: Unable to read NTDDK_ERESOURCE\n", Resource );
  407. break;
  408. }*/
  409. //
  410. // Detect here if this is an NtDdk resource, and behave
  411. // appropriatelty. If the OwnerThreads is a pointer to the initial
  412. // owner threads array (this must take into account that the LOCAL
  413. // data structure is a copy of what's in the remote machine in a
  414. // different address)
  415. //
  416. // DdkResource = (PNTDDK_ERESOURCE)&ResourceContents;
  417. {
  418. DdkResource = 0;
  419. GetFieldValue( Resource,"nt!_ERESOURCE","ActiveCount", ActiveCount);
  420. GetFieldValue( Resource,"nt!_ERESOURCE","ContentionCount",ContentionCount);
  421. GetFieldValue( Resource,"nt!_ERESOURCE","NumberOfExclusiveWaiters",NumberOfExclusiveWaiters);
  422. GetFieldValue( Resource,"nt!_ERESOURCE","NumberOfSharedWaiters",NumberOfSharedWaiters);
  423. GetFieldValue( Resource,"nt!_ERESOURCE","Flag",Flag);
  424. GetFieldValue( Resource,"nt!_ERESOURCE","OwnerTable",OwnerTable);
  425. GetFieldValue( Resource,"nt!_ERESOURCE","SharedWaiters",SharedWaitersSmpAdr);
  426. GetFieldValue( Resource,"nt!_ERESOURCE","ExclusiveWaiters",ExclusiveWaitersEvAdr);
  427. //
  428. // Grab the Flink->Blink and Blink->Flink contents to verify list integrity. Since
  429. // ExDeleteResource doesn't null any fields, it's possible that what looks like
  430. // a resource is no more.
  431. //
  432. FlinkBlink = BlinkFlink = 0;
  433. GetFieldValue( Resource,"nt!_ERESOURCE","SystemResourcesList.Flink",Link);
  434. GetFieldValue( Link,"nt!_LIST_ENTRY","Blink",FlinkBlink);
  435. GetFieldValue( Resource,"nt!_ERESOURCE","SystemResourcesList.Blink",Link);
  436. GetFieldValue( Link,"nt!_LIST_ENTRY","Flink",BlinkFlink);
  437. TableSize = 0;
  438. if (OwnerTable != 0) {
  439. if (GetFieldValue(OwnerTable,
  440. "nt!_OWNER_ENTRY",
  441. "TableSize",
  442. TableSize)) {
  443. dprintf("\n%08p: Unable to read TableSize for resource\n", OwnerTable);
  444. break;
  445. }
  446. }
  447. }
  448. TotalLocks++;
  449. if ((ResourceToDump != 0) || Verbose || (ActiveCount != 0)) {
  450. EXPRLastDump = Resource;
  451. if (SkippedLocks) {
  452. dprintf("\n");
  453. SkippedLocks = 0;
  454. }
  455. DetermineSharedOwners =
  456. AllSharedOwners = FALSE;
  457. dprintf("\n");
  458. dumpSymbolicAddress(Resource, Buffer, TRUE);
  459. dprintf("Resource @ %s", Buffer );
  460. if (ActiveCount == 0) {
  461. dprintf(" Available\n");
  462. } else if (Flag & ResourceOwnedExclusive) {
  463. TotalUsedLocks++;
  464. dprintf(" Exclusively owned\n");
  465. } else {
  466. // owned shared
  467. TotalUsedLocks++;
  468. dprintf(" Shared %u owning threads\n", ActiveCount);
  469. if (NumberOfSharedWaiters) {
  470. DetermineSharedOwners = TRUE;
  471. }
  472. else {
  473. AllSharedOwners = TRUE;
  474. }
  475. }
  476. if (FlinkBlink != Resource+ResourceListOffset) {
  477. dprintf("\nWARNING: SystemResourcesList->Flink chain invalid. Resource may be corrupted, or already deleted.\n\n");
  478. }
  479. if (BlinkFlink != Resource+ResourceListOffset) {
  480. dprintf("\nWARNING: SystemResourcesList->Blink chain invalid. Resource may be corrupted, or already deleted.\n\n");
  481. }
  482. if (ContentionCount != 0) {
  483. dprintf(" Contention Count = %u\n", ContentionCount);
  484. }
  485. if (NumberOfSharedWaiters != 0) {
  486. dprintf(" NumberOfSharedWaiters = %u\n", NumberOfSharedWaiters);
  487. }
  488. if (NumberOfExclusiveWaiters != 0) {
  489. dprintf(" NumberOfExclusiveWaiters = %u\n", NumberOfExclusiveWaiters);
  490. }
  491. if (ActiveCount != 0) {
  492. ULONG ThreadType;
  493. j = 0;
  494. if (DetermineSharedOwners) {
  495. // Extract the list of shared waiters from the semaphore.
  496. if (!GetWaitListFromDispatcherHeader( ShWaitListArray,
  497. sizeof( ShWaitListArray),
  498. SharedWaitersSmpAdr,
  499. &SharedWaiterCount)) {
  500. hr = E_INVALIDARG;
  501. goto exitBangLocks;
  502. }
  503. // The count could be -1 meaning there were too many for our array.
  504. if (-1 == SharedWaiterCount) {
  505. dprintf("<< Too many shared waiters to determine owners >>\n");
  506. DetermineSharedOwners = FALSE;
  507. SharedWaiterCount = NumberOfSharedWaiters;
  508. }
  509. if (SharedWaiterCount != NumberOfSharedWaiters) {
  510. dprintf("WARNING: Shared waiters in semaphore waitlist (%d) != count in resource (%d)\n",
  511. SharedWaiterCount, NumberOfSharedWaiters);
  512. }
  513. }
  514. dprintf(" Threads: ");
  515. // Print the embedded 2 owner entries
  516. if (DdkResource == 0) {
  517. GetFieldValue( Resource + OwnerThreadsOffset, "nt!_OWNER_ENTRY","OwnerThread",Thread);
  518. GetFieldValue( Resource + OwnerThreadsOffset, "nt!_OWNER_ENTRY","OwnerCount",ThreadCount);
  519. Owner = ResourceOwnedExclusive;
  520. ShowThread(dwProcessor, Thread, ThreadCount, Verbose, &j, Owner);
  521. GetFieldValue( Resource + OwnerThreadsOffset +SizeofOwnerEntry,
  522. "nt!_OWNER_ENTRY","OwnerThread",Thread);
  523. GetFieldValue( Resource + OwnerThreadsOffset +SizeofOwnerEntry,
  524. "nt!_OWNER_ENTRY","OwnerCount",ThreadCount);
  525. Owner = DetermineSharedOwners
  526. ? !FindQWord( Thread, ShWaitListArray, SharedWaiterCount)
  527. : AllSharedOwners;
  528. ShowThread(dwProcessor, Thread, ThreadCount, Verbose, &j, Owner);
  529. }
  530. if (TableSize > 2000)
  531. {
  532. // sanity check
  533. dprintf("Owner TableSize too large (%ld) - probably a bad resource.\n");
  534. hr = E_INVALIDARG;
  535. goto exitBangLocks;
  536. }
  537. // Now list the entries from the overflow owner table
  538. for (i = DdkResource ? 0 : 1; i < TableSize; i++) {
  539. {
  540. GetFieldValue( OwnerTable + SizeofOwnerEntry*i,
  541. "nt!_OWNER_ENTRY","OwnerThread",Thread);
  542. GetFieldValue( OwnerTable + SizeofOwnerEntry*i,
  543. "nt!_OWNER_ENTRY","OwnerCount",ThreadCount);
  544. }
  545. if ((Thread == 0) && (ThreadCount == 0)) {
  546. continue;
  547. }
  548. if (j == 4) {
  549. j = 0;
  550. dprintf("\n ");
  551. }
  552. Owner = DetermineSharedOwners
  553. ? !FindQWord( Thread, ShWaitListArray, SharedWaiterCount)
  554. : AllSharedOwners;
  555. ShowThread(dwProcessor, Thread, ThreadCount, Verbose, &j, Owner);
  556. if ( CheckControlC() ) {
  557. hr = E_INVALIDARG;
  558. goto exitBangLocks;
  559. }
  560. }
  561. // List any exclusive waiters
  562. if (NumberOfExclusiveWaiters) {
  563. // Extract the list of waiters from the event.
  564. if (!GetWaitListFromDispatcherHeader( ShWaitListArray,
  565. sizeof( ShWaitListArray),
  566. ExclusiveWaitersEvAdr,
  567. &SharedWaiterCount)) {
  568. hr = E_INVALIDARG;
  569. goto exitBangLocks;
  570. }
  571. // The count could be -1 meaning there were too many for our array.
  572. if (-1 == SharedWaiterCount) {
  573. dprintf("<< Too many exclusive waiters to list>>\n");
  574. }
  575. else {
  576. ULONG Count;
  577. if (SharedWaiterCount != NumberOfExclusiveWaiters) {
  578. dprintf("WARNING: Exclusive waiters in event waitlist (%d) != count in resource (%d)\n",
  579. SharedWaiterCount, NumberOfExclusiveWaiters);
  580. }
  581. dprintf("\n Threads Waiting On Exclusive Access:");
  582. for (Count = 0; Count < SharedWaiterCount; Count++) {
  583. if (0 == (Count % 4)) {
  584. dprintf("\n ");
  585. }
  586. dprintf("%08p ",ShWaitListArray[Count]);
  587. if ((0 == (Count % 10)) && CheckControlC()) {
  588. hr = E_INVALIDARG;
  589. goto exitBangLocks;
  590. }
  591. }
  592. dprintf("\n");
  593. }
  594. }
  595. if (j) {
  596. dprintf("\n");
  597. }
  598. }
  599. } else {
  600. if ((SkippedLocks++ % 32) == 0) {
  601. if (SkippedLocks == 1) {
  602. dprintf("KD: Scanning for held locks." );
  603. } else {
  604. dprintf("." );
  605. }
  606. }
  607. }
  608. if (ResourceToDump != 0) {
  609. break;
  610. }
  611. if (hr = GetFieldValue( Resource,"nt!_ERESOURCE","SystemResourcesList.Flink", Next))
  612. {
  613. dprintf("Error %lx in reading nt!_ERESOURCE.SystemResourcesList.Flink @ %p\n", Resource);
  614. goto exitBangLocks;
  615. }
  616. if ( CheckControlC() ) {
  617. hr = E_INVALIDARG;
  618. goto exitBangLocks;
  619. }
  620. }
  621. if (SkippedLocks) {
  622. dprintf("\n");
  623. }
  624. dprintf( "%u total locks", TotalLocks );
  625. if (TotalUsedLocks) {
  626. dprintf( ", %u locks currently held", TotalUsedLocks );
  627. }
  628. dprintf("\n");
  629. exitBangLocks:
  630. EXIT_API();
  631. return hr;
  632. }
  633. VOID
  634. DumpStaticFastMutex (
  635. IN PCHAR Name
  636. )
  637. /*++
  638. Routine Description:
  639. This function dumps the contention statistics for a fast mutex.
  640. Arguments:
  641. Name - Supplies a pointer to the symbol name for the fast mutex.
  642. Return Value:
  643. None.
  644. --*/
  645. {
  646. ULONG64 FastMutex;
  647. ULONG Contention;
  648. ULONG Result;
  649. //
  650. // Get the address of the fast mutex, read the fast mutex contents,
  651. // and dump the contention data.
  652. //
  653. FastMutex = GetExpression(Name);
  654. if ((FastMutex != 0) &&
  655. (!GetFieldValue(FastMutex,
  656. "nt!_FAST_MUTEX",
  657. "Contention",
  658. Contention))) {
  659. dprintf("%08p %10u %s\n",
  660. FastMutex,
  661. Contention,
  662. &Name[0]);
  663. }
  664. return;
  665. }