Теория информационных систем. Страница 50.
Сервисные функции
Набор сервисных функций, доступных драйверу, обычно представляет собой подмножество стандартной библиотеки того языка высокого уровня, на котором обычно пишутся драйверы. В большинстве современных ОС это С. При выборе этого подмножества используется простой критерий: удаляются или заменяются на более или менее ограниченные все функции, которые так или иначе содержат в себе системные вызовы. Так, функции memcpy или sprintf вполне можно оставить, malloc придется заменить на эквивалент (в ядре Linux эта функция называется kmaiioc), a fwrite драйверу вряд ли понадобится, особенно если учесть, что работа многих драйверов начинается до того, как будет смонтирована хоть одна файловая система.
Важную роль среди сервисных функций занимают операции, часто исполняемые одной командой, но такой, которую компиляторы ЯВУ в обычных условиях не генерируют. Это, прежде всего, операции обращения к регистрам ввода-вывода в машинах с отдельным адресным пространством ввода-вывода, а также команды разрешения и запрещения прерываний. На С такие операции реализуются в виде макроопределений, содержащих ассемблерную вставку.
Правила кодирования драйверов во многих ОС требуют, чтобы даже на машинах с единым адресным пространством обращения к регистрам устройств происходили посредством макросов. Такой код может быть легко портнрован на процессор с отдельным адресным пространством. В наше время, когда одни и те же устройства и одни и те же периферийные шины подключаются к различным процессорам, портирование драйверов между различными процессорами осуществляется весьма часто.
При портировании драйвера разработчик должен также принимать во внимание различия в порядке байтов устройства и текущего процессора. Для приведения этого параметра в соответствие обычно предоставляются функции или макросы перестановки байтов как в одном слове, так и в блоках значительного размера.
Асинхронная модель ввода-вывода с точки зрения приложений
В разд. Синхронный ввод-вывод, обсуждая асинхронную модель драйвера, мы задались вопросом: должна ли задача, сформировав запрос на ввод-вывод, дожидаться его завершения? Ведь система, приняв запрос, передает его асинхронному драйверу, который инициирует операцию на внешнем устройстве и освобождает процессор. Сама система не ожидает завершения запроса. Так должна ли пользовательская задача ожидать его?
Если было запрошено чтение данных, то ответ, на первый взгляд, очевиден: должна. Ведь если данные запрошены, значит они сейчас будут нужны программе.
Однако можно выделить буфер для данных, запросить чтение, потом некоторое время заниматься чем-то полезным, но не относящимся к запросу, и лишь к точке, когда данные действительно будут нужны, спросить систему: а готовы ли данные? Если готовы, то можно продолжать работу. Если нет, то придется ждать (рис. 10.9).
Во многих приложениях, особенно интерактивных или работающих с другими устройствами-источниками событий, асинхронное чтение оказывается единственно приемлемым вариантом, поскольку оно позволяет задаче одновременно осуществлять обмен с несколькими источниками данных и таким образом повысить пропускную способность и/или улучшить время реакции на событие.
Опережающее чтение
При записи, казалось бы, нет необходимости дожидаться физическою вершения операции. При этом мы получаем режим, известный как отложенная запись (lazy write— "ленивая" запись, если переводить дослоцц0\ Однако такой режим создает две специфические проблемы.
Во-первых, программа должна знать, когда ей можно использовать буфер данными для других целей. Если система копирует записываемые данные из пользовательского адресного пространства в системное, то эта же проблема возникает внутри ядра; внутри ядра проблема решается использованием многобуферной схемы, и все относительно просто. Однако копирование приводит к дополнительным затратам времени и требует выделения памяти под буферы. Наиболее остро эта проблема встает при работе с дисковыми и сетевыми устройствами, с которыми система обменивается большими объемами данных (а сетевые устройства еще и могут генерировать данные неожиданно). Проблема управления дисковыми буферами подробнее обсуждается в разд. Дисковый кэш.
В большинстве современных вычислительных систем общего назначения накладные расходы, обусловленные буферизацией запросов, относительно невелики или по крайней мере считаются приемлемыми. Но в системах реального времени и/или встраиваемых контроллерах, где время и объем оперативной памяти жестко ограничены, эти расходы оказываются серьезным фактором.
Перейти на другую страницу:
|