프로세스가 종료되기 위해서는 실행 중인 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
        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


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


문제가 있는 드라이버는 \Driver\MYFAULT (myfault.sys) 드라이버로 확인되었습니다. 하지만 Windows 운영체제는 아직 I/O 취소가 완료되지 않은 상황을 안전한 상태라고 판단할 수 없으므로 프로세스를 종료할 수 없기 때문에 시스템 재시작이 필요합니다. 실제 운영 머신에서 이런 현상이 나타난다면 문제가 해결된 새로운 버전의 드라이버를 찾아 업데이트가 필요합니다.


[참고자료]
Windows Internals 5th Edition


작성자 : Lai Go / 작성일자 : 2011.06.01
Posted by Lai Go