Студопедия.Орг Главная | Случайная страница | Контакты | Мы поможем в написании вашей работы!  
 

Пример 8.3. Функция переключения контекста в ядре Linux/x86 6 страница



Подсистема ввода-вывода OS/2
В качестве примера такого консерватизма можно привести подсистему ввода-вывода OS/2. Совместный проект фирм IBM и Microsoft, OS/2 1.x разрабатывалась как операционная система для семейства персональных компьютеров Personal System/2. Младшие модели семейства были основаны на 16-разрядном процессоре 80286, поэтому вся ОС была полностью 16-битной.
Позднее разработчики фирмы IBM реализовали 32-битную OS/2 2.0, но для совместимости со старыми драйверами им пришлось сохранить 16-битную подсистему ввода-вывода. Все точки входа драйверов должны находиться в 16-битных ('USE16') сегментах кода; драйверам передаются только 16-разрядные ('far') указатели и т. д.
По утверждению фирмы IBM, они рассматривали возможность реализации также и 32-битных драйверов, но их измерения не показали значительного повышения производительности при переходе к 32-битной модели. Позднее, впрочем, суперскалярные процессоры архитектуры х86, оптимизированные Дл^ исполнения 32-разрядного кода, все-таки продемонстрировали значительный рост производительности для такого кода по сравнению с 16-разрядным, и, начиная с OS/2 4.0 32-битный интерфейс все-таки предоставляется, но без отказа от поддержки старых, 16-разрядных драйверов.
Благодаря этому сохраняется возможность использовать драйверы, разработанные еще в конце 80-х и рассчитанные на OS/2 1.x. Эта возможность оказывается особенно полезна при работе со старым оборудованием.
Напротив, разработчики фирмы Microsoft отказались от совместимости с 16-битными драйверами OS/2 1.x в создававшейся ими 32-битной версии OS/2 называвшейся OS/2 New Technology. Фольклор утверждает, что именно это техническое решение оказалось причиной разрыва партнерских отношении между Microsoft и IBM, в результате которого OS/2 NT вышла на рынок под названием Windows NT 3.1.

Подсистема ввода-вывода Windows 9x/ME
Сама фирма Microsoft, впрочем, демонстрирует почти столь же трогательную приверженность к совместимости со старыми драйверами: системы линии Windows 95/98/ME до сих пор используют весьма своеобразную архитектуру, основной смысл которой — возможность применять, пусть и с ограничениями, драйверы MS DOS.
Windows 9х и Windows 3.x в enhanced-режиме предоставляют вытесняющую многозадачность для VDM (Virtual DOS Machine— Виртуальная машина [для] DOS), однако сами используют DOS для обращения к дискам и дискетам. Ядро однозадачной DOS не умеет отдавать управление другим процессам во время исполнения запросов ввода-вывода. В результате во время обращения к диску все остальные задачи оказываются заблокированы.
У современных PC время исполнения операций над жестким диском измеряется десятыми долями секунды, поэтому фоновые обращения к жесткому диску почти не приводят к нарушениям работы остальных программ. Однако скорость работы гибких дисков осталась достаточно низкой, следовательно, работа с ними в фоновом режиме блокирует систему на очень заметные промежутки времени.
Эффектная и убедительная демонстрация этой проблемы очень проста: достаточно запустить в фоновом режиме форматирование дискеты или просто команду COPY С:\ТМР\*.* А:, если в каталоге C:\TMP достаточно много данных. При этом работать с системой будет практически невозможно: во время обращений к дискете даже мышиный курсор не будет отслеживать движений мыши, будут теряться нажатия на клавиши и т. д.
Windows 95/98/ME использует несколько методов обхода DOS при обращениях к диску, поэтому пользователи этой системы не всегда сталкиваются с описанной проблемой. Однако при использовании блочных драйверов реального режима система по-прежнему применяет DOS в качестве подсистемы ввода-вывода, и работа с дискетами в фоновых задачах также нарушает работу задач первого плана.

