Поделиться через


Настройка и использование очередей устройств

Драйвер настраивает объект очереди устройства путем вызова KeInitializeDeviceQueue при инициализации драйвера или устройства. После запуска устройств драйвер вставляет IRP в эту очередь путем вызова KeInsertDeviceQueue или KeInsertByKeyDeviceQueue. На следующем рисунке показаны эти вызовы.

настройка и использование очередей устройств.

Как показано на этом рисунке, драйвер должен предоставить хранилище для объекта очереди устройств, который должен быть резидентом. Драйверы, которые настраивают объект очереди устройств, обычно выделяют необходимое хранилище в расширении устройства созданного драйвером объекта устройства, но хранилище может размещаться в расширении контроллера, если драйвер использует объект контроллера, или в непагированном пуле, выделенном самим драйвером.

Если драйвер предоставляет хранилище для объекта очереди устройства в расширении устройства, он вызывает KeInitializeDeviceQueue после создания объекта устройства и перед запуском устройства. Другими словами, драйвер может инициализировать очередь из своей подпрограммы AddDevice или при обработке запроса IRP_MN_START_DEVICE PnP. В вызове KeInitializeDeviceQueue драйвер передает указатель на хранилище, которое он предоставляет для объекта очереди устройства.

После запуска устройств драйвер может вставить IRP в очередь устройства, вызвав KeInsertDeviceQueue, который помещает IRP в хвост очереди или KeInsertByKeyDeviceQueue, который помещает IRP в очередь в соответствии со значением SortKey , определяемым драйвером, как показано на предыдущем рисунке.

Каждая из этих подпрограмм поддержки возвращает логическое значение, указывающее, был ли вставлен IRP в очередь. Каждый из этих вызовов также устанавливает состояние объекта очереди устройства в "занято", если очередь в данный момент пуста (Not-Busy). Однако если очередь пуста (Not-Busy), ни подпрограмма KeInsertXxxDeviceQueue не вставляет IRP в очередь. Вместо этого он задает состояние объекта очереди устройства в значение "Занято" и возвращает значение FALSE. Так как IRP не был поставлен в очередь, драйвер должен передать его другому подпрограмме драйвера для дальнейшей обработки.

При настройке дополнительных очередей устройств следуйте инструкциям по реализации.

Если вызов KeInsertXxxDeviceQueue возвращает FALSE, вызывающая сторона должна передать IRP, который она пыталась добавить в очередь, для дальнейшей обработки в другую функцию драйвера. Однако вызов KeInsertXxxDeviceQueue изменяет состояние объекта очереди устройства на "Занят", поэтому следующий IRP будет вставлен в очередь, если драйвер не вызовет KeRemoveXxxDeviceQueue первым.

Если для объекта очереди устройства задано состояние "Занято", драйвер может извлечь IRP из очереди для дальнейшей обработки или сбросить состояние до Not-Busy, вызвав одну из следующих вспомогательных процедур:

  • KeRemoveDeviceQueue, чтобы удалить IRP из начала очереди

  • KeRemoveByKeyDeviceQueue для удаления IRP, выбранного по значению SortKey, которое определяется драйвером.

  • KeRemoveEntryDeviceQueue чтобы удалить определенный IRP из очереди или определить, находится ли определенный IRP в очереди

    KeRemoveEntryDeviceQueue возвращает логическое значение, указывающее, находится ли IRP в очереди устройства.

Вызов любой из этих подпрограмм для удаления записи из очереди устройства, которая пуста, но Загружена, изменяет состояние очереди на Незагружено.

Каждый объект очереди устройств защищен встроенной спин-блокировкой (не показан на рисунке "Использование объекта очереди устройства"). В результате драйвер может вставить IRPs в очередь и безопасно для многопроцессорной системы удалить их из любой подпрограммы драйвера, работающей на уровне или ниже IRQL = DISPATCH_LEVEL. Из-за этого ограничения IRQL драйвер не может вызывать любую подпрограмму KeXxxDeviceQueue из своих подпрограмм ISR или SynchCritSection , которые выполняются в DIRQL.

Дополнительные сведения см. в разделе об управлении приоритетами оборудования и спин-блокировках. Требования IRQL для конкретной подпрограммы поддержки см. на справочной странице подпрограммы.