Управление вводом-выводом в операционных системах
ОГЛАВЛЕНИЕ
ВВЕДЕНИЕ 3
1. ФИЗИЧЕСКАЯ ОРГАНИЗАЦИЯ УСТРОЙСТВ ВВОДА-ВЫВОДА 4
2. ОРГАНИЗАЦИЯ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ ВВОДА-ВЫВОДА 6
3. ОБРАБОТКА ПРЕРЫВАНИЙ 8
4. ДРАЙВЕРЫ УСТРОЙСТВ 10
4.1. Блочные драйверы 11
4.2. Символьные драйверы 12
4.3. Потоковые драйверы 12
4.4. Независимый от устройств слой операционной системы 13
4.5. Пользовательский слой программного обеспечения 14
5. ПРИНЦИПЫ СИСТЕМНОЙ БУФЕРИЗАЦИИ ВВОДА/ВЫВОДА 15
6. СИСТЕМНЫЕ ВЫЗОВЫ ДЛЯ УПРАВЛЕНИЯ ВВОДОМ/ВЫВОДОМ 17
7. СИНХРОННЫЙ И АСИНХРОННЫЙ ВВОД-ВЫВОД 21
7.1. Синхронный ввод-вывод 21
7.2. Асинхронный ввод-вывод 22
ЗАКЛЮЧЕНИЕ 24
СПИСОК
ЛИТЕРАТУРЫ 25
ВВЕДЕНИЕ
Одна из важнейших функций операционной системы состоит в управлении всеми ввода/вывода компьютера. Любые операции по управлению ввода-вывода выполняются только кодам самой операционной системой, для обеспечения этого принципа вводятся режимы пользователя и супервизор.
Операционная система должна давать этим устройствам команды, перехватывать прерывания и обрабатывать ошибки. Она должна также обеспечить простой и удобный интерфейс между устройствами и остальной частью системы. Интерфейс, насколько это возможно, быть одинаковым для всех устройств (для достижения независимости от меняемого оборудования). Программное обеспечение ввода/вывода составляет существенную часть операционной системы. Программное обеспечение вода может быть структурировано в виде уровней, каждому из которых строго очерченный круг задач.
Традиционно в ОС выделяются три типа организации ввода/вывода и, соответственно, три типа драйверов. Блочный ввод/вывод главным образом предназначен для работы с каталогами и обычными файлами файловой системы, которые на базовом уровне имеют блочную структуру
Символьный ввод/вывод служит для прямого (без буферизации) выполнения обменов между адресным пространством пользователя и соответствующим устройством. Общей для всех символьных драйверов поддержкой ядра является обеспечение функций пересылки данных между пользовательскими и ядерным адресными пространствами.
Потоковый
ввод/вывод похож на символьный ввод/вывод,
но по причине наличия возможности
включения в поток
- ФИЗИЧЕСКАЯ ОРГАНИЗАЦИЯ УСТРОЙСТВ ВВОДА-ВЫВОДА
Устройства ввода-вывода делятся на два типа: блок-ориентированные устройства и байт-ориентированные устройства. Блок-ориентированные устройства хранят информацию в блоках фиксированного размера, каждый из которых имеет свой собственный адрес. Самое распространенное блок-ориентированное устройство - диск. Байт-ориентированные устройства не адресуемы и не позволяют производить операцию поиска, они генерируют или потребляют последовательность байтов. Примерами являются терминалы, строчные принтеры, сетевые адаптеры. Однако некоторые внешние устройства не относятся ни к одному классу, например, часы, которые, с одной стороны, не адресуемы, а с другой стороны, не порождают потока байтов. Это устройство только выдает сигнал прерывания в некоторые моменты времени.
Внешнее
устройство обычно состоит из механического
и электронного компонента. Электронный
компонент называется контроллером
устройства или адаптером. Механический
компонент представляет собственно
устройство. Некоторые контроллеры
могут управлять несколькими
устройствами. Если интерфейс между
контроллером и устройством стандартизован,
то независимые производители
Операционная система обычно имеет дело не с устройством, а с контроллером. Контроллер, как правило, выполняет простые функции, например, преобразует поток бит в блоки, состоящие из байт, и осуществляют контроль и исправление ошибок. Каждый контроллер имеет несколько регистров, которые используются для взаимодействия с центральным процессором. В некоторых компьютерах эти регистры являются частью физического адресного пространства. В таких компьютерах нет специальных операций ввода-вывода. В других компьютерах адреса регистров ввода-вывода, называемых часто портами, образуют собственное адресное пространство за счет введения специальных операций ввода-вывода (например, команд IN и OUT в процессорах i86).
ОС
выполняет ввод-вывод, записывая
команды в регистры контроллера.
Например, контроллер гибкого диска
IBM PC принимает 15 команд, таких как READ,
WRITE, SEEK, FORMAT и т.д. Когда команда
принята, процессор оставляет контроллер
и занимается другой работой. При
завершении команды контроллер организует
прерывание для того, чтобы передать
управление процессором операционной
системе, которая должна проверить
результаты операции. Процессор получает
результаты и статус устройства, читая
информацию из регистров контроллера.
- ОРГАНИЗАЦИЯ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ ВВОДА-ВЫВОДА
Основная идея организации программного обеспечения ввода-вывода состоит в разбиении его на несколько уровней, причем нижние уровни обеспечивают экранирование особенностей аппаратуры от верхних, а те, в свою очередь, обеспечивают удобный интерфейс для пользователей.
Ключевым принципом является независимость от устройств. Вид программы не должен зависеть от того, читает ли она данные с гибкого диска или с жесткого диска.
Очень близкой к идее независимости от устройств является идея единообразного именования, то есть для именования устройств должны быть приняты единые правила.
Другим важным вопросом для программного обеспечения ввода-вывода является обработка ошибок. Вообще говоря, ошибки следует обрабатывать как можно ближе к аппаратуре. Если контроллер обнаруживает ошибку чтения, то он должен попытаться ее скорректировать. Если же это ему не удается, то исправлением ошибок должен заняться драйвер устройства. Многие ошибки могут исчезать при повторных попытках выполнения операций ввода-вывода, например, ошибки, вызванные наличием пылинок на головках чтения или на диске. И только если нижний уровень не может справиться с ошибкой, он сообщает об ошибке верхнему уровню.
Еще один ключевой вопрос - это использование блокирующих (синхронных) и неблокирующих (асинхронных) передач. Большинство операций физического ввода-вывода выполняется асинхронно - процессор начинает передачу и переходит на другую работу, пока не наступает прерывание. Пользовательские программы намного легче писать, если операции ввода-вывода блокирующие - после команды READ программа автоматически приостанавливается до тех пор, пока данные не попадут в буфер программы. ОС выполняет операции ввода-вывода асинхронно, но
представляет их для пользовательских программ в синхронной форме.
Последняя проблема состоит в том, что одни устройства являются
разделяемыми, а другие - выделенными. Диски - это разделяемые устройства, так как одновременный доступ нескольких пользователей к диску не представляет собой проблему. Принтеры - это выделенные устройства, потому что нельзя смешивать строчки, печатаемые различными пользователями. Наличие выделенных устройств создает для операционной системы некоторые проблемы.
Для
решения поставленных проблем целесообразно
разделить программное
- Обработка прерываний,
- Драйверы устройств,
- Независимый от устройств слой операционной системы,
- Пользовательский слой программного обеспечения.
Рис. 1. Многоуровневая организация подсистемы ввода-вывода
- ОБРАБОТКА ПРЕРЫВАНИЙ
Прерывания
должны быть скрыты как можно глубже
в недрах операционной системы, чтобы
как можно меньшая часть ОС
имела с ними дело. Наилучший способ
состоит в разрешении процессу, инициировавшему
операцию ввода-вывода, блокировать
себя до завершения операции и наступления
прерывания. Процесс может блокировать
себя, используя, например, вызов DOWN для
семафора, или вызов WAIT для переменной
условия, или вызов RECEIVE для ожидания
сообщения. При наступлении прерывания
процедура обработки прерывания
выполняет разблокирование
USB-Unit Control Block – блок управления устройств ввода-вывода.
Рис
2. Процесс управление вводом-выводом в
ОС
- ДРАЙВЕРЫ УСТРОЙСТВ
Весь зависимый от устройства код помещается в драйвер устройства. Каждый драйвер управляет устройствами одного типа или, может быть, одного класса.
В операционной системе только драйвер устройства знает о конкретных особенностях какого-либо устройства. Например, только драйвер диска имеет дело с дорожками, секторами, цилиндрами, временем установления головки и другими факторами, обеспечивающими правильную работу диска.
Драйвер устройства принимает запрос от устройств программного слоя и решает, как его выполнить. Типичным запросом является чтение n блоков данных. Если драйвер был свободен во время поступления запроса, то он начинает выполнять запрос немедленно. Если же он был занят обслуживанием другого запроса, то вновь поступивший запрос присоединяется к очереди уже имеющихся запросов, и он будет выполнен, когда наступит его очередь.
Первый шаг в реализации запроса ввода-вывода, например, для диска, состоит в преобразовании его из абстрактной формы в конкретную. Для дискового драйвера это означает преобразование номеров блоков в номера цилиндров, головок, секторов, проверку, работает ли мотор, находится ли головка над нужным цилиндром. Короче говоря, он должен решить, какие операции контроллера нужно выполнить и в какой последовательности.
После передачи команды контроллеру драйвер должен решить, блокировать ли себя до окончания заданной операции или нет. Если операция занимает значительное время, как при печати некоторого блока данных, то драйвер блокируется до тех пор, пока операция не завершится, и обработчик прерывания не разблокирует его. Если команда ввода-вывода выполняется быстро (например, прокрутка экрана), то драйвер ожидает ее завершения без блокирования.
Буферизация также является важным вопросом как для блочных, так и для символьных устройств по самым разным причинам. Для блочных устройств аппаратное обеспечение обычно требует того, чтобы чтение или запись производились большими блоками. Но для пользовательских программ такого ограничения нет, и они вправе передавать любые объемы информации. Поэтому, если пользователь передал только половину блока, операционная система обычно не станет сразу записывать эти данные на диск, а дождется того, когда будет передана оставшаяся часть блока. Что касается символьных устройств, то пользователь может передавать данные быстрее, чем устройство в состоянии их воспринять, таким образом, также необходима буферизация. Не исключено также, что данные, например, от клавиатуры, могут опережать свое считывание, и в этом случае также не обойтись без буфера.
- Блочные драйвер
Блочные
драйверы предназначаются для
В случае, если копия требуемого блока не находится в буферном пуле или если по какой-либо причине требуется заменить содержимое некоторого обновленного буфера, ядро ОС UNIX обращается к процедуре strategy соответствующего блочного драйвера. Strategy обеспечивает стандартный интерфейс между ядром и драйвером. С использованием библиотечных подпрограмм, предназначенных для написания драйверов, процедура strategy может организовывать очереди обменов с устройством, например, с целью оптимизации движения магнитных головок на диске. Все обмены, выполняемые блочным драйвером, выполняются с буферной памятью. Перепись нужной информации в память соответствующего пользовательского процесса производится программами ядра, заведующими управлением буферами.
- Символьные драйверы
Символьные драйверы главным образом предназначены для обслуживания устройств, обмены с которыми выполняются посимвольно, либо строками символов переменного размера. Типичным примером символьного устройства является простой принтер, принимающий один символ за один обмен.
Символьные драйверы не используют системную буферизацию. Они напрямую копируют данные из памяти пользовательского процесса при выполнении операций записи или в память пользовательского процесса при выполнении операций чтения, используя собственные буфера.
Следует
отметить, что имеется возможность
обеспечить символьный интерфейс для
блочного устройства. В этом случае
блочный драйвер использует дополнительные
возможности процедуры
- Потоковые драйверы
Основным назначением механизма потоков (streams) является повышение уровня модульности и гибкости драйверов со сложной внутренней логикой (более всего это относится к драйверам, реализующим развитые сетевые протоколы). Спецификой таких драйверов является то, что большая часть программного кода не зависит от особенностей аппаратного устройства. Более того, часто оказывается выгодно по-разному комбинировать части программного кода.
Все
это привело к появлению
- Независимый от устройств слой операционной системы
Большая часть программного обеспечения ввода-вывода является независимой от устройств. Точная граница между драйверами и независимыми от устройств программами определяется системой, так как некоторые функции, которые могли бы быть реализованы независимым способом, в действительности выполнены в виде драйверов для повышения эффективности или по другим причинам.
Типичными функциями для независимого от устройств слоя являются:
- обеспечение общего интерфейса к драйверам устройств,
- именование устройств,
- защита устройств,
- обеспечение независимого размера блока,
- буферизация,
- распределение памяти на блок-ориентированных устройствах,
- распределение и освобождение выделенных устройств,
- уведомление об ошибках.
Остановимся на некоторых функциях данного перечня. Верхним слоям программного обеспечения не удобно работать с блоками разной величины, поэтому данный слой обеспечивает единый размер блока, например, за счет объединения нескольких различных блоков в единый логический блок. В связи с этим верхние уровни имеют дело с абстрактными устройствами, которые используют единый размер логического блока независимо от размера физического сектора.
При создании файла или заполнении его новыми данными необходимо выделить ему новые блоки. Для этого ОС должна вести список или битовую карту свободных блоков диска. На основании информации о наличии свободного места на диске может быть разработан алгоритм поиска свободного блока, независимый от устройства и реализуемый программным слоем, находящимся выше слоя драйверов.
Основная задача независимого от устройств программного обеспечения
заключается в выполнении функций ввода/вывода, общих для всех устройств, и предоставлении единообразного интерфейса для программ уровня пользователя.
4.5. Пользовательский слой программного обеспечения
Хотя
большая часть программного обеспечения
ввода-вывода находится внутри ОС, некоторая
его часть содержится в библиотеках,
связываемых с
count = write (fd, buffer, nbytes),
то библиотечная процедура write будет связана с программой. Набор подобных процедур является частью системы ввода-вывода. В частности, форматирование ввода или вывода выполняется библиотечными процедурами. Примером может служить функция printf языка С, которая принимает строку формата и, возможно, некоторые переменные в качестве входной информации, затем строит строку символов ASCII и делает вызов write для вывода этой строки. Стандартная библиотека ввода-вывода содержит большое число процедур, которые выполняют ввод-вывод и работают как часть пользовательской программы.
Другой категорией программного обеспечения ввода-вывода является подсистема спулинга (spooling). Спулинг – это способ работы с выделенными устройствами в мультипрограммной системе. Рассмотрим типичное устройство, требующее спулинга – строчный принтер. Вместо этого создается специальный процесс – монитор, который получает исключительные права на использование этого устройства. Также создается специальный каталог, называемый каталогом спулинга. Для того, чтобы напечатать файл, пользовательский процесс помещает выводимую информацию в этот файл и помещает его в каталог спулинга. Процесс-монитор по очереди распечатывает все файлы, содержащиеся в каталоге спулинга.
- ПРИНЦИПЫ СИСТЕМНОЙ БУФЕРИЗАЦИИ ВВОДА/ВЫВОДА
Традиционным способом снижения накладных расходов при выполнении обменов с устройствами внешней памяти, имеющими блочную структуру, является буферизация блочного ввода/вывода. Это означает, что любой блок устройства внешней памяти считывается прежде всего в некоторый буфер области основной памяти, называемой в ОС UNIX системным кэшем, и уже оттуда полностью или частично (в зависимости от вида обмена) копируется в соответствующее пользовательское пространство.
Принципами
организации традиционного
Эта традиционная схема буферизации вошла в противоречие с развитыми в современных вариантах ОС UNIX средствами управления виртуальной памятью и в особенности с механизмом отображения файлов в сегменты виртуальной памяти (см. пп. 2.4.5 и 3.1.2). (Мы не будем подробно объяснять здесь суть этих противоречий и предложим читателям поразмышлять над этим.) Поэтому в System V Release 4 появилась новая схема буферизации, пока используемая параллельно со старой схемой.
Суть новой схемы состоит в том, что на уровне ядра фактически воспроизводится механизм отображения файлов в сегменты виртуальной памяти. Во-первых, напомним о том, что ядро ОС UNIX действительно работает в собственной виртуальной памяти. Эта память имеет более сложную, но принципиально такую же структуру, что и пользовательская виртуальная память. Другими словами, виртуальная память ядра является сегментно-страничной, и наравне с виртуальной памятью пользовательских процессов поддерживается общей подсистемой управления виртуальной памятью. Из этого следует, во-вторых, что практически любая функция, обеспечиваемая ядром для пользователей, может быть обеспечена одними компонентами ядра для других его компонентов. В частности, это относится и к возможностям отображения файлов в сегменты виртуальной памяти.
Новая
схема буферизации в ядре ОС UNIX
главным образом основывается на
том, что для организации
- СИСТЕМНЫЕ ВЫЗОВЫ ДЛЯ УПРАВЛЕНИЯ ВВОДОМ/ВЫВОДОМ
Для
доступа (т.е. для получения возможности
последующего выполнения операций ввода/вывода)
к файлу любого вида (включая специальные
файлы) пользовательский процесс должен
выполнить предварительное
Последовательность действий системного вызова open (pathname, mode) следующая:
- анализируется непротиворечивость входных параметров (главным образом, относящихся к флагам режима доступа к файлу);
- выделяется или находится пространство для описателя файла в системной области данных процесса (u-области);
- в общесистемной области выделяется или находится существующее пространство для размещения системного описателя файла (структуры file);
- производится поиск в архиве файловой системы объекта с именем "pathname" и образуется или обнаруживается описатель файла уровня файловой системы (vnode в терминах UNIX V System 4);
- выполняется связывание vnode с ранее образованной структурой file.