NetInverse Developers Blog

April 11, 2009
Category: Debugging — Tags: , , , , — admin @ 4:00 pm

SOS Command: !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> k

ChildEBP RetAddr
0404ea04 77f5c524 SharedUserData!SystemCallStub+0x4
0404ea08 77e75ee0 ntdll!NtWaitForMultipleObjects+0xc
0404eaa4 5d9de9d6 KERNEL32!WaitForMultipleObjectsEx+0x12c
0404eb38 5d9def80 mscorwks!Thread::DoAppropriateAptStateWait+0x156
0404ecc4 5d9dd8bb mscorwks!Thread::DoAppropriateWaitWorker+0x360
0404ed20 5da628dd mscorwks!Thread::DoAppropriateWait+0xbb
0404ede4 5da4e2e2 mscorwks!CLREvent::Wait+0x29d
0404ee70 5da4dd41 mscorwks!AwareLock::EnterEpilog+0x132
0404ef34 5da4efa3 mscorwks!AwareLock::Enter+0x2c1
0404f09c 5d767880 mscorwks!AwareLock::Contention+0x483
0404f1c4 03f00229 mscorwks!JITutil_MonContention+0x2c0
0404f1f4 5b6ef077 image00400000!Worker.Work()+0x79
...

By looking at the code corresponding to Worker.Work()+0×79 (run “!u 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.

No Comments »

No comments yet.

RSS feed for comments on this post. TrackBack URL

Leave a comment

©2009 NetInverse. All rights reserved. Powered by WordPress