Если говорить о совместимости, то со многих точек зрения очень привлекательной представляется идея универсального драйвера — модуля, который без изменении или с минимальными изменениями может использоваться Для управления одним и тем же устройством в различных ОС.
К сожалению — несмотря даже на то, что, как мы увидим далее, в общих чертах архитектура драйвера в большинстве современных ОС удивительн похожа — идея эта, по-видимому, нереализуема. Даже для близкородственных ОС — например, систем семейства Unix — драйверы одного и того ж устройства не всегда могут быть легко перенесены из одной ОС в другую говоря уж о возможности использования без модификаций. Еще более удивительным является тот факт, что две линии ОС - Windows 95/98/MЕ и Windows NT/2000/XP — поставляемых одной и той же компанией Microsoft и реализующих почти один и тот же интерфейс системных вызовов — Win32 — имеют совсем разный интерфейс драйвера.
Проблема здесь в том, что интерфейс между драйвером и ядром ОС всегда двусторонний: не только прикладные программы и ядро вызывают функции драйвера, но и, наоборот, драйвер должен вызывать функции ядра. Структура интерфейсов ядра, доступных драйверу, определяет многие аспекты архитектуры ОС в целом.
В предыдущих главах мы уже обсуждали многие из ключевых вопросов: способ сборки ядра, стратегию управления памятью, способы обмена данными между ядром и пользовательскими процессами, и, наконец, механизмы межпоточного взаимодействия — между нитями самого драйвера (ниже мы увидим, что подавляющее большинство драйверов состоит как минимум из двух нитей), между драйвером и остальными нитями ядра и между драйвером и нитями пользовательских процессов.
Изложение решений перечисленных проблем составляет если и не полное описание архитектуры ОС, то, во всяком случае, значительную его часть. Так, переход от однозадачной системы или кооперативной многозадачности к вытесняющей многозадачности может потребовать не только изменения планировщика, но и радикальной переделки всей подсистемы ввода-вывода, в том числе и самих драйверов.
Таким образом, до тех пор, пока используются ОС различной архитектуры, разработка универсального интерфейса драйвера, если теоретически п возможна, то практически вряд ли осуществима.

Функции драйверов

Прежде всего, драйвер должен иметь функции, вызываемые ядром при загрузке и выгрузке модуля и при подключении модуля к конкретным устройствам. Например, в Sun Solans это перечисленные функции.


Каждая из инициализированных копий драйвера имеет собственный блок локальных переменных, в которых хранятся переменные состояния устройства. При вызове attach драйвер должен прочитать конфигурационный файл, где записаны параметры устройства (номенклатура этих параметров зависит от устройства и от драйвера), разместить и проинициализировать блок переменных состояния, зарегистрировать обработчики прерываний, проинициализировать само устройство и, наконец, зарегистрировать устройство как доступное для пользовательских программ, создав для него минорную запись (minor node). В ряде случаев драйвер создает для одного устройства несколько таких записей.
Например, каждый жесткий диск в Unix SVR4 должен иметь 16 записей — по две (далее мы поймем, для чего они нужны) для каждого из восьми допустимых слайсов (логических разделов, см. разд. Загрузка самой ОС) диска. Другой пример: в большинстве систем семейства Unix лентопротяжные устройства имеют две минорные записи. Одно из этих устройств при открытии перематывает ленту к началу, другое не перематывает. В действительности оба устройства управляются одним и тем же драйвером, который определяет текущий режим работы в зависимости от указанной минорной записи.
Современные Unix системы, в частности Solaris, используют отложенную инициализацию, когда для многих устройств attach вызывается только при первой попытке доступа пользовательской программы к устройству.

После того, как драйвер проинициализировался и зарегистрироват мино ную запись, пользовательские программы могут начинать обращаться к не му и к управляемым им устройствам. Понятно, что обеспечить единый ин терфейс к разнообразным категориям устройств, перечисленным в главе 9 по меньшей мере сложно. Наиболее радикально подошли к этой проблеме разработчики системы UNIX, разделившие все устройства на два класса-блочные (высокоскоростные устройства памяти с произвольным доступом в первую очередь, дисковые устройства) и последовательные или символьные устройства (всё остальное) (в действительности, у современных систем семейства Unix типов драйверов несколько больше, но об этом далее).
Над последовательными устройствами определен следующий набор операций, которые могут осуществляться прикладной программой (в простых случаях эти операции непосредственно транслируются в вызовы функций драйвера).

Слово long в названии функции появилось по историческим причинам: версиях Unix для 16-разрядных машин индекс позиции не мог обозначать-я словом, потому что это ограничивало бы логическую длину устройства недопустимо малым значением 65334 байт. Поэтому необходимо было использовать двойное слово, что соответствовало типу long языка С. Современные системы используют 64-разрядный off_t.

