
- •Введение
- •Подсистема ввода-вывода: общие принципы построения и работы
- •1.1. Взаимодействие процессора с внешними устройствами
- •1.2. Прямой доступ к памяти
- •Драйверы
- •Роль драйверов в операционной системе
- •Взаимодействие драйверов с компонентами операционной системы и пользовательскими программами
- •Стек обработки запросов ввода-вывода
- •Основы организации и работы подсистемы ввода-вывода unix
- •2.1. Драйверы в операционных системах семейства unix
- •Стратегическая функция драйвера блочного устройства
- •Функция обработки прерывания
- •Функция опроса устройства
- •Другие функции драйверов
- •Буферизация в символьных драйверах
- •Терминальный драйвер
- •2.2. Потоковая подсистема ввода-вывода в unix
- •Архитектура и принципы работы подсистемы streams
- •Архитектура и работа модулей потока
- •Функция модуля put
- •Функция модуля service
- •Структура сообщения
- •Основы организации и работы подсистемы ввода-вывода windows
- •3.1. Классификаций драйверов Windows
- •Драйверы пользовательского режима
- •Драйверы режима ядра
- •3.2. Объекты подсистемы ввода-вывода
- •Объект файл
- •Объект устройство
- •Объект драйвер
- •Объект пакет запроса ввода-вывода
- •Объект блок стека запросов ввода-вывода
- •3.3. Передача данных между пользовательским адресным пространством и пространством ядра
- •Буферизированный ввод-вывод
- •Прямой ввод-вывод
- •Ввод-вывод под управлением драйвера
- •3.4. Обработка запросов ввода-вывода
- •Прохождение запроса ввода-вывода вниз через стек обработки запросов ввода-вывода
- •Обработка прерывания по завершению ввода-вывода
- •Обратное прохождение запроса ввода-вывода вверх через стек запросов ввода-вывода
- •3.5. Буферизация запросов ввода-вывода
- •Системная очередь запросов
- •Очереди запросов под управлением драйвера
- •3.6. Диспетчер Plug-And-Play, установка и запуск драйверов
- •3.7. Диспетчер электропитания
- •3.8. Среда сетевых драйверов ndis
- •Драйверы среды ndis Минипорт-драйверы сетевых адаптеров
- •Драйверы протоколов
- •Промежуточные драйверы
- •Структура ndis пакета
- •Запросы к сетевым адаптерам
- •3.9. Порты завершения ввода-вывода
- •Заключение
- •Библиографический список
- •Оглавление
- •394026 Воронеж, Московский просп., 14
Обратное прохождение запроса ввода-вывода вверх через стек запросов ввода-вывода
Мы рассмотрели прохождение запроса ввода-вывода вниз через стек обработки, вплоть до физического устройства. Однако во многих случаях драйверу на текущем уровне стека обработки недостаточно только передать запрос на следующий уровень, часто ему необходимо знать статус завершения операции ввода-вывода на нижележащих уровнях, или требуется выполнить постобработку данных после нижележащих уровней, прежде чем передать ответ на верхние уровни. При этом каждый драйвер в стеке может выполнить собственную часть от общей процедуры обработки, последовательно приводя сырые данные от внешнего устройства в высокоуровневые данные для прикладной программы.
Для решения задач постобработки, драйвер, во время обработки запроса на проходе 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 из системной очереди будет передан первый пакет с указанным ключом.