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