Эта функция отсутствовала в старых версиях системы, но большинство современных систем семейства (BSD 4.4, ряд наследников BSD 4.3, SVR4 и Linux) поддерживают ее.
Речь идет об отображении в память данных, хранящихся на устройстве. Для устройств ввода-вывода, например, для принтера или терминала, эту функцию невозможно реализовать разумным образом. Напротив, для лент и других последовательных устройств памяти, поддерживающих функцию Iseek, отображение может быть реализовано с использованием аппаратных средств виртуализации памяти и операции read и write. Необходимость специальной функции отображения появляется у драйверов устройств, использующих большие объемы памяти, отображенной в адресное пространство системной шины, например, для растровых видеоадаптеров, некоторых звуковых устройств или страниц общей памяти (backpane memory — двухпортовой памяти, используемой как высокоскоростной канал обмена данными в многопроцессорных системах).
Механизм отображения доступных прикладной программе системных вызовов в функции драйвера относительно сложен. Этот механизм должен включать в себя следующее.

Способы, которыми эти вопросы решаются в современных операционных системах, обсуждаются в последующих разделах. А пока что мы подробнее обсудим, какие именно операции над устройством следует определить и почему.
Видно, что предлагаемый системами семейства Unix набор операций рассматривает устройство как неструктурированный поток байтов (или, ддя устройств ввода-вывода, два разнонаправленных потока — для ввода и для вывода). Такое рассмотрение естественно для устройств алфавитно-цифрового ввода-вывода и простых запоминающих устройств, например магнитных лент, однако далеко не столь естественно для более сложных устройств.
Стандартный ответ Unix-культуры в этом случае таков: любая, сколь угодно сложная структура данных может быть сериализована — преобразована в последовательный поток байтов. Например, изображение может быть превращено в последовательный поток байтов в виде растровой битовой карты или последовательности описаний графических примитивов — линий, прямоугольников и пр. Примерами такой сериализации для изображений могут являться язык PostScript [partners.adobe.com] и протокол распределенной оконной системы X Window [www.x.org] (оба протокола поддерживают как растровые образы, так и довольно богатые наборы векторных примитивов).
Нередки, впрочем, ситуации, когда нам интересна не только структура поступающих данных, но и время их поступления (в предыдущей главе мы предложили классифицировать устройства, которые могут быть использованы подобным образом, как генераторы событий) — это бывает в приложениях реального времени, а также в задачах, которые сейчас стало модно называть "задачами мягкого реального времени" — мультимедийных программах, генерирующих поток звука, синхронизованного с изображением, и, особенно, в компьютерных играх.
Для работы с таким устройством прикладная программа, так или иначе, должна зарегистрировать обработчик поступающих от устройства событии. В системах Unix такая регистрация состоит в открытии устройства для чтения, а ожидание события заключается в выполнении над этим устройством операции чтения. Для последовательных устройств ввода операция чтений разблокируется, когда с устройства поступят хоть какие-то данные (а не тогда, когда будет заполнен весь буфер), поэтому, если пришло только одно событие, мы его не пропустим. Драйверы многих устройств, способных работать в качестве генераторов событий, имеют команды ioctl, позволяющие более тонко управлять условием разблокирования функции read.
Для того чтобы во время ожидания события от генератора, заниматься еще какой-то полезной работой, предлагается либо выделить ожидающий события вызов read в отдельную нить, либо пользоваться системными вызовами lect и poll, позволяющими ожидать событий на нескольких устройствах (а также средствах межпроцессного взаимодействия) одновременно.
Другие ОС предоставляют для работы с устройствами-генераторами событий более сложные механизмы, зачастую основанные на callback (дословно — "вызов назад"; механизм взаимодействия подсистем, когда подсистема, запрашивающая сервис, передает обслуживающей подсистеме указатель на функцию, которую необходимо вызвать при наступлении определенного события).
Работа с генераторами событий требует решения еще одной задачи — хранения поступающих событий в периоды, когда пользовательская программа их не успевает обрабатывать. Необходимость относительно сложных схем работы с требуемыми для этого буферами вынудила разработчиков Unix System V Release 3 ввести еще один тип драйверов — потоковые (STREAMS) [docs.sun.com 805-7478-10]. Для прикладной программы потоковый драйвер не отличается от обычного символьного устройства, но отличий с точки зрения системы довольно много. Некоторые из этих отличий будут рассматриваться далее.
Unix System V Release 3 (SCO Open Desktop, SCO OpenServer), Release (SCO UnixWare, SGI Irix, Sun Solaris) и системы, испытавшие влияние OSF Unix (IBM AIX, HP/UX) используют потоковые драйверы для реализации таких важных псевдоустройств, как трубы и сокеты TCP/IP. Кроме того, потоковыми в этих системах являются драйверы сетевых адаптеров и терминальных устройств.
С другой стороны, в OS/2 и Windows NT/2000/XP существуют обширные номенклатуры типов драйверов с различными наборами функций. Так, в OS/2 используются драйверы физических устройств следующих типов:

