Внутренние прерывания (исключения) происходят при появлении аварийной ситуации в ходе исполнения некоторой инструкции программы – ошибки программирования.
Внешние (аппаратные) прерывания возникают в результате поступления сигналов от аппаратных устройств, в том числе от системного таймера, клавиатуры и других контроллеров внешних устройств компьютера. У процессора имеется специальный вход прерывания.
Программные прерывания возникают при выполнении особой команды процессора, исполнение которой имитирует прерывание, т. е. переход на новую последовательность инструкций.
Прерываниям приписывается приоритет, с помощью которого они ранжируются по степени важности и срочности. Процедуры, вызываемые по прерываниям, обычно называют обработчиками прерываний, или процедурами обслуживания прерываний.
Диспетчеризация прерываний является важной функцией операционной системы, и эта функция реализована практически во всех мультипрограммных ОС.
Можно заметить, что в общем случае в операционной системе реализуется двухуровневый механизм планирования работ. Верхний уровень планирования выполняется диспетчером прерываний, который распределяет процессорное время между потоками поступающих запросов на прерывание различных типов – внешних, внутренних и программных. Оставшееся процессорное время распределяется другим диспетчером – диспетчером потоков, на основании дисциплин планирования потоков.
На рис. 2.1 представлены уровни приоритетов при диспетчеризации различных прерываний в операционных системах семейства Windows NT.
Рис. 2.1. Уровни приоритетов при диспетчеризации прерываний в операционных системах Windows NT
Необработанные запросы на прерывание должны храниться в контроллерах устройств, чтобы не потеряться и дожидаться обслуживания при снижении уровня приоритета прерывания процессора, когда он закончит выполнение более срочных работ.
ОсобУЮ роль в работе вычислительной системы играет системный таймер: на основании его прерываний обновляются системные часы, определяющие очередной момент вызова планировщика потоков, момент выдачи управляющего воздействия потоком реального времени (такие имеются в Windows NT) и многое другое. Ввиду важности немедленной обработки прерываний от таймера ему дан весьма высокий уровень приоритета – более высокий, чем уровень любого устройства ввода-вывода.
Программные прерывания, обслуживающие системные вызовы от приложений (АРС), выполняются с низшим приоритетом, что соответствует концепции продолжения одного и того же процесса, но только в системной фазе, при выполнении системного вызова.
А вот для программных прерываний, исходящих от модулей ядра ОС, отводится более высокий уровень запросов, имеющих название «диспетчерский / DPC». Этот уровень приоритета называется диспетчерским, потому что именно в эту очередь помещаются программные запросы, вызывающие диспетчер потоков.
2.2. Управление памятью
Особая роль памяти объясняется тем, что процессор может выполнять инструкции программы только в том случае, если они находятся в оперативной памяти компьютера. Память распределяется как между модулями прикладных программ, так и между модулями самой операционной системы. Функции распределения и защиты памяти в ОС выполняет подсистема управления памятью.
2.2.1. Адресация к памяти
Для идентификации переменных и команд на различных этапах жизненного цикла программы используются символьные имена, виртуальные адреса и физические адреса ячеек памяти.
Символьные имена присваиваются пользователем при написании программы на алгоритмическом языке.
Виртуальные адреса, называемые иногда математическими, или логическими адресами, вырабатывает транслятор, переводящий программу на машинный язык. Поскольку во время трансляции не известно, в какое место памяти будет загружена программа, то транслятор присваивает переменным и командам виртуальные (условные) адреса, обычно считая по умолчанию, что начальным адресом программы будет нулевой адрес.
Физические адреса соответствуют номерам ячеек оперативной памяти, где в действительности расположены или будут расположены переменные и команды программы.
Существуют два принципиально разных подхода к преобразованию виртуальных адресов в физические: статический и динамический.
При статическом подходе замена виртуальных адресов на физические выполняется один раз для каждого процесса во время начальной загрузки программы при помощи специального модуля – перемещающего загрузчика. При этом внутри программы меняются все адресно-зависимые указатели.
При динамическом подходе программа загружается в память в неизменном виде в виртуальных адресах, а при выполнении программы при каждом обращении к оперативной памяти выполняется преобразование виртуального адреса в физический на основании смещения адресов для данного процесса, хранящегося в специальном регистре операционной системы.
Второй способ является более гибким, т. к. программа жестко не привязана к первоначально выделенному ей участку памяти. Но первый вариант более экономичен, т. к. преобразование адресов выполняется только один раз при загрузке программы.
Совокупность виртуальных адресов процесса называется виртуальным адресным пространством, который одинаков у всех процессов системы.
Например, при использовании 32-разрядных виртуальных адресов этот диапазон 00000000 16 … FFFFFFFF 16 (232=4 Гбайт при адресации к ячейкам памяти размером 1 байт). Совпадение виртуальных адресов переменных и команд различных процессов не приводит к конфликтам, т. к. операционная система отображает их на разные физические адреса. При этом ОС отображает либо все виртуальное адресное пространство, либо только определенную его часть.
Необходимо различать максимально возможное адресное пространство процесса (потенциальное, определяемое разрядностью схем адресации) и назначенное (выделенное) процессу виртуальное адресное пространство – действительно нужное процессу для работы. В ходе выполнения процессу при необходимости может быть увеличено выделенное виртуальное адресное пространство.
Сегодня типична ситуация, когда объем виртуального адресного пространства превышает доступный объем оперативной памяти. В этом случае для хранения данных виртуального адресного пространства процесса, не помещающихся в оперативную память, используется внешняя память на жестком диске. Именно на этом принципе основана виртуальная память – современный механизм, используемый в ОС для управления памятью.
Следует отметить, что виртуально адресное пространство и виртуальная память – различные механизмы и они не обязательно реализуются в операционной системе одновременно.
Содержимое назначенного процессу виртуального адресного пространства, т. е. коды команд, исходные и промежуточные данные, а также результаты вычислений, представляют собой образ процесса.
Обычно виртуальное адресное пространство процесса делится на две непрерывные части: системную, необходимую операционной системе, и пользовательскую. Системная часть виртуального адресного пространства является идентичной для всех процессов. Поэтому при смене активного процесса заменяется только пользовательская часть. Причем системная часть виртуальной памяти в ОС любого типа включает область, подвергаемую вытеснению на диск, и область, на которое вытеснение не распространяется.
2.2.2. Классификация алгоритмов распределения памяти
На рис. 2.2 приведена классификация алгоритмов распределения памяти, в которой все они разделены на два класса – в одних используется перемещение сегментов процесса между оперативной памятью и диском, в других – не используется.
Рис. 2.2. Классификация алгоритмов распределения памяти
Распределение памяти фиксированными разделами
При применении этого алгоритма память разбивается на несколько фиксированных (не одинаковых) областей, называемых разделами. Очередной процесс, поступивший на выполнение, помещается либо в общую очередь, либо в очередь к некоторому разделу, подходящему по размерам.
При очевидном преимуществе – простоте реализации, данный метод имеет существенный недостаток – жесткость: число одновременно выполняемых процессов фиксировано и не учитываются их реальные потребности в памяти. Такой алгоритм управления памяти применялся в ранних мультипрограммных ОС, а сейчас – в системах реального времени.
Распределение памяти динамическими разделами
В этом алгоритме память заранее не делится на разделы. Каждому вновь поступающему приложению на этапе создания процесса выделяется вся необходимая ему память непрерывным разделом. После завершения процесса выделенный ему раздел памяти освобождается, и на это место может быть загружен новый процесс. Однако маловероятно, что необходимая новому процессу память точно соответствует какому-то освободившемуся разделу.
В результате этот метод имеет серьезный недостаток – фрагментацию памяти: наличие большого числа несмежных участков свободной памяти маленького размера, недостаточного ни для одного создаваемого процесса.
Перемещаемые разделы
Одним из методов борьбы с фрагментацией является перемещение всех занятых участков памяти в сторону старших или младших адресов так, чтобы вся свободная память образовала единую область. Эта процедура называется сжатием и на нее требуется достаточно много времени.
Так как программы перемещаются по оперативной памяти в ходе своего выполнения, то при применении этого алгоритма распределения памяти невозможно использовать настройку адресов с помощью перемещающего загрузчика. Здесь можно использовать только динамическое преобразование адресов.
Свопинг и виртуальная память
В мультипрограммном режиме помимо активного процесса, который исполняется процессором, имеются приостановленные процессы, находящиеся либо в состоянии ожидания, либо в состоянии готовности и стоящие в очереди к процессору. Образы таких неактивных процессов могут быть временно выгружены на диск. Когда подходит очередь выполнения выгруженного процесса, его образ возвращается с диска в оперативную память. Если в памяти нет свободного места, то на диск сбрасывается один или несколько неактивных процессов.
Подмена оперативной памяти дисковой памятью позволяет повысить уровень мультипрограммирования – объем оперативной памяти теперь не столь жестко ограничивает количество одновременно выполняемых процессов. Суммарный объем памяти, занимаемой образами этих процессов, может существенно превосходить размер физической оперативной памяти компьютера.
Виртуальным называется ресурс, который пользователю или пользовательской программе представляется обладающим свойствами, которыми он в действительности не обладает.
Виртуализация памяти может быть осуществлена на основе двух различных подходов:
свопинг – образы процессов выгружаются на диск и возвращаются в оперативную память целиком, т. е. образы процессов в каждый момент времени существуют в одном экземпляре – в оперативной памяти или на диске;
виртуальная память – между оперативной памятью и диском перемещаются части (сегменты, страницы и т. п.) образов процессов, т. е. на диске постоянно хранятся полные образы всех процессов, а в оперативной памяти – их части.
Свопинг является частным случаем виртуальной памяти и более простым в реализации способом совместного использования оперативной памяти и диска. Однако ему присуща избыточность, т. к. при подкачке с диска не весь программный код образа процесса требуется для исполнения в текущем кванте его времени. Перемещение избыточных данных замедляет работу системы и приводит к неэффективному использованию памяти. Кроме того, невозможно загрузить на выполнение процесс, адресное пространство которого превышает имеющуюся свободную память. Поэтому свопинг в современных операционных системах почти не используется, а применяется механизм виртуальной памяти.
2.2.3. Страничное распределение памяти
При применении этого алгоритма виртуальное адресное пространство каждого процесса делится на части одинакового, фиксированного для данной системы размера, называемые виртуальными страницами. В общем случае размер виртуального адресного пространства процесса не кратен размеру страницы, поэтому последняя страница каждого процесса дополняется фиктивной областью.
Вся оперативная память компьютера также делится на части такого же размера, называемые физическими страницами (блоками, кадрами), равными степени двойки: 512, 1024, 4096 байт и т. д.
При создании процесса операционная система загружает в оперативную память несколько его виртуальных страниц (начальные страницы кодового сегмента и сегмента данных).
Копия всего виртуального адресного пространства каждого процесса постоянно находится на диске.
Для каждого процесса операционная система создает таблицу страниц, содержащую записи обо всех виртуальных страницах процесса. Пример страничного распределения памяти для двух процессов приведен на рис. 2.3.
Рис. 2.3. Пример страничного распределения памяти
для двух процессов
Каждая запись страницы (дескриптор страницы) включает следующую информацию о соответствующей виртуальной странице процесса:
признак присутствия (1/0) виртуальной страницы в оперативной памяти;
номер физической страницы, в которую загружена данная виртуальная страница;
признак модификации страницы (1/0) – изменялась страница, находящаяся в памяти, или нет;
признак обращения к странице (1/0), который устанавливается 1 при каждом обращении по адресу, относящемуся к данной странице.
Информация из таблиц страниц используется для решения вопроса о необходимости перемещения той или иной страницы между памятью и диском, а также для преобразования виртуального адреса в физический.
Сами таблицы размещаются в оперативной памяти, а адрес их размещения включается в контекст соответствующего процесса. При активации очередного процесса операционная система загружает адрес его таблицы страниц в специальный регистр процессора.
При каждом обращении к памяти выполняется поиск номера виртуальной страницы, содержащей требуемый адрес, затем по этому номеру определяется нужный элемент таблицы страниц, и из него извлекается описывающая страницу информация.
По признаку присутствия определяется, надо или нет загружать страницу. Если нужная страница в данный момент выгружена на диск, то выполняется так называемое страничное прерывание – выполняющийся процесс переводится в состояние ожидания (загрузки страницы), а в это время активируется другой процесс, находившийся в очереди готовых процессов.
По номеру физической страницы выполняется преобразование виртуального адреса в физический – простота такого преобразования определяется размером страниц, кратным степени двойки (в операционных системах для процессоров Pentium компании Intel размер страниц обычно 4096 байт = 4 Кбайт).
Любой виртуальный адрес процесса состоит из двух частей: старшие разряды соответствуют номеру виртуальной страницы, а младшие – номеру ячейки в странице. Замена виртуального адреса на физический состоит в замещении старших разрядов – номер виртуальной страницы меняется на номер соответствующей физической страницы памяти.
Размер страницы влияет на производительность системы и эффективность использования памяти. Чем меньше размер страницы, тем меньше фиктивная ее часть и неиспользуемая часть кода процесса, но учащается процесс смены страниц в оперативной памяти.
Размер страниц влияет и на количество записей в таблице страниц. Учитывая, что в современных процессорах максимальный объем адресного пространства процесса, как правило, не меньше 4 Гбайт, то при размере страницы 4 Кбайт и длине записи 4 байта для хранения таблицы страниц может потребоваться до 4 Мбайт памяти.
Так как у объемных процессов таблица страниц занимает несколько страниц физической памяти, то часть из них (менее интенсивно используемых) может быть вытеснена на диск. Для этого общее виртуальное пространство страниц процесса разбивается на разделы и для каждого раздела создается собственная таблица страниц, которая занимает в памяти одну страницу (для процессоров Pentium – на 1024 записи). Информация о страницах с таблицами находится в таблице разделов, которая постоянно расположена в оперативной памяти.
Страничное распределение памяти может быть реализовано в упрощенном варианте без выгрузки страниц на диск. Все виртуальные страницы процессов находятся в памяти. В этом случае нет преимуществ, которые дает виртуальная память, зато можно успешно бороться с фрагментацией памяти, т. к. все страницы имеют фиксированные размеры, а виртуальные страницы жестко не привязаны к физическим страницам.
2.2.4. Сегментное распределение памяти
При этом методе виртуальное адресное пространство процесса делится на части – сегменты, размер которых определяется с учетом смыслового значения содержащейся в них информации. Отдельный сегмент может представлять собой подпрограмму, массив данных и т. п. «Осмысленность» сегментов упрощает их защиту.
Деление виртуального адресного пространства на сегменты осуществляется компилятором на основе указаний программиста или по умолчанию, в соответствии с принятыми в системе соглашениями.
Сегменты не упорядочиваются друг относительно друга, так что общего для сегментов линейного виртуального адреса не существует. Виртуальный адрес задается парой чисел: номером сегмента и линейным виртуальным адресом внутри сегмента.
Максимальный размер каждого сегмента при 32-разрядной организации процессора равен 4 Гбайт.
При загрузке процесса в оперативную память помещается только часть его сегментов, полная копия виртуального адресного пространства находится в дисковой памяти.
На этапе создания процесса во время загрузки его образа в оперативную память создается таблица сегментов процесса (аналогичная таблице страниц), в которой для каждого сегмента указываются:
базовый физический адрес сегмента в оперативной памяти;
размер сегмента;
правила доступа к сегменту;
признаки модификации, присутствия и обращения к данному сегменту, а также некоторая другая информация.
Достоинства сегментного распределения памяти:
если виртуальные адресные пространства нескольких процессов включают один и тот же сегмент, то в таблицах сегментов этих процессов делаются ссылки на один и тот же участок оперативной памяти, в который данный сегмент загружается в единственном экземпляре, и который в этом случае называется разделяемой памятью;
возможно задание дифференцированных прав доступа процесса к его сегментам, например, только чтение или запись.
Недостатки:
более громоздкий механизм преобразования виртуальных адресов процесса в физические. При страничной организации страницы имеют одинаковый размер, кратный степени двойки. Поэтому ОС заносит в таблицы страниц не полный адрес физической памяти, а только номер физической страницы, который одновременно представляет собой старшие разряды физического адреса любой ячейки этой страницы при преобразовании адресов. При сегментной организации сегменты могут начинаться с любого физического адреса памяти, поэтому в таблице сегментов необходимо задавать полный начальный физический адрес;
избыточность, т. к. единицей перемещения между памятью и диском является сегмент, который в общем случае больше страницы;
фрагментация памяти, которая возникает из-за непредсказуемых размеров сегментов.
Сегментно-страничное распределение памяти.
В этом методе реализуются достоинства страничного и сегментного методов распределения памяти.
Как и при сегментной организации памяти, виртуальные адресные пространства разделены на сегменты. Это позволяет определить разные права доступа к разным частям кодов и данных программ.
Однако в большинстве современных реализаций все виртуальные сегменты образуют одно непрерывное линейное виртуальное адресное пространство процесса.
Перемещение данных между памятью и диском осуществляется не сегментами, а страницами. Для этого каждый сегмент и физическая память делятся на страницы одинакового размера, что позволяет эффективно использовать память, сократив до минимума фрагментацию.
Преобразование виртуального адреса в физический адрес происходит в два этапа.
На первом этапе работают механизмы сегментации. Однако в таблице сегментов в поле базового адреса указывается не начальный физический адрес сегмента в оперативной памяти, а начальный линейный виртуальный адрес сегмента в пространстве виртуальных адресов процесса. Поэтому исходный виртуальный адрес, заданный в виде пары (номер сегмента, смещение) преобразуется в линейный виртуальный адрес.
На втором этапе работает страничный механизм, при помощи которого полученный линейный виртуальный адрес преобразуется в искомый физический адрес.
2.3. Кэширование данных
2.3.1. Иерархия запоминающих устройств в компьютере
Память компьютера представляет собой иерархию запоминающих устройств, отличающихся средним временем доступа к данным и стоимостью хранения одного бита данных (рис. 2.4).
Внешняя память (дисковая) компьютеров в настоящее время достигла объема десятков…сотен гигабайт, но скорость доступа к данным является невысокой.
Оперативная память компьютера обычно является динамической (DRAM), которая имеет среднее время доступа 10…20 нс. Для хранения данных, к которым необходимо обеспечить быстрый доступ, используется статическая оперативная память (SRAM), не требующая специальных циклов регенерации, а поэтому более быстродействующая.
Известно – чем более быстродействующая память, тем дороже ее производство. Однако пользователю хотелось бы иметь и недорогую, и быстродействующую память. Кэширование данных представляет некий компромисс в решении этой проблемы.
Рис. 2.4. Иерархия запоминающих устройств компьютера
2.3.2. Кэш-память
Кэш-память, или просто кэш (cache), – это способ совместного функционирования двух типов запоминающих устройств (ЗУ), отличающихся временем доступа и стоимостью хранения данных, который за счет динамического копирования в быстрое ЗУ наиболее часто используемых данных из медленного ЗУ позволяет уменьшить среднее время доступа к данным и экономить более дорогую быстродействующую память.
Кэш-память прозрачна для программ и пользователей. С ней работает только операционная система.
Кэш-памятью называют не только способ организации работы двух типов запоминающих устройств, но и одно из них – быстрое ЗУ.
В современных компьютерах применяют кэширование, как оперативной памяти так и диска. Рассмотрим процесс кэширования на примере кэширования оперативной памяти, которую часто называют основной памятью.
В процессе работы системы в кэш-память заносятся данные, считываемые системой из оперативной памяти при выполнении каких-либо задач. Каждая запись в кэш-памяти включает в себя:
значение элемента данных;
адрес, который этот элемент данных имеет в основной памяти;
дополнительную информацию, которая используется для реализации алгоритма замещения данных в кэше и обычно включает признак модификации (1/0) и признак действительности данных (1/0).
При каждом обращении к основной памяти просматривается содержимое кэш-памяти с целью определения, не находятся ли там нужные данные. Кэш-память не является адресуемой, поэтому поиск осуществляется по содержимому. Далее возможна одна из двух ситуаций:
если данные обнаруживаются в кэш-памяти (кэш-попадание), то они считываются из нее;
если нужные данные отсутствуют в кэш-памяти (кэш-промах), то они считываются из основной памяти и одновременно с этим копируются в кэш-память.
Понятно, что эффективность кэширования зависит от вероятности кэш-попаданий, обусловленной разными факторами: объемом кэша, объемом кэшируемой памяти, алгоритмом замещения данных в кэше и другими особенностями компьютера и вычислительного процесса. Тем не менее, в большинстве систем процент кэш-попаданий не менее 90 %.
Достигается высокая степень попаданий за счет учета пространственной и временной локальности данных.
Временная локальность: если произошло обращение по некоторому адресу, то следующее обращение по тому же адресу с большей вероятностью произойдет в ближайшее время.
Пространственная локальность: если произошло обращение по некоторому адресу, то с высокой степенью вероятности в ближайшее время произойдет обращение к соседним адресам.
В начале работы системы, когда кэш-память пуста, почти каждый запрос к оперативной памяти сопровождается кэш-промахом и копированием данных в кэш. Затем, по мере накопления кэша, в полном соответствии со свойствами временной локальности возрастает вероятность обращения к данным, которые уже были использованы ранее и имеются в кэше.
Для использования свойства пространственной локальности данных в кэш-память считывается не один информационный элемент, к которому произошло обращение, а целый блок данных, расположенных в непосредственной близости к данным этого элемента.
В процессе работы содержимое кэш-памяти постоянно обновляется, данные из нее вытесняются. Алгоритм обновления данных в кэш-памяти существенно влияет на ее эффективность. Наличие в компьютере двух копий данных – в основной памяти и в кэше – порождает проблему их согласования. Если происходит запись в основную память по некоторому адресу, а содержимое этой ячейки находится в кэше, то в результате соответствующая запись в кэше становится недостоверной.
Возможны два решения проблемы: сквозная и обратная запись.
Сквозная запись. При каждом запросе к основной памяти, в том числе и при записи, просматривается кэш. Если данные в кэше отсутствуют, то запись выполняется только в основную память. Если же данные находятся в кэше, то запись выполняется одновременно в кэш и основную память. При вытеснении данных из кэша они просто теряются.
Обратная запись. Аналогично при возникновении запроса к памяти выполняется просмотр кэша. И если данных там нет, то запись выполняется только в основную память. В противном случае производится запись только в кэш-память, при этом в описателе данных кэша делается специальная отметка (признак модификации), которая указывает на то, что при вытеснении этих данных из кэша необходимо переписать их в основную память, чтобы обновить устаревшее содержимое основной памяти.
При выполнении запросов к оперативной памяти во многих вычислительных системах используется двухуровневое кэширование. Кэш первого уровня имеет меньший объем и более высокое быстродействие, чем кэш второго уровня. Кэш второго уровня играет роль основной памяти по отношению к кэшу первого уровня.
2.3.3. Отображение основной памяти на кэш
Принцип прозрачности требует, чтобы правило отображения основной памяти на кэш-память не зависело от работы программ и пользователей. Для кэширования используются две основные схемы отображения: случайное отображение и детерминированное отображение.
При случайном отображении элемент оперативной памяти вместе со своим адресом может быть размещен в произвольном месте кэш-памяти. При каждом запросе к памяти выполняется поиск в кэше по адресу искомого элемента методом полного перебора. Так как такой поиск требует времени, то с целью ускорения его реализуют аппаратно, что удорожает кэш-память.
В такой кэш-памяти вытеснение старых записей происходит лишь при ее полном заполнении. Обычно вытесняются записи, к которым меньше всего не было обращений.
Детерминированный (прямой) способ отображения предполагает, что любой элемент основной памяти всегда отображается в одно и то же место кэш-памяти. Между номерами строк кэш-памяти и адресами основной памяти устанавливается соотношение «один ко многим»: одному номеру строки соответствует несколько адресов оперативной памяти.
Очевидно, что поиск данных в таком кэше сокращается по времени, однако вытеснение данных из кэша может происходить, когда в ней достаточно свободного места, т. к. каждая строка кэша предназначена строго для определенных адресов основной памяти.
Во многих современных процессорах кэш-память строится на основе сочетания этих двух подходов, что позволяет совместить их достоинства.
При смешанном подходе произвольный адрес оперативной памяти отображается не на один адрес кэш-памяти и не на любой адрес, а на некоторую группу адресов. Все группы пронумерованы. Поиск в кэше осуществляется вначале по номеру группы (детерминированно), а затем в пределах группы путем просмотра адресов записей. Выгрузка из группы выполняется лишь при ее переполнении по критерию меньшего обращения.
Таким образом, в данном способе комбинируется прямое отображение на группу и случайное отображение в пределах группы.
2.4. Управление вводом-выводом
Основными компонентами подсистемы ввода-вывода являются драйверы, управляющие внешними устройствами, и файловая система.
2.4.1. Контроллеры и драйверы
Каждое устройство ввода-вывода вычислительной системы – диск, принтер, монитор и т. п. – снабжено специализированным блоком управления, называемым контроллером. Контроллер взаимодействует с драйвером – системным программным модулем, предназначенным для управления данным устройством (рис. 2.5).
Рис. 2.5. Взаимодействие устройства ввода-вывода с операционной системой
Устройство, находящееся под управлением контроллера, может некоторое время выполнять свои операции автономно, не требуя внимания со стороны центрального процессора и операционной системы.
Даже самый примитивный контроллер, выполняющий простые функции, обычно тратит довольно много времени на самостоятельную работу после получения очередной команды от процессора.
Драйвер взаимодействует, с одной стороны, с модулями ядра операционной системы (модулями подсистемы ввода-вывода, модулями системных вызовов, модулями подсистемы управления процессами и памятью и т. д.), а с другой стороны – с контроллером внешних устройств. Поэтому существует два типа интерфейсов: интерфейс «драйвер – ядро» и интерфейс «драйвер – устройство».
Интерфейс «драйвер – ядро» должен быть стандартным в любом случае, а интерфейс «драйвер – устройство» имеет смысл стандартизовать, когда подсистема ввода-вывода не разрешает драйверу непосредственно взаимодействовать с аппаратурой контроллера, а выполняет эти операции самостоятельно. Драйвер в этом случае становится независимым от аппаратной платформы.
Для того, чтобы операционная система не испытывала недостатка в драйверах, необходимо наличие четкого, удобного и открытого интерфейса между драйверами и другими компонентами операционной системы. Это важно для того, чтобы драйверы писали не только разработчики ОС, но и производители внешних устройств.
Многослойное построение программного обеспечения, характерное для ОС вообще, оказывается особенно естественным и полезным при построении подсистем ввода-вывода. При большом разнообразии устройств ввода-вывода иерархическая структура программного обеспечения позволяет соблюсти баланс между двумя противоречивыми требованиями: с одной стороны, необходимо учесть все особенности каждого устройства, а с другой стороны, обеспечить единое логическое представление и унифицированный интерфейс для устройств всех типов.
При этом нижние слои подсистемы ввода-вывода должны включать индивидуальные драйверы, написанные для конкретных физических устройств, а верхние слои должны обобщать процедуры управления этими устройствами, представляя общий интерфейс если не для всех устройств, то, по крайней мере, для групп устройств, обладающих некоторыми общими характеристиками, например, для принтеров определенного производителя или для всех матричных принтеров и т. п.
Первоначально под драйвером понимался программный модуль, который:
входит в состав ядра операционной системы, работая в привилегированном режиме;
непосредственно управляет внешним устройством, взаимодействуя с его контроллером с помощью команд ввода-вывода компьютера;
обрабатывает прерывания от контроллера устройства;
предоставляет прикладному программисту удобный логический интерфейс работы с устройством, экранируя от него низкоуровневые детали управления устройством и организации его данных;
взаимодействует с ядром операционной системы с помощью строго оговоренного интерфейса, описывающего формат передаваемых данных, структуру буферов, способы включения драйвера в состав ОС, способы вызова драйвера, набор общих процедур подсистемы ввода-вывода, которыми драйвер может пользоваться, и т. п.
По мере развития операционных систем наряду с традиционными драйверами в операционной системе появились так называемые высокоуровневые драйверы, которые располагаются в общей модели подсистемы ввода-вывода над традиционными драйверами.
Традиционные драйверы, которые стали называться аппаратными драйверами, низкоуровневыми драйверами или драйверами устройств, освобождаются от высокоуровневых функций и занимаются только низкоуровневыми операциями.
Высокоуровневые драйверы оформляются по тем же правилам, что и аппаратные драйверы. Единственным отличием является то, что высокоуровневые драйверы, как правило, не вызываются по прерываниям, т. к. взаимодействуют с управляемым устройством через посредничество аппаратных драйверов.
Разделение на аппаратные и высокоуровневые драйверы можно продемонстрировать на примере подсистемы сетевых устройств. Аппаратными драйверами у них являются драйверы сетевых адаптеров, которые выполняют функции низкоуровневых канальных протоколов (Ethernet, Frame Relay, ATM и др.). Эти драйверы выполняют простые функции – организуют передачу кадров данных между компьютерами одной физической сети.
Над ними располагается слой модулей (драйверов), которые реализуют функции более интеллектуальных сетевых протоколов (IP, IPX), которые могут обеспечить межсетевое взаимодействие. Над слоем драйверов сетевых протоколов располагается слой драйверов транспортных протоколов (TCP, UDP, SPX и др.). Еще выше располагается слой драйверов прикладного уровня, которые предоставляют пользователям сети конечные услуги по доступу к ресурсам сети.
В подсистеме управления дисками аппаратные драйверы поддерживают для верхних уровней представление диска как последовательного набора блоков одинакового размера (наиболее часто размером 512 байт), преобразуя вместе с контроллером номер блока в более сложный адрес, состоящий из номеров цилиндра, головки и сектора.
Однако такие понятия как «файл» и «файловая система», аппаратные драйверы дисков не поддерживают – эти удобные для пользователя абстракции создаются на более высоком уровне программным обеспечением файловых систем, которые в современных ОС также оформляются как драйвер, только высокоуровневый.
Для унификации представления различных файловых систем в подсистеме ввода-вывода может использоваться общий драйвер верхнего уровня, играющий роль диспетчера нескольких драйверов файловых систем. На рис. 2.6 в качестве примера показана структура драйверов дисковой подсистемы, реализованная в диспетчере VFS (Virtual File System), применяемом в операционных системах UNIX.
Рис. 2.6. Пример многослойной структуры драйверов дисковой подсистемы
Разнообразие устройств ввода-вывода делает особенно актуальной функцию операционной системы по созданию экранирующего логического интерфейса между периферийными устройствами и приложениями. Практически все ОС поддерживают в качестве основного такого интерфейса файловую модель периферийных устройств, когда любое устройство выглядит для прикладного программиста последовательным набором байт, с которым можно работать с помощью унифицированных системных вызовов (например, read и write), задавая имя файла-устройства и смещение от начала последовательности байт.
В подсистемах ввода-вывода для согласования скоростей обмена широко используется буферизация данных в оперативной памяти. Однако буферизация только на основе оперативной памяти оказывается недостаточной – разница между скоростью обмена с оперативной памятью, куда процессы помещают данные для обработки, и скоростью работы внешнего устройства часто становится слишком значительной, чтобы в качестве временного буфера использовать оперативную память – ее может просто не хватить. Для таких случаев часто используют в качестве буфера дисковый файл, называемый спул-файлом.
Типичным примером спулинга является организация вывода данных на принтер. Другим решением этой проблемы является использование большой буферной памяти в контроллерах внешних устройств.
2.4.2. Организация внешней памяти на магнитных дисках
Для организации внешней памяти используются недорогие, но достаточно быстродействующие и емкие устройства с прямым доступом к данным – накопители на жестких магнитных дисках (НЖМД) или просто диски. Дисковая подсистема для большинства компьютеров является одной из важных, поэтому рассмотрим ее подробнее. Именно на магнитных дисках чаще всего располагается загружаемая в компьютер ОС, которая и обеспечивает удобный интерфейс для работы.
Из оперативной памяти в НЖМД и обратно данные передаются байтами, а вот записываются непосредственно на диск и считываются с него они уже последовательно (побитно). Из-за того, что запись и считывание бита данных не является абсолютно надежными операциями, данные перед записью кодируЮтся с достаточно большой избыточностью. Для этой цели применяют коды Рида–Соломона.
Избыточное кодирование информационных данных позволяет не только обнаруживать ошибки, но и автоматически исправлять их. Следовательно, перед тем как данные, считанные с поверхности диска, будут переданы в оперативную память, их нужно предварительно обработать – декодировать. На эту операцию необходимо некоторое время, за которое диск успевает повернуться на некоторый угол.
Поэтому на диске данные хранятся порциями – кодовыми блоками, имеющими информационную часть и некоторую проверочную часть. Эти блоки называют секторами (sectors), имеющими стандартизованный размер информационной части 512 байт.
При фиксированном положении головки секторы образуют дорожку (трек – track). Дорожки и секторы создаются в результате выполнения процедуры физического или низкоуровневого форматирования диска, предшествующего использованию диска (при производстве диска).
Группы дорожек одного радиуса, расположенные на поверхностях дисков образуют цилиндры (cylinders). Выбор конкретной дорожки в цилиндре осуществляется указанием головки (head) записи-считывания. Таким образом, адрес конкретного блока данных ранее указывался с помощью трех координат C - H - S – номеров цилиндра, головки и сектора (рис. 2.7).
Рис. 2.7. Структура размещения данных на диске
Сейчас применяют другой метод адресации, при котором все секторы просто пронумерованы – спецификация LBA (Logical Block Addressing).
Для структуризации данных на магнитном диске полезно поделить все дисковое пространство на разделы (partitions). Такое деление позволяет организовать на одном физическом устройстве несколько логических устройств (логических дисков). Причем на каждом разделе может быть организована своя файловая система.
Если на компьютере необходимо иметь несколько операционных систем, то каждую ОС желательно устанавливать в разные разделы, а, например, операционной системе Linux нужно иметь не менее двух разделов, поскольку файл подкачки (страничный файл) должен располагаться в отдельном разделе.
Структура данных, несущая информацию о логической организации диска, вместе с небольшой программой, с помощью которой можно ее проанализировать, а также найти и загрузить в оперативную память программу загрузки ОС, получила название главной загрузочной записи (Master Boot Record, MBR).
MBR располагается в самом первом секторе диска, т. е. в секторе с координатами 0-0-1. Программа, расположенная в MBR, носит название внесистемного загрузчика.
Так как сектор состоит всего из 512 байт и кроме программы в нем должна располагаться информация об организации диска, то внесистемный загрузчик прост, а структура данных, называемая таблицей разделов (Partition Table), занимает всего 64 байт. Таблица разделов содержит всего четыре элемента (строки) по 16 байт.
Каждый элемент таблицы описывает один раздел двумя способами: через координаты C - H - S начального и конечного секторов, а также через номер первого сектора в спецификации LBA и общее число секторов в разделе (табл. 2.1).
|
Таблица 2.1
|
Формат элемента таблицы разделов
|
Название записи элемента таблицы разделов
|
Длина, байт
|
Флаг активности раздела
|
1
|
Номер головки начала раздела
|
1
|
Номер сектора и цилиндра загрузочного сектора раздела
|
2
|
Кодовый идентификатор операционной системы
|
1
|
Номер головки конца раздела
|
1
|
Номер сектора и цилиндра последнего сектора раздела
|
2
|
Младшие и старшие двухбайтовые слова относительного номера начального сектора по спецификации LBA
|
4
|
Младшие и старшие двухбайтовые слова размера раздела в секторах
|
4
|
Активным (128(80 h) – активен, 0 – не активен) может быть только один раздел – он является системным загрузчиком, и процесс загрузки ОС осуществляется путем загрузки его первого сектора и передачи управления на расположенную в нем программу, которая и продолжает загрузку.
Кодовый идентификатор операционной системы указывает на принадлежность данного раздела к той или иной ОС и на установку в этом разделе соответствующей файловой системы.
Если таблица разделов повреждена, то не будет загружаться ни одна установленная на компьютере операционная система.
Разделы диска могут быть двух типов: первичные и расширенные.
Первичные (primary), или простейшие (примитивные), разделы нельзя разбить на логические диски. Поэтому, если создавать только первичные разделы, то их будет всего четыре. И только один из них может быть активным. Причем для DOS -систем, Windows 9 x и еще некоторых операционных систем остальные первичные разделы в этом случае считаются невидимыми. Поэтому с помощью DOS утилиты fdisk можно создать только один первичный раздел.
Расширенный (extended) раздел на диске может быть только один, но его можно разбить на большое количество логических дисков (рис. 2.8).
Рис. 2.8. Пример разбиения диска на разделы
Расширенный раздел содержит вторичную запись MBR (Secondary MBR, SMBR), в состав которой вместо таблицы разделов входит аналогичная ей таблица логических дисков. Эта таблица описывает размещение и характеристики единственного логического диска, а также может указывать на следующую запись SMBR (следующего логического диска) и т. д.
Важно отметить, что каждый раздел начинается с первого сектора на заданных цилиндре и поверхности (головке) и имеет размер не менее одного цилиндра.
Поэтому на нулевой дорожке нулевой поверхности кроме первого сектора с MBR остальные секторы не используются.
В настоящее время для формирования таблиц разделов кроме уже упоминавшейся утилиты fdisk широко используются другие программы с графическим интерфейсом, в частности –
|