이벤트 개체 정의 및 사용
이벤트 개체를 사용하는 모든 드라이버는 이벤트를 대기, 설정, 지우기 또는 다시 설정하기 전에 KeInitializeEvent, IoCreateNotificationEvent 또는 IoCreateSynchronizationEvent 를 호출해야 합니다. 다음 그림에서는 스레드가 있는 드라이버가 동기화에 이벤트 개체를 사용하는 방법을 보여 줍니다.
이전 그림과 같이 이러한 드라이버는 상주해야 하는 이벤트 개체에 대한 스토리지를 제공해야 합니다. 드라이버는 드라이버에서 만든 디바이스 개체의 디바이스 확장 , 컨트롤러 개체를 사용하는 경우 컨트롤러 확장 또는 드라이버가 할당한 비페이지 풀을 사용할 수 있습니다.
드라이버가 KeInitializeEvent를 호출하는 경우 이벤트 개체에 대한 드라이버의 상주 스토리지에 대한 포인터를 전달해야 합니다. 또한 호출자는 이벤트 개체에 대한 초기 상태(신호 또는 신호되지 않음)를 지정해야 합니다. 또한 호출자는 다음 중 하나일 수 있는 이벤트 유형을 지정해야 합니다.
SynchronizationEvent
동기화 이벤트가 Signaled 상태로 설정되면 이벤트가 다시 설정되기를 기다리는 단일 스레드가 Not-Signaled 실행할 수 있게 되고 이벤트의 상태가 Not-Signaled로 자동으로 다시 설정됩니다.
대기가 충족될 때마다 Signaled 상태가 자동으로 다시 설정되기 때문에 이 유형의 이벤트를 자동 경화 이벤트라고도 합니다.
NotificationEvent
알림 이벤트가 Signaled 상태로 설정되면 이벤트가 다시 설정되기를 기다리던 모든 스레드가 Not-Signaled 실행될 수 있게 되고, 이벤트는 Not-Signaled 대한 명시적 재설정이 발생할 때까지 Signaled 상태로 유지됩니다. 즉, 지정된 Event 포인터를 사용하여 KeClearEvent 또는 KeResetEvent를 호출합니다.
공유 리소스를 보호하는 이벤트를 대기하여 작업을 동기화할 수 있는 스레드 집합은 물론 단일 드라이버 전용 스레드가 있는 디바이스 또는 중간 드라이버는 거의 없습니다.
이벤트 개체를 사용하여 I/O 작업이 완료될 때까지 기다리는 대부분의 드라이버는 KeInitializeEvent를 호출할 때 입력 형식을 NotificationEvent로 설정합니다. 드라이버가 IoBuildSynchronousFsdRequest 또는 IoBuildDeviceIoControlRequest 로 만드는 IRP에 대해 설정된 이벤트 개체는 호출자가 하나 이상의 하위 수준 드라이버에 의해 요청이 충족되었다는 알림을 받기 위해 이벤트를 대기하기 때문에 거의 항상 NotificationEvent 로 초기화됩니다.
드라이버가 자체를 초기화한 후 드라이버 전용 스레드(있는 경우) 및 기타 루틴이 이벤트에 대한 작업을 동기화할 수 있습니다. 예를 들어 시스템 플로피 컨트롤러 드라이버와 같이 IRP의 큐를 관리하는 스레드가 있는 드라이버는 이전 그림과 같이 이벤트에서 IRP 처리를 동기화할 수 있습니다.
디바이스에서 처리를 위해 IRP를 큐에서 제거한 스레드는 초기화된 이벤트 개체에 대한 드라이버 제공 스토리지에 대한 포인터를 사용하여 KeWaitForSingleObject 를 호출합니다.
다른 드라이버 루틴은 IRP를 충족하는 데 필요한 I/O 작업을 디바이스에 수행하고, 이러한 작업이 완료되면 드라이버의 DpcForIsr 루틴은 이벤트 개체에 대한 포인터, 스레드에 대한 드라이버 결정 우선 순위 상승(이전 그림과 같이 증분), 부울 대기가 FALSE로 설정된 KeSetEvent를 호출합니다. KeSetEvent를 호출하면 이벤트 개체가 Signaled 상태로 설정되어 대기 중인 스레드의 상태가 준비되도록 변경됩니다.
커널은 프로세서를 사용할 수 있는 즉시 실행하기 위해 스레드를 디스패치합니다. 즉, 우선 순위가 높은 다른 스레드가 현재 준비 상태이며 더 높은 IRQL에서 실행할 커널 모드 루틴이 없습니다.
이제 DpcForIsr 가 IRP를 사용하여 IoCompleteRequest 를 호출하지 않은 경우 스레드에서 IRP를 완료할 수 있으며 디바이스에서 처리할 다른 IRP를 큐에서 제거할 수 있습니다.
Wait 매개 변수가 TRUE로 설정된 KeSetEvent를 호출하면 KeSetEvent에서 반환할 때 KeWaitForSingleObject 또는 KeWaitForMultipleObjects 지원 루틴을 즉시 호출하려는 호출자의 의도가 표시됩니다.
Wait매개 변수를KeSetEvent로 설정하기위한 다음 지침을 고려합니다.
IRQL < DISPATCH_LEVEL 실행되는 페이지 가능한 스레드 또는 페이딩 가능한 드라이버 루틴은 Wait 매개 변수가 TRUE로 설정된 KeSetEvent를 호출해서는 안 됩니다. 이러한 호출은 호출자가 KeSetEvent 와 KeWaitForSingleObject 또는 KeWaitForMultipleObjects 호출 간에 페이징되는 경우 심각한 페이지 오류를 발생합니다.
IRQL = DISPATCH_LEVEL 실행되는 모든 표준 드라이버 루틴은 시스템을 중단하지 않고 디스패처 개체에서 0이 아닌 간격을 기다릴 수 없습니다. 그러나 이러한 루틴은 IRQL에서 실행되는 동안 keSetEvent 를 호출할 수 DISPATCH_LEVEL.
표준 드라이버 루틴이 실행되는 IRQL에 대한 요약은 하드웨어 우선 순위 관리를 참조하세요.
KeResetEvent 는 지정된 이벤트의 이전 상태를 반환합니다. KeResetEvent 호출이 발생했을 때 Signaled로 설정되었는지 여부입니다. KeClearEvent 는 지정된 이벤트의 상태를 신호되지 않음으로 설정하기만 하면됩니다.
이전 지원 루틴을 호출하는 시기에 대한 다음 지침을 고려합니다.
성능을 향상시키려면 호출자가 KeResetEvent 에서 반환한 정보를 필요로 하지 않는 한 모든 드라이버는 KeClearEvent 를 호출하여 다음에 수행할 작업을 결정해야 합니다.