Многоуровневые драйверы

  Массивное тело Сабляк-Паши выглядело необычно, словно под кожей у него была одежда, а на голове, под скальпом, тюрбан. М. Павич

Нередка ситуация, когда драйвер не может осуществлять управление устройством полностью самостоятельно. Как пример можно рассмотреть драйвер лентопротяжного устройства конструктива -SCSI. Для выполнения любой операции над устройством такой драйвер должен сформировать команду или последовательность команд SCSI, передать ее устройству, дождаться ответа и проанализировать его.
Проблема здесь в том, что передача команды и получение ответа происходят при посредстве еще одного устройства, НВА. НВА могут быть разнотипными и нуждаются в собственных драйверах. Дополнительная проблема состоит в том, что к одному НВА скорее всего подключены несколько устройств, и, наверняка, большинство из них не является лентопротяжками, поэтому целесообразно выделение драйвера НВА в отдельный модуль и отдельную мониторную нить.
В системах семейства Unix драйверы целевых устройств SCSI представляют собой обычные символьные или блочные драйверы, с тем лишь отличием, что они не управляют своими устройствами непосредственно, а формируют команды драйверу НВА (рис. 10.1). Команда содержит собственно команду протокола SCSI и указатели на буферы, откуда следует взять и куда следует положить данные, передачей которых должна сопровождаться обработка команды. Передав команду драйверу НВА, драйвер целевого устройства может либо дождаться ее завершения, либо заняться чем-то другим, например обработкой следующего запроса. Во втором случае, после завершения операции НВА, будет вызван предоставленный целевым драйвером callback.

Рис. 10.1. Драйверы целевых устройств SCSI и драйвер НВА

Напротив, драйвер НВА напрямую не доступен прикладным программам (в отдельных случаях, впрочем, позволяют осуществлять над этим драйвером операции ioctl), а набор функций этого драйвера отличается от символьных и блочных устройств. Порядок инициализации таких драйверов (функции _init, attach и т. д.) в целом такой же, как и у обычных драйверов.
Как правило, драйвер имеет функцию transport (например, в Solaris эта функция называется tran_start), которая осуществляет передачу целевому устройству команды, сформированной драйвером этого устройства. Если до завершения отработки предыдущей команды поступит следующая, драйвер может либо положиться на способность целевого устройства поддерживать очередь запросов, либо, если устройство этого не умеет, реализовать очередь запросов самостоятельно.
Кроме того, драйвер адаптера производит первичный анализ пришедших ответов на команды: какой из ранее переданных команд соответствует ответ, чем завершилась операция — успехом или ошибкой, пришли ли в ответ данные и если пришли, то сколько именно и куда их положить и т. д.
После завершения обработки запроса, драйвер НВА вызывает callback драйвера целевого устройства. Эта callback-процедура может сформировать следующий запрос к адаптеру (или повторную попытку, если операция завершилась восстановимой ошибкой) либо просто оповестить пользовательский процесс о завершении операции и освободить память, занятую структурой запроса и буферами данных.
Аналогичные ситуации возникают и с другими устройствами. Например, с IBM PC-совместимыми компьютерами могут работать три основных типа устройств позиционного ввода: мыши, использующие протокол обмена, совместимый с Microsoft Mouse, мыши с протоколом Logitech, планшеты дигитайзеры с протоколом Summagraphics. Устройства всех этих, а т нескольких менее распространенных типов могут подсоединяться как нимум к четырем различным периферийным портам: специальном "мышиному" разъему PS/2, к последовательной шине USB и к послсюва тельному порту RS232, причем в качестве порта RS232, может использовать ся как один из четырех стандартных портов IBM PC, так и, например. один из выходов мультипортовой платы (рис. 10.2).

Рис. 10.2. Различные типы позиционных устройств ввода

