Critical Regions (ntinsider 2015-03)

http://ethobis-lab.blogspot.kr/2017/10/apcasychronous-procedure-call.html

위 포스트와 이어집니다.

이 글은 NTInsider 2015 3월판에 있는 내용을 번역해 약간 각색(?) 했습니다.

Critical Regions은 컨셉을 잘못 설명해서 Windows 커널 모드 개발을 할 때 약간 모호한 부분이 있다고 하네요. 대부분의 개발자는 영향을 받지 않지만 파일 시스템 드라이버(필터 드라이버) 개발할 때는 신경을 써야합니다. 기본적인 코드는 KeEnterCriticalRegion 또는 FsRtlEnterFileSystem (KeEnterCriticalRegion의 래퍼)을 호출하여 Critical Region에 진입하고, KeLeaveCriticalRegion 또는 FsRtlExitFileSystem을 호출하여 Critical Region을 탈출합니다. Critical Region은 현재 쓰레드 컨텍스트(특정한 컨텍스트)에만 적용되기 때문에 동기화 메커니즘이 아닙니다. FsRtlEnterFileSystem 주석을 보면 Critical Region에 진입하면 쓰레드를 일시정지(Suspend) 시키는 것을 막아준다고 되어있습니다. 쓰레드 일시정지는 KAPC에 의해 수행되는데, KAPC는 단순히 특정 쓰레드 컨텍스트에 대한 커널 모드 콜백입니다. Critical Region에 진입하면 쓰레드의 User APC와 Normal Kernel APC가 현재 쓰레드에서 실행되는 것을 차단합니다. 일시정지를 막아준다는 것은 이것을 의미합니다. KeEnterGuardedRegion는 Special Kernel APC를 차단한다는 것 말고는 위에 내용과 동일합니다.

그래서 다음과 같은 두 가지 결론이 나올 수 있습니다.

1. Critical Region에 진입한 쓰레드는 일시정지 할 수 없습니다.

2. Critical Region에 진입하지 않은 쓰레드는 일시정지 될 수 있습니다. (IRQL == PASSIVE_LEVEL)

생각해보면 저도 드라이버에서 쓰레드가 일시 정지되는 것을 생각해본적이 별로 없는 것 같습니다(아예 없다고 하는 것이 맞을까요). 흔한 일이 아니어서 인지하기가 어려울 뿐이지 Caller인 프로세스가 권한이 충분하다면 쓰레드를 일시정지 할 수 있습니다. 현재 쓰레드가 일시정지 된 경우 시스템의 다른 쓰레드에 영향을 미치는지 항상 생각해야합니다. 대부분의 문제는 Lock을 획득할 때 발생합니다. Lock을 획득한 후 쓰레드가 일시정지되면 문제가 심각해집니다. 예를 들어 파일 시스템은 유저모드에서 I/O 요청을 처리하는 동안 상당히 많은 횟수의 파일&볼륨 잠금을 수행합니다. 쓰레드가 일시정지 됐을 때 하필 Lock을 획득한 상태라면 다른 쓰레드가 Lock을 획득할려고 시도할 때 Deadlock이 발생할 수 있습니다.

우리는 이 문제를 두 가지 방법 중 하나로 해결합니다.

첫 번째 방법은,

암시적으로 Critical Region에 들어가는 Lock을 획득하는 것입니다.

- Spinlocks
- Kernel Mutexes
- Fast Mutexes
- Guarded Mutexes

암시적으로 Critical Region에 진입하지 않는 Lock은 반드시 명시적으로 KeEnterCriticalRegion/KeLeaveCriticalRegion로 명시해서 쓰레드가 일시정지 되지 않도록 해야합니다. 이러한 락은 아래와 같습니다.

- Executive Resources
- Unsafe Fast Mutex
- KEVENT
- KSEMAPHORE

결론은 Critical Region은 단순히 쓰레드 일시정지를 차단하는 방법으로 생각할 수 있습니다. 커널 모드에서 실행 중인 쓰레드는 언제든지 일시정지 될 수 있습니다. 드라이버가 쓰레드 간 종속성을 생성하지 않으면 (공유 영역 사용) 괜찮습니다. Critical Region에 진입하고 탈출하는 것은 전적으로 개발자의 몫입니다.

Microcurruption Addis Ababa

11 Microcurruption의 Addis Ababa다. 4482: 3f40 0a00 mov #0xa, r15 4486: b012 5045 call #0x4550 <putchar> 448a: 8193 0...