30 September, 2011

Чем опасен managed DllMain или история одного deadlock'а

Собственно этот пост возник из-за проблемы с dotTrace. При профиляции приложения пользователя программа намертво зависала. Отладка показала, что зависание происходило точно в момент загрузки Microsoft.DirectX.Direct3D.dll внутри профайлерного эвента ModuleLoadFinished(). Другими словами виноват однозначно dotTrace.


Более детальная отладка показала забавную картину: внутри модуля ModuleLoadFinished() происходил вызов _beginthreadex, который отрабатывал без ошибок, но новый тред при этом не запускался!!! Вернее он создавался, но при этом висел на локе где-то в дебрях операционной системы. Пришлось подключать WinDbg. Выяснилось, что висел он на лоадер-локе (1 шт на процесс) который берется во время любого вызова DllMain, в том числе и в момент, когда новый тред извещает уже загруженные сборки о своем появлении на свет или о своей кончине.

Теперь нужно было найти причину такого поведения. Оказалось, что Microsoft.DirectX.Direct3D содержит native DllMain (managed метод с атрибутом native) который внутри себя вызывает managed код. Красиво, правда... Мне тоже понравилось. Но зачем-же столько мороки? Оказалось, что есть такая статья Initialization of Mixed Assemblies в MSDN. В которой говорится, что не хорошо использовать managed код в момент инициализации DLL - это может привести к зависанию. Другими словами сборка Microsoft.DirectX.Direct3D сознательно написана так, чтобы это правило нарушать...

Увы, за эту вольность поплатился dotTrace, а не разработчики из Microsoft. На данный момент фикс для dotTrace 4.5.1 & dotCover 1.2 готов и проходит тестирование.


No comments: