Настройка и использование заблокированных очередей
Новые драйверы должны использовать безопасную для отмены платформу очередей IRP , предпочитая методы, описанные в этом разделе.
Драйверы с потоками, выделенными для устройств, или драйверы, использующие потоки исполнительной роли, такие как большинство системных FSD, являются наиболее вероятными типами драйверов для управления собственным внутренним очередем среды выполнения IRP в заблокированной очереди. Все драйверы PnP, включая драйверы WDM, также должны ставить определенные irP в очередь при выполнении переходов состояния PnP и питания.
Как правило, эти драйверы настраивают вдвойне связанную очередь с блокировкой; каждый IRP содержит элемент типа LIST_ENTRY, который драйвер может использовать для удвоения irp, которые он в настоящее время удерживает. Драйвер не может перезапустить irps для повторных попыток, если он настраивает отдельно связанную заблокированную очередь.
Драйвер должен настроить свою очередь с блокировкой при инициализации устройства. На следующем рисунке показана связанная вдвойне связанная очередь, подпрограммы поддержки, которые драйвер должен вызвать для настройки такой очереди, и набор процедур ExInterlockedXxx , которые драйвер может вызвать для вставки IRP в очередь и удаления из нее.
Как показано на этом рисунке, драйвер должен предоставить хранилище для самой очереди и для следующего, чтобы настроить вдвойне связанную переблокированную очередь:
Исполнительный спин-блокировка, которую драйвер должен вызвать KeInitializeSpinLock для инициализации. Обычно драйвер инициализирует спин-блокировку при настройке расширений устройства для своих объектов устройства в процедуре AddDevice .
Головка списка для очереди, которую драйвер должен инициализировать, вызвав InitializeListHead.
Большинство драйверов, использующих вдвойне связанные очереди с блокировкой, предоставляют необходимое хранилище в расширении устройства для созданного драйвером объекта устройства. Очередь и исполнительный спин-блокировка могут вместо этого находиться в расширении контроллера (если драйвер использует объект контроллера) или в невыгружаемом пуле, выделенном драйвером.
Пока драйвер принимает запросы ввода-вывода, он может вставить IRP в свою очередь путем вызова любой из следующих процедур поддержки, если ListHead имеет тип LIST_ENTRY, как показано на предыдущем рисунке:
ExInterlockedInsertTailList для размещения IRP в конце очереди
ExInterlockedInsertHeadList , чтобы поместить IRP в начало очереди. Водители обычно называют эту подпрограмму только в том случае, если им необходимо повторить определенный запрос.
Драйвер должен передавать указатели на IRP (ListEntry), а также указатели ListHead и executive spin lock (Lock), которые он инициализировал ранее, на каждую из этих подпрограмм ExInterlockedInsertXxxList . Если драйвер выводит IRP из очереди путем вызова ExInterlockedRemoveHeadList, требуются только указатели на ListHead и Lock. Чтобы предотвратить взаимоблокировку, драйвер не должен содержать значение ExecutiveSpinLock, которое он передает любой подпрограмме ExInterlockedXxx .
Так как заблокированная очередь защищена исполнительной спин-блокировкой, драйвер может вставить irP в свою дважды связанную очередь и удалить их в многопроцессорном режиме из любой подпрограммы драйвера, работающей со значением меньше или равным IRQL = DISPATCH_LEVEL.
Очередь с ListHead типа LIST_ENTRY, как показано на предыдущем рисунке, является списком, связанным вдвойне. Список с типом ListHead SLIST_HEADER является последовательно связанным списком. Драйвер инициализирует ListHead для последовательно связанной очереди, вызывая ExInitializeSListHead.
Драйвер, который никогда не повторяет операции ввода-вывода, может использовать ExInterlockedPushEntrySList и ExInterlockedPopEntrySList для управления очередями irp внутри последовательной, отдельно связанной очереди. Любой драйвер, использующий этот тип заблокированной очереди, также должен предоставлять резидентное хранилище для ListHead типа SLIST_HEADER и executiveSpinLock, как показано на предыдущем рисунке. Он должен инициализировать спин-блокировку и настроить свою очередь перед вызовом ExInterlockedPushEntrySList для вставки начальной записи в очередь.
Дополнительные сведения см. в разделе Управление приоритетами оборудования и спин-блокировками. Требования IRQL для конкретной процедуры поддержки см. на странице справочника по подпрограмме.