From 28b4285b4d71a9aa9b9deb40a17ee356e5ef440f Mon Sep 17 00:00:00 2001 From: Mike McLaughlin Date: Tue, 6 Nov 2018 10:42:53 -0800 Subject: Enable SyncBlk for xplat SOS (#20830) Add SyncBlk to xplat SOS. --- src/ToolBox/SOS/Strike/sos_unixexports.src | 1 + src/ToolBox/SOS/Strike/sosdocsunix.txt | 84 ++++++++++++++++++++++++++++-- src/ToolBox/SOS/Strike/strike.cpp | 6 +++ src/ToolBox/SOS/lldbplugin/soscommand.cpp | 1 + 4 files changed, 89 insertions(+), 3 deletions(-) (limited to 'src/ToolBox') diff --git a/src/ToolBox/SOS/Strike/sos_unixexports.src b/src/ToolBox/SOS/Strike/sos_unixexports.src index be8ad961e6..ac27c02a71 100644 --- a/src/ToolBox/SOS/Strike/sos_unixexports.src +++ b/src/ToolBox/SOS/Strike/sos_unixexports.src @@ -43,6 +43,7 @@ IP2MD Name2EE PrintException StopOnCatch +SyncBlk Threads ThreadState Token2EE diff --git a/src/ToolBox/SOS/Strike/sosdocsunix.txt b/src/ToolBox/SOS/Strike/sosdocsunix.txt index 45e4c433e2..5cd3a87a78 100644 --- a/src/ToolBox/SOS/Strike/sosdocsunix.txt +++ b/src/ToolBox/SOS/Strike/sosdocsunix.txt @@ -34,12 +34,12 @@ GCRoot (gcroot) GCInfo PrintException (pe) EHInfo bpmd (bpmd) - Examining CLR data structures Diagnostic Utilities ----------------------------- ----------------------------- DumpDomain VerifyHeap EEHeap (eeheap) FindAppDomain Name2EE (name2ee) DumpLog (dumplog) +SyncBlk (syncblk) DumpMT (dumpmt) DumpClass (dumpclass) DumpMD (dumpmd) @@ -308,7 +308,7 @@ DumpHeap [-stat] DumpHeap is a powerful command that traverses the garbage collected heap, collection statistics about objects. With it's various options, it can look for -particular types, restrict to a range, or look for ThinLocks (see SyncBlk +particular types, restrict to a range, or look for ThinLocks (see syncblk documentation). Finally, it will provide a warning if it detects excessive fragmentation in the GC heap. @@ -361,7 +361,7 @@ The arguments in detail: -live Only print live objects -dead Only print dead objects (objects which will be collected in the next full GC) --thinlock Report on any ThinLocks (an efficient locking scheme, see SyncBlk +-thinlock Report on any ThinLocks (an efficient locking scheme, see syncblk documentation for more info) -startAtLowerBound Force heap walk to begin at lower bound of a supplied address range. @@ -1208,6 +1208,84 @@ all loaded modules in all domains. And remember that you can browse all the types in a module with DumpModule -mt . \\ +COMMAND: syncblk. +SyncBlk [-all | ] + +A SyncBlock is a holder for extra information that doesn't need to be created +for every object. It can hold COM Interop data, HashCodes, and locking +information for thread-safe operations. + +When called without arguments, syncblk will print the list of SyncBlocks +corresponding to objects that are owned by a thread. For example, a + + lock(MyObject) + { + .... + } + +statement will set MyObject to be owned by the current thread. A SyncBlock will +be created for MyObject, and the thread ownership information stored there +(this is an oversimplification, see NOTE below). If another thread tries to +execute the same code, they won't be able to enter the block until the first +thread exits. + +This makes syncblk useful for detecting managed deadlocks. Consider that the +following code is executed by Threads A & B: + + Resource r1 = new Resource(); + Resource r2 = new Resource(); + + ... + + lock(r1) lock(r2) + { { + lock(r2) lock(r1) + { { + ... ... + } } + } } + +This is a deadlock situation, as Thread A could take r1, and Thread B r2, +leaving both threads with no option but to wait forever in the second lock +statement. syncblk will detect this with the following output: + + 0:003> syncblk + Index SyncBlock MonitorHeld Recursion Owning Thread Info SyncBlock Owner + 238 001e40ec 3 1 001e4e60 e04 3 00a7a194 Resource + 239 001e4124 3 1 001e5980 ab8 4 00a7a1a4 Resource + +It means that Thread e04 owns object 00a7a194, and Thread ab8 owns object +00a7a1a4. Combine that information with the call stacks of the deadlock: + +(threads 3 and 4 have similar output) + 0:003> bt + ChildEBP RetAddr + 0404ea04 77f5c524 SharedUserData!SystemCallStub+0x4 + 0404ea08 77e75ee0 ntdll!NtWaitForMultipleObjects+0xc + 0404eaa4 5d9de9d6 KERNEL32!WaitForMultipleObjectsEx+0x12c + 0404eb38 5d9def80 clr!Thread::DoAppropriateAptStateWait+0x156 + 0404ecc4 5d9dd8bb clr!Thread::DoAppropriateWaitWorker+0x360 + 0404ed20 5da628dd clr!Thread::DoAppropriateWait+0xbb + 0404ede4 5da4e2e2 clr!CLREvent::Wait+0x29d + 0404ee70 5da4dd41 clr!AwareLock::EnterEpilog+0x132 + 0404ef34 5da4efa3 clr!AwareLock::Enter+0x2c1 + 0404f09c 5d767880 clr!AwareLock::Contention+0x483 + 0404f1c4 03f00229 clr!JITutil_MonContention+0x2c0 + 0404f1f4 5b6ef077 image00400000!Worker.Work()+0x79 + ... + +By looking at the code corresponding to Worker.Work()+0x79 (run "clru 03f00229"), +you can see that thread 3 is attempting to acquire the Resource 00a7a1a4, which +is owned by thread 4. + +NOTE: +It is not always the case that a SyncBlock will be created for every object +that is locked by a thread. In version 2.0 of the CLR and above, a mechanism +called a ThinLock will be used if there is not already a SyncBlock for the +object in question. ThinLocks will not be reported by the syncblk command. +You can use "dumpheap -thinlock" to list objects locked in this way. +\\ + COMMAND: dumpmt. DumpMT [-MD] diff --git a/src/ToolBox/SOS/Strike/strike.cpp b/src/ToolBox/SOS/Strike/strike.cpp index b15084804a..d7794f45dd 100644 --- a/src/ToolBox/SOS/Strike/strike.cpp +++ b/src/ToolBox/SOS/Strike/strike.cpp @@ -5141,6 +5141,8 @@ DECLARE_API(GCHeapStat) #endif // FEATURE_PAL } +#endif // FEATURE_PAL + /**********************************************************************\ * Routine Description: * * * @@ -5323,14 +5325,18 @@ DECLARE_API(SyncBlk) ExtOut("-----------------------------\n"); ExtOut("Total %d\n", dwCount); +#ifdef FEATURE_COMINTEROP ExtOut("CCW %d\n", CCWCount); ExtOut("RCW %d\n", RCWCount); ExtOut("ComClassFactory %d\n", CFCount); +#endif ExtOut("Free %d\n", freeCount); return Status; } +#ifndef FEATURE_PAL + #ifdef FEATURE_COMINTEROP struct VisitRcwArgs { diff --git a/src/ToolBox/SOS/lldbplugin/soscommand.cpp b/src/ToolBox/SOS/lldbplugin/soscommand.cpp index 0a54f63526..3565b9eebe 100644 --- a/src/ToolBox/SOS/lldbplugin/soscommand.cpp +++ b/src/ToolBox/SOS/lldbplugin/soscommand.cpp @@ -145,6 +145,7 @@ sosCommandInitialize(lldb::SBDebugger debugger) interpreter.AddCommand("ip2md", new sosCommand("IP2MD"), "Displays the MethodDesc structure at the specified address in code that has been JIT-compiled."); interpreter.AddCommand("name2ee", new sosCommand("Name2EE"), "Displays the MethodTable structure and EEClass structure for the specified type or method in the specified module."); interpreter.AddCommand("pe", new sosCommand("PrintException"), "Displays and formats fields of any object derived from the Exception class at the specified address."); + interpreter.AddCommand("syncblk", new sosCommand("SyncBlk"), "Displays the SyncBlock holder info."); interpreter.AddCommand("histclear", new sosCommand("HistClear"), "Releases any resources used by the family of Hist commands."); interpreter.AddCommand("histinit", new sosCommand("HistInit"), "Initializes the SOS structures from the stress log saved in the debuggee."); interpreter.AddCommand("histobj", new sosCommand("HistObj"), "Examines all stress log relocation records and displays the chain of garbage collection relocations that may have led to the address passed in as an argument."); -- cgit v1.2.3