Примеры использования очередей ввода-вывода
Для каждого устройства, подключенного к системе и поддерживаемого определенным драйвером, драйвер может использовать следующие сочетания очередей ввода-вывода и обработчиков запросов:
Одна очередь ввода-вывода по умолчанию и один обработчик запросов EvtIoDefault. Платформа доставляет все запросы устройства в очередь по умолчанию и вызывает обработчик EvtIoDefault драйвера для доставки каждого запроса драйверу.
Одна очередь ввода-вывода по умолчанию и несколько обработчиков запросов, таких как EvtIoRead, EvtIoWrite и EvtIoDeviceControl. Платформа доставляет все запросы устройства в очередь по умолчанию. Он вызывает обработчик EvtIoRead драйвера для доставки запросов на чтение, обработчик EvtIoWrite для доставки запросов на запись и обработчик EvtIoDeviceControl для доставки запросов на ввод-вывод устройства.
Несколько очередей ввода-вывода, например одна для запросов на чтение, а другая — для запросов на запись. Для каждой очереди драйвер предоставляет только один обработчик запросов, так как очередь получает только один тип запроса.
Несколько очередей ввода-вывода, каждая из которых имеет несколько обработчиков запросов.
Некоторые примеры сценариев включают следующее:
Одна очередь последовательных операций ввода-вывода
Если вы создаете драйвер функции для диска, который может обслуживать только запросы на чтение и запись по одному, драйверу функции требуется только одна очередь ввода-вывода на устройство.
Драйвер может использовать очередь ввода-вывода по умолчанию, созданную платформой, когда драйвер вызывает WdfIoQueueCreate и устанавливает для DefaultQueueзначение TRUE в структуре WDF_IO_QUEUE_CONFIG очереди. В структуре WDF_IO_QUEUE_CONFIG драйвер также должен указать следующее:
WdfIoQueueDispatchSequential в качестве метода диспетчеризации, поэтому очередь ввода-вывода по умолчанию будет синхронно доставлять запросы ввода-вывода драйверу.
Одна функция обратного вызова события EvtIoDefault, которая будет принимать все запросы ввода-вывода.
Каждый раз, когда запрос ввода-вывода доступен в очереди ввода-вывода драйвера по умолчанию, платформа будет доставлять запрос драйверу, вызывая обработчик запросов EvtIoDefault драйвера. Если в очереди будет доступен другой запрос, платформа не доставляет его, пока драйвер не вызовет WdfRequestComplete для ранее доставленного запроса.
Несколько последовательных очередей ввода-вывода и очередь вручную
Рассмотрим устройство с последовательным портом со следующими характеристиками:
Он может одновременно выполнять одну операцию чтения и одну операцию записи.
Он не может выполнять несколько операций чтения или записи асинхронно.
Он может получать запросы на управление вводом-выводом устройства для получения сведений о состоянии. Для выполнения некоторых из этих запросов драйверу устройства может потребоваться много времени (например, запрос на ожидание изменения состояния).
Драйвер функции для этого устройства может использовать несколько последовательных очередей ввода-вывода на каждом устройстве. Драйвер будет вызывать WdfIoQueueCreate три раза: один раз, чтобы создать очередь по умолчанию, и дважды, чтобы создать две дополнительные очереди ввода-вывода. В структуре WDF_IO_QUEUE_CONFIG для каждой из этих очередей драйвер должен указать:
WdfIoQueueDispatchSequential — метод диспетчеризации для каждой очереди, поэтому платформа будет синхронно доставлять запросы ввода-вывода драйверу.
Отдельный обработчик запросов для каждой очереди (EvtIoDefault, EvtIoRead и EvtIoWrite), который будет получать запросы ввода-вывода очереди.
После вызова WdfIoQueueCreate драйвер может дважды вызвать WdfDeviceConfigureRequestDispatching , чтобы перенаправить все запросы на чтение в одну из дополнительных очередей и все запросы на запись в другую.
В этой конфигурации функция обратного вызова EvtIoDefault очереди ввода-вывода устройства по умолчанию будет получать только запросы на управление вводом-выводом устройства для получения сведений о состоянии.
Если драйвер должен хранить запрос состояния в течение длительного времени, он может создать четвертую очередь и указать WdfIoQueueDispatchManual в качестве метода диспетчеризации. Когда драйвер получает запрос на получение сведений, которые он должен ждать, он может поместить запрос в эту дополнительную очередь до тех пор, пока сведения о состоянии не станут доступны. Затем драйвер может получить запрос из очереди и завершить его. Тем временем очередь по умолчанию может доставить драйверу еще один запрос.
Одна параллельная очередь ввода-вывода
Контроллеры дисков интегрированной среды разработки могут перекрывать некоторые операции ввода-вывода, но не перекрывать другие. Например, когда контроллер обрабатывает операцию чтения или записи на одном диске, он может отправить команду seek на другой диск. С другой стороны, несколько одновременных команд чтения и записи не поддерживаются.
Драйвер функции для этого контроллера должен проверять каждый запрос ввода-вывода. Если драйвер получает команду seek, он должен определить, можно ли обработать команду seek. Команда seek не может быть обработана, если:
Указанный диск уже занят.
Диск форматируется, поэтому другие диски не могут быть активными.
Для каждого устройства, подключенного к контроллеру, драйвер может вызвать WdfIoQueueCreate , чтобы создать очередь ввода-вывода по умолчанию. В структуре WDF_IO_QUEUE_CONFIG для каждой из этих очередей драйвер должен указать:
WdfIoQueueDispatchParallel — метод диспетчеризации для каждой очереди, поэтому платформа будет асинхронно доставлять запросы ввода-вывода драйверу.
Функция обратного вызова события EvtIoDefault для каждой очереди, которая будет получать запросы ввода-вывода очереди.
При такой конфигурации каждому устройству назначается одна параллельная очередь ввода-вывода. Драйвер должен изучить каждый запрос ввода-вывода, который платформа доставляет из каждой очереди ввода-вывода. Если драйвер может обработать запрос немедленно, он делает это. В противном случае драйвер вызывает WdfIoQueueStop, что приводит к тому, что платформа перестает доставлять запросы, пока драйвер не вызовет WdfIoQueueStart.
Несколько параллельных очередей ввода-вывода
Адаптер узла SCSI — это пример устройства, поддерживающего асинхронные перекрывающиеся операции ввода-вывода. К адаптеру можно подключить до 32 устройств. Рассмотрим систему со следующей конфигурацией:
Некоторые устройства, подключенные к адаптеру SCSI, поддерживают повторную выборку, а некоторые — нет. Если устройство SCSI поддерживает повторное выделение, то во время операции ввода-вывода устройство может временно освободить адаптер, чтобы адаптер смог обслуживать другое устройство. Первое устройство позже повторно выполняет выбор, чтобы завершить свою работу.
Адаптер SCSI использует аппаратные почтовые ящики для передачи запросов и ответов между драйвером и устройствами. Если устройство готово к запросу, но нет доступных почтовых ящиков, устройство должно подождать.
Для оптимальной производительности драйвер функции для этого адаптера узла SCSI должен получать запросы ввода-вывода от платформы сразу после их доступности. Драйвер должен проверить каждый запрос и определить, можно ли запустить его немедленно или отложить до тех пор, пока устройство и ресурсы (например, память почтового ящика) не станут доступными.
Драйвер, вероятно, должен использовать несколько параллельных очередей ввода-вывода. Для каждого устройства, подключенного к адаптеру, драйвер вызывает WdfIoQueueCreate , чтобы создать очередь ввода-вывода по умолчанию. В структуре WDF_IO_QUEUE_CONFIG для каждой из этих очередей драйвер должен указать:
WdfIoQueueDispatchParallel — метод диспетчеризации для каждой очереди, поэтому платформа будет асинхронно доставлять запросы ввода-вывода драйверу.
Функция обратного вызова события EvtIoDefault для каждой очереди, которая будет получать запросы ввода-вывода очереди.
Функция обратного вызова EvtIoDefault каждой очереди ввода-вывода должна проверять запросы ввода-вывода очереди по мере их доставки и определять, можно ли обслуживать каждый из них немедленно. Если устройство и системные ресурсы доступны, драйвер запускает операцию ввода-вывода. Если устройство или ресурсы недоступны, драйвер должен вызвать WdfIoQueueStop , чтобы остановить доставку дополнительных запросов до тех пор, пока не будет обработан текущий.
При необходимости драйвер может вызвать WdfIoQueueCreate , чтобы создать дополнительные очереди для каждого устройства. Затем драйвер может вызвать WdfRequestForwardToIoQueue для повторной отправки некоторых типов запросов в дополнительные очереди. Когда платформа доставляет запросы из дополнительной очереди, драйвер при необходимости может вызвать WdfIoQueueStop в этой очереди, а не из очереди по умолчанию, тем самым сводя к минимуму количество или тип запросов, для которых отложена доставка.