제가 가진 몇 안되는 디바이스 드라이버 책 중에 하나가 "Windows 2000 디바이스 드라이버"입니다. 질럿님께서 번역하셔서 더 애착이 가는 책이기도 합니다. ㅋ 물론 설명이 다른 책에 비해서 훨씬 쉬운 것도 한 가지 장점이 아닌가 생각해 봅니다.
각설하고 그 Windows 2000 디바이스 드라이버의 400 페이지를 보면 시스템 스레드를 종료하기 위해서 시스템 스레드를 대기하는 코드가 나옵니다. 코드를 발췌하면 아래와 같습니다.
KeWaitForSingleObject(
&pDE->pThreadObj,
Executive,
KernelMode,
FALSE,
NULL);
ObDereferenceObject(&pDE->pThreadObj);
pDE->pThreadObj는 PETHREAD로 선언된 변수입니다. 별 생각없이 이 코드를 그대로 DriverUnload에 붙였더니 공포의 블루스크린이 마구 뜨더군요. 그런데도 첨에는 왜 뜨는지를 이해하질 못했습니다. 디버그 로그를 보니 단지 스레드가 종료되지 않았다는 것은 알 수 있었습니다. 더 훼이크 스러운건 KeSetEvent나 KeWaitForSingleObjects로 넘어가는 대부분의 인자가 &variable 형태라는 것 입니다. 그래서 더욱 헤맸습니다.
제가 내린 결론는 위 코드가 *아마도* 잘못된 것이 아닐까하는 것입니다. KeWaitForSingleObject의 인자로는 PVOID가 들어갑니다. 커널 오브젝트의 포인터죠. KEVENT라는 커널 이벤트 객체가 있다면 PKEVENT가 인자로 넘어가는 겁니다. 따라서 pDE->pThreadObj는 ETHREAD의 포인터인 PETHREAD로 선언된 변수이기 때문에 굳이 다시 주소 연산자를 사용해서 주소를 넘길 필요가 없습니다. 위 코드에서 &부분을 뺀 다음 테스트를 해보니 정상적으로 동작을 하더군요. ObDereferenceObject 함수도 마찬가지입니다.