summaryrefslogtreecommitdiff
path: root/src/ToolBox/SOS
diff options
context:
space:
mode:
authorMike McLaughlin <mikem@microsoft.com>2018-11-06 10:42:53 -0800
committerGitHub <noreply@github.com>2018-11-06 10:42:53 -0800
commit28b4285b4d71a9aa9b9deb40a17ee356e5ef440f (patch)
treed6041f023b9ed444bb29be3b75dcb874c0b2d783 /src/ToolBox/SOS
parent39d673dc3a6840c8d76a2baa86e9dcca4b1f784c (diff)
downloadcoreclr-28b4285b4d71a9aa9b9deb40a17ee356e5ef440f.tar.gz
coreclr-28b4285b4d71a9aa9b9deb40a17ee356e5ef440f.tar.bz2
coreclr-28b4285b4d71a9aa9b9deb40a17ee356e5ef440f.zip
Enable SyncBlk for xplat SOS (#20830)
Add SyncBlk to xplat SOS.
Diffstat (limited to 'src/ToolBox/SOS')
-rw-r--r--src/ToolBox/SOS/Strike/sos_unixexports.src1
-rw-r--r--src/ToolBox/SOS/Strike/sosdocsunix.txt84
-rw-r--r--src/ToolBox/SOS/Strike/strike.cpp6
-rw-r--r--src/ToolBox/SOS/lldbplugin/soscommand.cpp1
4 files changed, 89 insertions, 3 deletions
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 <module pointer>.
\\
+COMMAND: syncblk.
+SyncBlk [-all | <syncblk number>]
+
+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] <MethodTable address>
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.");