В этом случае также целесообразно реализовать четыре самостоятельных драйвера транспортных портов (тем более что к этим портам могут подключаться и другие устройства) и три драйвера протоколов обмена, способных работать с любым транспортным портом. Объединение этих драйверов в одном модуле может создать некоторые — довольно, впрочем, сомнительные — удобства администратору системы, в которой используется стандартная комбинация порта и мыши, но поставит в безвыходное положение администратора системы, в которой комбинация нестандартная, например, не позволяя использовать мышь, подключенную к мультипортовой плате.
В современных системах семейства Unix многоэтапная обработка запросов штатно поддерживается потоковыми драйверами: система предоставляет специальные системные вызовы push и pop, позволяющие добавлять дополнительные драйверы, обслуживающие поток. Дополнительные могут преобразовывать данные потока (например, символы протокола мыши в координаты курсора и нажатия и отпускания кнопок) или обрабатывать запросы ioctl [docs.sun.com 805-7478-10].
В частности, в современных системах семейства Unix драйверы терминальных устройств должны уметь обрабатывать достаточно обширный набор запросов ioctl и выполнять ряд важных функций по управлению заданиями [Хевиленд/Грэй/Салама 2000]. В монолитных системах эти функции обязан реализовать сам драйвер устройства (хотя ядро и облегчает создателю драйвера эту работу, предоставляя библиотеку сервисных функций — см. [Максвелл 2000]), в то время как в системах, имеющих потоковые драйверы, драйвер устройства может ограничиться решением своей собственной задачи — обеспечением обмена данными с устройством, а все сложные терминальные сервисы, если это необходимо, предоставляются простым добавлением к потоку драйвера модуля терминальной дисциплины (рис. 10.3).

Рис. 10.3. Модули STREAMS

Многоуровневые драйверы в OS/2
Рассмотрим еще один подход к организации многоуровневых драйверов на примере DMD (Device Manager Driver-драйвер-менеджер класса устройств)
в OS/2 [www.ibm.com OS/2 DDK] и достаточно типичной аппаратной конфцп, рации, содержащей НВА SCSI, к которому подключены пять устройств: жесткий диск, привод CD-ROM, магнитооптический диск, лентопротяжка и сканер. riD этом каждое из устройств имеет свою специфику, так что управление ими сложно свести к общему набору функций.
Жесткий и магнитооптический диски наиболее схожи между собой, так как и то и другое является запоминающим устройством большой емкости с произволь' ным доступом. Однако жесткий диск— неудаляемое устройство, а магнитооп-тический носитель можно извлечь из привода, не выключая компьютера. Это накладывает определенные требования на стратегию кэширования соответствующего устройства и требует от драйвера способности понимать и обрабатывать аппаратный сигнал о смене устройства.
Такой сигнал следует передать модулям управления дисковым кэшем и файловой системой, которые, в свою очередь, обязаны разумно обработать его: как минимум, дисковый кэш должен объявить все связанные с диском буферы неактуальными, а менеджер файловой системы должен сбросить все свои внутренние структуры данных, связанные с удаленным диском, и объяснить всем пользовательским программам, работавшим с этим диском, что их данные пропали. Другие аспекты работы с удаляемыми носителями обсуждаются в разд. Устойчивость ФС к сбоям.
CD-ROM, в свою очередь, нельзя рассматривать как удаляемый диск, доступный только для чтения: практически все CD-ROM приводы, кроме функции считывания данных, еще имеют функцию проигрывания музыкальных компакт-дисков.
Лентопротяжка и сканер вообще не являются устройствами памяти прямого доступа, а сканер даже с самой большой натяжкой нельзя рассматривать как устройство памяти.
Когда OS/2 управляет описанной аппаратной конфигурацией, оказываются задействованы пять DMD (рис. 10.4)
OS2DASD.DMD управляет классом запоминающих устройств прямого доступа и предоставляет стандартные функции для доступа к дискам.
OPTICAL.DMD обеспечивает управление устройствами прямого доступа с удаляемыми носителями. Основная его задача — обработка аппаратного сигнала смены носителя и оповещение других модулей системы (дискового кэша, файловой системы) об этой смене.
OS2CDROM.DMD обеспечивает специфические для приводов CD-ROM функции, например проигрывание аудизаписей.
OS2SCSI.DMD OS2ASPI.DMD — эти два модуля будут описаны далее.
Каждый из этих DMD не работает непосредственно с аппаратурой, а транслирует запросы пользовательских программ и других модулей ядра (в первую очередь, менеджеров файловых систем) в запросы к драйверу нижнего уровня. Такой подход позволяет вынести общую для класса устройств логику в DMD и не заниматься повторной реализацией этой логики в каждом новом драйвере.





Дата публикования: 2014-11-18; Прочитано: 376 | Нарушение авторского права страницы | Мы поможем в написании вашей работы!



studopedia.org - Студопедия.Орг - 2014-2024 год. Студопедия не является автором материалов, которые размещены. Но предоставляет возможность бесплатного использования (0.015 с)...