Асинхронный ввод-вывод
В системах семейства Unix драйверы блочных устройств обязательно асинхронные.
Кроме того, в современных версиях системы асинхронными драйверами являются
драйверы потоковых устройств. Многие другие ОС, в том числе однозадачные
(такие, как DEC RT-11), используют исключительно асинхронные драйверы.
Драйвер, использующий асинхронную архитектуру, обычно предоставляет вместо
отдельных функций read, write, ioctl и т. д.
единую функцию, которая в системах семейства Unix называется strategy,
а мы будем называть стратегической функцией
(рис. 10.7).
Запросы к драйверу в VMS
В операционной системе VAX/VMS драйвер получает запросы на ввод-вывод
из очереди запросов. Элемент очереди называется IRP (lnput[Output] Request
Packet — пакет запроса ввода-вывода). Обработав первый запрос в очереди,
драйвер начинает обработку следующего. Операции над очередью запросов
выполняются специальными командами процессора VAX и являются атомарными.
Если очередь пуста, основная нить драйвера завершается. При появлении
новых запросов система вновь запустит ее.
Рис. 10.7. Стратегическая функция и очередь запросов
IRP содержит:
- код операции (чтение, запись или код SPFUN— специальная
функция, подобная ioctl в системах семейства Unix);
- адрес блока данных, которые должны быть записаны, или
буфера, куда данные необходимо поместить;
- информацию, используемую при постобработке, в частности,
идентификатор процесса, запросившего операцию.
В зависимости от кода операции драйвер запускает соответствующую
подпрограмму. В VAX/VMS адрес подпрограммы выбирается из таблицы FDT (Function
Definition Table). Подпрограмма инициирует операцию и приостанавливает
процесс, давая системе возможность исполнить другие активные процессы.
Затем, когда происходит прерывание, его обработчик инициирует fork-процесс,
исполняющий следующие этапы этого запроса. Завершив один запрос, fork-процесс
сообщает об этом процедурам постобработки (разбудив соответствующий процесс)
и, если в очереди еще что-то осталось, начинает исполнение следующего
запроса.
В качестве параметра стратегическая функция получает указатель на структуру
запроса, в которой содержатся код требуемой операции и блок данных. При
этом возникает сложный вопрос, а именно — в каком адресном пространстве
размещается этот блок?
На первый взгляд, идеальным решением было бы размещение этого блока сразу
в пользовательском адресном пространстве. Проблема здесь в том, что стратегическая
функция — особенно при обработке не первого запроса в очереди — исполняется
не в пользовательском контексте, когда можно применять примитивы обмена
данными с адресным пространством задачи,в контексте fork-процесса,
а то и в контексте прерывания, когда адресное пространство пользователя
не определено.
Возможны два варианта решения этой проблемы: хранить в структуре запроса
иноке и указатель на пользовательское адресное пространство, либо все-таки
копировать данные в адресное пространство системы на этапе предобработки,
и обратно в пользовательское на этапе постобработки запроса. Драйвер в
этом случае не должен беспокоиться ни о каком копировании, зато разработчик
ОС получает дополнительную головную боль в виде логики управления буферами
в адресном пространстве системы и выделения памяти для них.
Буферизация запросов и формирование очереди к блочным устройствам в Unix
осуществляется специальным модулем системы, который называется дисковым
кэшем. Принцип работы дискового кэша будет обсуждаться в разд.
Дисковый кэш. Очереди запросов к потоковым устройствам
имеют меньший объем, поэтому выделение памяти для них осуществляется обычным
kmalloc. |