프로세스가 종료되기 위해서는 실행 중인 Thread 의 모든 I/O 가 종료되어야 정상적으로 프로세스 종료가 가능합니다. 프로세스 관리자는 모든 I/O 가 취소된 후에야 Thread 종료를 진행하기 때문입니다. 프로세스가 종료될 때 시나리오는 다음과 같습니다.
어플리케이션 종료 요청이 전달되면 시스템은 해당 프로세스와 연관된 모든 I/O 에 대해서 취소 요청을 하게 되고 I/O Manager 에서 Cancel routine(s) 를 호출하여 모든 IRP가 완료되거나 취소된 이후에 프로세스가 종료됩니다. 단, 드라이버가 취소 루틴을 설정한 IRPs 만이 취소될 수 있고 모든 I/O가 취소되거나 완료되지 않을 경우 기다리게 됩니다.
I/O 취소가 처리되지 않아 프로세스가 종료되지 않는 현상에 대해서 아래와 같이 정리하였습니다.
[시나리오]
Windows Server 2003 에서 NotMyFault.exe 라는 프로세스가 작업 관리자에서 해당 프로세스를 강제 종료하기 위해 "프로세스 끝내기" 버튼을 클릭해도 종료되지 않는 상황
[로컬 커널 디버그 확인 결과]
lkd> !process 0 7 notmyfault.exe
PROCESS 8e313c48 SessionId: 1 Cid: 0394 Peb: 7ffdd000 ParentCid: 0a80
DirBase: 78941560 ObjectTable: e108d5e8 HandleCount: 39.
Image: NotMyfault.exe
VadRoot 8e31d4b0 Vads 57 Clone 0 Private 174. Modified 19. Locked 0.
DeviceMap e2101458
Token e2d7c030
ElapsedTime 01:39:26.394
UserTime 00:00:00.062
KernelTime 00:00:00.031
QuotaPoolUsage[PagedPool] 56180
QuotaPoolUsage[NonPagedPool] 2280
Working Set Sizes (now,min,max) (992, 50, 345) (3968KB, 200KB, 1380KB)
PeakWorkingSetSize 998
VirtualSize 31 Mb
PeakVirtualSize 35 Mb
PageFaultCount 1133
MemoryPriority BACKGROUND
BasePriority 8
CommitCharge 306
PROCESS 8e313c48 SessionId: 1 Cid: 0394 Peb: 7ffdd000 ParentCid: 0a80
DirBase: 78941560 ObjectTable: e108d5e8 HandleCount: 39.
Image: NotMyfault.exe
VadRoot 8e31d4b0 Vads 57 Clone 0 Private 174. Modified 19. Locked 0.
DeviceMap e2101458
Token e2d7c030
ElapsedTime 01:39:26.394
UserTime 00:00:00.062
KernelTime 00:00:00.031
QuotaPoolUsage[PagedPool] 56180
QuotaPoolUsage[NonPagedPool] 2280
Working Set Sizes (now,min,max) (992, 50, 345) (3968KB, 200KB, 1380KB)
PeakWorkingSetSize 998
VirtualSize 31 Mb
PeakVirtualSize 35 Mb
PageFaultCount 1133
MemoryPriority BACKGROUND
BasePriority 8
CommitCharge 306
THREAD 8d86e950 Cid 0394.0eb0 Teb: 7ffdc000 Win32Thread: 00000000 WAIT: (Unknown) KernelMode Non-Alertable
8d84e084 NotificationEvent
Not impersonating
DeviceMap e2101458
Owning Process 8e313c48 Image: NotMyfault.exe
Attached Process N/A Image: N/A
Wait Start TickCount 46169 Ticks: 382737 (0:01:39:40.265)
Context Switch Count 2
UserTime 00:00:00.000
KernelTime 00:00:00.000
Win32 Start Address 0x00401e55
Start Address kernel32!BaseThreadStartThunk (0x7c8217ec)
Stack Init b97f9000 Current b97f8ba8 Base b97f9000 Limit b97f6000 Call 0
Priority 12 BasePriority 8 PriorityDecrement 2
ChildEBP RetAddr Args to Child
b97f8bc0 8082ffb7 8d86e950 8d86e9f8 00000101 nt!KiSwapContext+0x25 (FPO: [Uses EBP] [0,0,4])
b97f8bd8 808287b4 8d94acc8 8d84e084 00000000 nt!KiSwapThread+0x83 (FPO: [0,2,0])
b97f8c1c 808eb80a 8d84e084 00000000 00000000 nt!KeWaitForSingleObject+0x2e0 (FPO: [5,12,4])
b97f8c48 808ed471 0084e084 8d94acc8 8d94ad38 nt!IopCancelAlertedRequest+0x68 (FPO: [2,2,0])
b97f8c64 808ee169 8d8769e8 00000103 8d84e028 nt!IopSynchronousServiceTail+0x19b (FPO: [7,0,4])
b97f8d00 808e6cca 000000c8 00000000 00000000 nt!IopXxxControlFile+0x5e5 (FPO: [SEH])
b97f8d34 80883908 000000c8 00000000 00000000 nt!NtDeviceIoControlFile+0x2a (FPO: [10,0,0])
b97f8d34 7c9685ec 000000c8 00000000 00000000 nt!KiFastCallEntry+0xf8 (FPO: [0,0] TrapFrame @ b97f8d64)
00f7fee8 72466b6c 43656d61 6e696168 00323140 ntdll!KiFastSystemCallRet (FPO: [0,0,0])
WARNING: Frame IP not in any known module. Following frames may be wrong.
00f7ff50 656c4377 76457261 40746e65 6e000034 0x72466b6c
8d84e084 NotificationEvent
Not impersonating
DeviceMap e2101458
Owning Process 8e313c48 Image: NotMyfault.exe
Attached Process N/A Image: N/A
Wait Start TickCount 46169 Ticks: 382737 (0:01:39:40.265)
Context Switch Count 2
UserTime 00:00:00.000
KernelTime 00:00:00.000
Win32 Start Address 0x00401e55
Start Address kernel32!BaseThreadStartThunk (0x7c8217ec)
Stack Init b97f9000 Current b97f8ba8 Base b97f9000 Limit b97f6000 Call 0
Priority 12 BasePriority 8 PriorityDecrement 2
ChildEBP RetAddr Args to Child
b97f8bc0 8082ffb7 8d86e950 8d86e9f8 00000101 nt!KiSwapContext+0x25 (FPO: [Uses EBP] [0,0,4])
b97f8bd8 808287b4 8d94acc8 8d84e084 00000000 nt!KiSwapThread+0x83 (FPO: [0,2,0])
b97f8c1c 808eb80a 8d84e084 00000000 00000000 nt!KeWaitForSingleObject+0x2e0 (FPO: [5,12,4])
b97f8c48 808ed471 0084e084 8d94acc8 8d94ad38 nt!IopCancelAlertedRequest+0x68 (FPO: [2,2,0])
b97f8c64 808ee169 8d8769e8 00000103 8d84e028 nt!IopSynchronousServiceTail+0x19b (FPO: [7,0,4])
b97f8d00 808e6cca 000000c8 00000000 00000000 nt!IopXxxControlFile+0x5e5 (FPO: [SEH])
b97f8d34 80883908 000000c8 00000000 00000000 nt!NtDeviceIoControlFile+0x2a (FPO: [10,0,0])
b97f8d34 7c9685ec 000000c8 00000000 00000000 nt!KiFastCallEntry+0xf8 (FPO: [0,0] TrapFrame @ b97f8d64)
00f7fee8 72466b6c 43656d61 6e696168 00323140 ntdll!KiFastSystemCallRet (FPO: [0,0,0])
WARNING: Frame IP not in any known module. Following frames may be wrong.
00f7ff50 656c4377 76457261 40746e65 6e000034 0x72466b6c
Stack trace 를 통해 I/O 를 시작한 Thread 에서는 IRP가 취소되었다는 것을 알 수 있습니다. (IoSynchronousServiceTail 함수가 IoCancelAlertedRequest를 호출함) 즉, I/O 취소 또는 완료되기를 기다리는 중입니다. !irp 명령을 사용하여 해당 드라이버를 찾을 수 있습니다.
lkd> !irp 8d94acc8
Irp is active with 1 stacks 1 is current (= 0x8d94ad38)
No Mdl: No System Buffer: Thread 8d86e950: Irp stack trace.
cmd flg cl Device File Completion-Context
>[ e, 0] 5 0 8d8769e8 8d84e028 00000000-00000000
\Driver\MYFAULT
Args: 00000000 00000000 83360020 00000000
lkd> lmvm MYFAULT
start end module name
f79ab000 f79ac480 myfault (no symbols)
Loaded symbol image file: \??\C:\WINDOWS\system32\drivers\myfault.sys
Image path: \??\C:\WINDOWS\system32\drivers\myfault.sys
Image name: myfault.sys
Timestamp: Sun Mar 08 09:38:30 2009 (49B31386)
CheckSum: 0000E1ED
ImageSize: 00001480
Translations: 0000.04b0 0000.04e4 0409.04b0 0409.04e4
Irp is active with 1 stacks 1 is current (= 0x8d94ad38)
No Mdl: No System Buffer: Thread 8d86e950: Irp stack trace.
cmd flg cl Device File Completion-Context
>[ e, 0] 5 0 8d8769e8 8d84e028 00000000-00000000
\Driver\MYFAULT
Args: 00000000 00000000 83360020 00000000
lkd> lmvm MYFAULT
start end module name
f79ab000 f79ac480 myfault (no symbols)
Loaded symbol image file: \??\C:\WINDOWS\system32\drivers\myfault.sys
Image path: \??\C:\WINDOWS\system32\drivers\myfault.sys
Image name: myfault.sys
Timestamp: Sun Mar 08 09:38:30 2009 (49B31386)
CheckSum: 0000E1ED
ImageSize: 00001480
Translations: 0000.04b0 0000.04e4 0409.04b0 0409.04e4
문제가 있는 드라이버는 \Driver\MYFAULT (myfault.sys) 드라이버로 확인되었습니다. 하지만 Windows 운영체제는 아직 I/O 취소가 완료되지 않은 상황을 안전한 상태라고 판단할 수 없으므로 프로세스를 종료할 수 없기 때문에 시스템 재시작이 필요합니다. 실제 운영 머신에서 이런 현상이 나타난다면 문제가 해결된 새로운 버전의 드라이버를 찾아 업데이트가 필요합니다.
[참고자료]
Windows Internals 5th Edition
작성자 : Lai Go / 작성일자 : 2011.06.01