Skip to content

Commit

Permalink
Enable SyncBlk for xplat SOS (dotnet/coreclr#20830)
Browse files Browse the repository at this point in the history
Add SyncBlk to xplat SOS.




Commit migrated from dotnet/coreclr@28b4285
  • Loading branch information
mikem8361 authored Nov 6, 2018
1 parent 5640d20 commit c3ce494
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 3 deletions.
1 change: 1 addition & 0 deletions src/coreclr/src/ToolBox/SOS/Strike/sos_unixexports.src
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ IP2MD
Name2EE
PrintException
StopOnCatch
SyncBlk
Threads
ThreadState
Token2EE
Expand Down
84 changes: 81 additions & 3 deletions src/coreclr/src/ToolBox/SOS/Strike/sosdocsunix.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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.

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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>

Expand Down
6 changes: 6 additions & 0 deletions src/coreclr/src/ToolBox/SOS/Strike/strike.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5141,6 +5141,8 @@ DECLARE_API(GCHeapStat)
#endif // FEATURE_PAL
}

#endif // FEATURE_PAL

/**********************************************************************\
* Routine Description: *
* *
Expand Down Expand Up @@ -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
{
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/src/ToolBox/SOS/lldbplugin/soscommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.");
Expand Down

0 comments on commit c3ce494

Please sign in to comment.