Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Любой драйвер, использующий объект события, должен вызывать KeInitializeEvent, IoCreateNotificationEvent или IoCreateSynchronizationEvent , прежде чем он ожидает, задает, очищает или сбрасывает событие. На следующем рисунке показано, как драйвер с потоком может использовать объект события для синхронизации.
Как показано на предыдущем рисунке, такой драйвер должен предоставить хранилище для объекта события, который должен быть резидентом. Драйвер может использовать расширение устройства объекта устройства, созданного драйвером; расширение контроллера, если он использует объект контроллера; или непагированный пул, выделенный драйвером.
Когда драйвер вызывает KeInitializeEvent, он должен передать указатель на резидентное хранилище драйвера для объекта события. Кроме того, вызывающий должен указать начальное состояние (сигнальное или не сигнальное) для объекта события. Вызывающий объект также должен указать тип события, который может быть следующим:
SynchronizationEvent
Если для события синхронизации задано состояние Signaled, один поток, ожидающий сброс события в Not-Signaled, становится допустимым для выполнения, и состояние события автоматически сбрасывается на Not-Signaled.
Этот тип события иногда называется событием автоматической очистки, так как его сигнальное состояние автоматически сбрасывается при каждом выполнении выжидания.
NotificationEvent
Если событие уведомления установлено в состояние Signaled, все потоки, ожидавшие, пока событие будет сброшено в Not-Signaled, становятся готовыми к выполнению. Событие остается в состоянии Signaled до тех пор, пока не будет выполнен явный сброс до Not-Signaled: то есть, должен быть вызван KeClearEvent или KeResetEvent с заданным указателем Event.
Немногие драйверы устройств или промежуточных драйверов имеют один выделенный драйвером поток, не говоря уже о наборе потоков, которые могут синхронизировать свои операции, ожидая события, которое защищает общий ресурс.
Большинство драйверов, использующих объекты событий для ожидания завершения операции ввода-вывода, задают входной тип на NotificationEvent при вызове KeInitializeEvent. Объект события, настроенный для IRPs, создаваемый драйвером с помощью IoBuildSynchronousFsdRequest или IoBuildDeviceIoControlRequest , почти всегда инициализирован как NotificationEvent , так как вызывающий объект ожидает события для уведомления о том, что его запрос был удовлетворен одним или несколькими драйверами нижнего уровня.
После инициализации драйвера его выделенный драйвером поток, если он есть, и другие подпрограммы могут синхронизировать свои операции с событием. Например, драйвер с потоком, который управляет очередью IRP, например драйвер контроллера дисковода гибких дисков системы, может синхронизировать обработку IRP по событию, как показано на предыдущем рисунке.
Поток, который извлек IRP для обработки на устройстве, вызывает KeWaitForSingleObject с указателем на предоставленную драйвером память для инициализированного объекта события.
Другие подпрограммы драйверов выполняют операции ввода-вывода, необходимые для выполнения IRP, и, когда эти операции завершены, подпрограмма DpcForIsr драйвера вызывает KeSetEvent с указателем на объект события, приростом приоритета, определяемым драйвером для потока (Increment, как показано на предыдущем рисунке), и логическим значением Wait, установленным в FALSE. Вызов KeSetEvent переводит объект события в сигнальное состояние, тем самым изменяет состояние ожидающего потока на готовое.
Ядро отправляет поток для выполнения сразу после того, как процессор доступен: т. е. ни один другой поток с более высоким приоритетом в настоящее время находится в состоянии готовности, и подпрограммы режима ядра не выполняются на более высоком уровне IRQL.
Теперь поток может завершить IRP, если DpcForIsr еще не вызвал IoCompleteRequest с IRP, и извлечь другой IRP для обработки на устройстве.
Вызов KeSetEvent с параметром Wait, заданным значением TRUE, указывает на намерение вызывающего немедленно вызвать функцию KeWaitForSingleObject или KeWaitForMultipleObjects после возвращения из KeSetEvent.
Рассмотрим следующие рекомендации по настройке параметра WaitвKeSetEvent:
Подпрограмма для страничного потока или страничного драйвера, выполняемая в IRQL < DISPATCH_LEVEL, никогда не должна вызывать KeSetEvent с параметром Wait , заданным значением TRUE. Такой вызов вызывает фатальную ошибку страницы, если вызывающий объект будет выгружен из памяти между вызовами KeSetEvent и KeWaitForSingleObject или KeWaitForMultipleObjects.
Любая стандартная подпрограмма драйвера, выполняющаяся на уровне IRQL = DISPATCH_LEVEL, не может останавливаться на ненулевой интервал на объектах диспетчера, не приводя к сбою системы. Однако такая подпрограмма может вызывать KeSetEvent во время работы на IRQL, не превышающем DISPATCH_LEVEL.
Для получения краткого обзора IRQLs, на которых выполняются стандартные подпрограммы драйверов, см. раздел Управление приоритетами оборудования.
KeResetEvent возвращает предыдущее состояние заданного события: задано ли значение Signaled или нет при вызове KeResetEvent . KeClearEvent просто задает состояние заданного события на «Не сигнализируется».
Рассмотрим следующее руководство о том, когда вызывать предыдущие поддерживающие подпрограммы:
Для повышения производительности каждый драйвер должен вызывать KeClearEvent , если вызывающий объект не нуждается в информации, возвращаемой KeResetEvent , чтобы определить, что делать дальше.