Identify deadlock through the hwnd handler


 


 


As we know, there are some good articles discussing about deadlock detection in action:


 


Advanced Techniques To Avoid And Detect Deadlocks In .NET Apps


http://msdn.microsoft.com/zh-cn/magazine/cc163618(en-us).aspx


 


contextSwitchDeadlock


http://msdn.microsoft.com/en-us/library/ms172233.aspx


 


There are also some automatic tools can help us to detect deadlock with postmortem dump files, especially for famous DebugDiag 1.1:


 


http://www.microsoft.com/downloadS/details.aspx?FamilyID=28bd5941-c458-46f1-b24d-f60151d875a3&displaylang=en


 


However, due to the complicated resource locking symptom, there is no a common way to identify all deadlock pattern so far. Here is one interesting sample about deadlock happens between hwnd and event handler.


 


Symptom


==========


One customer uses a new thread to create COM object. But always experience no responding on object creating. I collected the memory dump while issue happens. There is no any critical section lock. Several threads seems run under tasks, but in waiting status.


 


Analysis


=========


Thread 13 call stack is interesting:


 


0:013> kbnL


 # ChildEBP RetAddr  Args to Child             


00 02b8f0d8 7739d1ec 77391908 003a0428 00000405 ntdll!KiFastSystemCallRet


01 02b8f114 7739c337 00b11728 00000405 0000babe user32!NtUserMessageCall+0xc


02 02b8f134 776f58ee 003a0428 00000405 0000babe user32!SendMessageW+0x7f


03 02b8f168 77733822 001918c0 02b8f218 02b8f188 ole32!CDllHost::GetApartmentToken+0x203


04 02b8f178 776f67b8 02b8f218 02b8f390 02b8f19c ole32!DoSTApartmentCreate+0x12


05 02b8f188 776acd3c 00000000 00000002 02b8f218 ole32!CClassCache::GetActivatorFromDllHost+0xa3


06 02b8f19c 776accf1 02b8f1b8 02b8f390 02b8f218 ole32!CClassCache::GetOrCreateApartment+0x20


07 02b8f1f0 776acc78 0019dd5c 00000000 02b8f390 ole32!FindOrCreateApartment+0x46


08 02b8f22c 776ad907 77794960 02b8f5b0 02b8f244 ole32!CProcessActivator::GetApartmentActivator+0xc7


09 02b8f248 776acb27 77794960 00000001 00000000 ole32!CProcessActivator::CCICallback+0x17


0a 02b8f268 776acad8 77794960 02b8f5b0 00000000 ole32!CProcessActivator::AttemptActivation+0x2c


0b 02b8f2a4 776ada17 77794960 02b8f5b0 00000000 ole32!CProcessActivator::ActivateByContext+0x4f


0c 02b8f2cc 776aaf7e 77794960 00000000 02b8f754 ole32!CProcessActivator::CreateInstance+0x49


0d 02b8f30c 776aaf19 02b8f754 00000000 02b8fc9c ole32!ActivationPropertiesIn::DelegateCreateInstance+0xf7


0e 02b8f33c 776aaf7e 7779487c 00000000 02b8f754 ole32!CClientContextActivator::CreateInstance+0x8f


0f 02b8f37c 776ab10f 02b8f754 00000000 02b8fc9c ole32!ActivationPropertiesIn::DelegateCreateInstance+0xf7


10 02b8fd50 776a679a 02b8fe20 00000000 00000017 ole32!ICoCreateInstanceEx+0x3f8


11 02b8fd84 776a6762 02b8fe20 00000000 00000000 ole32!CComActivator::DoCreateInstance+0x6a


12 02b8fda8 776a6963 02b8fe20 00000000 00000017 ole32!CoCreateInstanceEx+0x23


13 02b8fdd8 7825037e 02b8fe20 00000000 00000017 ole32!CoCreateInstance+0x3c


 


Look at frame 2, SendMessageW tried to send message to a window. Check the function definition, the first parameter is hwnd: 003a0428


 


Then I go through other threads to see which one owns the hwnd 003a0428, by checking the ole data stored in each COM thread, found it is thread 9 actually:


 


$t0=00000009


   +0x074 hwndSTA : 0x003a0428 HWND__


 


0:009> kbL


ChildEBP RetAddr  Args to Child             


0207fe88 7c827cfb 77e6202c 00000001 0207fed8 ntdll!KiFastSystemCallRet


0207fe8c 77e6202c 00000001 0207fed8 00000000 ntdll!ZwWaitForMultipleObjects+0xc


0207ff34 77e62fbe 00000001 02601920 00000001 kernel32!WaitForMultipleObjectsEx+0x11a


0207ff50 00423f08 00000001 02601920 00000001 kernel32!WaitForMultipleObjects+0x18


0207ffb0 0042413e 00000000 77e64829 015dcf20 MyModule!Run+0x3f8


0207ffb8 77e64829 015dcf20 00000000 00000000 MyModule! ThreadFunc+0x2e


0207ffec 00000000 00424110 015dcf20 00000000 kernel32!BaseThreadStart+0x34


 


Check thread 9 in detail, WaitForMultipleObjectsEx only waits on one handle 0x00000314:


 


0:009> dc 0207fed8 L1


0207fed8  00000314


 


And the 314 is actually a thread event handler of thread 13:


 


0:009> !handle 0x00000314 f


Handle 00000314


  Type                    Thread


….


    Thread Id   d80.b04


    Priority    9


    Base Priority 0


 


0:009> ~13


  13  Id: d80.b04 Suspend: 1 Teb: 7ffad000 Unfrozen


 


Now the deadlock graph is clear. Thread 13 is pending on Thread 9 to pick up message on a whindow which handle is 003a0428, but thread 9 is waiting on Thread 13 complete its task.


 


Solution


==========


The deadlock is unusual, who made it happen and how to Resolve?


 


Review thread 13 again, at frame 3, the function was called:


 


ole32!DoSTApartmentCreate


 


Actually this function will only be called when a Main STA object is created. That’s why thread 13 stuck on thread 9, which is the main STA thread.


 


Ask customer to change the thread type for this object in registry, from Main STA to Apartment STA. Open Registry Editor, check the key for the IND_COMMON.clsExecProc compoenent:


 


 HKCR\CLSID\ {<Object class ID>}\InprocServer32

Make sure the "ThreadingModel" value is "Apartment"


 


Summary


===========


As a summary, we learn:


 


1.       Deadlock pattern is quite various, this can happen to allocating different types of resources. In this sample, one is STA window, another is Thread event. We must identify which resource is occupied carefully during debugging process.


2.        We cannot use main STA object in COM/COM+ environment, it is easily cause performance or locking issue.


 


More information


==================


About COM thread modes:


 


150777  INFO: Descriptions and Workings of OLE Threading Models


http://support.microsoft.com/default.aspx?scid=kb;EN-US;150777


 


 Regards,


 


 By Freist Li

Comments (1)

  1. Ethanxu says:

    Thank you very much~

Skip to main content