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


Примеры использования очередей ввода-вывода

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

  • Одна очередь ввода-вывода по умолчанию и один обработчик запросов 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 в этой очереди, а не из очереди по умолчанию, тем самым сводя к минимуму количество или тип запросов, для которых отложена доставка.