Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Учебное пособие 3000377.doc
Скачиваний:
29
Добавлен:
30.04.2022
Размер:
2.52 Mб
Скачать

Обратное прохождение запроса ввода-вывода вверх через стек запросов ввода-вывода

Мы рассмотрели прохождение запроса ввода-вывода вниз через стек обработки, вплоть до физического устройства. Однако во многих случаях драйверу на текущем уровне стека обработки недостаточно только передать запрос на следующий уровень, часто ему необходимо знать статус завершения операции ввода-вывода на нижележащих уровнях, или требуется выполнить постобработку данных после нижележащих уровней, прежде чем передать ответ на верхние уровни. При этом каждый драйвер в стеке может выполнить собственную часть от общей процедуры обработки, последовательно приводя сырые данные от внешнего устройства в высокоуровневые данные для прикладной программы.

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

VOID IoSetCompletionRoutine( // указатель на IRP, // завершение обработки которого ожидается IN PIRP Irp, // адрес функции которая автоматически будет // вызвана при завершении обработки IRP IN PIO_COMPLETION_ROUTINE CompletionRoutine, // указатель на область памяти // который будет передан в CompletionRoutine IN PVOID Context, // флаги, определяющие // когда вызывать CompletionRoutine IN BOOLEAN InvokeOnSuccess, IN BOOLEAN InvokeOnError, IN BOOLEAN InvokeOnCancel )

Когда выполнится хотя бы одно условие, определенное при вызове функции IoSetCompletionRoutine, диспетчер ввода-вывода автоматически вызовет процедуру, указанную в параметре CompletionRoutine и передаст ей IRP для постобработки.

3.5. Буферизация запросов ввода-вывода

В многозадачной операционной системе к одному и тому же устройству за небольшой интервал времени может поступить множество запросов. Поскольку устройство обычно не допускает параллельной обработки нескольких запросов, в драйвере необходимо предусмотреть механизм буферизации, позволяющий сохранить поступающие запросы до освобождения устройства и последовательно обработать их.

Системная очередь запросов

Система Windows предусматривает общесистемный механизм буферизации запросов, который может быть использован драйвером.

Для этого драйвер должен предусмотреть специальную процедуру StatIo и сохранить адрес точки входа в нее в поле DriverStartIo структуры DRIVER_OBJECT.

При использовании системной буферизации, если диспетчерская функция драйвера не может выполнить запрос немедленно, она помечает запрос как отложенный и вызывает функцию IoStartPacket, определенную следующим образом:

VOID IoStartPacket( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PULONG Key OPTIONAL IN PDRIVER_CANCEL CancelFunction OPTIONAL );

Назначение параметров DeviceObject и Irp очевидно. Параметр Key позволяет драйверу самому определить порядок выполнения запросов из системной очереди, если принятая по умолчанию дисциплина FIFO не подходит.

При постановке запроса в системную очередь драйвер может указать функцию, которую диспетчер ввода-вывода должен будет вызвать, если запрос ввода-вывода будет отменен, пока он находится в очереди (параметр CancelFunction в функции IoStartPacket).

Системная очередь связана с объектом устройство и реализуется с использованием полей KDEVICE_QUEUE_ENTRY DeviceQueueEntry структуры IRP и KDEVICE_QUEUE DeviceQueue структуры DEVICE_OBJECT. Отметим некоторые поля этих структур.

Структура KDEVICE_QUEUE_ENTRY:

  • LIST_ENTRY DeviceListEntry – точка входа объекта IRP в список необработанных запросов;

  • DWORD SortKey – ключ сортировки, указанный драйвером при вызове IoStartPacket().

Структура KDEVICE_QUEUE:

  • LIST_ENTRY DeviceListHead – начало очереди необработанных запросов к устройству;

  • KSPIN_LOCK Lock – спин-блокировка для взаимоисключающего выполнения операций вставки и удаления элементов очереди;

  • BOOLEAN Busy – признак занятости устройства обработкой очередного запроса из очереди.

Структура очереди запросов показана на рис. 20.

Рис.20. Структура системной очереди запросов

После вызова драйвером функции IoStartPacket, диспетчер ввода-вывода поставит запрос в системную очередь, или сразу же вызовет процедуру драйвера StartIo, если в заголовке очереди не установлен признак занятости устройства обработкой запроса (поле Busy в структуре KDEVICE_QUEUE).

При использовании системной буферизации, целесообразно выполнять все взаимодействие с устройством исключительно из функции StartIo, оставив в диспетчерских функциях драйвера только проверку и немедленное завершение некорректных запросов. Все остальные запросы диспетчерские функции должны перенаправлять в процедуру StartIo через системную очередь.

Завершив обработку очередного запроса, процедура StartIo должна вызвать функцию IoStartNextPacket. При этом, если системная очередь запросов не пуста, будет снова вызвана процедура StartIo.

Драйвер может реализовать сортировку запросов из очереди в соответствии с принятой стратегией, использую функцию IoStartNextPacketByKey, вместо функции IoStartNextPacket. При этом на обработку в функцию StartIo из системной очереди будет передан первый пакет с указанным ключом.