Управление взаимосвязанными очередями с помощью потока Driver-Created

Новые драйверы должны использовать безопасную для отмены платформу очередей IRP в соответствии с методами, описанными в этом разделе.

Как и драйвер системного контроллера гибких дисков, драйвер с выделенным устройством потоком, а не подпрограммой StartIo , как правило, управляет собственной очередью irp в двойной связанной очереди. Поток драйвера извлекает irp из своей заблокированной очереди, когда на устройстве требуется выполнить работу.

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

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

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

Любой поток, созданный драйвером, выполняется по irQL = PASSIVE_LEVEL и с базовым приоритетом во время выполнения, ранее заданным, когда драйвер называется PsCreateSystemThread. Вызов потока к ExInterlockedRemoveHeadList временно вызывает irQL для DISPATCH_LEVEL на текущем процессоре, пока IRP удаляется из внутренней очереди драйвера. Исходный irQL восстанавливается до PASSIVE_LEVEL при возвращении из этого вызова.

Любой поток драйвера (или предоставляемый драйвером обратный вызов рабочего потока) должен тщательно управлять списками IRQL, в которых он выполняется. Рассмотрим следующий пример.

  • Так как системные потоки обычно выполняются в среде IRQL = PASSIVE_LEVEL, поток драйвера может ожидать установки объектов диспетчера, определенных ядром, в состояние сигнального состояния.

    Например, выделенный устройством поток может ожидать, пока другие драйверы удовлетворят событие, и завершить некоторое количество irp частичной передачи, которые поток настраивает с помощью IoBuildSynchronousFsdRequest.

  • Однако такой выделенный для устройства поток должен вызвать IRQL на текущем процессоре, прежде чем вызывать определенные процедуры поддержки.

    Например, если драйвер использует DMA, выделенный устройством поток должен вкладывать свои вызовы в AllocateAdapterChannel и FreeAdapterChannel между вызовами KeRaiseIrql и KeLowerIrql , так как эти подпрограммы и некоторые другие подпрограммы поддержки для операций DMA должны вызываться по адресу IRQL = DISPATCH_LEVEL.

    Помните, что подпрограммы StartIo выполняются в DISPATCH_LEVEL, поэтому драйверам, которые используют DMA, не нужно вызывать подпрограммы KeXxxIrql из своих процедур StartIo .

  • Поток, созданный драйвером, может получить доступ к страничной памяти, так как он выполняется в неарбитарном контексте потока (его собственном) в IRQL = PASSIVE_LEVEL, но многие другие стандартные подпрограммы драйвера выполняются в IRQL >= DISPATCH_LEVEL. Если поток, созданный драйвером, выделяет память, доступ к которому может осуществляться с помощью такой подпрограммы, он должен выделить память из непагированного пула. Например, если выделенный устройством поток выделяет любой буфер, к которому позже будет обращаться isR драйвера или SynchCritSection, AdapterControl, AdapterListControl, ControllerControl, DpcForIsr, CustomDpc, IoTimer, CustomTimerDpc или в более высоком уровне драйвера IoCompletion подпрограмма, выделенная потоком память не может быть страничной.

  • Если драйвер хранит общие сведения о состоянии или ресурсы в расширении устройства, поток драйвера (например, подпрограмма StartIo ) должен синхронизировать свой доступ к физическому устройству и общим данным с другими подпрограммами драйвера, которые обращаются к тому же устройству, расположению памяти или ресурсам.

    Если поток совместно использует устройство или состояние с ISR, он должен использовать KeSynchronizeExecution для вызова предоставленной драйвером процедуры SynchCritSection для программирования устройства или для доступа к общему состоянию. См . раздел Использование критически важных разделов.

    Если поток совместно использует состояние или ресурсы с подпрограммами, отличными от ISR, драйвер должен защитить общее состояние или ресурсы с помощью инициализированной инициализированной исполнительной спиновой блокировки, для которой драйвер предоставляет хранилище. Дополнительные сведения см. в разделе Спин-блокировки.

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