반응형

http://process3.blog.me/20065867268



`WinDBG로 Deadlock 알아내기

IT이야기 2009/05/31 21:22
대학에서 운영체제 시간에 Deadlock에 대해서 배울 때, 많이 거론되는 것이 Dijkstra의 '식사하는 철학자' 일 것이다. 
멀티 쓰레딩 프로그래밍을 하다 보면 아주 많은 주의를 기울여야 할 Deadlock 문제. 
다양한 deadlock 문제 중에 윈도우 프로그래밍의 critical section에서 야기될 수 있는 deadlock을 WinDBG를 사용해서 발견하는 방법을 설명하려고 한다. 
멀티쓰레딩 프로그램에서 hang이 발생하면 우선 deadlock을 의심해볼 수 있다. 
처음으로 할 일은 hang dump를 수집하는 것이다. 
windbg의 attach process 기능을 사용하던지, ADPlus나 UserDump 프로그램을 사용해서 응답하지 않는 프로그램의 hang dump를 수집한다. 
hang dump는 약간의 시차(한 10초 정도)를 두고 3번 정도 반복해서 만드는 것이 좋다. 
dump가 생성되면 windbg를 사용해서 디버깅을 시작한다. 
dump 파일을 open 하고 난 뒤, command line에 '!locks'라고 친다. 
user mode 디버깅에서는 locks는 ntsdexts.locks와 동일한 명령이다. 
이 명령은 ntdll.dll에 있는 RtlInitializeCriticalSection에 의해서 초기화된 critical section 객체의 정보를 쭉 보여준다. 

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


0:000> !locks

CritSec w3svc!g_pWamDictator+a0 at 68C2C298
LockCount          0
RecursionCount     1
OwningThread       d1
EntryCount         1
ContentionCount    0
*** Locked

CritSec SMTPSVC+66a30 at 67906A30
LockCount          0
RecursionCount     1
OwningThread       d0
EntryCount         1
ContentionCount    0
*** Locked


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

여 기에 아무런 옵션이 없으면 현재 프로세스에 속한 critical section 객체만을 보여주고, 옵션으로 -v를 붙이면 프로세스 밖에 있는 critical section 객체도 보여준다. '-o' 옵션은 Windows XP와 그 이후의 운영체제만 지원하는 것으로 orphaned information(유효하지 않은 critical section을 가르키고 있는 포인터)만을 보여준다. 
locks 명령 말고도 비슷한 모양으로 정보를 보여주는 명령어는 !critecs, !cs 등이 있다.

이 위의 출력물에 대한 의미는 다음과 같다. 

  • Windows XP와 그 이전 것들
    • LockCount 필드는 이 critical section으로 진입하기 위한 EnterCriticalSection()을 호출한 thread의 수에서 하나를 뺀 것과 같다. 왜 하나를 빼야 하냐면, 이 필드는 -1을 unlock 상태로 표시하고 EnterCriticalSection()이 호출될 때마다, 하나씩 증가하기 때문이다. 나중에 LeaveCriticalSection()이 호출되면 하나씩 감소시킨다. 예를 들어, 만약 이 값이 3이라면 하나의 thread는 이 critical section에 진입한 상태이고, 3개의 다른 thread들이 이 곳에 진입하기 위해서 기회를 노리고 있다는 의미이다. 
    • RecursionCount 필드는 critical section에 진입한 thread가 다시 EnterCriticalSection()을 몇 번 더 호출하고 있는지를 나타낸다. 
    • EntryCount 필드는 critical section에 진입하지 못한 thread가 몇 번이나 EnterCriticalSection()을 호출하고 있는지를 나타낸다. 
    • CritSec w3svc!g_pWamDictator+a0 at 68C2C298에서 at 다음에 있는 숫자는 critical section의 핸들이다. 
    • Owning thread는 말 그대로 이 critical section 객체를 현재 가지고 있는  thread이다. 

  • 그 이후 것들(Windows Server 2003 SP1과 그 이후것들)은 'Debugging Tools for Windows'의 Help에 Display a Critical Section 편을 보면 자세히 나와 있다.


Deadlock에 빠진 것이라면, !locks 명령어를 실행했을 때, LockCount가 1 이상인 것들이 하나 이상 존재해야 한다.  
만약 그렇다면 이 thread들의 call stack을 훑어 봐야 한다. 
call stack을 보면 top 언저리에 ntdll!RtlpWaitForCriticalSection+0x132와 비슷하게 보이는 frame이 존재하는데 이 함수의 첫번째 인자가 그 thread가 지금 기다리고 있는 critical section의 핸들이다. 이 핸들을 !locks으로 출력됐던 결과에서 봤을 때, critical section을 가지고 있는 두 놈이 서로의 것을 기다리고 있다면, 100%입니다.

반응형

+ Recent posts