Академический Документы
Профессиональный Документы
Культура Документы
ВУДХАЛЛ
ОПЕРАЦИОННЫЕ
СИСТЕМЫ
Разработка и реализация
3-е издание
�nnTEP®
Москва· Санкт-Петербург· Нижний Новгород· Воронеж
Новосибирск Ростов-на-Дону Екатеринбург Самара
• • •
2007
ББК 3 2.973-018. 2
УДК 004.451
Т18
ISBN 978-5-469-01403-4
5-469-01403-7
Третье издание классического труда Эндрю Таненбаума «Operating Systems: Design and
Implementation» - это единственный в своем роде учебник, в котором успешно сочетаются теория
и практика построения операционных систем. В книге подробно описываются процессы и
межпроцессное взаимодействие, семафоры, мониторы, передача сообщений, алгоритмы работы
планировщика, ввод/вывод, разрешение тупиковых ситуаций, драйверы устройств, алгоритмы
управления памятью, разработка файловых систем, а также затрагиваются вопросы
безопасности и защиты данных. В то же время обсуждается конкретная UNIХ-совместимая
операционная система MINIX и приводится ее исходный код (вы найдете его на компакт-диске).
Это позволяет не только изучать основополагающие принципы, но и наблюдать их применение
в реальных операционных системах.
ББК 3 2.973-018. 2
УДК 004.451
Информация, содержащаяся в данной книге, получена из источников, рассматриваемых иэдатепьством как надежные Тем не менее,
имея в виду возможные человеческие или технические ошибки, издательство не может гарантировать абсолютную точность и полноту
приводимых сведений и не несет ответственности за возможные ошибки, связанные с использованием книги
Об авторах . 11
П редисловие 14
Глава 1 . Введение 18
Глава 2 . Процессы 78
Глава 3 . Ввод-вывод 252
Глава 4 . Управление памят ью 41 4
Глава 5 . Файловые системы 530
Глава 6 . Библиографи я . . . 669
Приложение А. Установка MI N IX 3 683
Приложение Б. С писок файлов MI N IX 3 на компакт-диске 69 1
Алфавитн ы й указател ь 694
Ком п акт-диск MINIX 3 . 703
Соде рж а н и е
Об авторах 11
Предисловие 14
От издателя перевода . . . . 17
Глава 1 . Введение . . 18
1 . 1 . Понятие операционной системы 21
1 . 1 . 1 . Операционная система как расширенная машина 21
1 . 1 .2. Операцион ная система как менеджер ресурсов . 22
1 .2. История развития операционных систем . . . . . . . . 24
1 .2. 1 . Первое поколение ( 1 945-1 955): электронные лампы и коммутационные панели 24
1 .2.2. Второе поколение ( 1955-1 965): транзисторы и системы пакетной обработки 25
1 .2.3. Третье поколение ( 1 965-1 980): интегральные схемы и многозадачность 27
1 .2.4. Четвертое поколение (с 1 980 года по наши дни): персональные компьютеры 33
1 .2.5. История MINIX 3 . 35
1 .3. Основные концепции 39
1 .3. 1 . Процессы 40
1 .3.2. Файлы . . . . 42
1 .3.3. Оболочка . . 46
1 .4. Системные вызовы 47
1 .4. 1 . Системные вызовы для управления процессами 50
1 .4.2. Системные вызовы для управления сигналами . 53
1 .4.3. Системные вызовы для управления файлами . . 55
1 .4.4. Системные вызовы для управления каталогами 60
1 .4.5. Системные вызовы для защиты . . . . . . . . 63
1 .4.6. Системные вызовы для управления временем 64
1 .5. Структура операционной систем ы . 65
1 .5. 1 . Монолитные системы . . . 65
1 .5.2. Многоуровневые системы . 67
1 .5.3. Виртуальные машины . 69
1 .5.4. Экзоядра . . . . . . . . 72
1 .5.5. Модель клиент-сервер . 72
1.6. Краткий обзор остальных глав . 74
Резюме . . . . . . . . 75
Вопросы и задания 75
Глава 2. Процессы . . 78
2.1 . Знакомство с процессами . 78
2.1.1 . Модель процессов 78
2. 1 .2. Создание процессов 80
2.1 .3. Завершение процессов 82
2. 1 .4. Иерархии процессов . 83
2. 1 .5. Состояния процессов . 84
2.1 .6. Реализация процессов 86
2. 1 .7. Программные потоки . 88
2.2. Взаимодействие между процессами 92
2.2. 1 . Гонки . . . . . . . . . . . . 93
Содержание 7
Texty за лучший учебник. А в 2005 году Э. Таненбаум стал одним из пяти новых
профессоров Королевской Академии ( Royal Acaderny). Его домашняя страница
в Интернете расположена по адресу http://www . cs .vu . nl/-ast/.
Альберт Вудхалл (Albert S. Woodhull) получил степень бакалавра в Массачу
сетсском технологическом университете и степень доктора в университете Ва
шингтона. Поступив в Массачусетсский институт, чтобы стать электротехником,
он окончил его как биолог. Сам себя он называет �ученым, неплохо разбираю
щимся в технике•. Более 20 лет он был преподавателем Школы естественных
наук Хэмпширского колледжа, Массачусетс, преподавая параллельно в несколь
ких других колледжах и университетах. Как биолог, пользующийся электрон
ным оборудованием, он начал работать с микрокомпьютерами, когда они стали
доступными. Его технические курсы для студентов развились в лекции, посвя
щенные взаимодействию и программированию задач реального времени.
Доктор Вудхалл всегда испытывал большой интерес к преподаванию и к вопро
сам влияния науки и технологии на производство. Перед поступлением в аспи
рантуру он в течение двух лет преподавал естественные науки в Нигерии. Позже
он потратил несколько своих отпусков на обучение студентов вычислительной
технике в Никарагуа, в Universidad Nacional de Ingenieria и Universidad Nacional
Autonorna de Nicaragua.
В сферу его интересов входят компьютеры как электронные системы и взаимо
действие компьютеров с другими электронными системами. Он особенно насла
ждается преподаванием архитектуры вычислительной техники, операционных
систем и компьютерных коммуникаций, программирования на языке ассемблер.
А. Вудхалл также работал консультантом по разработке электронного оборудо
вания и связанного с ним программного обеспечения, а также системным адми
нистратором.
Помимо этого у него немало других, не академических интересов, включая спор
тивные игры на открытом воздухе, радиолюбительство и чтение. Он любит путеше
ствовать и изучать другие языки помимо родного английского. Вудхалл являет
ся пользователем и горячим сторонником системы MINIX. Его страничка в Сети
управляется MINIX и располагается по адресу http://minix1 . ham psh ire.edu/asw/.
Сюзанне, Барбаре, Марвину, памяти моих дорогих п и Брэма.
Э. Таненбаум
Барбаре и Гордону.
А. Вудхалл
Пр еди с л о в и е
От и здателя перевода
Ваши замечания, предложения и вопросы отправляйте по адресу электронной
почты comp@piter.com (издательство � Питер� , компьютерная редакция).
Мы будем рады узнать ваше мнение!
Все исходные тексты, приведенные в книге, вы можете найти по адресу http://
www. piter. com/download.
Подробную информацию о наших книгах вы найдете на веб-сайте издательства:
http://www. piter.com.
Глава 1
Вв еде ни е
Банковская Заказ
система авиабилетов Веб-браузер } Программы-приложения
Компиляторы Редакторы Интерпретаторы
команд } с"""'""ые -··ы
)
Операционная система
Машинный язык
Микроархитектура Оборудооа"'"·""""""" "
Физические устройства
Рис . 1 . 1. Компьютер состоит из аппаратного обеспечения, а также
системных и прикладных программ
Далее следует микроархитектурный уровень, на котором физические устройства
группируются в функциональные блоки. Как правило, на микроархитектурном
уровне находятся внутренние регистры ЦПУ (центральное процессорное устрой
ство) и тракт данных, включающий арифметико-логическое устройство. На каждом
такте процессора данные извлекаются из регистров и обрабатываются арифме
тико-логическим устройством (к примеру, участвуют в операции арифметического
или логического суммирования). Результат сохраняется в одном или нескольких
регистрах. В некоторых компьютерах функционирование тракта данных находит
ся под управлением особой программы, называемой микропрограммой. В осталь
ных случаях управление обеспечивают аппаратные схемы.
Тракт данных предназначен для выполнения наборов команд. Некоторые на
боры могут быть выполнены в одном цикле тракта данных, другие же требуют
нескольких тактов. В распоряжении команд находятся различные аппаратные
средства, в том числе регистры. Аппаратное обеспечение и команды, доступ
ные программисту на языке ассемблера, образуют архитектуру набора команд
(Instгuction Set Architecture, ISA). Зачастую данный уровень называют машин
ным языком.
Обычно машинный язык содержит от 50 до 300 команд, служащих преимуще
ственно для перемещения данных в пределах компьютера, выполнения ариф
метических операций и сравнения величин. Управление устройствами на этом
уровне осуществляется путем загрузки определенных величин в специальные
регистры устройств. Например, диску можно дать команду чтения, записав в его
регистры адрес места на диске, адрес в основной памяти, число байтов для
чтения и направление действия (чтение или запись). На практике нужно переда
вать больше параметров, а информация о статусе операции, возвращаемая дис
ком, достаточно сложна. Кроме того, при программировании многих устройств
ввода-вывода (Input/Output, 1/0) очень важную роль играют временн Ьl:е соот
ношения.
Основное предназначение операционной системы - скрыть все эти сложности
и предоставить программисту более удобную систему команд. Чтение блока из
20 Глава 1 . Введение
файла в этом случае представляется намного более простым действием, чем в слу
чае, когда программисту приходится думать о перемещении головок диска, о за
держках, связанных с их установкой в нужное место и т. д.
Поверх операционной системы на нашем рисунке расположены остальные сис
темные программы. Здесь находятся интерпретатор команд (оболочка) , ком
пиляторы, редакторы и т. д. Важно понимать, что подобные программы не яв
ляются частью операционной системы, хотя обычно поставщики компьютеров
устанавливают их на машины. Это очень важное, хотя и тонкое, замечание. Под
операционной системой обычно понимается то программное обеспечение, кото
рое запускается в режиме ядра или, как его еще называют, режиме супервизора.
Операционная система защищена от вмешательства пользователя с помощью
аппаратных средств (мы не рассматриваем в данный момент некоторые старые
микропроцессоры, которые вообще не имеют аппаратной защиты). Компилято
ры и редакторы запускаются в полъзователъском режиме. Если пользователю не
нравится какой-либо компилятор, он при желании может написать собственный,
но ему не удастся написать собственный обработчик прерываний от системных
часов, являющийся частью операционной системы и обычно защищенный аппа
ратно от попыток его модифицировать.
Подобная классификация имеет весьма размытые границы во встраиваемых сис
темах, допускающих отсутствие ядра, и в интерпретируемых системах (к приме
ру, в Jаvа-системах, где компоненты разделяются путем интерпретации, а не ап
паратно ) . Тем не менее в традиционных компьютерах операционная система
является элементом, исполняемым в режиме ядра.
Во многих системах применяются программы, хотя и исполняемые в пользо
вательском режиме, но призванные помогать операционной системе или ре
шать привилегированные задачи. Распространенный пример - программа сме
ны пароля пользователями. Она не является частью операционной системы и не
работает в режиме ядра, однако несет важную функцию и, очевидно, требует осо
бой защиты.
В некоторых системах, включая MINIX 3, описанный подход реализован столь
утрированно, что компоненты, традиционно относимые к операционной системе
(к примеру, файловая система), функционируют в пользовательском режиме. Гра
ница между системным и прикладным программным обеспечением размывается.
Очевидно, что компоненты, исполняемые в режиме ядра, относятся к операцион
ной системе, однако многие 4Пользовательские� программы также несут систем
ные функции либо, как минимум, тесно связаны с ними. К примеру, в MINIX 3
файловая система представляет собой не что иное, как большую С-программу,
исполняемую в пользовательском режиме.
Подведем итог вышесказанному: поверх системных программ выполняются при
кладные программы. Обычно они покупаются пользователем (или пишутся им)
для решения собственных проблем - обработки текста, электронных таблиц,
технических расчетов или хранения информации в базе данных.
1 . 1 . Понятие операционной системы 21
1 . 1 . 2 . Операционная система
как менеджер ресурсов
Концепция, в которой операцион ная система, прежде всего, рассматривается как
удобный интерфейс пользователя, - это взгляд сверху вниз. Альтернативный
взгляд, снизу вверх, дает представление об операционной системе как о механиз
ме, предназначенном для управления всеми частями компьютера. Современные
компьютеры состоят из процессоров, памяти, таймеров, дисков, мыши, сетевых
интерфейсов, принтеров и огромного количества других устройств. В соответ
ствии со вторым подходом назначение операционной системы - обеспечение
организованного и контролируемого распределения процессоров, памяти и уст
ройств ввода-вывода между различными программами, состязающимися за пра
во их использовать.
Представьте, что случилось бы, если бы три программы, работающие на одном
компьютере, одновременно попытались напечатать свои выходные данные на од
ном и том же принтере. Возможно, первые несколько строк на листе появились
бы в результате работы первой программы, следующие несколько - в результате
1 . 1 . Понятие операционной системы 23
1 . 2 . И стория развития
операционны х систем
История развития операционных систем насчитывает уже много лет. В следую
щих разделах книги мы кратко рассмотрим некоторые основные моменты. Так
как операционные системы появились и развивались в процессе конструирова
ния компьютеров, то эти события исторически тесно связаны. Поэтому чтобы
представить, как выглядели операционные системы, мы обсудим следующие друг
за другом поколения компьютеров. Такая схема взаимосвязи поколений опера
ционных систем и компьютеров довольно груба, но она обеспечивает некоторую
структуру, без которой ничего не было бы понятно.
Первый настоящий цифровой компьютер был изобретен английским математи
ком Чарльзом Бэббиджем (Charles Babbage, 1792- 187 1 ). Хотя большую часть жиз
ни Бэббидж посвятил попыткам создания своей �аналитической машины� , он
так и не смог заставить ее работать должным образом. Это была чисто механиче
ская машина, а технологии того времени не были достаточно развиты. Не стоит
и говорить, что аналитическая машина Бэббиджа не имела операционной системы.
Интересный исторический факт: Бэббидж понимал, что для аналитической ма
шины ему необходимо программное обеспечение, поэтому он нанял молодую
женщину по имени Ада Лавлейс (Ada Lovelace), дочь знаменитого британского
поэта Лорда Байрона. Она и стала первым в мире программистом, а язык про
граммирования Ada назван в ее честь.
очень хорош для считывания карт, копирования лент и печати выходных дан
ных, но не подходил для числовых вычислений.
Другие, более дорогостоящие машины, такие как IBM 7094, использовались для
настоящих вычислений (рис. 1 .2).
Устройство
записывания Входная Системная
лента Выходная
Устройство магнитных лент лента
1111111111111111111111 1111111111111111111111
7094 1401
а б в г д е
Ранняя система пакетной обработки: программист приносит карты для IBM 1401 ;
Рис. 1 . 2 . а -
б- IBM 1401 записывает пакет заданий на магнитную ленту; в оператор приносит входные
-
данные на ленте к IBM 7094; IBM 7094 выполняет вычисления; д оператор переносит
г - -
ленту с выходными данными на IBM 1 401 ; е IBM 1 401 печатает выходные данные
-
/ $КОНЕЦ
/ /
/
/
Данные для программы /
/
/ /
, ,
1
/$ЗАПУСТИТЬ -
/$ЗАГРУЗИТЬ /
/ /
,
/
/
Программа на Фортране /
/
/
/ / ,___ /
1 -
/$FORTRAN f--
/
/
/
$ЗАДАНИЕ, 1 0,6610802, Марвин Таненбаум -
/
/
,____
Задание З
Задание 2
Разделы
Задание 1 памяти
Операционная
система
Рис. 1 . 4 . Многозадачная система с тремя заданиями в памяти
Мысль о том, что машины, гораздо более мощные, чем их мэйнфрейм GE-645,
будут продаваться миллионами по цене тысяча долларов за штуку всего лишь
через тридцать лет, казалась чистейшей научной фантастикой, как если бы сего
дня кто-либо вздумал проектировать сверхзвуковые трансатлантические подвод
ные поезда.
Успех MULTICS не был полным. Предполагалось, что система сможет обслужи
вать сотни пользователей, будучи лишь немногим мощнее персональных компь
ютеров на базе Intel 80386 (хотя система MULТICS значительно превосходила
их в объеме ввода-вывода). Идея была не столь безумна, как кажется, поскольку
в то время люди умели писать компактные и эффективные программы (похоже,
впоследствии это умение было утрачено). Системе M ULTI CS не удалось поко
рить мир в силу целого ряда причин, весьма важной из которых является ис
пользование языка PL/I для ее создания. Компилятор PL/I появился с опозда
нием на несколько лет и оказался практически нефункциональным. Кроме того,
для своего времени система M U LT I C S была чересчур амбициозной, подобно
аналитической машине Бэббиджа в XIX веке.
В итоге система MULTICS стала источником многих конструктивных идей для
компьютерных теоретиков, но превратить ее в серьезный продукт и добиться
коммерческого успеха оказалось намного труднее, чем ожидалось. Группа иссле
довательских лабораторий Bell Labs выбыла из проекта, а компания General
Electric совсем оставила компьютерный бизнес. Однако Массачусетсский техно
логический институт проявил упорство и со временем получил вполне работо
способную систему. В конце концов, она была продана как коммерческое из
делие компанией Honeywell, купившей компьютерный бизнес General Electric,
и установлена примерно в восьмидесяти больших компаниях и университетах по
всему миру. Несмотря на небольшой тираж системы MULTICS, ее пользователи
проявили исключительную лояльность к своему приобретению. Компании General
Motors, Ford и Национальное агентство безопасности США свернули системы
MULТICS лишь в конце 90-х, а последняя машина MULТICS, работавшая в Ми
нистерстве обороны Канады, была снята с эксплуатации в октябре 2000 г. Не
смотря на неудачу с точки зрения коммерции, система MULTICS значительно
повлияла на последующие операционные системы [24, 25, 28, 94, 1 0 1 ) . В Интерне
те имеется веб-сайт, на котором представлена обширная информация о системе
MULTICS, ее разработчиках и пользователях (www . multicians.org).
Словосочетание �компьютерное приложение� вышло из употребления, однако
в последние годы его идея получила �вторую жизнь�. В простейшем случае компь
ютеры, или рабочие станции (персональные компьютеры большой мощности),
расположенные в компании или классной комнате, посредством локальной сети
подключаются к файловому серверу, хранящему все программы и данные. При
такой топологии системный администратор устанавливает и обеспечивает защиту
единственного набора программ и данных. Администратору не нужно заботить
ся об извлечении и сохранении локальных данных неисправного компьютера;
он может без проблем переустановить его программное обеспечение. В неодно
родном окружении появляется дополнительный класс программ, называемых
32 Глава 1 . Введение
1 . 2 . 5 . История M I N IX 3
Во времена молодости UNI X (версии 6) ее исходные коды были широко дос
тупны по лицензии АТ&Т и активно изучались. Джон Лайонс (John Lions) из
университета Нового Южного Уэльса в Австралии даже написал небольшую
брошюру, шаг за шагом описывающую работу UNIX [82]. С разрешения АТ&Т
эта брошюра использовалась во многих университетских курсах по операцион
ным системам.
36 Глава 1 . Введение
1 . 3 . Основные кон ц еп ц и и
Интерфейс между операционной системой и пользовательскими программами
определяется набором «расширенных инструкций� , предоставляемых системой.
По традиции эти расширенные инструкции называют системными вызовами, хо
тя сейчас для их реализации используются несколько разных способов. Чтобы
действительно понять, что может делать операционная система, нужно тщатель
но изучить этот интерфейс. Поддерживаемые вызовы у разных операционных
систем могут значительно различаться (хотя скрывающиеся за ними концепции
оказываются схожими).
Таким образом, при описании основных концепций, относящихся к операци
онным системам, нам пришлось делать выбор между размытыми обобщения
ми ( «операционные системы поддерживают системные вызовы для чтения фай
лов�) и спецификой конкретной системы ( « MINIX 3 поддерживает системный
вызов READ с тремя параметрами: один указывает, какой файл будет считы
ваться, другой - куда поместить считанные данные, а третий задает количество
считываемых байтов� ) .
Мы выбрали второй подход. Он сложнее, но дает гораздо больше в плане по
нимания того, как работают операционные системы. В пункте 1 .4 представлен
более подробный обзор основных системных вызовов, поддерживаемых UNIX
(включая различные версии BSD), LINUX и MINIX 3. Для простоты мы будем
рассматривать только M INIX 3, но в большинстве случаев соответствующие
вызовы UNIX и LINUX тоже основаны на стандарте POSIX. Однако перед рас
смотрением реальных системных вызовов имеет смысл дать общий обзор MINIX 3,
чтобы почувствовать, что это за система. Этот обзор в равной степени применим
и к UNIX и LINUX.
Системные вызовы MINIX 3 можно грубо разделить на две категории: вызовы
для работы с процессами и вызовы для работы с файловой системой. Рассмот
рим каждую из этих групп.
40 Глава 1 . Введение
1 . 3 . 1 . П роцессы
Ключевое понятие MINIX 3 и любой другой операционной системы процесс. -
1 Слово �core�. которое можно перевести как �сердечник� . напоминает об использовавшейся дав
ным-давно памяти на магнитных сердечниках.
1 .3 . Основные концепции 41
1 . 3 . 2 . Ф айл ы
Другая обширная группа системных вызовов относится к файловой системе. Как
было замечено ранее, основной функцией операционной системы является скры
тие особенностей устройства дисков и других устройств ввода-вывода и предо
ставление пользователю понятной и удобной абстрактной модели независимых
от устройств файлов. Системные вызовы очевидно необходимы для создания,
удаления, чтения или записи файлов. Перед тем как прочитать файл, его нужно
разместить на диске и открыть, а после прочтения его нужно закрыть. Все эти
функции осуществляют системные вызовы.
Предоставляя место для хранения файлов, операционные системы используют
понятие каталога (directory) как средства объединения файлов в группы. На
пример, студент может иметь по одному каталогу для каждого изучаемого им
курса (для программ, необходимых в рамках этого курса) , каталог для элек
тронной почты и еще один - для своей домашней веб-страницы. Для создания
и удаления каталогов также необходимы системные вызовы. Они же обеспечива
ют перемещение существующего файла в каталог и удаление файла из каталога.
Содержимое каталогов моrут составлять файлы или другие каталоги. Эта мо
дель образует иерархию - файловую систему (рис. 1 .6).
Иерархии и процессов, и файлов организованы в виде деревьев, однако на этом
их сходство заканчивается. Иерархия процессов обычно не очень глубока (в ней
редко бывает больше трех уровней), тогда как файловая структура достаточно
часто имеет четыре, пять или даже больше уровней в глубину. Иерархия процес-
1 .3 . Основные конце п ции 43
сов обычно существует очень недолго, как правило, несколько минут, иерархия
каталогов может существовать годами. Механизмы принадлежности и защиты
также различны для процессов и файлов. Обычно только родительский процесс
может управлять дочерним процессом или даже просто иметь к нему доступ, в то
же время практически всегда существует механизм, позволяющий читать файлы
и каталоги не только владельцу файла, но и более широкой группе пользователей.
Корневой каталог
Студенты Факультет
Профессор Профессор
Гр• Уайт
Курсы
�
CS1 01 t.! �О Ж
CS1 05
Рис. 1 .6.
Каждый файл в иерархии каталогов можно определить, задав его имя пути, на
зываемое обычно полны.м именем файла. Путь начинается из вершины структуры
каталогов, называемой корневым каталогом. Такое абсолютное имя пути состо
ит из списка каталогов, которые нужно пройти от корневого каталога к файлу,
с разделением отдельных компонентов косой чертой. На рис. 1 . 6 путь к файлу
C S 1 0 1 выглядит как / Fa cu l ty / Pro f . B rown / Cours e s / C S 1 0 1 . Первая косая
черта говорит о том, что этот путь - абсолютный, то есть начинается от корнево
го каталога. В MS- DOS и Windows для разделения компонентов вместо символа
косой черты используется символ обратной косой черты ( \ ) . Тогда этот путь
будет выглядеть так: \ F acu l ty \ Pro f . Brown \ Cour s e s \ C S 1 0 1 . В нашей книге
для записи пути мы в основном будем использовать соглашения UNIX.
В каждый момент времени у каждого процесса есть текущий ра,бачий каталог, в ко
тором ищутся имена путей, не начинающиеся с косой черты. Например, если на
рис. 1 . 6 каталог / F a c u l ty / Pro f . Brown является рабочим, то использование
44 Глава 1 . Введение
пути Cours e s / C S 1 0 1 даст тот же самый файл, что и показанный ранее абсолют
ный путь. Процессы могут изменять свой рабочий каталог, используя системные
вызовы.
В операционной системе MINIX 3 каждому файлу и каталогу присваивается
1 1-разрядный двоичный код защиты. Код защиты включает три 3-разрядных поля:
одно - для владельца, одно - для прочих членов группы владельца (разбиение
пользователей на группы осуществляется системным администратором) и од
но - для всех остальных пользователей. Два оставшихся бита мы рассмотрим
позднее. В каждом поле имеется бит доступа по чтению, бит доступа по записи и
бит доступа по исполнению. Эти три бита в совокупности называют rwх-бита
ми 1 . К примеру, код защиты rwxr - x - - x означает, что владелец файла может
читать, записывать и запускать файл, другие члены группы владельца - только
читать и запускать файл (без права записи), и, наконец, все прочие пользовате
ли - только исполнять файл (без права чтения и записи) . Для каталога, в от
личие от файла, доступ по исполнению означает возможность поиска. Прочерк
указывает на отсутствие разрешения (значение соответствующего бита равно О).
Перед тем как прочесть или записать файл, его нужно открыть, в это же время
проверяется разрешение доступа. Если доступ разрешен, система возвращает не
большое целое число, называемое дескриптором файла и используемое в после
дующих операциях. Если доступ запрещен, то возвращается код ошибки ( - 1 ) .
Другое важное понятие в MINIX 3 - это смонтированная файловая система.
Почти все персональные компьютеры имеют один или несколько дисководов
для компакт-дисков, куда можно вставить и откуда можно вынуть диск. Что
бы предоставить возможность общения со сменными носителями ( СD-дисками,
DVD-дисками, дискетами, Ziр-дисками), MINIX 3 позволяет присоединять фай
ловую систему сменного диска к главному дереву. Рассмотрим ситуацию, пока
занную на рис. 1 .7, а. Перед вызовом системной процедуры rnount корневая фай
ловая система на жестком диске и вторая файловая система на компакт-диске
существуют раздельно и никак не связаны между собой.
Однако файлы на компакт-диске нельзя использовать, потому что для них не
возможно определить путь. MINIX 3 не позволяет присоединять к началу пути
название диска или его номер, так как это привело бы к жесткой зависимости
от устройств, которой операционная система должна избегать. Вместо этого
системный вызов rnoun t позволяет присоединять файловую систему на гибком
диске к корневой файловой системе в том месте, где этого захочет программа.
На рис. 1 .7, б файловая система диска О установлена в каталог Ь, таким обра
зом, обеспечен доступ к файлам по путям / Ы х / и / Ь / у . Если каталог Ь со
держал какие-либо файлы, они будут недоступны, пока смонтирован гибкий
диск, так как теперь имя /Ь ссылается на корневой каталог диска О. ( Невоз
можность доступа к этим файлам не так страшна, как кажется с первого взгля
да: файловые системы почти всегда устанавливаются в пустые каталоги.) Если
1 Аббревиатура rwx образована тремя английскими словами: read - чтение, write - запись, execution -
исполнение - Примеч. пер .
1 .3 . Основные конце п ции 45
система содержит несколько жестких дисков, они все могут быть встроены в од
но дерево таким же образом.
N с{Ъ а б
Монтирование файловой системы: - перед монтированием файлы на диске О
Рис. 1 . 7 . а
недоступны; б - после монтирования они становятся частью общей файловой структуры
Еще одно важное понятие в MINIX 3 - это специальный файл. Специальные
файлы служат для того, чтобы устройства ввода-вывода выглядели как файлы.
При этом можно прочесть информацию из специальных файлов или записать ее
туда с помощью тех же самых системных вызовов, что используются для чтения
и записи файлов. Существует два вида специальных файлов: блочные специ
альные файлы и си.м,вольные специальные файлы . Блочные специальные файлы
используются для моделирования устройств, состоящих из набора произволь
но адресуемых блоков, таких как диски. Открывая блочный специальный файл
и читая, скажем, блок 4, программа может напрямую получить доступ к блоку 4
на устройстве без обращения к содержащейся на нем файловой системе. Таким
же образом символьные специальные файлы используются для моделирования
принтеров, модемов и других устройств, которые принимают или выдают поток
символов. По соглашению специальные файлы хранятся в каталоге / dev. На
пример, файл / dev / lp может быть строковым принтером.
И последнее понятие, которое мы здесь обсудим, - это каналы (pipe), имеющие
отношение и к процессам, и к файлам. Канал (также иногда называемый трубой)
представляет собой псевдофайл, который можно использовать для связывания
двух процессов, как показано на рис. 1 .8. Если процессы А и В захотят пооб
щаться с помощью канала, они должны установить его заранее. Когда процесс А
решает отправить данные процессу В, он пишет их в канал, как если бы это был
выходной файл. Процесс В может прочесть данные, читая их из канала, как если
бы он был файлом с входными данными. Таким образом, взаимодействие между
процессами в UNIX очень похоже на обычные чтение и запись файлов. Более того,
только сделав специальный системный вызов, процесс может обнаружить, что
выходной файл, в который он пишет данные, - это не реальный файл, а канал.
Процесс Процесс
�
�
Рис. 1 . 8 . Два процесса, соединенные каналом
46 Глава 1 . Введение
1 . 3 . 3 . Оболочка
Операционная система представляет собой программу, выполняющую систем
ные вызовы. Редакторы, компиляторы, ассемблеры, компоновщики и командные
интерпретаторы не являются частью операционной системы, несмотря на их
большую важность и полезность. Поскольку есть риск запутаться в этих поняти
ях, мы кратко рассмотрим только командный интерпретатор MINIX 3, называе
мый оболочкой (shell). Хотя оболочка не входит в операционную систему, но во
всю пользуется многими функциями операционной системы и поэтому является
хорошим примером того, как могут применяться системные вызовы. Кроме это
го, оболочка предоставляет основной интерфейс между пользователем, сидящим
за своим терминалом, и операционной системой, если, конечно, пользователь не
использует графический интерфейс. Существуют целый ряд оболочек, включая
c sh, ksh, z sh и bash. Все они поддерживают описываемую здесь функциональ
ность исходной оболочки ( sh).
Когда какой-либо пользователь входит в систему, запускается оболочка. Стан
дартным входным и выходным устройством для оболочки является терминал.
Оболочка начинает работу с печати приzлашения (prompt) - знака доллара,
говорящего пользователю, что оболочка ожидает ввода команды. После этого
пользователь может вводить команды, например:
da t e
Вызов Описание
п read(fd, buffer, пbytes)
= Читает данные из файла в буфер
п write(fd, buffer, пbytes)
= Пишет данные из буфера в файл
pos lseek(fd, offset, wheпce)
= Передвигает указатель файла
s stat(пame, &buf)
= Получает информацию о состоянии файла
s fstat(fd, &buf)
= Получает информацию о состоянии файла
fd dup(fd)
= Закрепляет за открытым файлом новый дескриптор
s pipe(&fd[O])
= Создает канал
s ioctl(fd, request, argp)
= Специальные действия с файлом
s access(пame, amode)
= Проверяет доступность файла
s reпame(old, пеw)
= Переименовывает файл
s fcпtl(fd, cmd, ... )
= Захватывает файл и выполняет другие действия
Управление каталогами и файловой системой
s mkdir(пame, mode)
= Создает новый каталог
s rmdir(пame)
= Удаляет пустой каталог
s liпk(пame1 , паmе2)
= Создает новый элемент с именем паmе2, указывающий
на паmе1
s = uпliпk(пame) Удаляет элемент каталога
s = mouпt(special, паmе, flag) Монтирует файловую систему
s = umouпt(special) Демонтирует файловую систему
s = sупс() Сбрасывает все кэшированные блоки на диск
s = chdir(dirпame) Изменяет рабочий каталог
s = chroot(dirпame) Изменяет корневой каталог
Защита
s chmod(пame, mode)
= Изменяет биты защиты файла
uid getuid()
= Определяет идентификатор пользователя для вызвавшего
gid getgid()
= Определяет идентификатор группы для вызвавшего
s setuid(uid)
= Устанавливает идентификатор пользователя для вызвавшего
s setgid(gid)
= Устанавливает идентификатор группы для вызвавшего
s chowп(пame, owпer, group)
= Меняет идентификатор владельца файла
oldmask umask(complmode)
= Меняет режим маскирования
Управление временем
secoпds time(&secoпds)
= Получает время, прошедшее с 1 января 1 970 года
s stime(tp)
= Устанавливает время, прошедшее с 1 января 1 970 года
s utime(file, timep)
= Устанавливает время последнего доступа к файлу
s times(buffer)
= Определяет время работы пользовательского процесса
и системы
Особое внимание следует обратить на то, что преобразование вызовов РОSIХ
процедур в системные вызовы не является взаимно однозначным. Стандарт
POSIX определяет ряд процедур, которые должны поддерживать совместимые
системы, но он не указывает, являются ли они системными вызовами, библио
течными вызовами или чем-нибудь еще. В некоторых случаях РОSIХ-процеду
ры поддерживаются в MINIX 3 библиотечными функциями. Иногда требуемые
50 Глава 1 . Введение
1 4 1
. Систем ные вызовы
. .
для передачи программе такой информации, как тип терминала или имя домаш
него каталога. В листинге 1 . 1 третий параметр равен нулю, поскольку дочернему
процессу ничего не передается.
Если команда ехее кажется сложной, не огорчайтесь, потому что это - один из
наиболее сложных системных вызовов в POSIX. Все остальные намного про
ще. В качестве еще одного примера рассмотрим вызов ex i t , процессы должны
52 Глава 1 . Введение
использовать его при завершении работы. У него есть всего один параметр, статус
выхода, изменяющийся от О до 255. Он возвращается родительскому процессу
через переменную s t a t l oc в системном вызове wa i t p i d. Младший байт этой
переменной содержит значение статуса выхода, который равен О при нормальном
завершении работы и ненулевому значению при завершении по ошибке. Старший
байт содержит статус завершения дочернего процесса (от О до 255). Например:
n = wa i t p i d ( - 1 , & s t atus , opt i ons ) ;
Если родительский процесс выполнит эту команду, то его работа будет приоста
новлена до завершения дочернего процесса. Если дочерний процесс завершится,
скажем, через вызов exi t с параметром 4, то когда родительский процесс про
должит работу, n будет содержать PID дочернего процесса, а s t a t l o c значе -
Адрес (шестнадцатеричный)
�---� FFFF
Стек
Промежуток
Данные
Текст
'------' 0000
Рис. 1 . 9 . Под процессы отводится три сегмента: текст, данные и стек. В данном примере
все три расположены в едином адресном пространстве, однако также поддерживаются
раздельные пространства сегментов команд и данных
Для удобства программиста предлагается библиотечная процедура sbrk, так
же меняющая размер сегмента данных. Ее единственный параметр указывает, на
сколько должен быть увеличен размер сегмента (чтобы уменьшить сегмент, нуж
но передавать отрицательные значения). Процедура работает так: вызовом brk
определяется текущий размер сегмента, затем вычисляется новый размер, после
чего делается еще один системный вызов, запрашивающий требуемое количест
во байтов. Оба вызова (brk и sbrk) не относятся к стандарту POSIX. Для дина
мического выделения памяти программисты могут использовать библиотечную
1 .4. Системные вызовы 53
В этом случае сигнал от нажатия клавиш Ctrl+C не должен влиять на работу фо
нового процесса, поэтому после вызова f orc, но перед вызовом ехес оболочка
делает следующие вызовы:
s i ga c t ion ( S I G I NT , S I G_I GN , NULL ) ;
s igac t i on ( S I GQUI T , S I G_IGN , NULL ) ;
только один сиrnал. Если сделать вызов a l arrn, указав задержку 1 0 секунд, а за
тем, по истечении 3 секунд, еще раз выполнить вызов a l arrn с параметром 20 се
кунд, придет сигнал только от того вызова, который сделан последним. Первый
вызов отменяется. Чтобы отменить сделанный ранее вызов a l arrn, нужно еще
раз сделать вызов a l arrn, передав в качестве аргумента О. Если пришедший сиг
нал S I GALARМ не обрабатывать, то выполняется действие по умолчанию, и про
цесс завершается.
Иногда возникают ситуации, когда процессу нечем заняться до прибытия сиrnала.
Например, рассмотрим компьютерную программу для проверки скорости чтения
и внимательности. Эта программа выводит некоторый текст, а затем делает вы
зов a l a rrn с параметром 30 секунд. Пока ученик читает текст, программа ничего
не должна делать. Программа может выполнять пустой цикл, но это будет бес
смысленной тратой процессорного времени, которое может потребоваться дру
гому процессу. Гораздо лучше использовать системный вызов pau s e , который
заставляет MINIX 3 приостановить выполнение процесса до прихода сигнала.
Эта команда создаст файл с именем аЬс и установит для него права доступа 075 1
(в С числа с ведущим нулем считаются восьмеричными). Младшие 9 бит этого
числа показывают, что владелец файла имеет права доступа rwx (7 означает
права на чтение, запись и исполнение) , члены группы владельца имеют права
на чтение и исполнение (5), а прочие пользователи - только на исполнение ( 1 ).
Вызов creat не только создает новый файл, но и открывает его для записи неза
висимо от указанного режима. Дальнейшая запись в файл производится через
его дескриптор fd, значение которого возвращается вызовом. Если выполнить
вызов c reat для существующего файла, то файл усекается до нулевой длины
(если, конечно, права доступа позволяют это). Сейчас вызов crea t устарел и под
держивается для обратной совместимости, вместо него нужно использовать
вызов open.
Чтобы создать специальный файл, нужно вместо creat выполнить вызов rnknod.
Вот типичный пример:
fd = mknod ( " / dev/ t ty c 2 " , 020744 , Ох 0 4 0 2 ) ;
Эта команда создает файл с именем / dev / t ty c 2 (обычно это имя соответствует
второй консоли) и задает для него права доступа 0207 44 (специальный символьный
56 Глава 1 . Введение
Когда пользователь дает оболочке эту команду, то оболочка создает канал и со
единяет стандартный вывод первого процесса с входом канала, а стандартный
ввод второго процесса с выходом канала. Чтобы создать канал, применяется сис
темный вызов p ipe, возвращающий два дескриптора файлов: один для чтения
из канала, другой для записи в него:
58 Глава 1 . Введение
pipe ( & f d [ O ) ) ;
1 4 4 Системные вызовы
. . .
Тогда файл rnerno из каталога j irn появится в каталоге a s t под названием not e.
Соответственно, имена / u s r / j irn/rnerno и / u s r / a s t / not e после этого будут
ссылаться на один и тот же файл.
1 . 4 . Системные вызовы 61
а б
Рис. 1 . 1 0 .Механизм выполнения вызова liпk: а -два каталога до присоединения
/usr/jim/memo к каталогу ast; б - те же каталоги после вызова liпk
Возможно, станет понятнее, что делает системный вызов 1 ink, если разобраться
в том, как он работает. Каждый файл в UNI X имеет уникальный номер, который
идентифицирует файл. Этот номер представляет собой индекс в таблице индекс
ных узлов (index nodes), или i-узлов (i-nodes), содержащей по одному индексному
узлу на файл. Каждый индексный узел включает в себя информацию о владель
це файла, о том, какие блоки на диске он занимает и т. д. Каталог представляет
собой просто файл, содержащий набор пар из номера индексного узла и АSСП
имени. В первых версиях UNIX каждый элемент каталога занимал 16 байт: 2 на
номер индексного узла и 14 на имя. Для поддержки длинных имен файлов
требуется более сложная структура, однако концептуально каталог представля
ет собой файл с парами номеров индексных узлов и АSСП-имен. На рис. 1 . 1 0
файл rna i l имеет номер индексного узла 1 6 и т . д . Действие вызова l ink заклю
чается в создании нового элемента каталога, имя которого, возможно, является
новым, а номер индексного узла равен номеру индексного узла существующе
го файла. На рис. 1 . 1 0 , б два элемента имеют одинаковый номер индексного
узла (70) и, таким образом, ссылаются на один и тот же файл. Если впоследст
вии один из них будет удален с помощью системного вызова unl ink, другой
элемент останется. Если будут удалены оба файла, UNIX обнаружит, что больше
нет записей, соответствующих этому файлу (поле в таблице индексных узлов
хранит данные с номером элемента каталога, указывающего на файл), и удалит
файл с диска.
Как упоминалось ранее, системный вызов rnount позволяет две файловых систе
мы объединить в одну. Обычная ситуация такова: на жестком диске находится
корневая файловая система, содержащая двоичные (исполняемые) версии об
щих команд и наиболее часто использующиеся файлы. При этом пользователь
может вставить в дисковод компакт-диск с файлами для чтения.
При помощи системного вызова rnount файловую систему с гибкого диска можно
присоединить к корневой файловой системе, как показано на рис. 1 . 1 1 . Типич
ная команда на языке С, выполняющая монтирование, выглядит так:
mount ( " / de v / c dromO " , " / mnt " , 0) ;
а б
Рис. 1 . 1 1 . Файловая система: а - до вызова mount; б - после вызова mount
После вызова rnoun t доступ к файлу на диске О можно получить, просто указав
его путь из корневого или рабочего каталога, независимо от того, на каком диске
он находится. В действительности второй, третий и четвертый диски тоже мож
но встроить в любое удобное место в дереве. Вызов rnount позволяет объединить
съемные носители в единую интегрированную файловую структуру, не заботясь
о том, на каком из устройств фактически находится файл. Хотя в нашем примере
рассматривались компакт-диски, жесткие диски или их части, часто называемые
раздела.ми (partition), или второстепенными устройства.ми (minor devices), мон
тируются аналогично. Когда файловая система более не нужна, ее можно демон
тировать с помощью системного вызова urnount .
MINIX 3 поддерживает блочное кэширование, то есть система кэширует в памяти
последние блоки, к которым были совершены обращения, чтобы избежать слиш
ком частых обращений к диску. Если блок в кэше модифицирован (например,
вызовом wr i t e ) и система рухнет до того, как обновленный блок будет записан
на диск, и файловая подсистема окажется поврежденной. Чтобы снизить риск
повреждения, важно периодически сбрасывать содержимое кэша на диск, чтобы
в случае сбоя системы терялось только небольшое количество данных. Систем
ный вызов sync заставляет MINIX 3 сбросить на диск все кэшированные блоки,
измененные с момента считывания. Обычно при старте MINIX вместе с систе
мой запускается фоновая программа upda t e , каждые 30 секунд выполняющая
вызов sync.
Для работы с каталогами служат еще два вызова, chd i r и chroot . Первый из
них меняет текущий каталог, а второй корневой. Например:
chd i r ( " / u s r / a s t / t e s t " ) ;
В M INIX 3 для каждого файла определен используемый для его защиты 1 1 -раз
рядный код режима, иногда также называемый модой (mode). Код режима вклю
чает 9 бит, по три (чтение, запись и выполнение) для владельца, для членов
группы владельца и для других пользователей. Системный вызов chmod предо
ставляет возможность изменения кода режима для файла. Например, следующий
вызов предоставит всем, кроме владельца, доступ к файлу только для чтения;
владелец же сможет еще и выполнять файл:
chmod ( " f i l e " , 0644 ) ;
маску, применяемую для маскирования битов прав доступа к файлу при его со
здании. Например:
шna s k ( 0 2 2 ) ;
Если сделать такой вызов, то при вызовах c r e a t или mknod в правах доступа
к создаваемому объекту будут маскироваться биты 022. Иначе говоря, следую
щий вызов создаст файл с правами доступа 0755, а не 0777:
creat ( " f i l e " , 0777 ) ;
1 . 4 . 6 . Системные вызовы
для управления временем
Для работы с системными часами MINIX 3 поддерживает четыре системных вы
зова. Вызов t ime возвращает текущее время в секундах, причем нулем считается
полночь 1 января 1970 года (имеется в виду начало дня, а не его конец). Кроме
того, чтобы считывать значение системного таймера, нужно иметь возможность
сначала это значение установить. Возможность установить часы дает вызов
s t ime, доступный только суперпользователю. Третий вызов - u t ime, он позво
ляет владельцу файла изменить значение времени, записанное в индексном узле
файла. У этого вызова довольно ограниченная область применения, но некото
рым программам он нужен, например, программа t ou c h устанавливает время
в индексном узле файла в соответствие с текущим временем.
1 . 5. Структура о п ерационной системы 65
Наконец, вызов t ime s позволяет узнать, сколько времени процессор провел, ис
полняя процесс, и сколько времени потрачено на систему (то есть на обработку
системных вызовов). Кроме того, суммируется и возвращается общее время сис
темы и процесса для всех дочерних процессов.
Адрес
)
OxFFFFFFFF
Возврат в вызвавший процесс Библиотечная
Переход в режим ядра процедура
Помещение кода для чтения в регистр read
Пространство
пользователя
3
2
Инкремент SP
Call read
Push fd
Push пbuffer
11
] Пользовательская
программа,
вызывающая read
1 Push &bytes
Пространство ядра
(операционная система)
Jl
о
Рис. 1 . 1 2 . Выполнение системного вызова read (fd , buffer, п bytes) за 1 1 шагов
Библиотечная процедура, возможно, написанная на языке ассемблера, обычно по
мещает номер системного вызова туда, куда требует операционная система (напри
мер, в регистр, как показано на шаге 5). Затем процедура исполняет инструкцию
t r ap, чтобы переключиться из пользовательского режима в режим ядра и начать
исполнение с определенного адреса внутри ядра (шаг 6). Запущенный код ядра
анализирует номер системного вызова и выбирает для него соответствующий об
работчик, как правило, с помощью таблицы указателей на обработчики систем
ных вызовов, индексируемой по номеру системного вызова (шаг 7). Затем вы
бранный обработчик запускается (шаг 8). По завершении его работы управление
может быть возвращено библиотечной процедуре и передано инструкции, сле
дующей за t rap (шаг 9). Процедура, в свою очередь, возвращает управление
программе пользователя так же, как любая другая процедура (шаг 10).
1 .5. Структура о п ерационной системы 67
Главная
процедура
Сервисные
процедуры
Утилиты
Рис. 1 . 1 3 . Простая структурная модель монолитной системы
1 . 5 . 2 . М ногоуровневые системы
Обобщением этого подхода является организация операционной системы в виде
иерархии уровней. Первой системой, построенной таким образом, была система
ТНЕ, созданная Э. Дейкстрой ( Е. W. Dijkstra) и его студентами в 1 968 году. Она
была простой пакетной системой для голландского компьютера Electrologica Х8,
память которого состояла из 32 К 27-разрядных слов.
68 Глава 1 . Введение
Виртуальные 370-е
Системные вызовы
Команды ввода-вывода CMS
,__..,._
..,. ��--�����....����---1
..
Прерывания
Прерывания VM/370
«Голое» оборудование 370
Рис. 1 . 1 4. Структура VM/370 с системой CMS
кода для SP ARC, а затем его интерпретатор, однако интерпретировать JVM -ар
хитектуру значительно легче. У JVM есть и другое важное преимущество: если
интерпретатор реализован корректно (что отнюдь не является нетривиальным),
входящие JVМ-программы можно проверять на безопасность и затем испол
нять в безопасной среде, чтобы избежать похищения дю;1ных и деструктивных
последствий.
1 . 5 . 4 . Экзоядра
В системе VM/370 каждый процесс пользователя получает точную копию настоя
щей машины. На Pentium, в режиме виртуальной машины 8086, каждый пользо
вательский процесс получает точную копию другой машины. Шагнув несколько
дальше, исследователи из Массачусетсского технологического института изобре
ли систему, которая обеспечивает каждого пользователя абсолютной копией ре
ального компьютера, но. со своим подмножеством ресурсов [43, 75]. Например,
одна виртуальная машина может получить блоки на диске с номерами от О до
1 023, следующая - от 1 024 до 2047 и т. д.
На нижнем уровне в режиме ядра работает программа, которая называется экзо
ядро (exokernel). В ее задачу входит распределение ресурсов для виртуальных
машин, а после этого проверка их использования (то есть отслеживание попыток
машин задействовать чужой ресурс). Каждая виртуальная машина на уровне
пользователя может работать с собственной операционной системой, как на
VM/370 или виртуальных машинах 8086 для Pentium, с той разницей, что каж
дая машина ограничена набором ресурсов, которые она запросила и которые ей
бьши предоставлены.
Преимущество схемы экзоядра заключается в том, что она позволяет обойтись
без уровня отображения. При других методах работы каждая виртуальная маши
на считает, что она использует собственный диск с нумерацией блоков от О до
некоторого максимума. Поэтому монитор виртуальной машины должен поддер
живать таблицы преобразования адресов на диске (и всех других ресурсов). Не
обходимость преобразования отпадает при наличии экзоядра, которому нужно
только хранить запись о том, какой виртуальной машине выделен данный ре
сурс. Подобный подход имеет еще одно преимущество: он отделяет многозадач
ность (в экзоядре) от операционной системы пользователя (в пользовательском
пространстве) с меньшими затратами, так как для этого ему необходимо всего
лишь не допускать вмешательства одной виртуальной машины в работу другой.
1 . 5 . 5 . Модел ь клиент-сервер
Система VM/370 сильно выигрывает в простоте благодаря переносу значитель
ной части кода (обеспечивающего расширенную машину) традиционной опера
ционной системы на верхний уровень, в систему CMS. Однако VM/370 и при
этом останется сложной комплексной программой, потому что моделирование
1 . 5 . Структура о п ерационной системы 73
нескольких виртуальных машин 370 само по себе не так просто (особенно если
вы хотите сделать это достаточно эффективно).
В развитии современных операционных систем наблюдается тенденция в сторо
ну дальнейшего переноса кода на верхние уровни и удалении при этом всего, что
только возможно, из операционной системы, оставляя минимальное ядро. Обыч
но для этого решение большинства задач операционной системы перекладывает
ся на пользовательские процессы. Получая запрос на обслуживание, например
чтение блока файла, пользовательский процесс (теперь называемый клиент
ским ) посылает запрос серверному процессу, который его обрабатывает и высы
лает назад ответ.
В модели, показанной на рис. 1 . 1 5, в задачу ядра входит только управление взаи
модействием между клиентами и серверами. Благодаря разделению операци
онной системы на части, каждая из которых управляет всего одним элементом
системы (файловой подсистемой, процессами, терминалом или памятью), все
части становятся небольшими и легко управляемыми. К тому же, поскольку все
серверы работают как процессы в пользовательском режиме, а не в режиме ядра,
они не имеют прямого доступа к оборудованию. Поэтому если происходит ошиб
ка на файловом сервере, может оказаться неработоспособной служба обработки
файловых запросов, но это обычно не приводит к остановке машины в целом.
Сеть
Сообщение от клиента серверу
Рис . 1 . 1 6 . Модель клиент-сервер в распределенной системе
74 Глава 1 . Введение
Резюме
Операционную систему можно рассматривать с двух точек зрения: как менеджер
ресурсов и как расширенную машину. Как менеджер ресурсов операционная
система рационально управляет различными частями системы. С точки зрения
расширенной машины, работа операционной системы состоит в предоставлении
пользователям виртуальной машины, более удобной, чем настоящий компьютер.
Операционные системы имеют достаточно долгую историю развития, которая на
чинается с тех дней, когда операционные системы заменили оператора, и про
должается до современных многозадачных систем.
Сердцем любой операционной системы является набор системных вызовов, ко
торые она может обработать. Они говорят о том, что реально делает операцион
ная система. Мы рассмотрели шесть групп системных вызовов для MINIX 3.
Первая группа обеспечивает создание и завершение процессов. Вторая группа
предназначена для работы с сигналами. Третья - для чтения и записи файлов.
Четвертая нужна для управления каталогами. Пятая включила в себя управле
ние защитой, а шестая - управление временем.
Операционные системы могут быть структурированы по-разному. В наиболее
общем случае структурирование может быть таким: монолитные системы, иерар
хические многоуровневые системы, виртуальные машины, экзоядра, модель кли
ент-сервер.
В оп рос ы и з адан ия
1 . Каковы две главные функции операционной системы?
2. В чем различие между режимом ядра и пользовательским режимом? Почему
это различие представляет важность для операционной системы?
3. Что такое многозадачность?
4. Что такое подкачка? Как вы считаете, будут ли передовые персональные ком
пьютеры будущего поддерживать подкачку данных в качестве стандартной
функции?
5. На ранних компьютерах чтение или запись каждого байта данных управля
лись напрямую центральным процессором (то есть тогда не было прямого
доступа к памяти). Какой смысл имеет это понятие для многозадачности?
6. Почему системы разделения времени не были широко распространены на
компьютерах второго поколения?
7. Какая из следующих команд должна быть разрешена только в режиме ядра:
1 ) отключение всех прерываний;
2) чтение счетчика даты/времени;
3) изменения счетчика даты/времени;
4) изменение схемы распределения памяти.
76 Глава 1 . Введе н ие
2 . 1 . Знакомство с п ро цессам и
Все современные компьютеры могут одновременно делать несколько вещей. На
пример, параллельно с запущенной пользователем программой может выполнять
ся чтение с диска и вьmод текста на экран монитора или на принтер. В многозадач
ной системе процессор переключается между программами, предоставляя каждой
от десятков до сотен миллисекунд персонального времени. При этом в каждый
конкретный момент времени процессор занят только одной программой, но за
секунду он успевает поработать с несколькими, создавая у пользователей ил
люзию одновременной работы со всеми программами. Иногда в этом контексте
говорят о псевдопараллелизме, в отличие от настоящего параллелизма в много
процессорных системах (в которых установлено два и более процессора, имею
щих общую физическую память). Отслеживать работу параллельно протекающих
процессов достаточно трудно, поэтому со временем разработчики операционных
систем прИдумали концептуальную модель логически упорядоченных процессов.
В данной главе мы опишем применение этой модели, а также некоторые резуль
таты ее использования.
2 . 1 . 1 . Модел ь процессов
В модели процесса все функционирующее на компьютере программное обеспе
чение, иногда включая собственно операционную систему, организовано в виде
набора логическ:и упорядоченных процессов, или, для краткости, просто процессов.
Процессом является выполняемая программа, вместе с текущими значениями
счетчика команд, регистров и переменных. С позиций данной абстрактной модели
у каждого процесса есть собственный виртуальный центральный процессор.
2. 1 . З н акомство с пр оцессами 79
с в
А
D Время --.
а б в
Иллюстрация многозадачности:
Рис. 2 . 1 . а - четыре программы в многозадачном.режиме;
б- принципиальная модель четырех независимых логически упорядоченных процессов;
в в каждый момент времени активна только одна программа
-
2 . 1 . 2 . Создание процессов
Операционной системе нужен способ, позволяющий удостовериться в существо
вании всех обслуживаемых процессов. В простейших системах, а также в систе
мах, разработанных для выполнения единственного приложения (таких как кон
троллер микроволновой печи), нетрудно реализовать ситуацию, в которой все
требуемые процессы уже присутствуют в системе при ее запуске. Однако в мно
гоцелевых системах требуется способ создания и завершения процессов по мере
необходимости. Сейчас мы рассмотрим несколько связанных с этим вопросов.
Существуют четыре основных события, приводящие к созданию процессов:
1 . Инициализация системы.
2. Исполнение запущенным процессом системного вызова создания процесса.
3. Запрос пользователя на создание процесса.
4. Инициализация пакетного задания.
При загрузке операционной системы зачастую создаются несколько процессов.
Некоторые из них являются приоритетными, то есть процессами, взаимодейст
вующими с пользователями (людьми) и выполняющими для них определенную
работу. Другие процессы являются фоновыми: они не связаны с конкретными
2 . 1 . З н акомство с п роцессами 81
2 . 1 3 Завершение п роцессов
. .
2. 1 4
. . Иерархии п роцессов
В некоторых системах после порождения одного процесса другим между дочер
ним и родительским процессами продолжает существовать определенная связь.
Дочерний процесс может также создавать новые процессы, тем самым порождая
иерархию. В отличие от растений и животных, размножающихся половым путем
и имеющих двух родителей, процессы имеют единственного родителя. В то же
время число дочерних процессов может быть любым - О, 1, 2 или более.
В операционной системе MINIX 3 процесс, его детей и прочих потомков можно
объединить в группу. Сигнал, посланный пользователем с клавиатуры, может
быть передан всем членам группы процессов, в данный момент связанной с клавиа
турой (как правило, это все процессы, созданные в текущем окне). Это - сигналь
ная зависимость. Каждый член группы процессов может по-своему отреагировать
на переданный группе сигнал: перехватить, проигнорировать или выполнить
действие по умолчанию (завершиться).
В качестве простого примера использования деревьев процессов рассмотрим ини
циализацию операционной системы MINIX 3. В ее загрузочном образе имеются
два специальных процесса - сервер реинкарнации (reincarnation server) и i n i t .
В функции сервера реинкарнации входит запуск и перезапуск драйверов и дру
гих серверов. Первое, что он делает, - блон:ируется и ожидает сообщения, указы
вающему ему, что нужно создать.
Процесс i n i t запускает сценарий / e t c / rc, с помощью которого передает сер
веру реинкарнации команды запуска драйверов и серверов, отсутствующих в за
грузочном образе. В результате все драйверы и серверы, запущенные подобным
образом, являются потомками сервера реинкарнации. Это означает, что если кто
либо из них завершит выполнение, сервер реинкарнации получит об этом уве
домление и сможет перезапустить (реинкарнировать) драйвер или сервер. Такой
механизм позволяет MINIX 3 справляться с авариями драйверов и серверов, по
скольку в этом случае перезапуск осуществляется автоматически. На практике
переустановить драйвер значительно проще, чем сервер, поскольку влияние драй
вера на систему меньше. Мы не утверждаем, что наше решение работает идеаль
но, и ведем работу над его улучшением.
Далее процесс i n i t считывает конфигурационный файл / e t c / t tyt ab, чтобы
получить информацию о существующих реальных и виртуальных терминалах.
Для каждого терминала ini t создает новый процесс get ty с помощью системно
го вызова f o rk, отображает приглашение для входа в систему и ожидает ввода.
84 Глава 2. Процессы
Процессы
о 1
. . .
п-2 n-1
Планировщик
Рис. 2 . 3 . Нижний уровень операционной системы отвечает за прерывания
и планирование. Выше расположены логически упорядоченные процессы
2 . 1 . 7. П рограммные потоки
В традиционных операционных системах у каждого процесса есть адресное
пространство и один поток управления. В сущности, это почти полностью оп
ределяет процесс. Тем не менее нередко возникают ситуации, в которых же
лательно иметь несколько потоков управления, квазипараллельно выполняю
щихся в одном адресном пространстве так, как будто они представляют собой
отдельные процессы (за исключением общности адресного пространства). Такие
2 . 1 . Знакомство с п роцессами 89
Пространство
пользователя
Поток Поток
Пространство Ядро Ядро
ядра
а б
Рис. 2 . 4 . Модель программных потоков: атри процесса с собственным программным
-
программный поток? Что случится, если один программный поток изменит об�
работчик сигнала, не предупредив об этом остальные программные потоки?
Последняя проблема, порождаемая программными потоками, - управление сте
ками. Во многих системах при переполнении стека процесса ядро автоматически
увеличивает его. Если у процесса несколько программных потоков, стеков тоже
должно быть несколько. Если ядро не знает о существовании этих стеков, оно не
может их автоматически наращивать при переполнении. Ядро может даже не
связать ошибки памяти с переполнением стеков.
Разумеется, эти проблемы преодолимы, но на их примере хорошо видно, что
введение программных потоков в существующую систему без тщательной и про
думанной реконструкции всей системы не имеет смысла. По крайней мере, при
дется изменить семантику системных запросов и переписать библиотеки. И ре
зультат ваших трудов должен быть совместим с существующими программами
для процессов с одним программным потоком. Дополнительную информацию
о программных потоках см. в [56, 83] .
2 . 2 . 1 . Гонки
В некоторых операционных системах процессы, работающие совместно, сообща
испол:ьзуют некое общее хранилище данных. Каждый из процессов может счи
тывать что-либо из общего хранилища данных и записывать туда информацию.
Это хранилище представляет собой область в основной памяти (возможно, в струк
туре данных ядра) или файл общего доступа. Местоположение разделяемой па
мяти не влияет на суть взаимодействия и возникающие проблемы. Рассмотрим
взаимодействие между процессами на простом, но очень распространенном при
мере системы буферизации (спулере) печати. Если процессу требуется вывести
на печать файл, он помещает имя файла в специальный катало� спулера. Другой
процесс, демон печати, периодически проверяет наличие отправленных на пе
чать файлов, печатает их и удаляет их имена из каталога.
Представьте, что каталог спулера состоит из большого числа сегментов, прону
мерованных последовательно (О, 1 , 2, ".), в каждом их которых может храниться
имя файла. Также есть две совместно используемые переменные: out, указываю
щая на следующий файл для печати, и i n, указывающая на следующий свобод
ный сегмент. Эти две переменные можно хранить в одном файле (состоящем из
двух слов), доступном всем процессам. Пусть в данный момент сегменты с О по 3
пусты (соответствующие файлы уже напечатаны), а сегменты с 4 по 6 заняты
(файлы ждут своей очереди на печать). Пусть более или менее одновременно
процессы А и В решают поставить файл в очередь на печать. Описанную ситуа
цию схематически иллюстрирует рис. 2.5.
Директория
спулера
.
4 аЬс out = 4
�:
prog.c
ргоg.п
7 iп = 7
� .
переменной next_ f r e e_s l o t . В данный момент оба процесса считают, что сле
дующий свободный сегмент - седьмой. Процесс В сохраняет в каталоге спулера
имя файла и заменяет значение in на 8, затем продолжает заниматься своими
задачами, не связанными с печатью.
Наконец, управление переходит к процессу А, и он продолжает с того места, на
котором остановился. Он обращается к переменной next_ f r e e_ s l o t , считыва
ет ее значение и записывает в сегмент 7 имя файла (разумеется, удаляя при этом
имя файла, помещенное туда процессом В). Затем он заменяет значение in на 8
(next_f ree_s l o t + 1 8). Структура каталога спулера не нарушена, поэтому
=
2 . 2 . 2 . Критические секци и
Как избежать гонок? Основным способом предотвращения проблем в этой и лю
бой другой ситуации, связанной с конкурентным использованием памяти, фай
лов и чего-либо еще, является запрет одновременной записи и чтения данных
более чем одним процессом. Говоря иными словами, необходимо взаимное ис
'КЛЮЧение. То есть в тот момент, когда один процесс использует общие данные,
другому процессу это должно быть запрещено. Проблема, описанная в предыду
щем разделе, вознин:ла из-за того, что процесс В начал работу с одной из общих
переменных до того, как процесс А ее закончил. Выбор подходящей простейшей
операции, реализующей взаимное исключение, является серьезным моментом
разработки операционной системы, и сейчас мы рассмотрим его подробно.
Проблему исключения условий гонок можно сформулировать на абстрактном
уровне. Некоторый промежуток времени (слот) процесс занят внутренними рас
четами и другими задачами, не приводящими к условиям гонок. В другие момен
ты времени процесс обращается к совместно используемым файлам или памяти.
Часть программы, в которой происходит обращение к общей памяти, называется
критической секцией. Если нам удастся избежать одновременного нахождения
двух процессов в критических секциях, мы сможем избежать гонок.
Несмотря на то что поставленное требование исключает гонки, его недостаточно
для правильной совместной работы параллельных процессов и эффективного ис
пользования общих данных. Для этого необходимо выполнение четырех условий.
1 . Два процесса не должны одновременно находиться в критических секциях.
2. Нельзя делать никаких предположений относительно скорости или количест
ве процессоров.
2 . 2 . Взаимодействие между процессам и 95
:1 В блокирован :1 :1
Т2 Тз Т4
Время •
Рис. 2 . 6 . Взаимное исключение с использованием критических секций
Запрет на прерывания
Самое простое решение состоит в запрете всех прерываний при входе процесса
в критическую секцию и разрешение прерываний по выходу из нее. Если преры
вания запрещены, невозможно прерывание по таймеру. Запрет на прерывания
исключает передачу процессора другому процессу. Таким образом, запретив пре
рывания, процесс может спокойно считывать и сохранять общие данные, не опа
саясь вмешательства конкурентов.
И все же было бы неразумно давать пользовательскому процессу полномочия
для запрета прерываний. Представьте себе, что процесс отключил все прерывания
96 Глава 2 . Процессы
Переменные блокировки
Теперь попробуем найти программное решение. Рассмотрим одну совместно ис
пользуемую переменную блокировки, изначально равную О. Если процесс хочет
попасть в критическую секцию, он предварительно считывает значение пере
менной блокировки. Если переменная равна О, процесс изменяет ее на 1 и входит
в критическую секцию. Если же переменная равна 1, то процесс ждет, пока ее
значение сменится на О. Таким образом, О означает, что ни одного процесса в кри
тической секции нет, а 1 свидетельствует, что какой-либо процесс уже находится
в критической секции.
К сожалению, у предложенного метода те же проблемы, что и в примере с ката
логом буферизации печати. Представьте, что один процесс считывает перемен
ную блокировки, обнаруживает, что она равна О, но прежде чем он успевает из
менить ее на 1 , управление получает другой процесс, успешно изменяющий ее
на 1 . Когда первый процесс снова получит управление, он тоже установит пере
менную блокировки в 1, и два процесса одновременно окажутся в критических
секциях.
Можно подумать, что проблема решается повторной проверкой значения пере
менной до ее замены, но это не так. Второй процесс может получить управление
как раз после того, как первый процесс закончит вторую проверку, но еще не
успеет изменить значение переменной блокировки.
Строгое чередование
Третий метод реализации взаимного исключения иллюстрирует листинг. 2 . 1 .
Этот фрагмент программного кода, как и многие другие в данной книге, написан
на С. Язык С был выбран, поскольку практически все существующие операцион
ные системы написаны на С (или С++), а не на языках, подобных Jаvа. Язык С
обладает всеми необходимыми свойствами для написания операционных систем,
это - мощный, эффективный и предсказуемый язык программирования. А язык
Java, например, не является предсказуемым, поскольку у программы, написан
ной на нем, может в критический момент закончиться свободная память, и она
вызовет �сборщик мусора� в исключительно неподходящее время. В случае С
это невозможно, поскольку в С процедура сборки мусора в принципе отсутствует.
2 . 2 . Взаимодействие между п роцессами 97
/ * Проце с с 2 * /
wh i l e ( TRUE ) {
wh i l e ( t urn ! = l ) ! * ожидание * / ;
c r i t i c al_r e g i on ( ) ;
t u rn= O ;
nonc r i t i c a l_re g i on ( ) ;
Алгоритм Петерсона
Датский математик Деккер (Т. Dekker) был первым, кто разработал программ
ное решение проблемы взаимного исключения, не требующее строгого чередова
ния. Подробное изложение алгоритма можно найти в [38].
В 198 1 году Петерсон ( G. L. Peterson) придумал существенно более простой
алгоритм взаимного исключения. С этого момента вариант Деккера считается
устаревшим. Алгоритм Петерсона, представленный в листинге 2.2, состоит из
двух процедур, написанных на языке С, соответствующем стандарту ANSI, что
предполагает необходимость прототипов для всех определяемых и используе
мых функций. В целях экономии места мы не будем приводить прототипы для
этого и последующих примеров.
Листинг 2.2. Решение Петерсона для взаимного исключения
# d e f ine FAL S E О
# d e f ine TRUE 1
# de f ine N 2 /* Количе с т в о проце с с о в * /
int turn ; /* Чья с ейчас очередь ? * /
int i n t e r e s t ed [ N ] ; /* В с е переменные и з начально
/* ра вны О ( FAL S E ) * /
Прежде чем обратиться к общим переменным (то есть перед тем, как войти в кри
тическую секцию), процесс вызывает процедуру ent er_r e g i on со своим но
мером (О или 1 ) в качестве аргумента. Поэтому процессу при необходимости
приходится ждать, прежде чем входить в критическую секцию. После выхода из
критической секции процесс вызывает процедуру l e ave_reg i on, чтобы обо
значить свой выход и тем самым разрешить другому процессу вход в критиче
скую секцию.
2 . 2 . Взаимодействие между процессами 99
Команда TSL
Рассмотрим решение, поддерживаемое аппаратно. Многие компьютеры, особен
но разработанные с расчетом на несколько процессоров, имеют в составе коман
ду T S L (Test and Set Lock - проверить и заблокировать):
TSL RX , LOCK
2 . 2 . 4 . П римитивы взаимодействия
между процессам и
Оба решения - Петерсона и с использованием команды T SL - корректны, но
они обладают одним и тем же недостатком: наличием активного ожидания. В сущ
ности, оба они реализуют следующий алгоритм: перед входом в критическую
секцию процесс проверяет, можно ли это сделать. Если нельзя, процесс ожидает
разрешения на вход в критическую секцию в бесконечном цикле.
Этот алгоритм не только бесцельно расходует ресурсы процессора, но и может
иметь некоторые неожиданные последствия. Рассмотрим два процесса: Н с вы
соким приоритетом и L с низким приоритетом. Правила планирования в этом
случае таковы, что процесс Н запускается немедленно, как только он оказывает
ся в состоянии ожидания. В какой-то момент, когда процесс L находится в кри
тической секции, процесс Н оказывается в состоянии ожидания (например, он
закончил операцию ввода-вывода). Процесс Н попадает в состояние активного
ожидания, но поскольку процессу L при условии работающего процесса Н про
цессорное время предоставлено быть не может, у процесса L не будет возможно
сти выйти из критической секции, и процесс Н навсегда останется в цикле. Эту
ситуацию иногда называют проблемой инверсии приоритета.
Теперь рассмотрим некоторые примитивы взаимодействия между процессами,
применяемые вместо циклов ожидания (в которых лишь напрасно расходуется
процессорное время). Эти примитивы блокируют процессы в случае запрета на
вход в критическую секцию. Одной из простейших является пара примитивов
s l eep и wakeup. Примитив s l eep - системный вызов, в результате которого
вызывающий процесс блокируется, пока его не запустит другой процесс. Вызов
2 . 2 . Взаи модействие между процессами 1 01
void produc e r ( vo i d )
{
int i t em ;
vo i d consumer ( vo i d )
int i t em ;
wh i l e ( TRUE ) / * Повторять непрерывно * /
if ( c ount О) s l eep ( ) ; / * Если буфер пус т , уйти в с о с тояние
! * ожидания * /
i t em = remove_i t em ( ) ; ! * З абрать элемент и з буфера * /
c ount = c ount - 1 ; / * Уменьшить сче тчик элементов в буфере * /
i f ( c ount = = N - 1 ) wakeup ( produ c e r ) ; / * Был ли буфер полон? * /
c onsume_i t em ( i t e m ) ; ! * Отправить элемент на печать * /
2 . 2 . 5 . Семафоры
В 1965 году Дейкстра (Е. W. Dijkstra) показал, как использовать целую перемен
ную для подсчета сигналов запуска, сохраненных на будущее. Им был предло
жен новый тип переменных, так называемых семафоров, значение которых мо
жет быть нулем (в случае отсутствия сохраненных сигналов активизации) или
некоторым положu:тельным числом, соответствующим количеству отложенных
сигналов.
Дейкстра предложил две операции, down и up (обобщения примитивов s l eep
и wakeup ). Операция down сравнивает значение семафора с нулем. Если значе
ние семафора больше нуля, операция down уменьшает его (то есть расходует один
из сохраненных сигналов активизации) и просто возвращает управление. Если
значение семафора равно нулю, процедура down не возвращает управление про
цессу, а процесс переводится в состояние ожидания. Все операции проверки
значения семафора, его изменения и перевода процесса в состояние ожидания
выполняются как единое и неделимое атомарное действие. Тем самым гаран
тируется, что после начала операции ни один процесс не получит доступа к се
мафору до окончания или блокирования операции. Атомарность операции чрез
вычайно важна для разрешения проблемы синхронизации и предотвращения
условий гонок.
Операция up увеличивает значение семафора. Если с этим семафором связаны
один или несколько ожидающих процессов, которые не могут завершить более
раннюю операцию down, один из них выбирается системой (например, случай
ным образом) и ему разрешается завершить свою операцию down. Таким обра
зом, после операции up, примененной к семафору, связанному с несколькими
ожидающими процессами, значение семафора так и остается равным О, но число
ожидающих процессов уменьшается на единицу. Операция увеличения значения
семафора и активизации процесса тоже неделима. Ни один процесс не может
быть блокирован во время выполнения операции up, как ни один процесс не мог
быть блокирован во время выполнения операции wakeup в предыдущей модели.
В оригинале Дейкстра употреблял вместо down и up обозначения Р и v соответ
ственно. Мы не будем в дальнейшем использовать оригинальные обозначе
ния, поскольку тем, кто не знает голландского языка, эти обозначения ничего не
скажут (да и тем, кто знает язык, говорят немного). Впервые обозначения down
и up появились в языке Алгол 68.
vo i d produ c e r ( vo i d )
{
int i t em ;
vo i d c onsumer ( vo i d )
i n t i t em ;
wh i l e ( TRUE ) /* Бес конечный цикл * /
down ( & f u l l ) ; /* Уменьшить чис ло полных с е гментов буфера * /
down ( &mu t ex ) ; /* Вход в критическую с е кцию * /
i t em = r emove_i t em ( ) ; /* Удалить элемент и з буфера * /
up ( &mu t ex ) ; /* Выход и з критичес кой с е кции * /
up ( &empty ) ; /* Уве личить с ч е тчик пус тых с е гментов буфера * /
c onsume_i t em ( i t em ) ; /* Обработка элемента * /
2 . 2 . 6 . М ьютексы
Иногда, если не нужно применять семафор как счетчик, используется его упро
щенный вариант, называемый мъютексом (mutex). Мьютексы способны лишь
обеспечивать взаимное исключение для общего ресурса или фрагмента кода.
Их реализация отличается простотой и эффективностью, что делает мьютексы
исключительно полезными в программных потоках, реализуемых исключитель
но в пространстве пользователя.
Мьютекс представляет собой переменную, способную находиться в одном из двух
состояний: блокированном и разблокированном. Для хранения такой перемен
ной достаточно одного бита, хотя на практике мьютекс имеет целочисленный тип:
нулевое значение соответствует разблокированному состоянию, а любое ненуле
вое - блокированному. Мьютексы управляются двумя процедурами. Когда про
цессу (или программному потоку) ·необходимо войти в критическую секцию, он
вызывает процедуру mut ex_ l o ck. Если мьютекс в этот момент разблокирован
1 06 Глава 2 . Процессы
2 . 2 . 7 . Мониторы
Взаимодействие между процессами с применением семафоров выглядит доволь
но просто, не правда ли? Но эта простота кажущаяся. Взгляните внимательнее
на порядок выполнения процедур down перед помещением элементов в буфер
или удалением их из буфера в листинге 2.5. Представьте себе, что две процедуры
down в программе производителя поменялись местами, так что значение mu tex
было уменьшено раньше, чем empty. Если буфер был заполнен, производитель
блокируется, сбросив mut ex в О. Соответственно, в следующий раз, когда потре
битель обратится к буферу, он выполнит операцию down с переменной mut ex,
равной О, и тоже заблокируется. Оба процесса навсегда оказываются заблокиро
ванными. Эта неприятная ситуация называется взаимной блокировкой (deadlock),
и мы вернемся к ней в главе 3.
Описанная ситуация показывает, с какой аккуратностью нужно обращаться с се
мафорами. Одна маленькая ошибка, и все останавливается. Это напоминает про
граммирование на ассемблере, но на самом деле еще сложнее, поскольку такие
ошибки приводят к абсолютно невоспроизводимым и непредсказуемым услови
ям гонок, взаимным блокировкам и т. п.
Чтобы упростить написание программ, Бринч Хансен (Brinch Hansen) в 1973 го
ду и Хоар (Hoare) в 1974 году предложили примитив синхронизации более вы
сокого уровня, называемый монитором. Их предложения несколько отличались
друг от друга, как мы увидим дальше. Монитор - это набор процедур, пере
менных и других структур данных, объединенных в особый модуль, или пакет.
Процессы могут вызывать процедуры монитора, но у процедур, объявленных вне
монитора, нет прямого доступа к внутренним структурам данных монитора. По
добное правило, обычное для современных объектно-ориентированных языков,
таких как ] ava, было нестандартным в то время, хотя объекты поддерживались
уже в языке Simula 67. В листинге 2.6 представлен монитор, написанный на во
ображаемом языке, некоем •местечковом диалекте• - •пиджин• Pascal.
Реализации взаимных исключений способствует важное свойство монитора: при
обращении к монитору в любой момент времени активным может быть только
один процесс. Мониторы являются структурным компонентом языка програм
мирования, поэтому компилятор знает, что обрабатывать вызовы процедур мони
тора следует иначе, чем вызовы остальных процедур. Обычно при вызове процеду
ры монитора первые несколько команд процедуры проверяют, нет ли в мониторе
2 . 2 . Взаимодействие между п роцессами 1 07
end ;
end ;
end moni t o r ;
pro c e du r e i n s e r t ( i t em : i n t e g e r ) ;
beg i n
i f c ount = N t hen wa i t ( fu l l ) ;
i n s e rt_i t em ( i t em ) ;
c ount : = c ount + l ;
i f c ount = 1 then s i gna l ( empty )
end ;
func t i on remove : i n t e g e r ;
begin
if c ount = О then wa i t ( empty ) ;
remove = remove_i t em ;
c ount : = c ount-1 ;
i f c ount = N - 1 t hen s i gnal ( f u l l )
end ;
c ount : = О ;
end moni t o r ;
2 . 2 . 8 . Передача сообщений
В роли чего-то другого выступает механизм передачи сообщений. Взаимодействие
между процессами такого рода строится на двух примитивах: s end и r e c e ive,
которые являются скорее системными вызовами, нежели структурными компо
нентами языка (что отличает их от мониторов и делает похожим на семафоры).
Поэтому их легко можно инкапсулировать в библиотечные процедуры, например:
s end ( de s t i na t ion , &me s sage ) ;
r e c e ive ( sourc e , &me s s age ) ;
i n t i t em ;
me s s age m ; / * Буфер для с о о бщений * /
whi l e ( TRUE )
i t em = produc e_i t em ( ) ; / * Сформировать нечто , чтобы з аполнить
! * буфер * /
r e c e i ve ( consumer. , &m ) ; / * Ожидание прибытия пу с т о г о с о общения * !
bu i l d_me s sage ( &m , i t em ) ; ! * Сформировать с о о бщение для отправки * !
s end ( con sumer , &m ) ; ! * Отослать эл емент потребителю * /
vo i d c on sumer ( vo i d )
i n t i t em , i ;
me s s age m ;
for (i = О; i < N; i++ )
{
s end ( produc er , &m ) ;
/ * Отослать N пус тых с о о бщений * /
wh i l e ( TRUE ) {
r e c e ive ( produc e r , &m ) ; /* Полу чить с о о бщение с эл ементом * /
i t em = ext rac t_i t em ( &m ) ; /* Из влечь элемент и з с о о бщения * /
s end { p roduc er , &m ) ; /* Отослать пу с т о е соо бщение * /
con sume_i t em ( i t em ) ; !* Обработка эл емента * /
Можно изменить программу так, чтобы после получения левой вилки проверя
лась доступность правой. Если правая вилка недоступна, философ кладет левую
обратно, ждет некоторое время и повторяет весь процесс. Этот подход также не
будет работать, хотя и по другой причине. Если не повезет, все пять философов
могут начать процесс одновременно, взять левую вилку, обнаружить отсутст
вие правой, положить левую обратно на стол, одновременно взять левую вилку,
и так до бесконечности. Ситуация, в которой все программы продолжают рабо
тать сколь угодно долго, но не могут добиться хоть какого-то прогресса, называ
ется зависанием (starvation).
Вы можете подумать: <1: Если философы будут размышлять в течение некото
рого случайно выбранного промежутка времени после неудачной попытки взять
правую вилку, вероятность того, что все процессы будут продолжать топтать
ся на месте хотя бы в течение часа, невелика� . Это правильно, и для большинст
ва приложений повторение попытки спустя некоторое время снимает проблему.
Например, в локальной сети Ethernet в ситуации, когда два компьютера посы
лают пакеты одновременно, каждый должен подождать случайно заданное вре
мя и повторить попытку - на практике это решение хорошо работает. Тем не
менее в некоторых приложениях предпочтительным является другое решение,
работающее всегда и не зависящее от случайных чисел ( например, в прило
жении, предназначенном для обеспечения безопасности на атомных электро
станциях).
Листинг 2.9 можно улучшить, исключив взаимные блокировки и зависания процес
сов; для этого достаточно защитить пять команд, следующих за запросом think,
бинарным семафором. Тогда философ должен будет выполнить операцию down
для переменной rnut ex прежде, чем тянуться к вилкам. А после возврата вилок
на место ему следует выполнить для переменной rnut ex операцию up. С теорети
ческой точки зрения решение вполне подходит. С позиций практики возникают
проблемы эффективности: в каждый момент времени может есть спагетти только
один философ. Но вилок пять, поэтому логичней бьто бы разрешить есть в каж
дый момент времени двум философам.
Решение, представленное в листинге 2. 1 0, исключает взаимные блокировки и по
зволяет реализовать максимально возможный параллелизм для любого числа
философов. Здесь используется массив s t a t e для отслеживания душевного со
стояния каждого философа: он либо ест, либо размышляет, либо голодает (пы
таясь получить вилки). Философ может начать есть, только если ни один из его
соседей не ест. Соседи философа i определяются макросами LEFT и RIGHT (то
есть если i 2, то LEFT 1 и R I GHT 3).
= = =
if ( state [ i ]
== HUNGRY & & s t a t e [ LEFT ] != EAT ING & & s t a t e [ RIGHT ] != EAT ING ) {
s t a t e [ i ] = EAT ING ;
up ( & s [ i ] ) ;
vo i d reader ( vo i d )
vo i d wr i t e r ( vo i d )
Первый читающий процесс выполняет операцию down для семафора dЬ, чтобы
получить доступ к базе. Последующие читатели просто увеличивают значение
счетчика rc. По мере уменьшения числа читающих из базы значение счетчика
уменьшается, и последний читающий процесс выполняет для семафора dЬ опера
цию up, позволяя блокированному пишущему процессу получить доступ к базе.
В этом решении один момент требует комментариев. Представьте, что в то время
как один читатель уже пол ьзуется базой, другой читатель запрашивает к ней
доступ. Доступ разрешается, поскольку читающие процессы друг другу не меша
ют. Доступ разрешается и третьему., и последующим читателям.
1 18 Глава 2. П роцессы
2 . 4 . Планиро вание
Когда компьютер работает в многозадачном режиме, на нем могут быть активны
ми несколько процессов, пытающихся одновременно получить доступ к процес
сору. Эта ситуация возникает, когда два и более процессов находятся в состоя
нии готовности. Если доступен только один процессор, необходимо выбирать
между процессами. Отвечающая за это часть операционной системы называется
планировщиком, а используемый алгоритм алгоритмом планирования.
-
2 . 4 . 1 . Основы планирования
Давным-давно, в о времена систем пакетной обработки, перфокарт и магнитных
лент в качестве устройств ввода, алгоритм планирования был прост: запустить
следующую задачу. С появлением систем разделения времени алгоритм пла
нирования усложнился, поскольку теперь несколько задач одновременно могли
ожидать обслуживания. На некоторых мэйнфреймах до сих пор совмещаются
системы пакетной обработки и службы разделения времени. Может показаться,
что на персональных компьютерах активным является только один процесс: в са
мом деле, пользователь, работающий с документом в текстовом редакторе, едва
ли станет компилировать программу в фоновом режиме. В то же время фоновые
задания отнюдь не являются редкостью. Примером является демон электронной
почты, осуществляющий прием и передачу сообщений. Вы также можете поду
мать, что в последние годы быстродействие компьютеров возросло настолько, что
о нехватке ресурсов процессора можно забыть. Однако и требования современных
2.4. План ирова н ие 1 19
Поведение процесса
Почти все процессы чередуют периоды интенсивной вычислительной работы
с вводом-выводом (в том числе дисковым), как показано на рис. 2.8. Как прави
ло, в течение некоторого времени процессор работает без остановки, а затем
выполняется системный вызов на запись или чтение файла. По завершении сис
темного вызова процессор вновь продолжает вычисления до тех пор, пока не воз
никнет потребность получения или записи данных и т. д. Обратите внимание, что
некоторые действия по вводу-выводу считаются вычислительными. Примером
служит копирование процессором битов в видеопамять для обновления экрана.
Здесь мы имеем дело именно с вычислениями, поскольку в данной операции за
действован центральный процессор. Под вводом-выводом в таком контексте сле
дует понимать ситуацию, когда процесс блокируется и ожидает окончания работы
внешнего устройства.
Время
____,
•�
Рис. 2 . 8 . Чередование периодов использования процессора и ожидания ввода-вывода:
а - процесс ограничен вычислительными возможностями; б процесс ограничен
-
возможностями ввода-вывода
Рисунок 2.8 иллюстрирует одну важную вещь. Некоторые процессы (рис. 2.8, а)
большую часть своего времени тратят на вычисления, другие же процессы
(рис. 2.8 , б) в основном ожидают ввода-вывода. Первые оzраничены вычисли
телънъtМи возможностями, вторые возможностями ввода-вывода. Процессы,
-
+ Интерактивные системы:
+ время отклика - быстрая реакция на запросы;
+ пропорциональность - соответствие ожиданиям пользователей.
+ Системы реального времени:
+ соответствие временным ограничениям - избежание потерь данных;
+ предсказуемость - избежание потери качества в мультимедиа-системах.
При всех обстоятельствах необходимо справедливое распределение процессор
ного времени. Сопоставимые процессы должны получать сопоставимое обслу
живание. Выделять одному процессу намного больше ресурсов процессора, чем
другому, эквивалентному, несправедливо. Разумеется, с различными категория
ми процессов следует обращаться совершенно по-разному. Сравните, например,
задачи обеспечения безопасности атомной электростанции и начисления зара
ботной платы в компьютерном центре.
Применение системных политю< связано со справедливым распределением ре
сурсов. Если, к примеру, локальная политика требует, чтобы процессы управле
ния безопасностью могли быть запущены в любой момент даже при условии, что
программа выдачи платежных ведомостей будет задержана на 30 секунд, плани
ровщик должен обеспечить выполнение таких условий работы.
Еще одна общая цель планировщика - по возможности загружать все части сис
темы работой. Если процессор и все устройства ввода-вывода работают непре
рывно, их производительность выше, чем при простое каких-либо компонентов.
Например, в системе пакетной обработки планировщик решает, ка1ше процессы
загружать в память для выполнения. Предпочтительнее иметь в памяти несколь
ко из процессов, ограниченных возможностями процессора и ввода-вывода, чем
сначала загрузить и выполнить только первые, а затем - только вторые. Процес
сы, ограниченные вычислительными возможностями, начнут конкурировать за
вычислительный ресурс, а диск в это время будет простаивать. Когда очередь
дойдет до процессов, ограниченных возможностями ввода-вывода, будет про
стаивать процессор, поскольку основная борьба развернется за устройства вво
да-вывода. Лучше всего поддерживать в работе всю систему, тщательно отбирая
процессы для обработки.
Как правило, менеджеры корпоративных компьютерных центров с интенсивной
пакетной обработкой оценивают производительность подведомственных систем
по трем показателям: пропускной способности, времени оборота и коэффициенту
использования процессора. Пропускной способностью называется число зада
ний, выполняемых системой в секунду. Ясно, что 50 заданий в секунду лучше,
чем 40. Время оборота - это среднее время с момента ввода задания до его вы
полнения. Оно показывает, сколько в среднем пользователь вынужден ждать
результатов обработки. Нетрудно сформулировать правило: чем меньше время
оборота, тем лучше.
Алгоритм планирования, максимизирующий пропускную способность, совсем не
обязательно сводит к минимуму время оборота. Например, если планировщик
выбирает из группы заданий в первую очередь самые короткие, а затем - самые
2. 4 . План и ро вание 1 23
8 4 4 4 4 4 4 8
А в с D в с D А
а б
Пример планирования по алгоритму «самое короткое задание - первое»: запуск
Рис. 2 . 9 . а -
сразу же, а три оставшиеся - через три минуты. Время выполнения этих за
даний составляет 2 , 4, 1, 1 и 1 мин соответственно, а время оборота О, О, 3, 3 -
Т рехуровневое планирован ие
С определенной точки зрения системы пакетной обработки позволяют осуще
ствлять планирование на трех разных уровнях, как показано на рис. 2 . 1 0. После
поступления в систему новые задания сначала помещаются в очередь, храни
мую на жестком диске. Далее планировщик допуска решает, какие задания при
нять в систему. Остальные ожидают во входной очереди, пока не будут выбра
ны планировщиком. Как правило, контроль допуска обеспечивает желательное
сочетание заданий, ограниченных возможностями процессора и ввода-вывода.
Возможен и другой подход - короткие задания выбираются быстрее, чем дли
тельные. Планировщик допуска может выбирать задания из очереди по собст
венному усмотрению, независимо от того, какие из них пришли раньше, а какие -
позже.
1 Процессор о 1
t Планировщик процессора
�о r ооооо
Задание Входная очередь
rЬd
1 1 101010 101
� О·=-.::.....
Планировщик Планировщик Диск
допуска памяти
Рис . 2 . 1 0 . Трехуровневое планирование
2.4. П л анирование 1 27
После того как задание допущено в систему, для него может быть создан про
цесс, способный претендовать на ресурсы процессора. Тем не менее возможна
ситуация, в которой процессов окажется так много, что в имеющейся памяти их
не удастся разместить. В этом случае часть процессов будет вытеснена на жест
кий диск. Какие процессы вытеснить, а какие оставить в памяти, решает второй
уровень планирования, а соответствующий планировщик называется планиров
щиком памяти.
Планирование памяти должно осуществляться регулярно, поскольку процессы,
находящиеся на диске, нуждаются в обслуживании. Однако перенос процесса
с диска в оперативную память является затратным, а потому планирование имеет
смысл выполнять не чаще одного раза в секунду. Постоянное •жонглирование•
содержимым памяти приведет к тому, что значительная часть пропускной спо
собности диска будет потеряна, замедлив ввод-вывод файлов.
Чтобы оптимизировать производительность системы в целом, планировщику па
мяти имеет смысл рассчитать желаемое число и типы процессов в памяти. Число
процессов называется степенью многозадачности. Зная, какие процессы ограни
чены вычислительными возможностями, а какие - возможностями ввода-вывода,
планировщик может нацелить усилия на поддержку в памяти нужного сочета
ния процессов. В качестве очень грубого приближения можно привести следую
щий пример: если некоторый класс процессов тратит 20 % времени на вычисле
ния, то наличие в памяти 5 таких процессов обеспечит 100-процентную загрузку
процессора.
Планировщик памяти периодически анализирует каждый процесс на жестком
диске, чтобы решить, следует ли перенести его в основную память. Решение мо
жет основываться на следующих критериях.
+ Сколько времени прошло с последнего переноса процесса в оперативную па-
мять или на жесткий диск?
+ Сколько процессорного времени получил данный процесс за последнее время?
+ Каков объем процесса? (Небольшие процессы вряд ли переполнят память.)
+ Насколько важным является процесс?
На третьем уровне планирования из находящихся в оперативной памяти процес
сов выбирается тот, который будет запущен следующим. Как правило, плани
ровщика этого уровня называют планировщиком процессора и именно его чаще
всего имеют в виду, говоря о планировании. Планировщик процессора может
использовать любой подходящий алгоритм с вытеснением или без вытесне
ния. Часть алгоритмов уже нами рассмотрена; другие мы рассмотрим в следую
щем разделе.
Циклическое планирован ие
Одним из наиболее старых, простых, справедливых и часто используемых явля
ется алгоритм циклического, или карусельного, планирования. Каждому процес
су предоставляется некоторый интервал времени процессора, так называемый
квантом. Если к концу кванта процесс все еще работает, он прерывается, а управ
ление передается другому процессу. Разумеется, если процесс блокируется или
прекращает работу раньше, переход управления происходит в этот момент. Реа
лизация циклического планирования проста. Планировщику нужно всего лишь
согласно поддерживать список процессов в состоянии готовности (рис. 2. 1 1 , а).
Исчерпав свой лимит времени, процесс отправляется в конец списка (рис. 2. 1 1 , б).
Текущий Текущий
процесс
�
�
а б
Рис. 2. 1 1 . Циклическое планирование: - список процессов в состоянии готовности;
а
б- список процессов в состоянии готовности после того, как процесс В
исчерпал свой квант
Единственным интересным моментом этого алгоритма является величина кван
та. Переключение с одного процесса на другой занимает некоторое время -
необходимо сохранить и загрузить регистры и карты памяти, обновить таблицы
и списки, сохранить и перезагрузить кэш памяти и т. п. Представим, что переклю
чение процессов, или переключение контекста, как его иногда называют, занимает
1 мс, включая переключение карт памяти, перезагрузку кэша и т. п. Пусть вели
чина кванта установлена равной 4 мс. В таком случае 20 % процессорного време
ни уйдет на администрирование - это слишком много.
Для повышения эффективности назначим размер кванта, скажем, 1 00 мс. Теперь
пропадает только 1 % времени. Но представьте, что будет в системе разделения
времени, если 10 пользователей одновременно нажмут клавишу возврата карет
ки. В список будет занесено 1 О процессов. Если процессор был свободен, первый
процесс будет запущен немедленно, второму придется ждать 1 00 мс и т. д. По
следнему процессу, возможно, придется ждать целую секунду, если все осталь
ные не блокируются за время кванта. Большинству пользователей секундная за
держка вряд ли понравится.
Важен и тот фактор, что если установленное значение кванта больше среднего
интервала работы процессора, переключение процессов будет происходить ред
ко. Напротив, большинство процессов окажутся заблокированными прежде, чем
истечет квант, сто потребует переключение процессов. Устранение принудитель
ных переключений процессов повышает производительность системы, так как
2 . 4 . План ирование 1 29
П риоритетное планирование
Алгоритм карусельного планирования базируется на важном допущении о том,
что все процессы равнозначны. В случае компьютера с большим числом пользо
вателей это может быть не так. Например, в университете первыми должны об
служиваться деканы, затем профессора, секретари, уборщицы, сторожа и лишь
потом студенты. Необходимость принимать во внимание подобные внешние фак
торы приводит к приоритетному планированию. Основная идея проста: каждому
процессу присваивается свой приоритет в 4Табеле о рангах� и управление пере
дается готовому к работе процессу с самым высоким приоритетом.
Даже на персональном компьютере с одним пользователем могут выполняться
несколько процессов, отдельные из которых являются более важными, чем дру
гие. Демон, отвечающий за пересылку электронной почты в фоновом режиме,
имеет более низкий приоритет, чем процесс, отображающий на экране видео
фильм в реальном времени.
Чтобы предотвратить бесконечное выполнение высокоприоритетных процессов,
планировщик может уменьшать приоритет выполняемого процесса с каждым
тактом (то есть по каждому прерыванию от таймера). Если в результате приори
тет текущего процесса окажется ниже приоритета следующего процесса, про
изойдет переключение. Возможно также предоставление каждому процессу мак
симального отрезка времени работы. Как только время кончается, управление
передается следующему по значимости процессу.
Приоритеты процессам могут присваиваться статически или динамически. На во
енной базе процессу, запущенному генералом, присваивается приоритет 100, пол
ковником 90, майором 80, капитаном 70, лейтенантом 60 и т. д. А в ком
- - - -
Готовые
Начало очередей к запуску процессы
Приоритет 4 (Самый высокий приоритет)
Приоритет 3
Приоритет 2
Приоритет 1 (Самый низкий приоритет)
Рис. 2. 1 2 . Алгоритм планирования с четырьмя классами приоритетов
Гарантированное планирование
Принципиально другим подходом к планированию является предоставление поль
зователям реальных обещаний и затем их исполнение. Вот обещание, которое
легко произнести и легко выполнить: если вместе с вами с процессором работа
ют п пользователей, вам будет предоставлено 1/п мощности процессора. И в сис
теме с одним пользователем и п запущенными процессорами каждому достанет
ся 1/п циклов процессора.
Чтобы сдержать это обещание, система должна отслеживать распределение про
цессора между процессами с момента создания каждого процесса. Затем система
рассчитывает количество ресурсов процессора, на которое процесс имеет право,
например, время с момента создания, деленное на п. После этого можно сосчи
тать отношение времени, предоставленного процессу, к времени, на которое он
имеет право. Полученное значение 0,5 означает, что процессу выделили только
половину положенного, а 2,0 говорит о том, что процессу досталось в два раза
больше его нормы. Далее запускается процесс, у которого это отношение наи
меньшее, пока оно не станет больше, чем у его ближайшего соседа.
Лотерейное планирование
Хотя идея обещаний пользователям и их выполнения хороша, но ее трудно реа
лизовать. Для получения предсказуемых результатов применяется другой алго
ритм, называемый лотерейным планированием [ 1 26].
В его основе лежит раздача процессам «лотерейных билетов� на доступ к раз
личным ресурсам, в том числе к процессору. Когда планировщику необходимо
принять решение, выбирается случайным образом лотерейный билет, и его обла
датель получает доступ к ресурсу. Что касается доступа к процессору, «лотерея�
может разыгрываться 50 раз в секунду, и победитель получает 20 мс времени
процессора.
2. 4 . Планирование 1 33
Справедливое планирован ие
До настоящего момента мы планировали процессы, игнорируя вопрос о том, кто
является их владельцами. Если, к примеру, пользователь 1 запустит 9 процессов,
а пользователь 2 - 1 процесс, то, согласно циклическому или приоритетному
планированию, пользователь 1 получит 90 % процессорного времени, а пользо
ватель 2 - 1 0 %.
Чтобы избежать подобного «неравенства» , некоторые системы используют в пла
нировании информацию о владельцах процессов. Каждому пользователю пре
доставляется определенная доля ресурсов процессора, и процессы выбираются
на исполнение таким образом, чтобы обеспечить принятый вариант разделения.
Например, если двум пользователям обещана половина процессорного времени,
система обеспечит этот показатель независимо от запущенных ими процессов.
Пусть пользователь 1 запустил четыре процесса А, В, С и D, а пользователь
-
! СР;;
i=t
�1.
2. Система
реального
времени
выбирает поток
1 . Ядро выбирает процесс 1 . Ядро выбирает поток lj
Возможные: А 1 , А2, АЗ, А 1 , А2, АЗ Возможные: А 1 , А2, АЗ, А 1 , А2, АЗ
Невозможные: А1 , В1 , А2, В2, АЗ, ВЗ Также возможные: А1 , В1 , А2, В2, АЗ, ВЗ
а б
Планирование программных потоков: - планирование программных
Рис. 2. 1 3 . а
потоков уровня пользователя при времени выполнения потока 5 мс и кванте 50 мс;
б -планирование программных потоков уровня ядра в тех же условиях
Система реального времени может использовать любой из алгоритмов плани
рования, описанных ранее. На практике чаще всего прибегают к циклическому
и приоритетному алгоритмам. Единственным ограничением является отсутствие
таймера, прерывающего программный поток, который выполняется слишком дошо.
2 . 5 . Процессы в MI N IX 3 1 37
2 . 5 . П роцессы в M I N IX 3
Сейчас, завершив изучение принципов управления процессами, взаимодействия
между ними и алгоритмы планирования, мы можем приступить непосредствен
но к их реализации в MINIX 3. В отличие от UNIX, где ядро представляет собой
1 38 Глава 2 . Процессы
1 ! !
Уровень
1 1 ...
lпit процесс процесс процесс процессы
1 1 ...
процессов система сервер сервер процессы пользователя
Я дро
1
1
1
Таймерное
задание
:
1
Системное
задание
Ядро } Режим ядра
Рис. 2 . 1 4 . Четыре уровня структуры MINIX 3. Только процессы нижнего уровня могут
использовать привилегированные команды (команды режима ядра)
Ядро, находящееся на нижнем уровне, осуществляет обработку и управление со
стояниями готовности, выполнения и блокировки (см. рис. 2.2). Кроме того, яд
ро обрабатывает все сообщения, передаваемые между процессами, - проверяет
допустимость адресата, обнаруживает в физической памяти буферы приема и пе
редачи и копирует байты от отправителя к получателю. Частью ядра является
механизм доступа к портам ввода-вывода и прерываниям, в современных про
цессорах требующий использования привилегированных команд режима ядра,
которые недоступны обычным процессам.
Помимо ядра, нижний уровень содержит два модуля, функционирующих по
добно драйверам устройств. Таймерное задание представляет собой драйвер вво
да-вывода в том смысле, что оно взаимодействует с аппаратным обеспечением,
генерирующим тактовые сигналы. Тем не менее, в отличие от драйвера диска
или линии связи, оно недоступно пользователю, поскольку имеет интерфейс
только с ядром.
Одной из главных функций уровня 1 является предоставление вышестоящим
драйверам и серверам набора вызовов ядра. С помощью этих вызовов осуществ
ляется чтение и запись портов ввода-вывода, копирование данных между адрес
ными пространствами и т. д. Реализация вызовов ядра возложена на системное
задание. Хотя системное и таймерное задания находятся в адресном пространстве
ядра, их планирование осуществляется раздельно, а сами процессы имеют собст
венные стеки вызовов.
2.5. Процессы в MI N IX 3 1 39
Большая часть ядра и все задания ядра и системы написаны на языке С. Однако
в некоторых небольших фрагментах ядра используется ассемблер - в тех, кото
рые отвечают за обработку прерываний, низкоуровневые механизмы управления
переключением контекста между процессами (сохранение и восстановление ре
гистров и т. п.) и устройствами управления памятью. В общем, ассемблер приме
нялся там, где ядру было необходимо непосредственное низкоуровневое взаимо
действие с аппаратным обеспечением, недоступное для языка С. При переносе
MINIX 3 на новую архитектуру ассемблерный код должен быть соответствую
щим образом переписан.
Три уровня, находящихся над ядром, могут рассматриваться как один, поскольку
ядро, в сущности, взаимодействует с ними одинаково. Уровни ограничены коман
дами полъзователъскоzо режима, а ядро планирует запуск каждого из них. Уров
ни не имеют прямого доступа к портам ввода-вывода и, более того, ни один из
них не способен обращаться к памяти за пределами выделенного ему сегмента.
Тем не менее привилегии процессов (к примеру, возможность вызывать ядро)
могут различаться. На этом и построено разделение по уровням 2, 3 и 4. Процессы
уровня 2 имеют самые широкие привилегии, процессы уровня 3 - более ограни
ченные, и, наконец, процессы уровня 4 совсем лишены привилегий. К примеру,
драйверы устройств, находящиеся на уровне 2, могут без ограничений требо
вать, чтобы системное задание выполнило чтение или запись данных в порты
ввода-вывода. Драйвер необходим каждому типу устройств - дискам, принте
рам, терминалам, сетевым интерфейсам и др. Драйверы устройств могут выпол
нять и другие вызовы ядра, например копирование считанных данных в адрес
ное пространство другого процесса.
Третий уровень включает серверы - процессы, предоставляющие полезные услу
ги пользовательским процессам. Два сервера являются обязательными. Менеджер
процессов (Process Manager, РМ) выполняет все системные вызовы MINIX 3,
связанные с запуском и остановкой процессов (например, f o rk, е х е с и exi t ) ,
а также сигналами (например, a l arrn и k i l l , т о есть вызовами, способными из
менить состояние процесса). Кроме того, менеджер процессов ответственен за
управление памятью, в частности, с помощью системного вызова br k. Файловая
система (File Systern, FS) выполняет все файловые системные запросы, такие
как re ad, rnount и chdi r.
Важно понимать различие между вызовами ядра и системными РОSIХ-вызова
ми. Вызовы ядра представляют собой низкоуровневые функции, предоставляе
мые системным заданием драйверам и серверам для выполнения необходимых
действий. Типичный вызов ядра - чтение данных из аппаратного порта ввода
вывода. Системные РОSIХ-вызовы, такие как read, f o rk и unl ink, напротив,
являются высокоуровневыми и доступны программам, расположенным на уров
не 4. Пользовательские программы выполняют большое количество систем
ных вызовов, однако не выполняют вызовов ядра. Конечно, если разрешить себе
�жонглирование• терминами, вызов ядра можно было бы назвать системным
вызовом. Механизмы выполнения обоих типов вызовов схожи, и вызовы ядра
допустимо рассматривать как особый частный случай системных вызовов.
1 40 Глава 2. Процессы
2 . 5 . 2 . Уп равление п роцессами в M I N IX 3
В MINIX 3 процессы соответствуют описанной несколько ранее обобщенной мо
дели процесса. Процессы могут запускать процессы-потомки, те, в свою очередь,
могут делать то же самое, образуя, таким образом, дерево процессов. По сути, все
пользовательские процессы в системе - листы одного дерева, в корне которого
находится процесс ini t (см. рис. 2. 14). Разумеется, особый случай представля
ют серверы и драйверы, поскольку часть из них должна быть запущена раньше
любого пользовательского процесса, включая i n i t .
1 42 Глава 2. Процессы
Запуск M I N IX 3
Каким же образом запускается операционная система? Этому вкратце посвяще
ны несколько следующих страниц. О загрузке некоторых других операционных
систем вы можете узнать в [4 1 ] .
В большинстве компьютеров, оснащенных дисковыми устройствами, имеется
иерархия загрузочных дисков. Как правило, если в дисководе обнаруживается
дискета, она используется в качестве загрузочного диска. Если дискеты нет, но
в устройство CD-ROM вставлен компакт-диск, система пытается загрузиться
с него. Если же ни дискета, ни компакт-диск не вставлены, в качестве загрузоч
ного выбирается первый жесткий диск. Порядок иерархии можно задать в BIOS
сразу после подачи питания на компьютер. Иногда поддерживается возможность
загрузки с других устройств, в основном сменных.
Аппаратное обеспечение считывает первый сектор первой дорожки загрузочного
диска в память и исполняет записанный на нем код. В случае дискеты этот сек
тор содержит программу начальной загрузки. Она очень мала - не более одного
сектора ( 5 1 2 байт). Программа начальной загрузки M INIX 3 загружает дру
гую, б ольшую программу boo t , а та, в свою очередь, - операционную систему.
В случае загрузки с жесткого диска требуется дополнительный промежуточный
этап. Жесткие диски разбиваются на разделы, и первый сектор жесткого диска
содержит небольшую программу и таблиИJJ разделов, вместе они называются глав
ной загрузочной записъю ( Master Boot Record, MBR). Программная часть считы
вает таблицу разделов и выбирает активный раздел. В первом секторе активного
раздела расположена программа начальной загрузки, которая загружается, после
чего действует так же, как при загрузке с дискеты, запуская программу boo t .
Устройства CD-ROM появились позже, чем дискеты и жесткие диски. При под
держке загрузки с компакт-диска существует возможность копирования в память
более чем одного сектора. Компьютер, поддерживающий загрузку с CD-RO M,
может единовременно разместить в оперативной памяти блок данных большого
объема. Как правило, в этом случае с компакт-диска загружается точная копия
загрузочной дискеты, которая используется в качестве виртуального диска. Да
лее управление передается виртуальному диску и загрузка продолжается так,
как будто в качестве физического загрузочного устройства используется диске
та. Устаревшие компьютеры, оснащенные устройством CD- RO М, но не поддер
живающие загрузку с компакт-диска, позволяют скопировать на дискету загру
зочный образ, посредством которого можно запустить систему (разумеется, при
вставленном в устройство чтения компакт-диске).
В любом случае после запуска программа boot ищет на диске различные компо
ненты системы и размещает их по нужным адресам - создает загрузочный образ.
Ключевыми составляющими загрузочного образа являются ядро (включающее
таймерное и системное задания), менеджер процессов и файловая система. В за
грузочный образ должен входить как минимум один драйвер диска. Кроме того,
в загрузочном образе имеется ряд других программ - сервер реинкарнации, вир
туальный диск, консоль, драйверы журналов и процесс ini t .
2 . 5 . Процессы в M I N IX 3 1 43
Следует особо подчеркнуть, что все части загрузочного образа являются отдель
ными программами. После загрузки необходимых компонентов - ядра, ме
неджера процессов и файловой системы - можно отдельно загрузить множество
других частей. Исключение составляет сервер реинкарнации, который должен
являться частью загрузочного образа. После инициализации он назначает обыч
ным загруженным процессам приоритеты, делающие их системными. Сервер ре
инкарнации также перезапускает драйверы в случае аварии (именно этим объ
ясняется его название). Как было отмечено ранее, загрузочный образ должен
содержать как минимум один дисковый драйвер. Если корневая файловая систе
ма подлежит копированию на виртуальный диск, также потребуется драйвер па
мяти (в противном случае его можно загрузить позднее). Драйверы t ty и l og
являются на загрузочном образе необязательными. Они загружаются как можно
раньше потому, что на начальной стадии запуска системы желательно иметь воз
можность отображать сообщения на консоли и записывать информацию в жур
нал. Разумеется, процесс ini t тоже можно загрузить позднее, однако он управ
ляет начальным конфигурированием системы, и включение его в загрузочный
образ упрощает работу.
Запуск системы - не простая операция. Программа boot вынуждена брать на
себя действия, выполняемые дисковым драйвером и файловой системой до того,
как эти компоненты будут готовы взять управление на себя. В следующем разделе
мы подробнее рассмотрим вопросы запуска MINIX 3, а сейчас достаточно сказать,
что как только процесс загрузки завершается, ядро начинает работу.
В процессе инициализации ядро запускает сначала таймерное и системное за
дания, затем - менеджер процессов и файловую систему. Менеджер процессов
и файловая система совместными усилиями запускают остальные серверы и драй
веры, входящие в загрузочный образ. После запуска и инициализации все эти
компоненты блокируются и ожидают действий. Планировщик MINIX 3 назнача
ет процессам приоритеты. Первый пользовательский процесс, ini t , запускается
лишь после того, как все задания, драйверы и серверы, загруженные из образа,
оказываются в состоянии блокировки. Системные компоненты, загружаемые
из загрузочного образа или в ходе инициализации, перечислены в табл. 2.3.
2 . 5 . З . Взаимодействие между
процессами в M I N IX
Для отправки и приема сообщений предусмотрено три примитива. Им соответ
ствуют следующие библиотечные процедуры языка С:
+ Отправление сообщения процессу dest:
send ( de s t , &me s s age ) ;
2 . 5 . 4 . Планирование п роцессов в M I N IX 3
Мультипрограммную операционную систему движет система прерываний. Сде
лав запрос на ввод данных, процесс блокируется, позволяя выполняться другим
процессам. Когда запрошенные данные становятся доступными, процесс преры
вается диском, клавиатурой или другим оборудованием. Кроме того, прерывания
генерируются и таймером, это гарантирует, что процесс, не требующий ввода, не
2.5. Процессы в M I NIX 3 1 49
будет работать слишком долго. Задача нижнего уровня MINIX 3 - скрыть пре
рывания, преобразовав их в сообщения. С точки зрения процессов, завершение
операции устройством ввода-вывода - это сообщение, передаваемое устройст
вом определенному процессу, пробуждающее его и приводящее его в состояние
готовности.
Прерывания также генерируются программно; в этом случае их иногда называют
исключения.ми. Описанные ранее операции s end и r e c e i ve транслируются сис
темной библиотекой в команды проzраммноzо прерывания, эффект от которого
ничем не отличается от аппаратного прерывания. Процесс, исполняющий про
граммное прерывание, немедленно блокируется, а ядро активизируется для об
работки прерывания. Пользовательские программы не обращаются к операциям
s end и rec e i ve впрямую, однако каждый раз при использовании одного из
системных вызовов, перечисленных в табл. 1 . 1 (непосредственно или через биб
лиотечную процедуру), происходит внутренний вызов s endrec и генерируется
программное прерывание.
Каждый раз, когда происходит прерывание процесса, независимо от источни
ка прерывания (таймер или периферийное устройство), у системы появляется
возможность принять решение, какому процессу больше требуется процессор.
Конечно, это обязательно нужно делать и при завершении процесса, но в систе
мах, подобных MINIX 3, переключения должны происходить чаще, чем заверше
ния процессов.
Планировщик MINIX использует многоуровневую систему очередей. Определе
ны шестнадцать очередей, хотя при повторной компиляции число очередей мож
но без труда увеличить или уменьшить. Самый низкий приоритет назначается
только процессу I DLE, который выполняется исключительно во время простоя.
По умолчанию пользовательские процессы запускаются с приоритетом на не
сколько уровней выше наименьшего.
Как правило, серверы в очереди имеют более высокий приоритет, чем пользова
тельские процессы, драйверы - более высокий приоритет, чем серверы, а тай
мерное и системное задания - самый высокий приоритет. Обычно в отдельно
взятый момент времени используются не все 1 6 возможных очередей, а лишь не
сколько. Процесс может быть перемещен из одной очереди в другую системой
или (с оговорками) пользователем при помощи команды n i c e . •дополнитель
ные� уровни открывают возможности для экспериментов и по мере добавления
в систему новых драйверов позволяют изменить предлагаемые по умолчанию
параметры для оптимизации производительности. Например, если вы захотите
добавить сервер, передающий в сеть потоковые аудио- и видеоданные, вы сможе
те назначить ему более высокий стартовый приоритет, чем у других серверов.
Вы также можете снизить приоритет текущего сервера или драйвера, чтобы обес
печить более высокую производительность нового сервера.
Помимо очередей с разными приоритетами, существует еще один механизм,
обеспечивающий одним процессам преимущество над другими. Квант, то есть
временной интервал, выделяемый процессу для работы, имеет разную длитель
ность для разных процессов. Квант пользовательских процессов относительно
1 50 Глава 2. П роцессы
короткий; драйверы и серверы же, как правило, выполняются до тех пор, пока не
входят в состояние блокировки. Квант применяется к драйверам и серверам для
того, чтобы избежать сбоев в работе системы (зависаний) , однако он значи
тельно длиннее, чем у пользовательских процессов. Если процесс исчерпал свой
квант, он считается готовым к работе и помещается в конец очереди. Если же
выясняется, что исчерпавший текущий квант процесс выполнялся и в предыду
щем кванте, это трактуется как признак <�:зацикливания», препятствующего ра
боте процессов с более низким приоритетом. В этом случае процесс помещается
в конец более низкоприоритетной очереди. Если ситуация повторяется, приори
тет процесса снова снижается тем же способом. В конечном счете система рано
или поздно выберет другой процесс для запуска.
Процесс, приоритет которого был снижен, может снова его повысить. Если про
цесс расходует свои кванты времени, но не препятствует выполнению других про
цессов, он помещается в очередь с более высоким приоритетом и может подобным
образом достичь наивысшего доступного ему уровня. Очевидно, что такой про
цесс нуждается в процессорном времени, но не захватывает его в ущерб другим.
В рамках очереди планирование процессов осуществляется при помощи цикли
ческого алгоритма с небольшим изменением. Если процесс не исчерпал свой
квант, но вышел из состояния готовности, это воспринимается как блокирование
по вводу-выводу. Когда процесс вновь готов к выполнению, он помещается в на
чало очереди, но ему выделяется не целый квант, а лишь неиспользованная часть
кванта, в ходе которого он был заблокирован. Такой подход обеспечивает опера
тивность реакции пользовательских процессов на ввод-вывод. Процесс, исчер
павший выделенный ему квант, помещается в конец очереди согласно классиче
скому циклическому алгоритму.
Поскольку задания, как правило, имеют наивысший приоритет, за ними следуют
драйверы, затем серверы и лишь затем пользовательские процессы, последние
выполняются только в случае, если все системные процессы бездействуют. Сис
темные же процессы ради обслуживания пользовательских процессов отложены
быть не могут.
Выбирая процесс для запуска, планировщик обращается к очереди с наивысшим
приоритетом. Если один или несколько ее процессов готовы, из их числа выби
рается первый. В противном случае аналогично проверяется очередь с более
низким приоритетом и т. д. Поскольку драйверы отвечают на запросы серверов,
а серверы - на запросы пользовательских процессов, в какой-то момент все вы
сокоприоритетные процессы заканчивают свою работу и переходят в состояние
ожидания, а пользовательские процессы получают возможность выполняться и
генерируют новые запросы. Если же система обнаружит, что ни один процесс не
готов, она выберет процесс I DLE, переводящий процессор в состояние низкого
энергопотребления до появления прерывания.
По каждому сигналу таймера проверяется, не истек ли квант текущего процесса.
Если квант истек, планировщик перемещает процесс в конец очереди (для этого
не требуется никаких действий, если очередь состоит из единственного процесса).
Затем выбирается следующий процесс. Предыдущий процесс может получить
2.6. Реализ ац ия п роцессов в M I N IX 3 1 51
второй квант времени подряд при двух условиях: очереди с более высокими при
оритетами отсутствуют, а в своей очереди он является единственным. В против
ном случае процессорное время получает процесс, находящийся в начале первой
по приоритету непустой очереди. Важные драйверы и серверы получают настоль
ко длинный квант, что, как правило, не прерываются таймером. Тем не менее их
приоритет может быть временно снижен в случае неполадок, чтобы предотвра
тить полную остановку системы. Возможно, сбой важного драйвера не позволит
системе выполнять полезные действия, однако, как минимум, есть шанс завер
шить ее работу корректно, без потери данных, и даже собрать отладочную ин
формацию для устранения неполадки.
Книга не попадает в печать в первый же день после того, как авторы ставят по
следнюю точку, и книга, и программное обеспечение постоянно развиваются.
Поэтому между приведенными в книге листингами и версиями кода на компакт
диске могут быть небольшие различия. Но обычно различия незначительны, не
более одной или двух строк. Приведенный исходный код упрощен: из него удале
ны не обсуждаемые в книге фрагменты. Полную версию вы найдете на компакт
диске. Кроме того, текущая редакция, включая новые средства, дополнительное
программное обеспечение и документацию, представлена на веб-сайте операци
онной системы MINIX 3 (http://www . minixЗ. org).
чала выполняется в каталоге, где находится файл исходного кода (или в указан
ном подкаталоге), и лишь затем при его отсутствии - в каталоге, предлагаемом
по умолчанию. Например, следующая команда считывает локальный файл:
Jl i nc lude " имя файла "
2 . 6 . 2 . Компиляция и запуск M I N IX 3
Чтобы скомпилировать операционную систему MINIX 3, запустите команду
make в каталоге s r c / t oo l s. Команда имеет ряд параметров, управляющих ре
жимами установки. Эти параметры можно просмотреть, запустив команду make
без параметров. Простейшим методом установки является выполнение команды
make image.
При использовании команды make image последняя копия заголовочных фай
лов каталога s r c / inc l ude / копируется в каталог u s r / inc l ude / . Затем ис
ходные коды каталога s r c / kerne l / и некоторых подкаталогов s rc / s ervers /
и s r c / dr i v er s / компилируются в объектные файлы. Все объектные файлы
s r c / kerne l / компонуются в единственную исполняемую программу, kerne l ,
объектные файлы s r с / s erver s / pm - в программу pm, а объектные файлы
s r c / s e rv e r s / f s / - в программу f s . Дополнительные программы, являю
щиеся в табл. 2.3 частью загрузочного образа, также подвергаются компиляции
и компоновке в своих каталогах. В частности, программы r s и i n i t создают
ся в подкаталогах s r c / dr iver s / , а memory, l og и t ty - в подкаталогах src /
dr iver s / . Компонент, упомянутый в табл. 2.3 как «драйверi> , может быть од
ним из нескольких дисковых драйверов. Мы будем считать, что операционная
система MINIX 3 сконфигурирована под загрузку с жесткого диска с использова
нием стандартного драйвера at_wini, компилируемого в каталоге src / drivers /
at_wini / . Можно добавить и множество других драйверов, однако большинст
во из них не обязательно включать в загрузочный образ. Это же касается и сете
вой поддержки; компиляция базовой системы MINIX 3 не зависит от наличия
или отсутствия сети.
Для того чтобы готовая к работе система MINIX 3 могла загружаться, програм
ма i ns t a l lboot (ее исходный код находится в каталоге s r c / boot l ) именует
kerne l , pm, f s , i n i t и прочие ее компоненты, дополняет их так, чтобы размер
каждого компонента был кратен размеру сектора диска (для упрощения незави
симой загрузки программ), и объединяет их в единый файл. Это файл является
загрузочным образом; вы можете скопировать его в каталог / bo o t / или под
каталог / boot / image / дискеты или раздела жесткого диска. Позже программа
монитора загрузки поместит загрузочный образ в память и передаст управление
операционной системе.
На рис. 2 . 1 5 показана структура памяти после того, как программы загрузочно
го образа отделены друг от друга и загружены. Ядро располагается в нижней час
ти адресного пространства, в то время как все остальные компоненты - выше
1 Мбайт. Сначала пользовательским программам выделяется свободное место
над ядром. Когда очередную программу не удается разместить там, ее поме
щают выше, над программой ini t. Разумеется, детали зависят от конфигурации
системы. Например, на рис. 2 . 1 5 система MINIX 3 содержит кэш блоков, способ
ный хранить 5 1 2 блоков размером по 4 Кбайт. Это весьма скромная конфигурация;
при достаточном объеме памяти размер кэша следует увеличить. В то же вре
мя, если размер кэша блоков сократить, всю систему можно разместить в памяти
1 56 Глава 2. П роцессы
ниже отметки 640 К, при этом в оставшуюся память можно загрузить несколько
пользовательских процессов.
• [Монитор
'l Память, доступная �
1 к о
пользовательским
программам
Системное задание 55 К
scr/kemel/kemel тсlймеРiiоезаданив
1- - - - - - - - - - - -
Ядро
i [Используется BIOSJ: 2 К Начало области ядра
[Векторы 1к
прерываний]
о
Рис. 2 . 1 5 . Структура памяти после загрузки MINIX З с диска. Ядро, серверы и драйверы
компилируются и компонуются независимо друг от друга. Названия соответствующих
программ перечислены слева. Размеры указаны приблизительно и не соответствуют
масштабам рисунка
Важно понимать, что MINIX 3 состоит из нескольких полностью независимых
друг от друга программ, взаимодействующих друг с другом посредством сообще
ний. Процедура p ani c из каталога s r c / s e rvers / f s / не конфликтует с одно
именной процедурой из каталога src / s erver s / prn / , поскольку при компонов
ке они помещаются в разные исполняемые файлы. Единственные процедуры,
совместно используемые тремя компонентами операционной системы, находят
ся в библиотеке s rc / l i Ы . Модульная структура позволяет с легкостью моди
фицировать, скажем, файловую систему, не затронув менеджер процессов. Более
того, не составляет труда полностью удалить файловую систему и поместить ее
на другой компьютер, играющий роль файлового сервера и взаимодействующий
с пользовательскими машинами, обмениваясь сообщениями по сети.
2 . 6 . Реал изаци я п роцессов в M I NIX 3 1 57
функций.
Еще один определенный здесь макрос проверки поддерживаемых функций -
вместо того, чтобы напрямую передавать значение О. Этот файл нужен в основ
ном файловой системе, но он же применяется в нескольких местах внутри ядра
и менеджера памяти.
Как мы увидим при рассмотрении уровня драйверов устройств MINIX в главе 3,
консольный и терминальный интерфейсы операционной системы сложны:, по
скольку большое количество различного оборудования должно взаимодейство
вать с операционной системой и пользовательскими программами стандартным
образом. Для управления устройствами ввода-вывода терминального типа исполь
зуются константы, макросы и функции, прототипы которых приведены в файле
t e rmi o s . h (строка 1000). Самая главная структура здесь - структура t e rmi o s .
2 . 6 . Реализация процессов в M I N IX 3 1 61
Как было отмечено ранее, большая часть условного кода удалена из текста, однако
мы сохранили этот пример, чтобы продемонстрировать механизм использования
условных определений. Maкpoc _EM_WS I Z E - еще один макрос проверки поддер
живаемых функций, определенный компилятором. Он задает размер слова дан
ных целевой системы в байтах. Последовательность # i f . . . # е l s е . . . # endi f
создает определения «раз и навсегда» , чтобы обеспечить корректную компиля
цию кода независимо от разрядности системы - 16 или 32 бит.
В операционной системе MINIX 3 широко используются несколько других файлов
из каталога inc lude / sy s / . Файл sy s / s i gcont ext . h (строка 1 600) определяет
2.6. Реализация п роцессов в M I N IX 3 1 63
int who ;
Такая функция может быть вызвана только кодом, расположенным в том же ис
ходном файле. Использовать макросы PRIVATE и PUBL I C необязательно, это -
только попытка исправить проблемы, вносимые соглашениями С (где по умол
чанию имена размещаются в глобальной области видимости, а должно быть
наоборот).
В оставшейся части файла cons t . h определяются константы, повсеместно ис
пользуемые в системе. Так, например, везде и всюду в коде фигурирует величина
базового блока памяти, зависящая от архитектуры системы. Для платформ Intel
она равна 1 024 байт. В строках 2673-268 1 определены другие ее значения, соот
ветствующие платформам Intel, Motorola 68000 и Sun SP ARC. Кроме того, в этом
файле определяются удобные макросы МАХ и MIN. Например, для вычисления
большего из двух значений можно применить следующую запись:
z = МАХ ( х , у ) ;
Еще один файл, косвенно включаемый при каждой компиляции в главные заго
ловочные файлы, - это t yp e . h (строка 2800). В нем содержится ряд описаний
ключевых типов и связанных с ними числовых констант.
1 68 Глава 2 . П роцессы
Первые две структуры определяют два различных типа карт памяти (строки
2828-2840): одна из них соответствует локальным областям (внутри пространст�
ва данных процесса), а другая - удаленным областям памяти (к примеру, вирту
альному диску). Здесь самое время рассказать о концепциях обращения к памя
ти. Как мы уже упомянули, размер базового блока памяти в MINIX 3 составляет
1024 байт. Существует две ссылки на память: ссылка phy s_c l i c k s использует
ся ядром для доступа к любому элементу памяти системы, а ссылка v i r_
c l i cks предназначена для всех процессов, отличных от ядра. Ссылка v i r_
c l i cks всегда указывается относительно начала сегмента памяти, выделенной
определенному процессу, и ядру зачастую приходится осуществлять преобразо
вания между виртуальными (относящимися к процессам) и физическими (отно
сящимися к оперативной памяти) адресами. Подобное неудобство компенсиру
ется тем, что процесс может самостоятельно выполнять внутренние обращения
к памяти, используя ссылку v i r_c l i ck s .
В ы могли бы предположить, что для задания размера памяти обоих типов доста
точно одной ссылки. Тем не менее указание выделенной процессу памяти с по
мощью ссылки v i r_c l i cks имеет одно преимущество: vi r_c l i cks гарантирует,
что ни одно обращение к памяти не выйдет за границы пространства, выделенного
процессу. Такая возможность присуща современным процессорам Intel, в част
ности семейству Pentiurn, и называется защищенным режимом. Отсутствие за
щищенного режима в ранних процессорах 8086 и 8088 вызывало проблемы при
разработке первых версий MINIX.
Еще одна важная структура, определенная в файле typ e . h, - s i gms g (строки
2866-2872). При перехвате сигнала ядро должно гарантировать, что процесс,
которому был послан сигнал, при следующем своем запуске начнет выполнять
процедуру обработки сигнала, а не продолжит работу в обычном порядке. Боль
шая часть работы по управлению сигналами выполняется менеджером процес
сов. В случае перехвата сигнала менеджер процессов передает ядру структуру,
подобную s i gmsg.
Структура k in f o (строки 2875-2893) используется для распространения инфор
мации о ядре среди других компонентов системы. Менеджер процессов задейст
вует эту информацию, формируя свою часть таблицы процессов.
Структуры данных и прототипы функций взаимодействия между процессам.и оп
ределены в заголовочном. файле ipc . h (строка 3000). Наиболее важным опреде
лением в этом файле является тип me s s age (строки 3020-3032). Его можно бы
ло бы задать как массив определенного количества байтов, но для поддержания
хорошего стиля программирования он описан как структура, содержащая объ
единение различных типов сообщений. Всего имеется семь форматов сообще
ний, с именами от me s s_l до me s s_B (формат me s s_б больше не использует
ся). В структуре me s s age есть поле m_s ource, представляющее собой структуру
с информацией об отправителе сообщения, поле m_typ e , определяющее формат
сообщения (для системного задания - SYS_EXEC), и поля с данными сообщения.
Структуры семи типов сообщений показаны на рис. 2. 1 6. Первые две и послед
ние две структуры кажутся одинаковыми. С точки зрения размеров элементов
2 . 6 . Реализация процессов в M I NIX 3 1 69
данных это действительно так, однако в типах данных имеется множество разли
чий. Если на 32-разрядном процессоре Intel типы int , l ong и указатели на дан
ные имеют одинаковую разрядность 32 бита, это отнюдь не означает, что на друтой
аппаратной платформе картина будет той же. Семь различных форматов введены
именно для упрощения перекомпиляции MINIX 3 под различные архитектуры.
передачи данных типа uns i gned l ong. Кто-то может сказать, что мы поступаем
неправильно, но если вы собираетесь перенести MINIX 3 на новую платформу,
то вам почти наверняка придется некоторое время поработать над точным фор
матом сообщений, теперь же вы предупреждены, что поведению компилятора
также нужно уделить немало внимания.
В файле ip c . h также определены прототипы ранее описанных примитивов пе
редачи сообщений (строки 3095-3 1 0 1 ). Наряду с основными примитивами s end
r e c e ive, s endrec и no t i fy, определен и ряд других. Последние применяются
редко и являются скорее пережитками ранних этапов разработки MINIX 3. Ста
рые компьютерные программы являются источником интересных <�:археологиче
ских находок� и в последующих выпусках операционной системы вполне могут
<�:вымереть� . Тем не менее без пояснений с нашей стороны некоторые читате
ли наверняка засомневаются. Неблокирующие вызовы nb_s end и nb_r e c e i ve
в основном заменены вызовом no t i fy, появившимся позднее и лучше разре
шавшим проблему передачи и проверки неблокирующих сообщений. Прототип
примитива e cho не имеет полей источника и приемника. Вызов e cho бессмыс
лен в рабочем коде, однако полезен в процессе разработки, поскольку позволяет
определять время передачи и приема сообщений.
Один из файлов каталога i n c l ude / rni n ix, sys l ib . h (строка 3200) использу
ется практически повсеместно и включен в главные заголовочные файлы всех
компонентов MINIX 3, относящихся к пользовательскому пространству. Для
доступа к самому себе ядру не нужны библиотечные функции, поэтому в заголо
вочном файле ядра, s rc / kerne l / k e rne l . h, ссылка на sys l ib . h отсутствует.
Файл sys l ib . h содержит прототипы библиотечных С-функций, вызываемых
из операционной системы для доступа к другим системным службам.
Мы не будем описывать детали, касающиеся библиотек С, однако многие биб
лиотечные функции являются стандартными и доступны в любом компиляторе
языка. Тем не менее функции, на которые ссылается файл sys l i b . h, специ
фичны для MINIX 3, и перенос MINIX 3 в систему с другим компилятором потре
бует переноса указанных функций. К счастью, это не составляет труда, посколь
ку большинство функций попросту извлекают параметры, указанные в вызове,
и вставляют их в структуру сообщения, а затем отсылают сообщение и извлека
ют результаты из ответа. Многие из таких библиотечных функций укладывают
ся в дюжину строк С-кода.
Отдельного внимания в файле sys l i b . h заслуживают четыре макроса досту
па к портам ввода-вывода по чтению и записи с использованием байтов и слов,
а также прототип функции sys_sdev i o , на которую ссылаются все макросы
(строки 324 1 -3250). Важнейшим механизмом, используемым в MINIX 3 и по
зволяющим переместить все драйверы устройств в пользовательское простран
ство, является передача запросов на чтение и запись портов ввода-вывода от драй
веров устройств к ядру.
Несколько функций, которые могли бы быть включены в файл sys l ib . h, вынесе
ны в другой файл, sysu t i l . h (строка 3400), поскольку их объектный код компи
лируется в отдельную библиотеку. Две функции нуждаются в более тщательном
2. 6. Реализаци я процессов в M I N IX 3 1 71
проверяется там, где при компиляции необходимо учитывать разницу между сис
темным и пользовательским кодом (например, может меняться знак кода возврата).
Затем в kerne l . h включаются другие заголовочные файлы из каталога inc lude /
и его подкаталогов inc lude / sy s / , inc lude / m i n i x / и inc lude / ibm / , в том
1 74 Глава 2 . Процессы
числе перечисленные в листинге 2 . 1 2 . Все эти файлы уже были нами рассмот
рены в двух предыдущих разделах. Затем присоединяются еще шесть заголовоч
ных файлов из локального каталога s r c / ke rne l / , имена которых заключены
в кавычки.
Файл kerne l . h позволяет легко включить в исходные файлы большое количе
ство необходимых определений при помощи одной команды:
# i nc lude " kernel . h "
Перед тем как двигаться дальше, заметим, что из-за микроядерной структуры
MINIX 3 таблица процессов, которую мы будем рассматривать, имеет аналоги
в менеджере процессов и файловой системе. Последние используют таблицы, за
писи которых характеризуют процессы, а содержащаяся в них информация отно
сится к функциональности соответствующего системного компонента MINIX 3.
В совокупности все три таблицы эквивалентны таблице процессов операцион
ной системы с монолитной структурой, однако обсуждая таблицу процессов здесь,
мы будем иметь в виду таблицу ядра. Остальные таблицы рассматриваются в со
ответствующих главах.
Каждая запись в таблице процессов определена как структура p r o c (строки
55 1 6-5545). Каждый элемент таблицы процессов хранит регистры процесса,
указатель стека, состояние процесса, карту памяти, предельный размер стека,
идентификатор процесса, информацию о времени срабатывания таймера, сооб
щениях и прочие сведения о процессе. Первая часть каждого элемента таблицы -
это структура s t ac k f rarne_s . Когда процесс переходит в состояние выполне
ния, его указатель стека восстанавливается по адресу из записи в таблице про
цессов, и все регистры процессора восстанавливаются из этой структуры.
Тем не менее состояние процесса - это больше, чем регистры процессора и дан
ные памяти. В MINIX 3 каждый процесс имеет указатель на структуру привиле
гий в своей записи в таблице процессов (строка 5522). Эта структура определяет
допустимых отправителей и получателей сообщений для данного процесса, а так
же множество привилегий. Мы рассмотрим детали позднее, а сейчас просто
обратите внимание на следующее: каждый системный процесс содержит указа
тель на уникальную копию этой структуры, однако привилегии пользователей
одинаковы, поскольку указатели пользовательских процессов ссылаются на од
ну и ту же копию. Кроме того, имеется поле размером 1 байт, содержащее набор
битовых флагов, p_rt s_f l ags (строка 5523). Назначения битов описаны далее.
Установка любого бита в 1 означает, что процесс не может быть запущен; таким
образом, нулевое значение поля указывает на готовность процесса.
Каждая запись в таблице процессов предоставляет место для информации, ко
торая может быть необходима ядру. Например, поле p_rnax_p r i o r i ty ( стро
ка 5526) указывает, в какую очередь следует поместить процесс, когда он будет
готов к выполнению в первый раз. Поскольку приоритет процесса может быть
понижен при условии, что он препятствует выполнению других процессов, имеет
ся поле p_p r i o r i ty, значение которого изначально совпадает с полем p_rnax_
p r i o r i ty. Поле p_p r i o r i ty определяет очередь, в которую процесс помеща
ется при готовности.
Время, затраченное процессом, регистрируется в двух переменных c l o ck_t (стро
ки 5532 и 5533). Ядро должно иметь доступ к этой информации, поэтому ее хра
нение в пространстве памяти процесса было бы неэффективно, хотя и возможно
2 . 6 . Р еал и з а ци я п роцессов в M I NIX 3 1 79
а б
Дисковые структуры, используемые при начальной загрузке:
Рис. 2 . 1 7 . а -диск
без разбиения на разделы, первый сектор является загрузочным блоком; б диск,
-
Если вы получили такое сообщение, это означает, что инициализация ядра за
вершена. Функция prepare_shut down (строка 7272) посылает всем процессам
сигнал S I GKSTOP (системным процессам нельзя посьшать сигналы так же, как
пользовательским), а затем устанавливает таймер, выделяя всем системным про
цессам время на «уборку� до вызова последней процедуры, shut down. Процеду
ра shut down, как правило, возвращает управление монитору загрузки MINIX 3.
Для этого к контроллерам прерываний применяются параметры, восстанавли
ваемые из BIOS с помощью функции i nt r_i n i t ( 0 ) (строка 7338).
2 . 6 . 8 . Обработка прерыван и й в M I N IX
Особенности обработки прерываний во многом зависят от аппаратной платфор
мы, но у любой системы должны быть элементы с подобной функционально
стью. В 32-разрядных процессорах Intel прерывания генерируются аппаратным
обеспечением и в виде электрических сигналов передаются сначала на контрол
лер прерываний. Это - интегральная схема, которая умеет различать несколько
подобных сигналов и для каждого из них генерировать уникальный идентифи
катор на шине данных процессора. Сам же процессор имеет лишь один вход для
всех устройств, а следовательно, не может определить, какое именно устройство
нуждается в обслуживании. У компьютеров с 32-разрядными процессорами Intel
обычно имеются два контроллера прерываний, каждый из которых обслуживает
8 устройств. Но один контроллер подчинен (slave) другому, то есть сигналы с его
выхода передаются на вход главного (master) контроллера. Таким образом, эта
комбинация контроллеров способна обслуживать 15 различных устройств, как
показано на рис. 2 . 1 8. Некоторые из 1 5 входов являются выделенными; напри
мер, вход таймера, I RQ О , не подключен к какому-либо разъему, предназначенному
для адаптеров. Остальные же входы подключены к разъемам и могут использо
ваться так же, как и обычные устройства.
Прерывание
------ IRQ О (часы)
INT Ji INT 14----- IRQ 1 (клавиатура)
�
::;;
Главный -.t----- IRQ 3 (tty 2)
CPU :s; контроллер -.t--- -- IRQ 4 (tty 1 )
u
прерываний �г----- IRQ 5 (винчестер ХТ)
INTA � ::t: АС К -.-1----- IRQ 6 (дисковод)
::t:
ltl
1:[
--.г----- IRQ 7 (принтер)
Подтверждение ltl
прерывания 3 ::t:
:s; IRQ 8 (часы реального времени)
INT IRQ 9 (перенаправление IRQ2)
Подчиненный IRQ 1 0
контроллер IRQ 1 1
\,------i
прерываний IRQ 12
i,.------.i
IRQ 1 3 (исключение FPU)
АСК IRQ 14 (винчестер АТ)
IRQ 1 5
Рис. 2. 1 8 . Обработка прерываний в 32-разрядных процессорах lntel
1 96 Глава 2. П роцессы
Разница только в том, что при аппаратном прерывании адрес процедуры берется
не из памяти, а из регистра контроллера.
Механизм переключения задач в 32-разрядных процессорах Intel, как ответ на
прерывание, довольно сложен, и изменение значения счетчика команд - только
часть этого процесса. Когда процессор, уже обрабатывающий некоторый процесс,
получает прерывание, он сначала выделяет новый стек, который будет использо
ваться для выполнения обработчика. Положение стека определяется значением
записи в сегменте состояния задания (Task State Segrnent, TSS). Эта структура
едина для всей системы, инициализируется при вызове prot_ini t и модифи
цируется при запуске каждого процесса. В результате каждый новый стек, со
здаваемый прерыванием, всегда начинается от конца структуры s t a c k f rarne_s
в записи в таблице процессов прерванного процесса. Затем процессор автомати
чески помещает в новый стек значения нескольких регистров, включая нужные
для восстановления стека и счетчика команд прерванного процесса. Обработчик
прерывания заносит в стек значения дополнительных регистров, заполняя кадр
стека, после чего переключается на другой стек, предоставляемый ядром. Этот
стек и используется для всех действий по обработке прерывания.
Завершив свою работу, обработчик прерывания переключается обратно на кадр
стека в таблице процессов (не обязательно на тот, который использовался для
предыдущего прерывания), затем самостоятельно извлекает из стека значения
2.6. Реализация процессов в M I N IX 3 1 97
случае обработка стека подпрограммой s ave оставит адрес функции _re s t art
в стеке ядра, что вызовет повторный запуск задания, драйвера, сервера или поль
зовательского процесса. С большой вероятностью это будет процесс, отличный
от того, который выполнялся в момент прерывания. Все зависит от того, привело
ли к изменению планирования процессов обслуживание сообщения, созданного
процедурой обработки прерывания. Как правило, в случае аппаратного прерыва
ния очереди процессов изменяются. Обработчики прерываний чаще всего пере
дают драйверам устройств сообщения, а драйверы размещаются в очередях с бо
лее высоким приоритетом, чем пользовательские процессы. Таким образом, мы
видим самое сердце механизма, обеспечивающего иллюзию нескольких одновре
менно выполняющихся процессов.
Для полноты упомянем, что в том случае, когда прерывание происходит в мо
мент выполнения кода ядра, стек ядра уже используется. Поэтому функция s ave
помещает в стек адрес r e s t ar t l . Тогда после завершения hwi nt_mas t er ко
мандой r e t работа ядра восстанавливается. Это позволяет делать вложенные
прерывания, которые запрещены в MINIX 3, поскольку прерывания недопусти
мы во время исполнения кода ядра. Тем не менее, как было отмечено, данный
механизм необходим для обработки прерываний. Когда выполнение низкоуров
невых процедур завершается, вызывается _r e s t a r t . В результате реакции на
исключение при исполнении кода ядра с высокой вероятностью следующим
будет запущен процесс, отличный от прерванного. Исключение в ядре приведет
к сбою, после которого система попытается завершить свою работу с минималь
ными повреждениями.
Процедура hwi nt_s l ave отличается от hwint_ma s t er только тем, что в ней
необходимо восстанавливать два контроллера, и подчиненный, и главный, так
как они оба блокируются при приеме сигнала подчиненным контроллером.
Теперь двинемся дальше и рассмотрим процедуру s ave (строка 6622), уже не
сколько раз упомянутую. Ее имя описывает ее предназначение, заключающееся
в том, чтобы сохранить контекст прерванного процесса в выделенном процессо
ром стеке (в кадре стека внутри таблицы процессов). Кроме того, для поддержки
вложенных прерываний s ave использует переменную _k_r e enter, чтобы под
считать число вложений и определить их наличие. Если процесс был прерван,
следующая инструкция (строка 6635) переключается на стек в ядре:
mov esp , k_s t kt o p
Устройство:
Передает контроллеру п рерываний
электрический сигнал
Контроллер:
1 Программа:
1.Записывает указатель на сообщение
и указатель на пункт назначения
1.
Преры вает централ ьный процессор в регистры процессора
2.
Отправляет цифровой идентификатор 2.Выполняет инструкцию программного
устройства, вызвавшего прерывание прерывания
Ядро:
l Ядро:
l
1.
Сохраняет состоя ние регистров 1.Сохраняет состоя ние регистров
2.
Отп равляет уведомление драйверу 2.Отправляет и/или получает сообщение
3. Перезапускает процесс 3. Перезапускает процесс (не обязател ьно
(возможно драйвер) вызывающий)
а б
Рис . 2 . 1 9 . Сравнение механизмов обработки а п п а ратного п р е р ы вания и системного вызова:
а - обработка ап паратного п р е р ы вания ; б - так происходит систе м н ы й вызов
- - -
-
<Zхолодна;»>' 1
/ Процесс
\ загрузка
.... ,...
/ или задача
- -
г - - - - - - - -
Пространство
пользователя
Рис . 2 . 20. Restart код, исполняемый как после запуска системы, так и после прерываний
-
адрес возврата, помещенный в стек при вызове s ave. Если прерывание произош
ло во время выполнения пользовательского процесса, завершающая инструкция
i r e t d передает управление следующему процессу в очереди планировщика, при
этом восстанавливаются его оставшиеся регистры, в том числе указатель и адрес
сегмента стека. Но если управление было передано через r e s t ar t l , то есть за
действован не кадр стека, а стек ядра, это означает, что после завершения совсем
не нужно переходить к новому процессу, а требуется завершить выполнение пре
рванного кода ядра. Процессор отслеживает подобную ситуацию, когда извлека
ет дескриптор сегмента кода из стека при выполнении i r e t d, и, обнаружив ее,
оставляет использоваться стек ядра.
Теперь самое время сказать несколько слов об исключениях. Исключения вы
зываются различными ошибками выполнения, однако это не всегда плохо. Ис
ключения полезны, чтобы побудить систему предоставить некоторые допол
нительные услуги, например выделить программе дополнительную память или
загрузить в оперативную память страницу, перемещенную в область подкачки
(хотя в MINIX 3 подобные услуги не предусмотрены). Иногда исключения обу
словлены ошибками в программах. Когда исключение возникает внутри ядра,
это вызывает серьезный сбой системы. Если исключение происходит в поль
зовательской программе, ее можно завершить, но такой подход неприменим
к операционной системе - она должна выполняться постоянно. Обрабаты
вают исключения так же, как и прерывания, то есть через дескрипторы в таб
лице дескрипторов прерываний. В этой таблице имеется шестнадцать запи
сей, содержащих указатели на точки входа обработчиков исключений, начиная
с _di vi de_error и заканчивая _copr_error, которые можно увидеть в кон
це файла rnpx3 8 6 . s (строки 6707-6769). Каждая из этих точек входа передает
управление процедуре exc ep t i on ( строка 6774) или e r r e x c ep t i on (стро
ка 6785 ) в зависимости от того, помещается ли при исключении в стек код
ошибки или нет. Обработка выполняется командами ассемблера и во многом на
поминает уже рассмотренный нами код: значения регистров сохраняются в сте
ке, и вызывается С-функция _exc ep t i on (обратите внимание на знак под
черкивания перед именем). Последствия исключений могут быть различными:
некоторые игнорируются, некоторые вызывают сообщение о сбое ядра, другие
посылают сигналы процессам. Самой функцией _excep t i on мы займемся в сле
дующем разделе.
Существует еще одна точка входа, которая обрабатывается как прерывание, -
это _l eve l O_c a l l (строка 6714). Она используется, когда код необходимо ис
полнить с нулевым (максимальным) уровнем привилегий. Эта точка входа нахо
дится в файле mрхЗ 8 6 . s вместе с прерываниями и исключениями потому, что
она также вызывается при помощи инструкции int <nnn>. Как и обработчики
исключений, она выполняет вызов s ave, а завершается инструкцией r e t , веду
щей к _r e s t ar t . Ее мы рассмотрим в следующем разделе, когда мы познако
мимся с кодом, нуждающемся в обычно недоступных (даже ядру) привилегиях.
Наконец, в конце ассемблерного файла выделяется место для хранения некото
рых данных. Определяются два различных сегмента данных.
206 Глава 2. П роцессы
. s e c t . rom
Это объявление в строке 6822 гарантирует, что указанная область памяти нахо
дится в самом начале сегмента данных ядра. Сюда компилятор помещает сигна
туру (магическое число), чтобы программа boot могла убедиться, что загружает
действительно ядро. При компиляции всей системы за магическим числом будут
размещены различные строковые константы. Еще одна область данных задается
следующей директивой (строка 6825):
. s e c t . bs s
2 . 6 . 9 . Взаимодействие м ежду
процессам и в M I N IX 3
В MINIX 3 процессы взаимодействуют друг с другом при помощи сообщений по
принципу рандеву. Когда процесс делает системный вызов s end (отправка сооб
щения), нижний уровень ядра проверяет, ожидает ли получатель сообщение от
отправителя (или от любого процесса - неопределенный отправитель имеет спе
циальное имя ANY). Если это так, сообщение копируется из буфера отправителя
в буфер получателя, и оба процесса помечаются как готовые к выполнению. Если
получатель не ждет сообщений, отправитель блокируется и помещается в оче
редь процессов, ожидающих отправки сообщения.
Когда процесс делает системный вызов r e c e i ve, ядро проверяет, есть ли в очере
ди ожидающих отправки процессов процессы, пытающиеся отправить сообщение
текущему процессу. Если таковые есть, сообщение передается из буфера отпра
вителя в буфер получателя, и оба процесса выходят из состояния блокировки.
Если ожидающих отправителей нет, процесс-получатель приостанавливается до
прибытия сообщения.
В операционной системе MINIX 3, где компоненты выполняются как полностью
независимые процессы, метод рандеву не всегда хорош. Именно для таких ситуа
ций предназначен примитив no t i fy, рассьmающий «базовые� сообщения. От
правитель не блокируется, если адресат такого сообщения не находится в ожида
нии приема, но при этом сообщение не теряется. При ближайшем совершении
получателем вызова r e c e i ve активные уведомления доставляются прежде обыч
ных сообщений. Уведомления применяются в ситуациях, где использование обыч
ных сообщений привело бы к взаимным блокировкам. Ранее мы указывали на
то, что необходимо избежать ситуации, когда процесс А блокируется при попыт
ке передать сообщение процессу В, а процесс В блокируется при попытке пере
дать сообщение процессу А. Если одно из сообщений является неблокирующим
уведомлением, проблема исчезает.
2 .6 . Реализация процессов в M I N IX 3 207
отправить сообщение процессу О. Если при этом процесс 4 также не сможет от
править сообщение процессу О, возникает ситуация, продемонстрированная на
рис. 2.2 1 , б.
·� ·�
4 p_q_link = О
3 p_q_link = О � p_q_link
2
1
о p_caller_q - >-- p_caller_q
т т т т
а б
Рис. 2 . 2 1 . Очереди процессов, ожидающих отправления сообщения процессу О
Функция rnini_rec e i ve (строка 7642) вызывается функцией sys_cal l в случае,
если значение переменной func t i on равно RECE IVE или вотн. Как мы упомяну
ли ранее, уведомления имеют более высокий приоритет, чем обычные сообщения.
Тем не менее уведомление никогда не передается в ответ на вызов s end, поэтому
битовые карты проверяются на наличие активных уведомлений лишь в случае,
если флаг S ENDREC_BUSY сброшен. При обнаружении уведомления оно помеча
ется как неактивное и доставляется (строки 7670-7685 ). При доставке использу
ются макросы Bu i l d.Мe s s и C opyMe s s , определенные в начале файла proc . с .
На первый взгляд может показаться, что, поскольку временная метка является
частью уведомления, он несет в себе полезную информацию. Например, если ад
ресат не мог выполнить вызов rec e i ve в течение какого-то времени, временная
метка поможет определить, как долго сообщение ожидало доставки. Однако
временная метка устанавливается при генерации уведомления, а именно - в мо
мент его доставки, а не отправки. Для этого есть причина. Дело в том, что для
сохранения уведомлений, которые не могут быть доставлены немедленно, не
нужно никаких специальных действий. Все, что требуется, - это установить бит,
указывающий на необходимость восстановления уведомления в момент, когда
доставка станет возможной. Таким путем достигается максимально экономичное
хранение уведомлений - 1 бит на одно активное уведомление.
Есть и еще одно основание записывать в качестве временной метки момент дос
тавки. Пусть, к примеру, с помощью уведомления менеджеру процессов переда
ется сообщение SYN_ALARМ. Если бы временная метка была проставлена при от
правке, менеджеру процессов пришлось бы запросить у ядра правильное время
перед проверкой очереди таймера.
Обратим внимание на то, что уведомления доставляются по одному за раз, после
чего функция rni ni_s end завершается (строка 7684 ) . Тем не менее отправи
тель не блокируется и сразу после получения уведомления может выполнить
еще один вызов r e c e i ve. Если уведомлений не обнаруживается, очереди от
правителя проверяются на наличие активных сообщений любых других типов
21 О Глава 2 . П роцессы
2 . 6 . 1 О. Планирование п роцессов в M I N IX 3
В MINIX 3 применяется многоуровневый алгоритм планирования. Процессам
назначаются начальные приоритеты, однако, как показано на рис. 2 . 1 4 , число
уровней больше, и приоритет процесса может меняться по ходу его выполнения.
Таймерные и системные задания выполняются на уровне 1 и имеют наивысший
приоритет. Драйверы устройств на уровне 2 имеют более низкие, но не равные
между собой приоритеты. Приоритет серверов уровня 3 ниже, чем у драйверов,
но выше, чем у некоторых других процессов. Пользовательские процессы запус
каются с одинаковым приоритетом, уступающим всем системным процессам, од
нако приоритет отдельного процесса может быть понижен или повышен при по
мощи команды n i c e.
Планировщик поддерживает 1 6 очередей готовых процессов, хотя не все из них
могут использоваться в конкретный момент времени. На рис. 2.22 показаны
2.6. Реал иза ц ия процессов в M I N IX З 21 1
очереди и помещенные в них процессы сразу после того, как ядро закончило
инициализацию и запустилось, то есть при вызове r e s t art в файле rnain . с ( стро
ка 7252). Массив rdy_head содержит по одному элементу для каждой очереди,
указ ывающему на первый процесс в очереди. Аналогично, элементы массива
rdy_t a i l указывают на последние процессы в каждой очереди. Оба массива оп
ределены с макросом EXTERN в файле proc . h (строки 5595 и 5596). Начальное
формирование очередей процессов при запуске системы определяется таблицей
irnage в файле t аЫ е . с (строки 6095-6 1 09).
rdy_head rdy_tail
1
I USER_Q �14о1(1------1 USER_Q \ 1
4 fs 4
3 rs 3
2 disk 2
tty
внутри области ядра, являются часы. А как же обстоит дело с драйверами уст
ройств, располагающих собственными адресными пространствами?
Ответ на данный вопрос состоит в том, что их обработкой занимается системное
задание. На самом деле, системное задание занимается практически всем, что ка
сается взаимодействия между ядром и процессами, находящимися в пользова
тельском пространстве. При необходимости регистрации обработчика прерыва
ний <�:пользовательский» драйвер устройства обращается к системному заданию
с вызовом sys_i rqc t l . Системное задание вызывает функцию put_i r q_
hand l e r, однако в поле обработчика прерываний вместо адреса, принадлежаще
го пространству драйвера, сохраняется адрес процедуры gene r i c_hand l e r, яв
ляющейся частью системного задания. Поле номера процесса в структуре irq_
hook используется процедурой gene r i c_handl e r для доступа к записи драй
вера в таблице привилегий и установки соответствующего бита в карте актив
ных прерываний. Затем gene r i c_hand l er посылает драйверу уведомление от
имени HARDWARE, в которое включается битовая карта активных уведомлений
драйвера. Таким образом, если драйверу необходимо отвечать на прерывания бо
лее чем одного источника, он может определить, какое из прерываний вызвало
передачу уведомления. Фактически установка битовой карты предоставляет
драйверу информацию обо всех активных прерываниях. Еще одно поле в струк
туре i rq_hook поле политики, определяющее, следует разрешить прерывание
-
немедленно или оставить его запрещенным. Во втором случае драйвер сам дол
жен будет выполнить вызов ядра sys_i rqenaЫ e по завершении обработки
прерывания.
Одна из целей создания операционной системы MINIX 3 поддержка реконфи
-
Она копирует блок данных из одной области физической памяти в любое другое
место. Оба передаваемых этой функции адреса абсолютные, то есть О означает
первый байт адресного пространства. Все три аргумента функции являются по
типу беззнаковыми длинными целыми.
В целях безопасности вся используемая программой память должна быть очищена
от любых данных, оставленных в ней предьщущей программой. В MINIX 3 эта за
дача решается с помощью системного вызова ех е с , в конечном счете, обращаю
щегося к функции phys_rnernset (строка 9248) - следующей в файле k l iЬЗ 8 6 . s .
Две следующие короткие функции специфичны для процессоров Intel. Функция
_rnern_rdw (строка 929 1 ) возвращает 1 6-разрядное слово из произвольного места
памяти. Результат дополняется нулями и помещается в 32 -разрядный регистр
еах. Функция _re s e t (строка 9307) сбрасывает процессор. Для этого в деск
риптор прерываний процессора загружается нулевой указатель, после чего вы
зывается программное прерывание. Результирующий эффект равносилен аппа
ратному сбросу.
2 . 7 . Системное задание в M I N IX З 22 1
Таблица 2.5. Типы сообщений, принимаемых системным заданием. Тип Апу означает
любой системный процесс. Пользовательские процессы не могут обращаться
к системному заданию напрямую
Тип сообщени й Источник Описание
sys_fork pm Процесс запущен
sys_exec pm Установить указатель стека после вызова ехес
sys_exit pm Процесс завершен
sys_пice pm Задать приоритет планирования
sys_privct� rs Задать или изменить привилегии
sys_trace pm Выполнить операцию вызова ptrace
sys_kill pm, fs, tty Послать сигнал процессу после вызова kill
sys_getksig pm Проверка активных сигналов менеджером процессов
sys_eпdksig pm Завершение обработки сигнала менеджером процессов
sys_sigseпd pm Послать сигнал процессу
sys_sigreturп pm Очистка после завершения сигнала
sys_irqctl Драйверы Разрешить, запретить или сконфигурировать
прерывание
sys_devio Драйверы Выполнить операцию чтения или записи над портом
sys_sdevio Драйверы Выполнить над портом операцию чтения или записи
строки
sys_vdevio Драйверы Выполнить вектор запросов ввода-вывода
sys_iпt86 Драйверы Выполнить вызов BIOS в реальном режиме
sys_пewmap pm Установить карту памяти процесса
sys_segctl Драйверы Добавить сегмент и получить его селектор (доступ
к удаленным данным)
sys_memset pm Записать символ в область памяти
sys_umap Драйверы Преобразовать виртуальный адрес в физический
sys_vircopy fs, драйверы Выполнить копирование с использованием
виртуальной адресации
sys_physcopy Драйверы Выполнить копирование с использованием
физической адресации
sys_virvcopy Апу Вектор запросов vcopy
sys_physvcopy Апу Вектор запросов physcopy
sys_times pm Получить время работы системы и процессов
sys_setalarm pm, fs, драйверы Запланировать сигнал синхронизации
sys_abort pm, tty Сбой: MINIX не может продолжать работу
sys_getiпfo Апу Запросить системную информацию
Для начала опишем назначение каждого вызова ядра. Типы сообщений в табл. 2.5
можно разделить на категории. Первые несколько сообщений относятся к управле
нию процессами. Очевидно, что вызовы sys_fork, sy s_exec, sy s_exi t и sys_
t ra c e тесно связаны с системными вызовами стандарта POSIX. Хотя n i c e не
относится к числу обязательных вызовов POSIX, изменение приоритета процес
са, в конечном счете, приводит к вызову sys_n i c e ядра. Единственным незна
комым вам вызовом из данной группы может быть лишь вызов sy s_p r i vc t l .
2 . 7 . Системное задание в M I N IX З 225
-------' з ------- ,
(...... Прерывание (...... Прерывание /
- _ _ _ _ _ ......
а б
Рис. 2 . 24. Доставка дан н ых по систем ному в ызову read: а - худш и й вариант чтения блока
требует 11 сообще н и й , б - луч ш и й вариант чтения блока требует 4
сообщения
2 . 8 . Та ймерное задан ие в M I N IX 3
Часы, также называемые таймерами, необходимы любой системе разделения
времени в силу ряда причин . Например, они хранят время и препятствуют мо
нопольному захвату ресурсов процессора одним процессом. Таймерное задание
в M INIX 3 имеет определенное сходство с драйвером устройства, поскольку
управляется аппаратно генерируемыми прерываниями. Тем не менее часы не отно
сятся ни к блочным устройствам, таким как диски, ни к символьным устройствам,
234 Глава 2. Процессы
Кварцевый осциллятор
--1 D I1-------.
�
1.-.,...1-..,1--г-1-тl---.-1--.1--.-1.,..l-,l,-.,.1 -,. 1---.-1-.1---.-1--.1-., °'""'" ' д•'Р"••�°""""' ори """"°" " " """""'
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
t Временный регистр используется
для загрузки счетчика
Та й мерное задание
Главный цикл таймерного задания принимает единственный тип сообщений,
HARD_INT, поступающих от обработчика прерываний. Все остальные сообщения
считаются ошибочными. Более того, главный цикл принимает сообщения не для
всех прерываний от таймера, хотя подпрограмма приема сообщений называется
do_c l o ckt i ck. Последняя вызывается только при необходимости планирова
ния процесса или при истечении таймера.
240 Глава 2. П роцессы
Сторожевые таймеры
Несколько страниц назад мы оставили открытым вопрос о том, как обеспечить
пользовательские процессы сторожевыми таймерами, которые обычно представ
ляют как пользовательские процедуры, исполняемые по истечении таймера.
Очевидно, в MINIX 3 это попросту невозможно. Тем не менее мы можем постро
ить мост между ядром и пользовательским пространством с помощью сигналов
синхронизации.
Сейчас самое время разобраться в том, что представляет собой сигнал синхрони
зации. Сигнал может генерироваться вне зависимости от того, какой процесс ис
полняется в текущий момент. То же касается и активации обычного сторожевого
таймера. Говорят, что такие события происходят асинхронно. Сигнал синхрони
зации доставляется в виде сообщения и может быть получен при выполнении
адресатом вызова rec e i ve. Мы говорим о синхронности потому, что адресат ожи
дает сигнал. Когда отправитель уведомляет адресата о сигнале с помощью проце
дуры no t i fy, отправителю не нужно блокироваться, а адресату - беспокоиться
2 . 8 . Таймерное задание в M I NIX З 24 1
о том, что сигнал будет пропущен. Если адресат не находится в ожидании, сооб
щения процедуры not i fy сохраняются. Для этой цели используется битовая
карта, где каждый бит соответствует возможному отправителю.
Сторожевые таймеры используют поле s_a l arm_t imer типа t imer_t , имею
щееся в каждом элементе таблицы привилегий. Каждому системному процессу
в этой таблице соответствует свой элемент. Чтобы установить таймер, систем
ный процесс, находящийся в пользовательском пространстве, выполняет вызов
sys_s e t a l arm, обрабатываемый системным заданием. Системное задание на
ходится в пространстве ядра и, таким образом, может инициализировать таймер
от имени вызывающего процесса. Инициализация включает размещение в нуж
ном поле адреса процедуры, запускаемой при истечении таймера, и ввод таймера
в список таймеров, как показано на рис. 2.27.
Разумеется, исполняемая процедура также должна находиться в пространстве
ядра. Это не является проблемой. Системное задание располагает сторожевой
функцией, c au s e_a l arm, генерирующей пользователю синхронное уведомле
ние в момент срабатывания с помощью процедуры not i fy. Данный сигнал мо
жет вызвать сторожевую функцию в пользовательском пространстве. «Настоя
щая• сторожевая функция находится внутри ядра, а пользовательский процесс
всего лишь получает сигнал синхронизации. Подобный алгоритм отличается от
исполнения пользовательской функции таймером. Он сопровождается больши
ми накладными расходами, однако проще, чем механизм прерываний.
Мы намеренно указали на то, что системное задание устанавливает сигналы от
имени некоторых процессов пользовательского пространства. Описанный меха
низм применяется лишь к системным процессам. У каждого системного процес
са есть собственная запись в таблице привилегий, а все несистемные процессы
используют единственную общую запись. Области таблицы привилегий, кото
рые не могут использоваться совместно, например битовая карта активных уве
домлений и таймер, недоступны пользовательским процессам вообще. Выход из
ситуации следующий: менеджер процессов управляет таймерами от имени поль
зовательских процессов . Аналогичным образом системное задание управляет
таймерами от имени системных процессов.
Когда пользовательский процесс выполняет системный вызов a l arm, чтобы
установить сигнал, он обрабатывается менеджером процессов, конфигурирую
щим таймер и помещающим его в список таймеров. Менеджер процессов просит
системное задание послать ему уведомление, когда для первого таймера в списке
будет назначено время истечения. Помощь менеджеру процессов требуется лишь
при изменении начального элемента списка таймеров - из-за того, что первый
таймер истек или был выключен, либо из-за нового вызова, таймер которого дол
жен оказаться в списке первым. Все это делается для поддержки системного
вызова a l arm, определенного стандартом POSIX. Подлежащая исполнению
процедура находится в адресном пространстве менеджера процессов. Во время
выполнения инициировавшему вызов пользовательскому процессу передается
сигнал, а не уведомление.
242 Глава 2 . П роцессы
М иллисекундные задержки
В файле c l o ck . с имеется процедура, обеспечивающая микросекундное разре
шение. Различным устройствам ввода-вывода требуются задержки длительно
стью всего лишь несколько микросекунд, которые невозможно обеспечить на
практике при помощи сигналов и интерфейса передачи сообщений. Счетчик,
используемый для генерации прерываний от таймера, может быть считан впрямую.
Его уменьшение выполняется с интервалом, приблизительно равным 0,8 мкс,
а значение достигает нуля 60 раз в секунду (один раз за 1 6,67 мс). Для того
чтобы использовать значение счетчика для задержек устройств ввода-вывода,
его необходимо опрашивать процедурой, находящейся в пространстве ядра, од
нако драйверы устройств размещены за его пределами. В настоящее время эта
функция используется только в качестве источника исходных данных для ге
нератора случайных чисел. Возможно, она окажется более полезной в системе
с высоким быстродействием, но это - вопрос будущего.
Службы времени
В табл. 2.6 перечислены службы файла c l ock . с , прямо или косвенно предостав
ляющие различные услуги. Несколько функций объявлены открытыми (puЬ l i c ),
что дает возможность вызывать их из ядра или системного задания. Все остальные
службы доступны только косвенно - с помощью системных вызовов, в конеч
ном счете, обрабатываемых системным заданием. Остальные системные процес
сы могут косвенно обращаться к системному заданию. Пользовательские про
цессы должны взаимодействовать с менеджером задач, который также прибегает
к службам системного задания.
Рез ю ме
Чтобы скрыть эффект прерываний, операционная система предоставляет кон
цептуальную модель, в которой параллельно выполняются логически упорядо
ченные процессы. Процессы могут взаимодействовать друг с другом при помощи
примитивов, таких как семафоры, мониторы и сообщения. Назначение примити
вов в том, чтобы гарантировать, что никакие два процесса не окажутся в крити
ческой секции единовременно. Процессы могут находиться в состоянии вы
полнения, готовности и приостановки, а также переходить из одного состояния
в другое, когда тот или иной процесс исполняет один из примитивов взаимодей
ствия между процессами.
Примитивы необходимы для решения таких проблем, как проблема производи
теля и потребителя, проблема обедающих философов, проблема писателей и чи
тателей. Но даже при использовании примитивов необходимо быть осторожным,
во избежание ошибок и взаимных блокировок. Известно много различных алго
ритмов планирования, таких как циклический алгоритм, приоритетный алго
ритм, алгоритм с многоуровневыми очередями, алгоритм управления политика
ми планирования.
Операционная система MINIX 3 поддерживает концепцию процесса и предо
ставляет примитивы для взаимодействия между процессами. Сообщения не бу
феризуются, поэтому вызов s end завершается успехом только после того, как
адресат получит сообщение. Аналогично, вызов r e c e i ve завершается лишь
тогда, когда сообщение уже отправлено. В противном случае сделавший вызов
процесс переходит в состояние ожидания. MINIX 3 также поддерживает небло
кирующую разновидность сообщений - уведомления, передаваемые с помощью
примитива no t i fy. Попытка послать уведомление адресату, не находящемуся
в состоянии ожидания, приводит к установке бита, вызывающего восстановле
ние уведомления при вызове r e c e i ve в будущем.
В качестве примера потока сообщений рассмотрим вызов r ead, выполняемый
пользовательским процессом. Процесс посылает запрос на чтение в виде сообще
ния, адресованного файловой системе. Если данные не удалось обнаружить в кэше,
файловая система запрашивает их чтение с диска у драйвера, а сама переходит
в состояние блокировки. При дисковом прерывании системное задание получает
уведомление, позволяющее ему передать ответ драйверу диска, а тому, в свою
очередь, - файловой системе. После этого файловая система запрашивает систем
ное задание скопировать данные из кэша, в который был помещен требуемый
блок, пользовательскому процессу. Перечисленные шаги иллюстрирует рис. 2.24.
За прерыванием может последовать переключение процессов. В случае прерывания
в элементе таблицы процессов, соответствующем прерванному процессу, созда
ется стек, в который помещается вся информация, необходимая для его переза
пуска. При перезапуске процесса указателю стека присваивается адрес элемента
таблицы процессов, далее выполняются команды, восстанавливающие регистры
процессора, а затем - команда i r e t d. Выбор элемента таблицы процессов, адрес
которого помещается в указатель стека, возлагается на планировщика.
246 Глава 2. П роцессы
В опросы и задания
1 . Почему многозадачность является основным требованием для современных
операционных систем?
2. Каковы три основных состояния процесса? Кратко опишите смысл каждого
из них.
3. Представьте, что вы разрабатываете усовершенствованную компьютерную
архитектуру, в которой процессы переключаются аппаратно, а не с помощью
прерываний. Какая информация потребуется процессору? Опишите возмож
ную реализацию аппаратного переключения процессов.
4. На всех существующих компьютерах как минимум часть обработчиков пре
рываний написана на ассемблере. Почему?
5. Измените рис. 2.2, добавив в него два состояния процесса - «новый� и «За
вершенный� . Процесс находится в состоянии «новый� после создания, а в со
стоянии «завершенный� - после окончания своей работы.
Вопросы и задания 247
2) Q > Т;
3) S < Q < Т;
4) Q = S;
5) Q около о.
27. Запуска ожидают пять заданий. Предполагаемое время выполнения заданий
составляет 9, 6, 3, 5 и Х. В каком порядке их следует запустить, чтобы мини
мизировать среднее время отклика? ( Ответ должен зависеть от Х.)
2 8 . Пять пакетных заданий, А, В , С, D , Е, поступают в компьютерный центр прак
тически одновременно. Ожидается, что время их выполнения составит 1 О, 6,
2, 4 и 8 мин. Их установленные приоритеты равны 3, 5, 2, 1 и 4, причем 5 -
высший приоритет. Определите среднее время оборота для каждого из сле
дующих алгоритмов планирования, пренебрегая потерями на переключение
между процессами:
1) циклическое планирование;
2 ) приоритетное планирование;
3) первым пришел - первым обслужен (в порядке 10, 6, 2, 4, 8);
4) самое короткое задание - первое.
В первом случае предполагается, что система многозадачная и каждому за
данию достается справедливая доля процессорного времени. В остальных
случаях считается, что в каждый момент времени выполняется одно задание,
работающее вплоть до завершения. Все задания ограничены исключительно
возможностями процессора.
29. Процессу, запущенному в СТSS-системе, для завершения необходимо 30 кван
тов. Сколько раз он будет выгружен на диск, учитывая самый первый раз
(прежде, чем он бьш запущен)?
30. Для предсказания времени выполнения используется алгоритм старения
с а = 1/2. Предыдущие четыре значения времени составляли 40, 20, 40 и 15 мс
(первое значение - самое давнее). Оцените следующее время выполнения.
3 1 . На рис. 2 . 1 0 изображена схема трехуровневого планирования в системе па
кетной обработки. Можно ли использовать его в интерактивной системе без
новых поступающих заданий? Как?
250 Глава 2 . П роцессы
уже висят несколько обезьян, движущихся на запад, бабуин ждет, когда ве
ревка освободится. Другое условие: нужно запретить для остальных движе
ние на запад, пока бабуин не перейдет на восток.
43. Решите задачу обедающих философов с помощью мониторов, а не семафоров.
44. Добавьте в ядро MINIX 3 код, который бы подсчитывал, сколько раз процесс
(или задание) i обратится к процессу (или заданию) j. Сделайте так, чтобы
полученная матрица печаталась по нажатию клавиши F4.
45. Измените планировщик MINIX 3 так, чтобы он отслеживал, сколько времени
каждый процесс занимал процессор последний раз. Когда все задания и сер
веры освобождают процессор для пользовательских процессов, выбирайте
тот из них, который меньше всех тревожил процессор.
46. Измените MINIX 3 так, чтобы каждый процесс мог явно задавать приори
тет своих дочерних процессов с использованием нового системного вызова
s e t pr i o r i ty с параметрами p i d и p r i or i ty.
47. Перепишите макросы hwint_rna s t er и hwint_s l ave из файла rnpxx3 8 6 . s
так, чтобы действия, выполняемые функцией s ave, были встроены в код. На
сколько увеличился объем кода? Можете ли вы измерить прирост производи
тельности?
48. Поясните все выводимые элементы команды sys env системы MINIX 3. Если
в вашем распоряжении нет работающей копии операционной системы, вос
пользуйтесь листингом 2 . 1 4 .
4 9 . Обсуждая инициализацию таблицы процессов, м ы упомянули, что некоторые
компиляторы С могут генерировать несколько лучший код при сложении ад
реса массива с константой, нежели при индексировании. Напишите пару ко
ротких С-программ, чтобы проверить это.
50. Измените систему M INIX 3 так, чтобы в ней осуществлялся сбор сведений
о передаче сообщений с указанием отправителей и получателей. Напишите
программу, выполняющую подобный сбор и печатающую статистику в удоб
ном для восприятия виде.
Глава 3
В вод - в ы вод
Табл ица З. 1 . Скорости передачи данных некоторых типичных устройств, шин и сетей
Устройство Скорость
Клавиатура 1 0 байт/с
Мышь 1 00 байт/с
Модем 56 Кбайт 7 Кбайт/с
Сканер 400 Кбайт/с
Цифровая камера 4 Мбайт/с
CD-ROM 52х 8 Мбайт/с
Firewire (IEEE 1 394) 50 Мбайт/с
USB 2.0 60 Мбайт/с
Монитор ХGА 60 Мбайт/с
Сеть SONEТ ОС- 1 2 78 Мбайт/с
Gigablt Etherпet 1 25 Мбайт/с
Диск Serial АТА 200 Мбайт/с
Диск SCSI Ultrawide 320 Мбайт/с
Шина PCI 528 Мбайт/с
3 . 1 2 Контроллеры устройств
. .
Монитор
D
Клавиатура USB CD-ROM Жесткий диск
11111111
Шина
Рис. 3 . 1 . Модель подключения процессора, памяти, контроллеров и устройств ввода-вывода
Мы упоминаем о различии между контроллером и устройством потому, что опе
рационная система практически всегда имеет дело с контроллером, а не с самим
устройством. У большинства небольших компьютеров взаимодействие с устрой
ствами организуется по модели единой шины (см. рис. 3. 1 ) . У больших машин,
мэйнфреймов, применяется другая модель с несколькими шинами, которые об
служиваются специализированными компьютерами ввода-вывода, называемыми
каналами ввода-вывода. Такая организация позволяет снизить нагрузку на основ
ной процессор.
Интерфейс между устройством и контроллером часто является интерфейсом
очень низкого уровня. Например, какой-нибудь жесткий диск может быть от
форматирован по 1 024 сектора на дорожку, с размером секторов по 5 1 2 байт.
В действительности с диска в контроллер поступает последовательный поток би
тов, начинающийся с заzоловка сектора (преамбулы), за которым следует 4096 бит
в секторе, и, наконец, контрольная сумма, также называемая кодом исправления
ошибок ( Error- Correcting Code, ЕСС). Заголовок сектора записывается на диск
во время форматирования. Он содержит номера цилиндров и секторов, размер
сектора, информацию синхронизации и т. п.
Работа контроллера заключается в преобразовании последовательного потока
битов в блок байтов и в коррекции ошибок, если это необходимо. Обычно блок
байтов собирается бит за битом в буфере контроллера. Затем проверяется кон
трольная сумма блока, и если она совпадает с указанной в заголовке сектора,
блок полагается считанным без ошибок, после чего он копируется в оператив
ную память.
Контроллер монитора (видеоконтроллер) также работает как последовательное
побитовое устройство на таком же низком уровне. Он считывает из памят и байты,
содержащие символы, которые следует отобразить, и формирует сигналы, исполь
зуемые для модуляции луча электронной трубки, заставляющие ее выводить
256 Глава 3 . Ввод-вывод
в - смешанный вариант
3 . 1 . 4 . П рерывания
Как правило, регистры контроллеров содержат один или несколько битов состоя
ния. Их можно проверить и определить, завершена ли операция вывода и имеются
ли новые данные в устройстве ввода. Цикл, выполняемый процессором и прове
ряющий бит состояния до готовности устройства принять или передать данные,
называется опросом, или активным ожиданием. Мы познакомились с этой кон
цепцией в пункте 2.2.3 в контексте работы с критическими секциями (впрочем,
в большинстве случаев активное ожидание нежелательно). Поскольку ожидание
258 Глав а 3. Ввод- вывод
К Накопитель
Буфер
1 . П роцессор
п рограммирует
Адрес Ji
ОМА-контроллер Счетчик
J Уп равление J 4. Подтверждение
Эта команда должна работать, невзирая на то, что именно указано в качестве
входного устройства - гибкий диск, I D Е-диск, SСSI -диск или клавиатура. В ка
честве выходного устройства также с равным успехом может быть указан экран,
файл на любом диске или принтер. Все проблемы, связанные с отличиями этих
устройств, должна разрешать операционная система.
Тесно связан с идеей независимости от устройств принцип единообразного и.м,е
нования. Имя файла или устройства должно быть просто текстовой строкой
или целым числом и никоим образом не зависеть от физического устройства.
В UNIX и MINIX 3 все диски могут быть произвольным образом интегрированы
в иерархию файловой системы, поэтому пользователю не обязательно знать,
какое имя какому устройству соответствует. Например, гибкий диск не запреща
ется монтировать поверх каталога / u s r / a s t / ba c kup, вследствие чего копи
рование файла в каталог / u s r / a s t / ba c kup / monday автоматически приведет
к копированию файлов на гибкий диск. Таким образом, все файлы и устройства
адресуются одним и тем же способом - по пути к ним.
Другим важным аспектом программного обеспечения ввода-вывода является
обработка ошибок. Ошибки должны обрабатываться как можно ближе к аппа
ратуре. Если контроллер обнаружил ошибку чтения, он должен попытаться по
возможности исправить эту ошибку сам. Если он не в силах это сделать, тогда
ошибку обязан обработать драйвер устройства, допустим, попытавш:ись прочи
тать этот блок еще раз. Многие ошибки бывают временными, например ошибки
чтения, вызванные пылинками на читающих головках. Такие ошибки часто не
воспроизводятся при повторной попытке чтения блока. Только если нижний
262 Глава 3 . Ввод-вывод
3 . 2 . 3 . Драйверы устройств
Ранее в этой главе мы узнали, что у каждого контроллера устройства есть реги
стры, в которые можно записывать команды, считывать состояние устройства
или делать и то и другое. Число регистров и смысл команд значительно изменя
ются от устройства к устройству. Например, драйвер мыши принимает инфор
мацию о ее перемещении и нажатых кнопках. В то же время драйверу диска
нужно знать о секторах, дорожках, цилиндрах, головках, их перемещении и вре
мени установки, двигателях и тому подобных вещах.
Поэтому для управления каждым устройством ввода-вывода, подключенным
к компьютеру, требуется специальная программа. Эта программа, называемая
драйвером устройства, часто пишется производителем устройства и распростра
няется на компакт-дисках вместе с самим устройством. Поскольку для каждой
операционной системы требуются специализированные драйверы, производите
ли обычно поставляют драйверы для нескольких наиболее популярных операци
онных систем.
Каждый драйвер обслуживает один тип устройств или более крупный класс сход
ных устройств. Например, было неплохо иметь один драйвер мыши, несмотря на
264 Глава 3. Ввод-вывод
то, что система поддерживает несколько типов мышей. Дисковый драйвер мог бы
поддерживать несколько типов дисков, различающихся объемами и скоростями,
а также, возможно, компакт-диски. С другой стороны, диск настолько непохож
на мышь, что им, безусловно, нужны разные драйверы.
Чтобы драйвер имел доступ к аппаратной части устройства, то есть к регистрам
контроллера, его традиционно интегрируют в ядро операционной системы. Та
кой подход обеспечивает максимальную производительность, но минимальную
надежность, поскольку ошибка в любом драйвере устройства способна вывести
из строя всю систему. В MINIX 3 используется другая, более надежная модель.
Как мы увидим, в этой операционной системе каждый драйвер устройства явля
ется отдельным процессом, выполняющимся в пользовательском пространстве.
Как мы говорили ранее, с точки зрения операционной системы бывают драйверы
для блочных устройств (например, диски) и символьных устройств (например,
клавиатуры и принтеры). Большинство операционных систем определяет два
стандартных интерфейса, которые должны поддерживаться всеми блочными
и всеми символьными устройствами компьютера соответственно. Интерфейсы
включают совокупность процедур, вызываемых операционной системой, чтобы
обеспечить драйверам возможность выполнять свою работу.
Вообще говоря, назначение драйвера в том, чтобы воспринимать абстрактные за
просы от аппаратно-независимых программ верхнего уровня и сообщать им, что
запрос выполнен. Типичный запрос, поступающий драйверу диска, - считать за
данный блок данных. При этом если в момент передачи запроса драйвер бездей
ствует, он сразу начинает работу. Если же драйвер занят, запрос обычно помеща
ется в очередь и обслуживается по мере возможности.
Первым шагом в обслуживании запроса ввода-вывода является проверка кор
ректности переданных параметров и при необходимости возврат ошибки. Если
запрос верен, следующий шаг - его преобразование из абстрактного представле
ния в конкретную форму. Скажем, драйвер диска должен выяснить, где находит
ся запрошенный блок данных, проверить, работает ли привод диска, находится
ли головка над нужной дорожкой и т. д. Говоря коротко, драйвер должен сам оп
ределить свою последовательность действий.
После того как необходимые команды определены, драйвер начинает передавать
их устройству через регистры контроллера. Простые контроллеры способны вос
принимать только по одной команде за раз, а более сложные поддерживают свя
занный список команд, выполняемых далее без вмешательства операционной
системы.
Когда все команды переданы, ситуация развивается по одному из двух сценари
ев. Во многих случаях драйвер устройства должен ждать, пока контроллер вы
полняет для него определенную работу, поэтому он блокируется до поступления
прерывания от устройства. В других вариантах операция завершается без за
держек, и драйверу не нужно блокироваться. Например, для прокрутки экрана
в символьном режиме требуется записать лишь несколько байтов в регистры
контроллера. Каких-либо физических перемещений нет, и вся операция занима
ет несколько микросекунд.
3 . 2 . П рограмм ное обеспечение ввода-вывода 265
3 . 2 . 4 . Н езависимое от устройств
программ ное обеспечение ввода-вывода
Хотя некоторая часть программного обеспечения предназначена для работы с кон
кретными устройствами, значительная его часть не зависит от устройств. Точ
ную границу между драйверами и независимым от устройств программным
обеспечением проводит система, так как некоторые функции, которые можно реа
лизовать независимо от устройств, часто выполняются прямо в драйверах из
различных соображений, в том числе с позиций эффективности. Следующие функ
ции обычно реализуются независимым от устройств программным обеспечением:
+ единообразный интерфейс для драйверов устройств;
+ буферизация;
+ сообщения об ошибках;
+ захват и освобождение выделенных устройств;
+ обеспечение аппаратно-независимого размера блока.
В MINIX 3 большинство независимых от устройств программ является частью
файловой системы. Файловую систему мы будем изучать в главе 5, а здесь дадим
только краткий обзор, чтобы продемонстрировать некоторые перспективы и луч
ше объяснить, как работают драйверы.
Главная цель независимого от устройств программного обеспечения - выполне
ние функций ввода-вывода, общих для всех устройств, и предоставление едино
образного интерфейса для программ пользовательского уровня. Далее мы рас
смотрим эти вопросы более подробно.
Буферизация
Буферизация также является важной как для блочных, так и для символьных
устройств. Для блочных устройств аппаратное обеспечение обычно требует, чтобы
чтение или запись производились большими блоками. Однако для пользователь
ских программ такого ограничения нет, и они вправе передавать любые объемы
информации. Поэтому если пользователь передает только половину блока, опе
рационная система обычно не сразу записывает эти данные на диск, а дожидает
ся передачи оставшейся части блока. Что же касается символьных устройств, то
пользователь может передавать данные быстрее, чем устройство в состоянии их
воспринять, таким образом, и здесь нужна буферизация. Не исключено также,
что данные, поступающие, например, от клавиатуры, могут опережать считыва
ние, и в этом случае также не обойтись без буфера.
Сообщения об ошибках
В контексте ввода-вывода ошибки - как нигде частое явление. Операционная
система должна приложить максимальные усилия к их обработке. Многие ошибки
являются специфичными для конкретного устройства и должны обрабатываться
драйвером, так как только он знает, что делать (например, повторить попытку,
игнорировать ошибку или инициировать сбой системы). Типичная ошибка - по
вреждение или недоступность блока на диске. Драйвер диска пытается несколь
ко раз повторить чтение и, если оно не удается, информирует вышестоящую про
грамму. С этого момента обработка ошибки является аппаратно-независимой.
Если ошибка имела место при чтении пользовательского файла, достаточно про
сто передать сообщение программе, сделавшей вызов. Если же невозможно про
читать критически важную системную структуру, не исключено, что системе
придется вывести информацию об ошибке и завершить свою работу.
Ответ
ввода-вывода Функции
Уровень ввода-вывода
Обращение к вызовам ввода-вывода;
Процесс пользователя
Запрос форматный ввод-вывод; спулинг
ввода-вывода
Устройство-независимое Именование, защита, блокирование,
программное обеспечение буферизация , назначение
3 . 3 . 1 . Ресурсы
Система может оказаться в ситуации взаимной блокировки, когда процессам
предоставляются исключительные права доступа к устройствам, файлам и т. д.
Чтобы максимально обобщить рассказ о взаимных блокировках, мы будем назы
вать объекты доступа ресурсами. Ресурсом может быть устройство (например,
3. 3. Взаи мная блоки ровка 27 1
Для того чтобы произошла взаимная блокировка, должны выполниться все эти
четыре условия. Если хоть одно из них не выполняется, тупиковая ситуация не
возможна.
В серии публикаций Левина [76-78] указывается на то, что в литературе тер
мином «взаимная блокировка• называют целый ряд ситуаций и перечисленные
в [2 1 ] условия относятся лишь к взаимной блокировке ресурсов. Известны приме
ры взаимных блокировок, не удовлетворяющих всем четырем сформулирован
ным условиям. Например, если четыре автомобиля одновременно встретятся на
перекрестке, то, согласно правилам, ни один из них не вправе продолжить дви
жение, однако здесь ни один из «процессов• (автомобилей) не является владель
цем уникального ресурса. Данная проблема называется взаимной блокировкой
планирования и разрешается внешним участником - полицейским, принимаю
щим решение о приоритетах машин.
Следует заметить, что каждое из условий относится к политике, которая может
быть принята или не принята в системе. Может ли определенный ресурс едино
временно использоваться более чем одним устройством? Выгружаемы ли ресур
сы? Возможно ли циклическое ожидание? Позже мы увидим, как справиться
с взаимными блокировками, нарушая некоторые из этих условий.
а б в
в - взаимная блокировка
Ребро, направленное от процесса к ресурсу, означает, что процесс в данный
момент блокирован и находится в состоянии ожидания доступа к этому ресур
су. На рис. 3.6, б процесс В ждет ресурс S. На рис. 3.6, в мы видим взаимную
блокировку: процесс С ожидает ресурс Т, удерживаемый процессом D. Про
цесс D вовсе не намеревается освобождать ресурс Т, потому что он ждет ре
сурс И, используемый процессом С. Оба процесса будут ждать до бесконечности.
274 Глава 3 . Ввод- вывод
А в с
Запрос R Запрос S Запрос Т
Запрос S Запрос Т Запрос R
Освобождение R Освоб ождение S Освобождение Т
Освобождение S Освобождение Т Освобождение R
а б в
1 . А запрашивает R
� ® @)
�% �%Ж
@)
2. В запрашивает S
3. С запрашивает Т
4. А запрашивает S
5. В запрашивает Т
6. С запрашивает R
Взаимоблокировка 0 (2] [2]
г д в ж
� cr � � ��
0�ш ш 0�шсь
3 и к
1 . А запрашивает R
�®� �®
2. С запрашивает Т
3. А запрашивает S
4. С запрашивает R
5. R
00Ш 00
А освобождает
6. А освобождает S
Взаимоблокировки нет
л м н о
�® �® 0®
00 00
п р с
3 . 3 . З . Ал горитм страуса
Самым простым подходом является «алгоритм страуса• : воткните голову в пе
сок и притворитесь, что проблемы вообще не существует. Различные люди от
зываются об этой стратегии по-разному. Математики считают ее полностью не
приемлемой и говорят, что взаимные блокировки нужно предотвращать любой
ценой. Инженеры спрашивают, как часто встает подобная проблема, как часто
система попадает в аварийные ситуации по другим причинам и насколько серь
езны последствия взаимных блокировок. Если взаимные блокировки случа
ются в среднем один раз в пять лет, а сбои операционной системы, ошибки ком
пилятора и поломки компьютера из-за неисправности аппаратуры происходят
раз в неделю, то большинство инженеров не захотят добровольно терять в произ
водительности и удобстве для того, чтобы ликвидировать возможность взаим
ных блокировок.
Чтобы подчеркнуть контраст между этими подходами, добавим, что UNI X и
MINIX 3 потенциально страдают от взаимных блокировок, которые даже не
3 . 3 . Взаимная блокировка 277
Первая проблема, вносимая этим подходом, заключается в том, что многие про
цессы не знают, сколько ресурсов им понадобится, до тех пор, пока не начнут ра
боту. Другая проблема состоит в том, что ресурсы не будут расходоваться опти
мально. Возьмем, например, процесс, который читает данные с входной ленты,
анализирует их в течение часа и затем пишет выходную ленту, а заодно и чертит
результаты на плоттере. Если все ресурсы нужно запрашивать заранее, то про
цесс целый час не позволит работать накопителю на магнитной ленте и принтеру.
Слегка отличающийся метод, позволяющий нарушить условие удержания и ожи
дания, вытекает из наложения следующего требования на процесс, запрашиваю
щий ресурс: процесс сначала должен временно освободить все используемые им
в данный момент ресурсы. Затем этому процессу разрешается попытаться сразу
получить все необходимое.
Попытка исключить третье условие ( нет принудительной выгрузки ресурса)
вселяет еще меньше надежд, чем устранение второго условия. Если процесс по
лучил принтер и в данный момент печатает выходные данные, насильственное
изъятие принтера по причине недоступности требуемого плоттера в лучшем слу
чае сложно, а в худшем - невозможно.
Остается только одно условие. Циклическое ожидание можно устранить несколь
кими путями. Один их них - просто следовать правилу, гласящему, что процессу
дано право только на один ресурс в конкретный момент времени. Если нужен вто
рой ресурс, процесс обязан освободить первый. Но подобное ограничение непри
емлемо для процесса, копирующего огромный файл с магнитной ленты на принтер.
Другой способ обойти циклическое ожидание заключается в поддержке общей
нумерации всех ресурсов, как показано на рис. 3.8, а. В этом случае действует
следующее правило: процессы могут запрашивать ресурс, когда хотят этого, но
все запросы должны быть сделаны в соответствии с нумерацией ресурсов. Про
цесс может запросить сначала сканер, затем накопитель на магнитной ленте, но
не вправе сначала потребовать плоттер, а затем сканер.
1 . Фотонаборное устройство
2. Сканер
3. Плоттер
4. Ленточный накопитель
5. Накопител ь CD-ROM
а б
Рис. 3 . 8 . Общая нумерация ресурсов: а - пронумерованные ресурсы; б граф ресурсов
-
так как этот номер меньше номера уже занятого им ресурса. Так или иначе, вза
имная блокировка исключена.
При работе с несколькими процессами сохраняется та же самая логика. В каж
дый момент времени один из предоставленных ресурсов будет иметь наивысший
номер. Процесс, использующий этот ресурс, уже никогда не запросит другие
занятые ресурсы. Он либо закончит свою работу, либо, в худшем случае, запро
сит ресурс с еще большим номером, а любой такой ресурс является доступным.
В итоге процесс завершит работу и освободит свои ресурсы. На этот момент сло
ж:йтся ситуация, когда ресурс с высшим номером уже занят каким-то другим
процессом, который также сможет нормально завершиться. То есть существует
алгоритм, по которому все процессы отрапортуют о выполнении без взаимной
блокировки.
Вариантом этого алгоритма является схема, в которой исключается требование
приобретения ресурсов в строго возрастающем порядке, но сохраняется условие,
что процесс не может запросить ресурсы с меньшим номером, чем уже у него
имеющиеся. Если процесс на начальной стадии запрашивает ресурсы 9 и 10, за
тем освобождает их, то это равнозначно тому, как если бы он начал работу зано
во, поэтому нет причины запрещать ему запрос ресурса 1 .
Хотя систематизация ресурсов путем их нумерации устраняет проблему взаимных
блокировок, бывают ситуации, когда невозможно найти порядок, удовлетворяю
щий всех. Когда ресурсы включают в себя области таблицы процессов, дисковое
пространство для спулинга, закрытые записи базы данных и другие абстрактные
ресурсы, число потенциальных объектов интереса и вариантов их применения
может быть настолько огромным, что никакая систематизация не спасет. Кроме
того, согласно [78), упорядочивание ресурсов сводит «на нет� взаимозаменяе
мость - копия ресурса при таких правилах может оказаться недоступной.
В табл. 3.2 обобщены различные методы предотвращения взаимных блокировок.
�
D:
!§ �
!ii
"
.D
:о
:>.
:о �
:о
:>.
:о
�
.D
:о
:>.
:о
s s s
а
i:::: !;;J а
i:::: !;;J а
i:::: !;;J
!'О !'О !'О
u
:s: :::!: u
:s: :::!: u
:s: :::!:
А о 6 А 1 6 А 1 6
в о 5 в 1 5 в 2 5
с о 4 с 2 4 с 3 4
D о 7 D 4 7 D 4 7
Свободно: 1 0 Свободно: 2 Свободно: 1
а б в
Т раектории ресурсов
Предыдущий алгоритм описан в терминах одного класса ресурсов (то есть в на
шем распоряжении имеются только принтеры или только ленточные накопители,
но не то и другое вместе). На рис. 3. 10 представлена модель системы с двумя про
цессами и двумя классами ресурсов, например принтером и плот:rером. По гори
зонтальной оси выводятся номера команд, выполняемых процессом А. По верти
кальной оси отложены номера команд, выполняемых процессом В. В команде 11
процесс А запрашивает принтер, в команде 12 ему требуется плоттер. Принтер
и плоттер освобождаются командами 13 и 14 соответственно. Процессу В необхо
дим плоттер с команды 15 по команду 17 и принтер с команды 16 по команду 18•
Каждая точка на диаграмме представляет совместное состояние двух процес
сов. Изначально система находится в точке р, когда ни один из процессов еще
не выполнил ни одной инструкции. Если планировщик запустит процесс А пер
вым, мы попадем в точку q, в которой процесс А выполнил какое-то количество
команд, а процесс В еще ничего не сделал. В точке q траектория становится
вертикальной, показывая, что планировщик решил запустить процесс В. При
наличии одного процессора все отрезки траектории могут быть только верти
кальными или только горизонтальными, но не наклонными. Кроме того, движе
ние всегда происходит на «север� или «восток� (вверх или вправо) и никогда
на «юг� или «запад� (вниз или влево), так как процессы не могут течь в обрат
ном направлении.
3 . 3 . Взаимная блокировка 283
! ! ::
Плоттер 1-----+� : ���-
•- - - - - - •
s
---�-�--�---- А
р q lз
Принтер oCt------1•
... �
...
,..,______,.
"Плоттер
Рис . 3 . 1 О. Две траектории ресурсов для процессов
Когда процесс А пересекает линию 11 на отрезке от точки r до точки s, он запра
шивает и получает принтер. Когда процесс В достигает точки t, он запрашивает
плоттер.
Особенно интересны заштрихованные области. Область со штриховкой из верх
него левого угла в правый нижний представляет промежуток времени, когда оба
процесса занимают принтер. Правило взаимного исключения делает попадание
в эту область невозможным. Вторая заштрихованная область соответствует то
му, что оба процесса используют плоттер, и это также невозможно.
Если система войдет в прямоугольник, ограниченный линиями 11 и 12 по сто
ронам и линиями 15 и 16 сверху и снизу, она в конце концов доберется до пере
сечения линий 12 и 16• В этот момент процесс А запросит плоттер, а процесс В по
требует принтер, но оба ресурса будут к тому времени заняты. Получается, что
тупиковым является целый прямоугольник и в него нельзя входить. В точке t
единственно безопасный вариант состоит в том, чтобы оставить процесс А рабо
тать до тех пор, пока он не достигнет команды 14• После нее любая траектория
дойдет до точки и.
Важный для понимания момент заключается в том, что в точке t процесс В за
прашивает ресурс. Система должна принять решение, предоставлять его или нет.
Если выдается разрешение, система попадает в небезопасную область и в итоге
блокируется. Чтобы избежать тупика, нужно приостановить процесс В до тех
пор, пока процесс А не запросит и не освободит плоттер.
А з о 1 1 А 1 1 о о Е = (6342)
в о 1 о о в о 1 1 2 Ар = (1(5322)
=
020)
с 1 1 1 о с з 1 о о
D 1 1 о 1 D о о 1 о
Е о о о о Е 2 1 1 о
Распределенные ресурсы Ресурсы, которые еще нужны
Рис . 3. 1 1 . Алгоритм банкира в системе с несколькими видами ресурсов
Если во время первой фазы какая-либо необходимая запись оказывается уже за
блокированной, процесс просто сбрасывает все свои блокировки и начинает пер
вую фазу заново. В некотором смысле этот метод похож на схему, в которой за
прос всех необходимых ресурсов происходит загодя или, по крайней мере, перед
тем, как произойдет что-то необратимое. В некоторых вариациях двухфазной
блокировки, если блокировка встретилась во время первой фазы, не происходит
возврата ресурсов и возобновления работы процесса. В таких вариациях может
возникнуть тупиковая ситуация.
Но эту стратегию нельзя обобщить. Н апример, в системах реального времени
и системах контроля процессов недопустимо частично завершить процесс из-за
того, что ресурс недоступен, а потом начинать все заново. Также недопустимо
перезапускать процесс, если он прочел сообщение из сети или написал его, обно
вил файлы и сделал что-нибудь еще, что не может быть безопасно повторено.
Алгоритм работает только в тех ситуациях, когда программист очень тщательно
подготовил все таким образом, что программу нетрудно остановить в любой точ
ке первой фазы и запустить заново. Многие программы не могут быть структу
рированы таким образом.
3 . 4 . В в од - вы в од в M I N IX 3
Структура системы ввода-вывода в MINIX 3 показана на рис. 3.5. Четыре верхних
уровня этой структуры соответствуют четырем уровням на рис. 2 . 1 4 . В следую
щих разделах мы вкратце рассмотрим каждый из этих уровней, делая акцент на
драйверах устройств. Механизм обработки прерываний MINIX 3 был рассмот
рен в предыдущей главе, а аппаратно-зависимый ввод-вывод будет обсуждаться
в главе 5 при изучении файловой системы.
3 . 4 . 2 . Драйверы устройств в M I N IX 3
Для каждого из классов устройств ввода-вывода в MINIX существует отдельный
драйвер. Эти драйверы являются полноценными процессами, каждый со своим
состоянием, регистрами, стеком и т. д. Драйверы взаимодействуют с файловой
системой при помощи механизма передачи сообщений, как и любые другие про
цессы MINIX 3. Код простого драйвера можно уместить в одном файле. Драйверы
виртуального диска, жесткого диска и дисковода для дискет расположены каждый
в своем файле; кроме того, они используют общие функции работы с блочными
устройствами, вынесенными в файль1 dr i ver . с и drv l ib . с. Подобное разделе
ние программного обеспечения на части, зависимые и независимые от аппарат
ного обеспечения, позволяет с легкостью приспосабливать его к самым разным
конфигурациям оборудования. Хотя дисковые драйверы пользуются некоторы
ми фрагментами общего кода, каждый из них работает как отдельный процесс.
Это изолирует драйверы друг от друга и ускоряет передачу данных.
Подобным же образом организован и исходный код драйвера терминала, где ап
паратно-независимый код помещен в файле t ty . с, а в отдельных файлах нахо
дится код для поддержки различных типов устройств, таких как отображаемые
на память консоли, клавиатура, последовательные интерфейсы и псевдотерми
налы. Однако в этом случае все типы устройств обслуживает один процесс.
3 .4. Ввод- вывод в M I N IX 3 29 1
Кроме того, для групп сходных устройств, например для дисков и терминалов,
есть еще и заголовочные файлы. Файл dr i ver . h поддерживает все драйверы
блочных устройств, а файл t ty . h предоставляет общие определения для всех
типов терминалов.
Поскольку система MINIX 3 построена на исполнении компонентов операционной
системы в пользовательском пространстве как полностью независимых процессов,
для нее характерны высокая степень модульности и приемлемая эффективность.
Это - одно из кардинальных отличий MINIX 3 от UNIX. В MINIX процесс, для того
чтобы прочитать файл, посылает сообщение файловой системе. В свою очередь,
файловая система может послать сообщение драйверу диска, запрашивая чтение не
обходимого блока. Драйвер диска использует вызовы ядра для фактического ввода
вывода и копирования данных между процессами. Эта последовательность (не
сколько упрощенная по сравнению с реальностью) изображена на рис. 3. 1 2, а.
За счет того, что взаимодействие происходит через механизм сообщений, обеспе
чивается стандартный коммуникационный интерфейс между частями системы.
Система, структурированная
с помощью процессов Монолитная система
Процесс
П ространство
пользователя
,,,,,. - -- - .......
(Аппаратное' 1 Пространство
.......
..рбеспечени�
_ _
_ ,,,,,. ядра
а б
Рис. 3. 1 2 . Два варианта взаимодействия пользователя и системы: а - сообщения с запРQСами
и ответами между четырьмя независимыми п роцессами; б - передача управления
в адресное п ростра нство ядра из пользовател ьского п ространства по п рерыванию
vo i d i o_dr i ver ( )
ini t i a l i z e ( ) ; / * Вы зы вает с я только один раз при инициализ ации * /
whi l e ( TRUE ) {
r e c e ive ( ANY , &me s s ) ; / * Ожидаем з апро с * /
c a l l e r = me s s . s ourc e ; / * Проце с с , с дела вший з апро с * /
s w i t c h ( me s s . typ e ) {
c a s e READ : r c o de = dev_read ( &me s s ) ; break ;
c a s e WR I T E : r c o d e = dev_wr i t e ( &me s s ) ; break ;
/ * Тут находитс я код для выполнения дру гих операций ,
таких как OPEN , CLOSE и I OCTL * /
de f au l t : r c o de = ERROR ;
me s s . type = DRIVER_REPLY ;
me s s . s t a t u s = r c o de ; / * Код в о з врата * /
s end ( c a l l e r , &me s s ) ; / * Отправляем о т в е т * /
294 Глава З. Ввод-вывод
3 . 5 . Бло ч н ы е устройства в M I N IX 3
В MINIX 3 поддерживается несколько типов блочных устройств, поэтому мы
начнем с обсуждения общих аспектов, затем изучим виртуальный диск, жесткий
диск и дисковод для дискет. Каждое из этих устройств по-своему интересно.
Виртуальный диск необычен тем, что это устройство обладает всеми атрибутами
обычного блочного устройства, за исключением того, что при его работе ника
кого реального ввода-вывода не происходит. Этот �диск� целиком находится
в оперативной памяти. Поэтому драйвер устроен просто и является хорошей от
правной точкой для изучения. Жесткий диск позволяет понять, на что похож
драйвер реального диска. Некоторым может показаться, что привод для дискет
(накопитель на гибких дисках) проще, чем жесткий диск, но это не так. Мы не
будем обсуждать драйвер гибкого диска в подробностях, но укажем на некото
рые связанные с ним сложности.
Закончив с драйверами блочных устройств, мы приступим к драйверу термина
ла (клавиатуры и дисплея), который важен для любой системы и, к тому же, яв
ляется удачным примером драйвера символьного устройства.
Каждый из разделов содержит описание соответствующего оборудования и прин
ципов построения программы драйвера, а также обзор реализации и сам код.
Такая организация делает информацию полезной еще и тем, кто не заинтересо
ван в деталях.
3 . 5 . 1 . Обзор драйверов
блоч ных устройств M I N IX 3
Ранее мы упомянули, что основной код большинства драйверов ввода-вывода
имеет единую структуру. У MINIX 3 в ядре всегда в наличии, как минимум, два
встроенных блочных драйвера ввода-вывода: драйвер виртуального диска и с ним
драйвер жесткого диска или дисковода для дискет. Как правило, присутствуют
три блочных драйвера, поскольку в системе есть и дисковод для дискет, и жест
кий диск стандарта IDE (Integrated Drive Electronics - встроенный интерфейс
дисковых накопителей). Драйверы всех блочных устройств компилируются не
зависимо, однако используют общую библиотеку исходного кода.
В состав предыдущих версий MINIX иногда включался отдельный драйвер
CD-RO M, который при необходимости можно было добавить. В настоящий
3 . 5 . Блочные устройства в M I N IX 3 297
момент такие драйверы считаются устаревшими. Они были нужны для поддерж
ки собственных интерфейсов различных производителей дисководов. Современ
ные накопители, как правило, подключаются к I DЕ-контроллеру, хотя на пор
тативных компьютерах дисководы часто используют интерфейс с шиной USB
( Universal Serial Bus - универсальная последовательная шина). Полная версия
драйвера жесткого диска MINIX 3 включает поддержку CD-ROM, однако в дан
ной книге она не рассматривается.
Конечно, каждому драйверу нужно выполнить некоторые действия для инициа
лизации. Драйвер виртуального диска должен зарезервировать необходимый объ
ем памяти, драйвер жесткого диска - определить параметры устройства и т. д.
Все драйверы дисков вызываются, инициализируются и, завершив инициализа
цию, входят в бесконечный цикл. Этот цикл никогда не завершается, в нем нет
команды выхода. В цикле драйвер получает сообщение, вызывается одна из функ
ций обработки и генерируется ответное сообщение.
Основной цикл, вызываемый каждым из драйверов, компилируется из файлов
каталога драйвера, в том числе dr ivers / l ibdr i ve r / dr i ver . с, а затем копия
объектного файла dri ver . о компонуется в исполняемый файл драйвера. Бла
годаря такому подходу каждый драйвер имеет возможность передать в основной
цикл параметр - указатель на таблицу адресов функций, которые драйвер дол
жен косвенно вызывать для выполнения требуемых действий.
Если бы драйверы компилировались в единый исполняемый файл, то потребова
лась бы всего одна копия главного цикла. На самом деле, главный цикл был на
писан для более ранней версии MINIX, в которой драйверы компилировались
вместе. В MINIX 3 акцент сделан на максимальную индивидуализацию компо
нентов операционной системы, однако использование общего исходного кода
разными программами остается хорошим способом повышения надежности.
Создав свободный от ошибок фрагмент кода, вы обеспечиваете им все драйверы,
а если в драйвере обнаружилась ошибка, то с большой вероятностью она присут
ствует и в других драйверах. В результате тестирование общего кода можно про
вести более тщательно.
В файле drivers / l iЬdr i ve r / drvl i b . c определен набор функций, потенци
ально полезных для различных дисковых драйверов. Эти функции скомпилирова
ны в объектный файл drvl ib . о. Их можно было бы включить в файл dr i ver . о,
однако полный функциональный набор нужен далеко не всем драйверам. Напри
мер, самый простой драйвер memo ry компилируется исключительно с файлом
dri ver . о. Драйвер at_wi n i , напротив, при компиляции использует и файл
dri ver . о, и файл drvl ib . о .
Главный цикл приведен в листинге 3.2. Команды, подобные следующей, являют
ся косвенными вызовами функций:
c ode = ( * ent ry_po i nt s - >dev_read ) ( &me s s ) ;
Каждый драйвер вызывает свою функцию dev_read, хотя главный цикл един
для всех драйверов. Но некоторые операции, например c l o s e , достаточно про
сты, чтобы для всех устройств можно было использовать одну и ту же функцию.
298 Глава 3 . Ввод-вывод
me s s . type = DRIVER_REPLY ;
me s s . s t at u s = rc ode ; / * Код воз врата * /
s end ( c a l l e r , &me s s ) ;
Операция SCATTERED_I O, без сомнений, известна менее всех других. Дело в том,
что трудно достигнуть приемлемой производительности блочного устройства,
если запрашивать данные последовательно, отдельными порциями. Исключение
составляют лишь очень быстрые устройства, такие как виртуальный диск. Опе
рация SCATTERED_I O позволяет системе сделать запрос на чтение или запись
нескольких блоков. В случае операции READ система пытается предугадать,
какие блоки может запросить процесс, и считывает их заранее. В таком запросе
не все затребованные данные обязательны. Каждый из запросов блока данных,
передаваемых драйверу устройства, можно модифицировать, установив бит, со
общающий, что запрос не обязателен. В результате файловая система может соз
дать запрос, который в переводе на человеческий язык звучал бы так: � Было бы
неплохо прочитать все эти данные, но все они вовсе не нужны мне прямо сей
час». Далее устройство само решает, что лучше делать. Например, гибкий диск
может прочитать все данные в пределах одной дорожки, говоря тем самым: � эти
данные я для тебя прочитаю, а остальные попроси потом, мне слишком долго
переходить на другую дорожку».
Когда необходимо записать данные, не возникает вопроса, обязательно ли запи
сывать каждый отдельный блок - все, что запрошено, обязательно для выполне
ния. Однако система вправе буферизовать несколько запросов на запись в наде
жде на то, что сразу их удастся обработать быстрее, чем по отдельности. При
запросе SCATTERE D_I O, будь то для чтения или для записи, список запрошен
ных блоков сортируется, что позволяет считывать данные более эффективно,
чем если бы они считывались в порядке поступления. Кроме того, передача не
скольких блоков за один раз уменьшает количество сообщений, пересылаемых
внутри MINIX 3.
* dr_t rans f er, которая копирует данные и выполняет другие действия, необхо
димые для ввода-вывода. Все подпрограммы, обрабатывающие передачу, ожида
ют в качестве аргумента массив запросов . В функции do_rdwt последним аргу
ментом является 1, что указывает массив из одного элемента.
Как мы увидим при обсуждении программного обеспечения диска в следующем
разделе, обслуживание дисковых запросов в порядке поступления может быть
неэффективным, и данная подпрограмма позволяет конкретному устройству
обслуживать запросы в оптимальном для себя порядке. Косвенный вызов по
максимуму маскирует различия конкретных устройств. Для виртуального дис
ка dr_t rans f er указывает на подпрограмму, совершающую вызов ядра, чтобы
скопировать данные из одной области физической памяти в другую посредством
системного задания, если вспомогательным устройством является / dev / rarn,
/ dev / rnern, / dev / krnern, / dev / bo o t или / dev / z e ro. Разумеется, при доступе
к / dev / nu l l никакого копирования не требуется. В случае реального диска
функция dr_t rans f er тоже должна запросить у системного задания передачу
данных. Тем не менее перед копированием (при чтении) или после него (при за
писи) нужно дополнительно вызвать ядро, чтобы системное задание выполнило
фактический ввод-вывод, записав в регистры дискового контроллера байты, оп
ределяющие место на диске, объем и направление передачи.
В подпрограмме передачи значение счетчика i ov_s i z e структуры i ove c l изме
няется и содержит либо отрицательное значение (код ошибки), либо положитель
ное значение, равное числу переданных байтов. Если число переданных байтов
равно нулю, это не обязательно означает ошибку; возможно, в процессе ввода
вывода был достигнут конец устройства. При возвращении в главный цикл код
ошибки или число байтов записывается в поле RE P_STATUS ответного сообще
ния процедуры dri ver_t a s k.
Следующая функция, do_vrdwt ( строка 1 1 182), обрабатывает разрозненные
запросы ввода-вывода. В сообщении драйверу, содержащем подобный запрос,
в поле ADDRE SS помещается адрес массива структур типа i ovec_t . Каждая из
этих структур хранит информацию для выполнения одного запроса: адрес буфе
ра и число передаваемых байтов. В MINIX 3 подобный запрос может быть сде
лан только для смежных блоков диска; начальное смещение на устройстве и вид
операции (чтение или запись) указаны в сообщении. Таким образом, все опера
ции одного запроса являются либо чтением, либо записью и отсортированы со
гласно следованию блоков в устройстве. В строке 1 1 198 проверяется, сделан ли
запрос от имени задания ввода-вывода внутри ядра. Эта проверка унаследована
из ранних редакций MINIX 3, в которых драйверы еще не были полностью пере
писаны для выполнения в пользовательском пространстве.
Код данной операции очень похож на чтение и запись в процедуре do_rdwt .
Делаются те же косвенные вызовы аппаратно-зависимых подпрограмм * dr_
p repare и * dr_t rans f er. Цикл для обработки множественных запросов вы
полняется внутри функции, на которую указывает * dr_t rans f e r. Последний
аргумент в этом случае не 1, а размер массива элементов i ovec_t . После заверше
ния цикла массив запросов копируется в обратном направлении. Поле i o_s i z e
3 . 5 . Блочные устройства в M I N IX 3 303
и т. д.). В небольших системах, с одним или двумя дисками, это можно вытер
петь, но на мощных компьютерах с несколькими десятками устройств постоянно
следить за всеми дисками невыносимо. Заметьте, что UNIX работает на компью
терах от IBM РС до рабочих станций и суперкомпьютеров, подобных IBM Blue
Gene/L, а MS- DOS используется только в малых системах.
На рис. 3. 13 показано устройство виртуального диска. Диск разбивается на п бло
ков, в зависимости от того, сколько памяти для него выделено. Размер каждого
блока равен размеру блока реального диска. Когда драйвер получает запрос на
чтение или запись блока, он просто вычисляет адрес и производит чтение или
запись по этому адресу, вместо того чтобы обслуживать дискету или жесткий
диск. Обмен данными выполняется системным заданием. Ассемблерная проце
дура ядра phy s_c opy копирует информацию в пользовательскую программу или
из нее с максимальной скоростью, поддерживаемой аппаратным обеспечением.
{
Пользовательские
программы
RАМ-диск
{
диска используется
Операционная эта память
система
Эта команда запустит программу а . out , н о все, что она выводит, будет игнориро
ваться. Драйвер виртуального диска считает, что размер этого устройства равен О,
поэтому никаких данных на него не записывается и с него не считывается. При
попьпке считывания вы сразу же получите символ конца файла (End of File, EOF).
Освоив назначения файлов каталога / dev / , вы, возможно, обратили внимание
на то, что единственным блочным устройством среди них является / dev / rarn,
все остальные устройства - символьные. Драйвер памяти поддерживает еще
одно блочное устройство - / dev / bo o t . С точки зрения драйвера это блочное
устройство находится в памяти, как и / dev / rarn. Тем не менее для его инициа
лизации требуется скопировать в память файл, присоединенный к загрузочному
3 . 6 . Ви ртуал ь ные диски 309
образу, а не начать с пустого блока, как в случае / dev / r am. Это устройство заре
зервировано на будущее и не используется в текущей версии MINIX 3, которой
посвящена книга.
Наконец, последним устройством, поддерживаемым драйвером памяти, является
символьный файл / dev / z ero. Иногда бывает удобно иметь источник нулевых
значений. Запись в / dev / z er o эквивалентна записи в / dev / nu l l , однако при
чтении из / dev / z ero вы получаете нули в любом нужном количестве - от од
ного символа до целого диска.
На уровне драйвера код, обслуживающий устройства / dev / r am, / d ev / mem,
/ dev / kmem и / dev / boot , идентичен. Единственное различие между этими че
тырьмя устройствами состоит в том, что они работают с разными областями па
мяти, задаваемыми массивами ram_or i g i n и ram_l imi t , каждый из которых
индексируется вспомогательным номером устройства. Файловая система управ
ляет устройствами на более высоком уровне. Она различает символьные и блочные
устройства, а следовательно, способна монтировать / dev / ram и / dev / bo o t ,
читать и записывать потоки данных (хотя чтение потока и з / dev / nu l l всегда
возвращает символ конца файла).
ального диска. Большая часть работы делается без служб ядра. Вызов a l l ocmem
(строка 1 1 1 87) является системным, но он не обращен к ядру, а обрабатывается
менеджером процессов, поддерживающим всю информацию, необходимую для
поиска доступных областей памяти. Тем не менее в конце без вызова ядра все
же не обойтись. Вызов sys_s egc t l ( строка 1 1 894) преобразует физический
адрес и размер, возвращаемый вызовом a l l o cmem, в сегментную информацию,
необходимую для будущего доступа.
Последняя функция в файле memo ry . с это m_geomet ry. Для виртуального
-
головке и сектору ( Cylinder- Head-Sector, CHS) имеет смысл лишь в случае, если
вы имеете дело с устаревшим компьютером, не поддерживающим логическую
адресацию блоков. Кроме того, нет смысла приобретать новый диск размером
400 Гбайт для компьютера РС-ХТ, купленного в 1 983 году: он не позволит вам
использовать более 8 Гбайт дискового пространства.
Здесь самое время рассказать о путанице, касающейся спецификаций дисков. Спе
циалисты в области вычислительной техники привыкли измерять емкость диска
в степенях с основанием 2. Так, килобайтом ( Кбайт) считается 2 1 0 = 1 024 байт,
мегабайтом ( Мбайт) - 2 20 = 1 024 2 байт и т. д. По такой логике 1 Гбайт равен
1 024 3 , или 2 3 0 байт. Однако производители дисков под гигабайтом понимают
1 09 байт, что означает заметное увеличение объема их продукции, но только на
бумаге. Таким образом, упомянутый ранее предел в 8 Гбайт на языке продавца
компьютерного магазина превращается в 8,4 Гбайт. В последнее время намети
лась тенденция к использованию термина «гибибайт� ( GiВibyte ), обозначающе
го 2 30 байт. Однако в этой книге авторы пользуются принятыми толкованиями
мега- и гигабайта, отдавая дань традиции и протестуя против искажения терми
нов в угоду рекламе.
3 . 7 . 2 . RAI D
Несмотря на то что современные диски значительно быстрее своих предшест
венников, производительность процессоров растет гораздо быстрее, чем дисков.
С течением времени специалистам неоднократно приходила в голову идея о том,
что параллельный дисковый ввод-вывод способен изменить ситуацию. Так по
явился новый класс устройств ввода-вывода, обозначаемый аббревиатурой RAID
( Redundant Array of Independent Disks - избыточный массив независимых дис
ков ). Разработчики RAID (университет Беркли) изначально понимали эту аб
бревиатуру иначе: Redundant Array of Inexpensive Disks ( избыточный массив
дешевых дисков), позиционируя ее как противоположность другой архитектуре,
SLED ( Single Expensive Large Disk - единственный дорогой большой диск). Тем
не менее, когда технология RAID стала пользоваться коммерческой популярно
стью, производители изменили расшифровку аббревиатуры, поскольку дорого
продавать продукт, в названии которого стояло слово «дешевый�, было затруд
нительно. Первоначальная идея RAID состояла в установке рядом с компьюте
ром (как правило, большим сервером) коробки, наполненной дисками, замене
дискового контроллера RАI D-контроллером, копировании данных в RАID-мас
сив и продолжении обычной работы.
Независимые диски можно совместно использовать целым рядом способов. Из-за
ограничений объема книги мы не можем исчерпывающе описать их все, к тому
же MINIX 3 пока не поддерживает RАID-массивы. Тем не менее при знакомстве
с операционными системами нельзя обойтись без упоминания хотя бы некото
рых из них. RAI D позволяет одновременно повысить скорость дискового досту
па и безопасность данных.
Рассмотрим, к примеру, простейший RАID-массив, состоящий из двух дисков.
Когда требуется записать на «диск� несколько секторов данных, RАID-контроллер
31 6 Глава З. Ввод- вывод
Начальная Необработанные
позиция запросы
1 lxl 1 1 1 1 1 1 1x
о 5
d1xbl1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 lxl lxl 1 1
10 15 20 25 30 35 Цилиндр
1
Последовательность
перемещения головки
Начальная
позиция
1
о
lxl 1 1 1
5
1 1 1 lx �lxl 1 1 lxl 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 lxl lxl 1 1 1
10 15 20 25 30 35 Цилиндр
Последовательность
'--.... перемещения головки
1
----·--
Рис. З. 1 5 . Элеваторный алгоритм планирования обращений к диску
Незначительная модификация этого алгоритма с меньшим разбросом времени
отклика состоит в том, чтобы сканировать цилиндры всегда в одном направле
нии [ 1 18]. После обслуживания обращения к цилиндру с самым большим номе
ром блок головок перемещается к самому нижнему запрашиваемому цилиндру
и далее продолжает движение вверх. Таким образом, самый нижний цилиндр как
бы считается расположенным выше самого верхнего.
Некоторые контроллеры дисков предоставляют программному обеспечению спо
соб узнавать номер текущего сектора под головкой. Такие контроллеры позволя
ют использовать дополнительный метод оптимизации. Если есть два или более
запросов к одному и тому же цилиндру, драйвер может выбрать из них тот, сек
тор которого пройдет под головкой первым. Обратите внимание, что при нали
чии нескольких головок у диска последовательные запросы могут обращаться
к различным дорожкам на одном цилиндре. Контроллер может практически
мгновенно переключаться с головки на головку, так как такое переключение не
требует ни перемещения блока головок, ни ожидания поворота диска.
По скорости передачи данных современные жесткие диски настолько превосходят
дисководы для дискет, что требуется автоматическое кэширование. Как правило,
при любом запросе на считывание сектора считываются все секторы до конца
текущей дорожки (включая требуемый) в зависимости от доступного свободного
места в кэше. В настоящее время размер кэша зачастую составляет 8 Мбайт и более.
При наличии нескольких дисководов необходимо поддерживать отдельные оче
реди активных запросов для каждого из них. При простое диска следует выпол
нить поиск и перевести его головку на цилиндр, который будет использоваться
320 Глава 3. Ввод- вывод
этим данным создает файл, состоящий целиком из таких блоков. Они помечают
ся как занятые, и в результате ни одна программа не будет пытаться обращаться
к ним. В результате ни одна из программ не попытается прочитать файл сбой
ных блоков, и ошибка не возникает.
Не читать поврежденные блоки - это проще сказать, чем сделать. Часто резерв
ные копии дисков создаются путем подорожечного копирования содержимого
диска на ленту или другой диск. Если следовать этой процедуре, избежать повре
жденных блоков невозможно. Пофайловое резервное копирование медленнее, но
может помочь решить проблему, если программа, зная имя файла поврежденных
блоков, не пытается его копировать.
Другая проблема, не решаемая при помощи файла поврежденных блоков, - это
нарушение системной структуры, которая должна занимать фиксированное поло
жение на диске. Практически у любой файловой системы есть структура, поло
жение которой должно быть одним и тем же с целью облегчения ее поиска. Если
файловая система разбита на разделы, то можно заново разбить ее и попробовать
обойти сбойный блок, но если повреждены первые несколько секторов диске
ты или жесткого диска, накопитель становится непригодным к использованию.
4 Умные� контроллеры резервируют несколько дорожек, делая их недоступными
пользовательским программам. При форматировании диска контроллер опреде
ляет, какие из секторов содержат ошибки, и автоматически замещает их одним
из запасных. Таблица, отображающая поврежденные блоки на запасные, хранит
ся во внутренней памяти контроллера и на диске. Подмена происходит незамет
но для драйвера, за исключением того, что не исключена потеря эффективности
тщательно отработанного элеваторного алгоритма, если контроллер будет 4Тайно�
использовать цилиндр 800 вместо запрошенного цилиндра 3. Технология произ
водства магнитных поверхностей исключительно точна, но все равно не идеаль
на. Поэтому механизм скрытия таких дефектов от пользователя имеет большое
значение. Для жестких дисков контроллер отслеживает появление новых сбой
ных блоков и, если ошибка неустранима, заменяет их запасными блоками. Рабо
тая с таким диском, драйвер практически никогда не будет видеть плохие блоки.
Дефектные секторы не являются единственным источником ошибок. Также воз
никают ошибки поиска цилиндра, вызванные механическими проблемами блока
головок. Контроллер следит за положением блока головок. При установке голов
ки на заданный цилиндр он выдает серию импульсов двигателю блока головок,
по одному импульсу на цилиндр. Когда блок головок устанавливается в требуе
мое положение, контроллер считывает истинное значение цилиндра из заголовка
первого попавшегося сектора. Если блок головок оказывается не на той дорожке,
на которой нужно, возникает ошибка поиска и предпринимается некоторое кор
ректирующее действие.
Практически все контроллеры жестких дисков автоматически исправляют ошиб
ки поиска, но большинство контроллеров гибких дисков (включая установленные
на компьютерах IBM РС) просто выставляют бит ошибки и оставляют все осталь
ное драйверу. Драйвер обрабатывает ошибку, выдавая команду r e c a l ibra t e .
При этом блок головок отодвигается н а самую внешнюю дорожку диска д о упора.
322 Глава 3 . Ввод-вывод
Кэширование дорожек
Время, требующееся на переход к новому цилиндру, обычно много больше, чем
время поворота диска, и всегда больше времени чтения или записи сектора. Дру
гими словами, если драйвер решил перевести куда-либо головку, многое зависит
от того, будет ли читаться только один сектор или вся дорожка. Эффект в осо
бенности заметен, если контроллер позволяет определить, над каким сектором
находится дорожка, чтобы драйвер мог отдать ему команду на чтение следующе
го сектора, тем самым считывая дорожку целиком за один оборот диска. ( Обыч
но в среднем на чтение отдельного сектора требуется половина оборота диска
плюс время на чтение одного сектора.)
Некоторые драйверы поддерживают специальный кэш дорожки, невидимый для
программ. Если запрошенный у контроллера сектор находится в этом кэше, об
мениваться данными с диском не нужно. Недостаток такого подхода (помимо
усложнения драйвера и необходимости выделения памяти для буфера) состоит
в том, что передача данных пользовательской программе из кэша должна про
изводиться процессором в программном цикле, а не путем прямого доступа к па
мяти (DMA).
По данной причине многие современные контроллеры поддерживают кэш до
рожки самостоятельно, в своей внутренней памяти. В этом случае кэширование
происходит прозрачно для драйвера и передачу данных можно производить пу
тем прямого доступа к памяти. Если контроллер поддерживает подобную функ
цию, не имеет большого смысла дублировать ее в драйвере. Заметьте, что обеспе
чить чтение одной дорожки целиком могут как контроллер, так и драйвер диска,
но не пользовательская программа, так как для пользовательских программ диск
представляется линейной последовательностью блоков без разбиения на дорожки
и цилиндры. Точная геометрия диска известна лишь его контроллеру.
3. 7 . Реал ь ные диски 323
Однако этот драйвер стоит рассматривать лишь как крайнее средство. В систе
мах с процессором 80386 и выше MINIX 3 работает в защищенном режиме, а код
B I O S всегда выполняется в реальном режиме (режим 8086). Переключение ре
жимов при каждом вызове функции B I O S требует очень много времени.
Кроме того, еще одна стратегия, которая используется в MINIX 3 при работе
с драйверами, сводится к тому, чтобы отложить инициализацию до самого по
сдеднего момента. Таким образом, если ни один из драйверов жестких дисков не
работает с некоторой конфигурацией, мы все равно можем запустить MINIX 3
с дискеты и выполнить некоторые полезные действия. Это не выглядит особо
дружественным пользователю, но примите во внимание то, что если бы все драй
веры пытались инициализироваться непосредственно при запуске системы, то
неправильная установка некоторых устройств, которые все равно лежат балла
стом, могла бы полностью парализовать ОС. Отложив инициализацию драйверов,
система может работать только с тем, что реально функционирует, давая пользо
вателю возможность исправить ситуацию.
Отступая в сторону, заметим, что этот урок тяжело нам дался. Ранние версии
MINIX пытались инициализировать жесткий диск при загрузке системы. Если
жесткого диска не было, система зависала. Такое поведение было особенно не
приятным потому, что система MINIX рассчитана также на машины без жестко
го диска, хотя это снижает и доступный объем памяти, и производительность.
В этом и следующем разделах мы будем рассматривать драйвер жесткого диска
в стиле АТ, устанавливаемый в MINIX 3 по умолчанию. Это - многоцелевой
драйвер, обеспечивающий поддержку широкого диапазона контроллеров, как
ранних, применявшихся в системах 286, так и современных с усовершенство
ванным интерфейсом жестких дисков с интегрированной электроникой (Extended
326 Глава З. Ввод-вы вод
жесткого диска в M I N IX З
Жесткие диски часто называют •винчестерами• . Существует несколько историй
о том, как родилось это название. Оно было у проекта компании IBM, разраба
тывавшей технологию, в которой магнитные головки •парят• над поверхностью
вращающегося диска, опираясь на тонкую воздушную прослойку. Одно из тол
кований названия в том, что у первых моделей было два герметически закрытых
корпуса: фиксированный (30 Мбайт) и сменный ( тоже 30 Мбайт) . Предполо
жительно, это напомнило разработчикам винчестер •30-30•, ставший •героем•
многих вестернов. Каково бы ни было происхождение названия, основа техно
логии остается той же самой, хотя типичные жесткие диски современных мик
рокомпьютеров гораздо миниатюрнее и хранят гораздо больше данных, чем их
1 4-дюймовый прототип начала 1 970-х.
Драйвер жесткого диска, рассчитанного на шину АТ, находится в файле at_
wini . с (строка 1 2 1 00). Драйвер предназначен для сложного устройства и со
держит несколько страниц макроопределений, задающих регистры контроллера,
биты состояния, команды, структуры данных и прототипы. Как и в случае с драй
верами других блочных устройств, в драйвере винчестера создается структура
типа driver, хранящаяся в переменной w_dtab (строки 123 16- 1233 1). Эта струк
тура заполняется адресами функций, которые и выполняют все основные функ
ции драйвера. Код большинства функций находится в файле а t_wini . с, но так
как для жесткого диска не нужны специальные действия для завершения работы,
поле dr_c l e anup структуры содержит ссылку на функцию nop_c l eanup в фай
ле dri ve r . с. Последняя используется всеми драйверами, которые не нуждаются
в особых действиях для завершения. Данный драйвер не нуждается еще в не
скольких функциях; соответствующие указатели ссылаются на функции семей
ства nop_. Точка входа в драйвер - это функция at_wi nche s t e r_t a s k (стро
ка 1 2336), которая выполняет аппаратно-зависимую инициализацию и вызывает
главный цикл (файл d r i ve r . c ) , передавая ему адрес w_dt ab. Главный цикл
(функция drive r_t a s k файла l i Ьdr i ve r / dr i ve r . c ) исполняется бесконеч
но, обслуживая поступающие запросы и вызывая функции, адреса которых запи
саны в полях структуры w_dt ab.
Поскольку в настоящее время мы имеем дело с электромеханическими устройст
вами хранения информации, функции i ni t__pa rarns (строка 1 2347) необходимо
сделать немало работы для инициализации драйвера жесткого диска. Различные
параметры жесткого диска хранятся в таблице wini (строки 12254- 1 2276). Таб
лица включает элемент для каждого из восьми ( МAX_DRIVE S ) поддерживаемых
дисков - до четырех обычных дисков и до четырех дисков на шине PCI с IDE
и SА ТА -контроллерами (аббревиатура SATA расшифровывается как Serial АТ
Attachrnent - последовательное АТ-подключение).
328 Глава 3. Ввод- вывод
но у нас нет другой альтернативы, кроме как верить в то, что заявляет диск. )
Кроме того, эти сведения содержат информацию о том, поддерживает л и диск
линейную адресацию блоков ( Linear Block Addressing, LBA). Если данная функция
поддерживается, драйвер вправе игнорировать цилиндры, дорожки и секторы и ад
ресовать секторы диска просто по их абсолютным номерам, что намного проще.
Как уже отмечалось, не исключена ситуация, когда функция i n i t_p a r arns
окажется не в состоянии получить информацию о конфигурации диска из BIOS.
Если такое случилось, код в строках 1 2666- 1 2674 делает попытку сформиро
вать подходящий набор параметров, основанных на тех данных, которые удалось
прочитать с самого диска. Основная идея состоит в том, что номера цилиндра,
дорожки и сектора не должны превышать соответственно 1 023, 255 и 63, то есть
учитывается заложенное в структуры данных BIOS ограничение на количество
битов, выделяемых под эти параметры.
Если команда ATA_I DENT I FY возвращает отрицательный результат, это может
просто означать, что вы столкнулись со старой моделью диска, который не под
держивает саму команду. В таком случае все, что мы имеем, - это параметры ло
гической конфигурации, ранее прочитанные функцией i ni t_pararns . Если они
корректны, то они и записываются в поля структуры wini , в противном случае
сообщается об ошибке, и система отказывается работать с диском.
Наконец, чтобы считать адреса в байтах, в MINIX 3 используется переменная
uЗ 2_t . Максимальный объем раздела, с которым умеет работать драйвер, огра
ничен значением в 4 Гбайт. Тем не менее структура devi c e , используемая для
хранения базового адреса и размера раздела и определенная в файле dr ivers /
l ibdrive r / driver . h (строки 1 0856- 1 0858), содержит числа типа u 6 4_t . Для
подсчета объема диска применяется операция 64-разрядного умножения ( стро
ка 1 2688). Далее базовый адрес и размер диска вводятся в массив wini и вызы
вается (дважды при необходимости) функция w_sp e c i fy, передающая обратно
контроллеру его рабочие параметры (строка 1 2 69 1 ). Затем выполняются вызовы
ядра. Вызов sy s_i rqs et p o l i cy (строка 1 2699) гарантирует, что по окончании
обслуживания прерывания от контроллера диска прерывания будут разрешены
автоматически. После этого вызов sys_i rqenaЫ e фактически разрешает пре
рывание.
Функция w_narne (строка 1 27 1 1 ) возвращает указатель на строку, содержащую
имя устройства: «AT-DO•, «AT-D 1 • , «AT-D2• или «AT- D3•. При необходимо
сти генерации сообщения об ошибке данная функция указывает, какой из дис
ков является ее источником.
Не исключено, что в силу какой-либо причины диск окажется несовместимым
с MINIX 3. Функция w_i o_t e s t (строка 12723) проверяет каждый из дисков
при первой попытке получения доступа к нему. Она пытается считать первый
блок диска с более коротким временем ожидания, чем при обычном функциони
ровании. Если попытка не удается, диск помечается как недоступный.
Функция w_spe c i fy (строка 1 2775) в дополнение к передаче параметров кон
троллеру выполняет повторную калибровку устройства (для старых моделей),
передавая команду поиска нулевого цилиндра.
3.7. Реал ь ные диски 33 1
и не могут исполнять команды чтения и записи регистров. Это означает, что сле
дует изучить вызовы ядра, снимающие данное ограничение.
Регистры, используемые стандартным контроллером жесткого диска, совмести
мым с I BM-AT, показаны в табл. 3.4.
+ LBA - для режима адресации по цилиндре, головке и сектору ( CHS) - О, для
режима линейной адресации блоков ( LBA) - 1 ;
+ D - для главного диска (rnaster) - О , для подчиненного (slave) - 1 ;
+ нsn - для режима C H S - выбор головки, для режима LBA биты 24-27 вы
бора блока.
Теперь рассмотрим, как при помощи функции c orn_out (строка 1 2947) команда
передается контроллеру. Эта функция вызывается после заполнения структуры
crnd уже изученной нами функцией do_t rans f e r. Прежде чем менять какие
либо регистры, программа узнает, занят ли контроллер, считывая бит STATUS_
BSY. Здесь важна скорость, и так как контроллер обычно должен быть свободен
или скоро освободится, здесь используется активное ожидание. В строке 12960
вызывается команда w_wa i t f or, тестирующая значение бита STATUS_BSY. Чтобы
проверить бит в регистре состояния, w_wa i t f o r делает вызов ядра, осуществ
ляющий чтение порта ввода-вывода. Цикл активного ожидания продолжается до
тех пор, пока бит не установится в значение готовности либо не истечет интервал
ожидания. Как только диск готов, цикл быстро прекращается. В качестве возвра
щаемого значения будет указана истина, если контроллер готов сразу, истина, ес
ли контроллер оказывается готов с некоторой задержкой, и ложь, если контрол
лер не приходит в состояние готовности в течение интервала ожидания. Более
подробно интервал ожидания рассматривается при описании функции w_wa i t for.
Контроллер способен обслуживать более одного диска, поэтому когда он освобо
ждается, в регистры записывается байт, выбирающий привод, головку и режим
работы (строка 12966), и функция w_wa i t f o r вызывается снова. Иногда приво
ду не удается выполнить команду или правильно вернуть код ошибки; в конце
концов, это - механическое устройство, которое может заесть или просто сломать
ся, и для страховки совершается вызов sys_s e t a l arrn ядра, чтобы системное
задание запланировало вызов подпрограммы, разблокирующей драйвер. Следом
за этим команда передается контроллеру, для чего сначала все параметры за
писываются в разные регистры, а затем в регистр команд кладется код самой
команды. Это делает вызов sys_voutb ядра, посылающий вектор пар (значение,
адрес ) системному заданию. Системное задание записывает каждое значение
в порт ввода-вывода, задаваемый адресом. Вектор данных для вызова sys_voutb
формируется с помощью макроса pv_s e t , определенного в файле inc lude /
rnirni x / devi o . h. Обработка начинается, когда в регистр команд записывается
код операции. По завершении генерируется прерывание и отправляется уведом
ление. Если при выполнении команды истечет интервал ожидания, синхронное
уведомление активирует дисковый драйвер.
Следующие несколько функций, которые мы рассмотрим, меньше по объему.
Функция w_need_re s e t (строка 1 2999) вызывается при истечении интервала
ожидания прерывания или готовности диска. Все, что делает w_need_re s e t , -
задает значение переменной s t at e для каждого диска в массиве win i , чтобы
вызвать инициализацию при следующей попытке доступа.
Функция w_do_c l o s e (строка 13016) в отношении обычного жесткого диска не
делает почти ничего. Если необходима поддержка CD-ROM, следует включить
в нее дополнительный код.
Функция c orn_s irnp l e отправляет команду контроллеру и немедленно заверша
ется без обмена данными. В данную категорию попадают команды, которые слу
жат для идентификации диска, установки некоторых параметров и повторной
калибровки привода. Пример использования этой функции мы видели в функции
3 .7 . Реальные диски 335
w_ident i fy. Перед ее вызовом структура c omrnand должна быть корректно ини
циализирована. Обратите внимание на то, что сразу же после вызова c orn_out
вызывается функция at_int r_wa i t . В конечном счете, она совершает вызов
r e c e i ve, который обеспечивает блокировку до тех пор, пока не будет получено
уведомление о прерывании.
Мы упомянули о том, что функция c orn_out выполняет вызов sys_s e t a l arrn
ядра перед тем, как обратиться к системному заданию за записью регистров,
устанавливающих и исполняющих команду. Как уже отмечалось, следующая опе
рация re c e i ve должна получить уведомление о прерывании. Если уведомление
бьто активизировано, а прерывания не случилось, следующим сообщением бу
дет SYN_ALARМ. В этом случае вызывается функция w_t irneout (строка 1 3046).
Конкретные действия, которые нужно выполнить, зависят от текущей команды
в w_c omrnand. Возможно, от предыдущей команды остался истекший интервал
ожидания, и значение w_c omrnand равно CMD_I DLE, что указывает на заверше
ние работы диска. В этом случае никаких действий выполнять не нужно. Если
работа не завершена и операция является чтением или записью, размер запросов
ввода- вывода можно сократить. Это делается в два этапа: количество запра
шиваемых секторов уменьшается сначала до 8, затем - до 1. Во всех случаях
истечения времени ожидания на экран выводится сообщение и для повторной
инициализации всех приводов при следующей попытке доступа вызывается
функция w_need_re s e t .
Когда требуется сброс, вызывается функция w_re s e t (строка 1 3076). Эта под
программа использует библиотечную функцию t i c kde l ay, устанавливающую
сторожевой таймер и ожидающую его истечения. Сначала w_r e s e t делает на
чальную задержку, чтобы дать приводу время вернуться в исходное состояние
после предыдущих действий. Затем стробируется бит регистра управления кон
троллера диска, то есть сначала на заданное время бит устанавливается в 1, а за
тем возвращается в О. Далее вызывается w_wa i t f o r, чтобы позволить диску
прийти в состояние готовности. Если сброс не завершился успехом, на экран вы
водится сообщение и возвращается код ошибки.
Команды, затрагивающие обмен данными с диском, обычно завершаются генера
цией прерывания, которое отправляет сообщение обратно драйверу. Фактически
прерывание генерируется каждый раз, когда считывается или записывается
сектор. Функция w_int r_wa i t (строка 1 3 1 23) циклически вызывает rece ive,
и если получено сообщение SYN_ALARМ, вызывается w_t irneout . Помимо со
общения S YN_ALARM, функция w_i nt r_wa i t воспринимает лишь один тип
сообщений - HARD_INT. При его получении выполняется считывание регистра
состояния, и прерывание инициализируется заново вызовом ack_arg s .
Функция w_int r_wa i t н е вызывается впрямую; при ожидании прерывания вы
зывается следующая функция, at_int r_wa i t (строка 1 3 1 52). После получения
ею прерывания выполняется быстрая проверка битов состояния диска. Штатным
считается состояние, в котором сброшены биты занятости, сбоя записи и ошиб
ки. В противном случае выполняется более тщательный анализ. Если регистр
вовсе не удалось прочитать, это считается сбоем системы. Если неполадка вызвана
336 Глава 3 . Ввод-вывод
Драйвер дисковода гибких дисков сложнее, чем драйвер жесткого диска, а объем
его кода больше. Это на первый взгляд парадоксально, так как механизмы диско
вода гибких дисков должны быть проще, чем механизмы винчестера, но кон
троллер первого сложнее и требует к себе больше внимания от операционной
системы. К тому же, дополнительные сложности вносит сменный носитель. В теку
щем разделе мы рассмотрим некоторые вопросы, которые могут оказаться полез
ными для программиста, имеющего дело с гибкими дисками. В основных дета
лях код драйвера дисковода сходен с кодом драйвера жесткого диска. Детально
же разбирать код, ввиду его сложности, мы не будем.
Одна из проблем, с которыми мы не столкнемся, работая с приводами дискет, -
это необходимость поддерживать много типов контроллеров, что было обяза
тельно для жестких дисков. Хотя использующиеся сейчас гибкие диски с высо
кой плотностью записи не поддерживались оригинальными машинами IBM РС,
все контроллеры гибких дисков обслуживаются одним драйвером. Такое от
личие от жестких дисков произошло, видимо, потому, что на дисководы гибких
дисков не оказывалось то давление, которое заставляло разработчиков повышать
производительность жестких дисков. Дискеты редко используются как рабочее
хранилище в компьютерной системе, их скорость и емкость слишком ограничены
по сравнению с винчестерами. Дискеты продолжают использоваться, но только
для переноса небольших файлов, поэтому такими дисководами все еще оснаще
но большинство компьютеров.
Драйвер дисковода гибких дисков не включает в себя сложных алгоритмов пла
нирования, таких как S S F или элеваторный алгоритм. Запросы выполняются
строго последовательно, причем следующий запрос не принимается, пока не вы
полнен текущий. Изначально при разработке MINIX предполагалось, что эта
система предназначена для персональных компьютеров, где большую часть вре
мени будет активен только один процесс, и вероятность появления одного запро
са во время обработки другого мала. Таким образом, поддержка очередей запро
сов не дала бы заметного увеличения производительности, зато потребовала бы
значительного усложнения кода. Сейчас это тем более не имеет смысла, так как
дискеты по большей части применяют для переноса отдельных файлов с одной
системы на другую.
Драйвер дисковода гибких дисков, как и любое блочное устройство, способен об
рабатывать запросы разрозненного ввода-вывода. Тем не менее массив запросов
у. него меньшего объема, чем у драйвера жесткого диска. Количество запросов
в массиве ограничено максимальным числом секторов на одной дорожке дискеты.
Простота устройства аппаратной части дисковода гибких дисков приводит к услож
нению его драйвера. Использовать в дешевых, медленных и обладающих малой
338 Глава 3 . Ввод-вывод
3 . 8 . Терминал ы
В течение десятилетий пользователи взаимодействуют с компьютерами при по
мощи устройств, состоящих из клавиатуры и дисплея. Посредством клавиатуры
пользователь вводит в компьютер данные, а компьютер отображает результаты
на дисплее. Долгое время клавиатура и дисплей объединялись в отдельное уст
ройство, подключаемое к компьютеру проводом. Большие мэйнфреймы, используе
мые в финансовой и туристической отраслях, до сих пор имеют такие терминалы.
340 Глава 3. Ввод-вывод
Сетевой
интерфейс
Х-терминал
Рис. 3. 1 6 . Типы терминалов
Отображаемые на память терминал ы
Первая широкая категория терминалов (см. рис. 3. 1 6) - это отображаемые на
память терминалы. Такие терминалы представляют собой составную часть самого
компьютера, в особенности персонального. Они состоят из клавиатуры и мани:-
3 . 8. Терми налы 341
Графический
Процессор Память адаптер
Видеопамять Экран
Адрес ОЗУ
т
AB C D
о 1 2 3
".х3х2х1х0
... xDxCxBxA
l.-- 1 eo символов -..!
ОхВООАО
ОхВОООО
!.-- 80 символов -..!
i�·
а б
Рис. 3. 1 8 . Область видеопамяти: а содержимое видеопамяти для монохромного
-
Те р м и н ал ы RS-232
Терминалы RS-232 представляют собой устройства, состоящие из клавиатуры
и экрана, которые взаимодействуют через последовательный интерфейс. Такой
интерфейс позволяет передавать по одному биту за раз (рис. 3. 19). Эти термина
лы подключаются через 9- или 25-контактный разъем, в котором один контакт
служит для передачи данных, один для приема и один для заземления. Осталь
ные контакты отвечают за разного рода управляющие функции, и большинство
из них не используется. Чтобы передать символ, терминал RS-232 должен от
правлять по одному биту, предварив передачу стартовым битом и завершив ее
одним или двумя стоповыми битами. Также может быть добавлен бит контроля
четности, который позволяет организовать простейшую проверку правильности
передачи, хотя обычно он требуется только для взаимодействия с мэйнфреймами.
Э тот бит может находиться перед стоповыми битами. Стандартно применяются
скорости передачи 14 400 и 56 ООО бит/с: первая для факсимильной информа
ции, вторая - для данных. Терминалы RS-232 обычно подключаются к удален
ной системе при помощи модема и телефонной линии.
Компьютер
Интерфейс
Процессор Память RS-232
Получив символ, драйвер должен начать его обработку. Если клавиатура переда
ет информацию о номере нажатой клавиши, а не о коде символа, который нужен
для прикладных программ, драйверу требуется преобразовать номер в код сим
вола при помощи таблицы. Не все IВМ-совместимые клавиатуры имеют одина
ковую нумерацию клавиш, поэтому драйвер, чтобы обеспечить поддержку раз
личных клавиатур, должен иметь разные таблицы перекодировки для разных
клавиатур. Простейший подход - скомпилировать драйвер с таблицей, предна
значенной для преобразования кодов клавиш в кодировку A S C I I (American
Standard Code for Information Interchange - американский стандартный код об
мена информацией). К сожалению, такое решение неудовлетворительно для не
англоязычных пользователей. В разных странах приняты разные раскладки кла
виатур, и стандартного набора АSСП-символов недостаточно для большинства
людей, населяющих восточное полушарие. Например, тем, кто разговаривает на
французском, португальском и испанском языках, требуются буквы с надстроч
ными знаками и знаки препинания, которых нет в английском. Чтобы обеспечить
гибкую работу с клавиатурными раскладками для различных языков, во многих
операционных системах имеется возможность загружать различные кодовые
страницы. Они позволяют выбирать (при загрузке или позже), как клавиатур
ные коды должны преобразовываться в коды символов.
Если терминал работает в каноническом режиме (режиме с обработкой), введен
ные символы должны храниться в буфере до тех пор, пока не будет завершена
вся строка, поскольку пользователь может решить удалить ее часть. Даже если
переключить терминал в неканонический режим, может оказаться, что програм
ма еще не запрашивала входные данные, поэтому введенные символы все равно
должны буферизироваться, чтобы позволить пользователю производить упреж
дающий ввод. (Разработчиков систем, не позволяющих пользователям вводить
символы с клавиатуры без возможности исправления, следует обмазывать дег
тем и вываливать в перьях, ибо заставить их пользоваться собственной системой
было бы слишком жестоким наказанием.)
Для буферизации символов обычно применяются два метода. В первом случае
в драйвере содержится центральный пул буферов, в каждом из которых хра
нится около 1 О символов. С каждым терминалом связана структура данных, со
держащая, среди прочего, указатель на цепочку буферов, в которых находятся
символы, введенные с данного терминала. Чем больше символов введено, тем
больше выделяется буферов, соединенных в цепь. Когда символ передается
пользовательской программе, буферы удаляются и память возвращается цен
тральному пулу.
Другой подход заключается в том, что буферизация производится прямо в струк
туре данных терминала, без центрального пула буферов. Поскольку пользовате
ли часто печатают команду, обработка которой требует некоторого времени (на
пример, на перекомпиляцию и сборку большой программы), а затем печатают
еще несколько строк, буфер драйвера должен вмещать не меньше 200 символов
для каждого терминала. В большой системе разделения времени с сотней терми
налов выделение по 20 Кбайт на буфер ввода с каждой клавиатуры кажется
3 . 8 . Терминалы 347
{
.------.
2 Буферная область
--------------
3
о для терминала О
�
а б
Рис. 3 . 20 . Варианты буферизации ввода:а центральный пул буферов;
-
дальше текущей строки. При удалении блока символов драйвер может как воз
вращать, так и не возвращать буферы в пул (если он используется).
Иногда символы ERASE или K I LL должны быть введены в строку как обычные
данные. Для этого служит символ LNEXT, действующий в качестве префиксноzо
сим.вола. В M INIX 3 ему по умолчанию соответствует сочетание клавиш Ctrl+V.
В более старых версиях UNIX для ввода символа K I LL часто использовалась
клавиша @, но впоследствии этот символ стал составной частью адресов элек
тронной почты Интернета (например, linda@cs.washington.edu). Те, кому привычнее
350 Глава 3. Ввод- вы вод
старые соглашения , могут переопределить символ KILL как @, но тогда при набо
ре адреса электронной почты им придется вводить символ @, нажимая сочетание
клавиш Ctrl+V, @. Сам символ LNEXT может быть введен, если дважды нажать
клавиши Ctrl+V. Встретив символ LNEXT, драйвер установит флаг, означающий,
что следующий символ не следует подвергать специальной обработке. Сам сим
вол LNEXT не помещается в очередь символов.
Чтобы приостановить и продолжить вывод на экран, также предоставляются спе
циальные управляющие коды. В MINIX 3 это символы STOP (Ctrl+S) и START
(Ctrl+Q). Они не хранятся в буфере, но используются для установки и сброса
флага в структуре данных терминала. При каждой операции вывода на экран
проверяется значение этого флага. Если флаг установлен, вывод не производит
ся. Эхопечать при этом, как правило, также подавляется.
Часто возникает необходимость прервать выполнение отлаживаемой програм
мы. Для этой цели могут использоваться символы INTR (Ctrl+C) и QUIT (Ctrl+\).
В MINIX 3 сочетание Ctrl+C посылает сигнал прерывания S I G INT всем процес
сам, запущенным с этого терминала. Реализация может быть непростой. Наи
более сложной является передача информации от драйвера в ту часть системы,
которая занимается обработкой сигналов, поскольку она не ожидает получения
подобной информации. Результат нажатия клавиш Ctrl+\ аналогичен нажатию
клавиш Ctrl+C, с той разницей, что процессам посьтается сигнал S I GQUI T, вы
зывающий прекращение работы процесса с сохранением дампа ядра, если этот
сигнал специально не перехватывается процессом или не игнорируется.
При нажатии любого из этих сочетаний клавиш драйвер должен вывести эхо
в виде символов перевода строки и возврата каретки, а также очистить свой бу
фер с накопленными символами, чтобы позволить начать новый ввод. Во многих
UNIХ-системах символ INТR по умолчанию генерируется клавишей Del. Посколь
ку программы зачастую используют Del наравне с клавишей забоя при редакти
ровании, в настоящее время предпочтение отдается комбинации Ctrl+C.
Специальный символ EOF (Ctrl+D) в MINIX 3 удовлетворяет активный запрос на
чтение и передает все содержимое буфера, даже если он пуст. Нажатие клавиш
Ctrl+D в начале строки приводит к тому, что программа считывает О байт. При
считьmании файла это обычно воспринимается и обрабатывается как конец файла.
Некоторые драйверы терминала предоставляют возможность более сложного ре
дактирования строки, чем бьто описано здесь. Они имеют специальные управ
ляющие символы, позволяющие удалять целиком слова, перемещать курсор впе
ред и назад по символам и по словам, вставлять текст в середину уже набранной
строки и т. д. Добавление подобных функций к драйверу значительно увели
чивает его. Кроме того, эти функции чаще всего оказываются неиспользуемыми
экранными редакторами, предпочитающими работать с драйверами клавиатуры
в режиме без обработки.
Стандарт POSIX требует того, чтобы в стандартной библиотеке бьти доступны
несколько функций, позволяющих программам управлять параметрами терми-
3 . 8 . Терминал ы 351
s t ruc t t e rm i o s {
t c f l ag_t c_i f l ag ; / * Режимы ввода * /
t c f l ag_t c _o f l a g ; / * Режимы вывода * /
t c f l ag_t c_c f l ag ; / * Режимы упра вления * /
t c f l ag_t c _l f l ag ; / * Локальные реж имы * /
speed_t c _ i s p e e d ; / * Скорость ввода * /
speed_t c_o speed ; / * Скоро с т ь вывода * /
c c _t с_с с [ NCC S J ; / * Управляющие с имволы * /
} ;
без обработки.
есть две виртуальные консоли, то нажав клавиши Alt+ F2, можно переключиться
на вторую, а нажатие клавиш Alt+ F1 активизйрует первую консоль. Для пере
ключения можно также использовать комбинацию клавиши Alt и клавиш управ
ления курсором. Кроме того, последовательные линии обеспечивают поддерж
ку двух удаленных пользователей, подключающихся через модем или кабель
RS-232, а псевдотерминалы позволяют пользователям подключаться через сеть.
Драйвер написан так, чтобы можно было легко добавлять новые терминалы.
Терминальный ввод
Чтобы лучше понять, как работает драйвер терминала, сначала рассмотрим, как
напечатанный пользователем символ прокладывает себе путь к ожидающей его
программе. Хотя этот раздел является обзорным, мы дадим читателю ссылки на
3 . 8 . Терми налы 357
Получив достаточно символов, драйвер терминала выполняет вызов ядра (8), за
прашивающий у системного задания копирование данных по адресу, затребован
ному оболочкой. Эта операция также не является передачей сообщения, поэтому
обозначена на рис. 3.2 1 многоточием (9). На рисунке изображено несколько
линий с цифрой 9, поскольку до того, как пользовательский запрос будет полно
стью выполнен, данные могут быть переданы несколько раз. Когда операция
полностью завершится, драйвер терминала отправляет файловой системе со
общение о том, что работа выполнена ( 10), а файловая система в результате от
правляет сообщение оболочке и выводит ее из состояния блокировки ( 1 1).
Определение количества обрабатываемых символов зависит от режима термина
ла. В каноническом режиме запрос считается выполненным, когда поступает
символ перевода строки, конца строки или конца файла. Также длина строки не
может превышать величину входной очереди, чтобы входные данные могли пра
вильно обрабатываться. В неканоническом режиме может запрашиваться гораз
до большее количество символов, и функции in_proc e s s может потребоваться
передавать данные несколько раз перед тем, как файловой системе будет возвра
щено сообщение, означающее завершение работы.
Обратите внимание на то, что системное задание копирует данные напрямую из
своего адресного пространства в адресное пространство оболочки. Данные не пе
редаются через файловую систему. При блочных операциях ввода-вывода ин
формация сначала поступает файловой системе, чтобы та могла поддерживать
кэш недавно запрошенных блоков. Если запрошенный блок оказывается в кэше,
файловая система может самостоятельно выполнить пользовательский запрос
без реального обращения к диску.
При работе с клавиатурой кэширование не имеет смысла. Кроме того, запрос фай
ловой системы к драйверу диска всегда может быть обслужен максимум за не
сколько сотен миллисекунд, поэтому нет большой проблемы в том, что файловой
системе приходится немного подождать. Операции с клавиатурой могут длиться
часами или вообще могут не завершаться (в каноническом режиме драйвер ждет
ввода полной строки, а в неканоническом ждет достаточно длинной строки, в за
висимости от параметров MIN и T IME) . Поэтому файловая система не должна
блокироваться, ожидая выполнения запросов терминального ввода-вывода.
Вполне вероятно, что пользователь введет какой-либо текст заранее, и символы
благодаря предыдущим прерываниям и событию 4 окажутся доступными до то
го, как они будут запрошены. В этом случае все события 1, 2 и 5- 1 1 происходят
сразу же после запроса, а события 3 вообще не происходит.
Читатели, знакомые с ранними версиями операционной системы MINIX, возмож
но, помнят, что в них драйвер терминала и все прочие драйверы были объединены
с ядром. У каждого драйвера был собственный обработчик прерываний в про
странстве ядра. Обработчик прерываний драйвера клавиатуры осуществлял бу
феризацию определенного количества кодов опроса и выполнял предваритель
ную обработку (большую часть кодов, полученных при отпускании клавиши,
можно отбросить, поскольку их буферизация необходима только при нажатии
360 Глава 3 . Ввод-вывод
клавиатурного ввода (рис. 3.22). В первом случае, когда драйвер терминала полу
чает сообщение, запрашивающее вводимые с клавиатуры символы, главная про
цедура, t ty_t a s k (строка 1 3740), вызывает процедуру do_read (строка 13953),
которая и выполняет запрос. Если имеющейся в буфере информации недостаточно
для выполнения запроса, процедура сохраняет параметры запроса в t ty_t aЫ e.
iп_traпsfer
Прочие функции
Обработка ввода драйвером терминала. Левая часть дерева соответствует
Ри с . 3 . 2 2 .
обработке запроса на чтение символов, а правая - передаче сообщения от клавиатуры
драйверу раньше, чем пользователь затребовал ввод
После этого, чтобы получить уже введенные данные, вызывается функция in_
t r ans f er (строка 144 1 6), а затем - функция handl e_events (строка 14358), ко
торая, в свою очередь, вызывает функцию kb_r ead через указатель * tp - >t ty_
devread (строка 1 5360) и еще раз функцию in_t rans f er, чтобы получить из
входного потока еще несколько символов. Функция kb_r ead несколько раз вы
зывает другие подпрограммы, не показанные на рис. 3.22. В результате пользова
телю копируются все доступные данные. Если доступных данных нет, ничего не
копируется. Когда вызов in_t r ans f er или handl e_event s полностью выпол
няет запрос, файловой системе отправляется сообщение, чтобы она могла раз
блокировать запросивший данные процесс. Если чтение не завершено (не введе
но ни одного символа или введено недостаточное количество), функция do_
report информирует об этом файловую систему, чтобы та могла либо заблоки
ровать вызвавший процесс, либо, если было запрошено неблокирующее чтение,
отменить запрос.
На правой части рис. 3.22 воспроизведены все события, возникающие, когда
драйвер терминала •просыпается» вследствие прерывания от клавиатуры. Когда
напечатан символ, •обработчик» прерываний kbd_int errup t (строка 1 5335) вы
зывает функцию s c an_k eybo ard, которая обращается к системному заданию за
выполнением ввода-вывода (мы заключили слово •обработчик» в кавычки пото
му, что функция kЬd_int errupt фактически обработчиком не является. Она вы
зывается, :когда t ty_t a s k получает сообщение от функции gener i c_handl er
362 Глава 3 . Ввод-вывод
Терминальный вывод
Вообще говоря, консольный вывод проще ввода, так как здесь действиями управ
ляет операционная система, и не нужно бояться, что события произойдут в не
подходящее время. Более того, процесс еще больше упрощается за счет того, что
в MINI X 3 консолью является отображаемый на память экран. Прерывания
не нужны, вывод производится путем копирования данных из одной области
памяти в другую. Однако в этом случае все операции по управлению экраном,
включая обработку управляющих последовательностей, ложатся на программ
ное обеспечение драйвера. Как и при изучении ввода в предыдущем разделе,
мы проследим, какие действия происходят при выводе символа на консольный
дисплей. В этом примере предполагается, что вывод производится на актив
ный дисплей. Небольшое усложнение, вносимое виртуальными консолями, мы
обсудим позже.
Обычно, когда процесс хочет что-нибудь напечатать, он вызывает функцию
p r i n t f . Эта функция делает системный вызов wr i t e, который отправляет фай
ловой системе сообщение с указателем на выводимые символы (но не сами
символы) . Затем файловая система посылает сообщение драйверу терминала,
а тот извлекает указанные ему символы и копирует их в видеопамять. Основ
ные подпрограммы, из которых складывается терминальный вывод, показаны
на рис. 3.23.
3 . 8 . Терминалы 363
tty_task
do_write
haпdle_eveпts
,
,
,
,
1
«Простые» ,' 1
/ Escape- Специальные
символы /
1
последовательности Конец строки
'
'
'
'
'
в UNIX символом новой строки является код LF (ОхОА) и иногда его необходимо
370 Глава 3. Ввод- вывод
Точкой входа для драйвера терминала является функция t ty_task (строка 137 40).
Перед тем как начать свой главный цикл, она вызывает функцию t ty_i n i t
(строка 13752). Информация о главном компьютере, необходимая для инициа
лизации клавиатуры и консоли, предоставляется вызовом sys_getrna c h i ne
ядра, а затем выполняется сама инициализация при помощи подпрограммы kb_
ini t_once. Такое имя было выбрано, чтобы отличить эту подпрограмму от дру
гой подпрограммы инициализации, вызываемой позднее для каждой виртуаль
ной консоли. Наконец, на вывод посылается один символ О, чтобы проверить вывод
и исключить неинициализированные устройства раньше, чем будут предприня
ты первые попытки их использования. В коде вызывается функция print f , но
она отличается от одноименной функции, вызываемой обычными программами.
Она вызывает локальную функцию putk драйвера консоли.
Главный цикл (строки 1 3764 - 1 3876) почти аналогичен главному циклу любого
другого драйвера. Принимается сообщение, при помощи инструкции swi t ch
для каждого типа сообщения вызывается соответствующая функция обработки,
после чего генерируется ответное сообщение. Однако есть и отличия. Первое со
стоит в том, что с момента последнего прерывания могут накопиться считанные
или выведенные на запись символы. Поэтому, прежде чем пытаться получить со
общение, главный цикл проверяет флаги tp - > t ty_event s для всех термина
лов. Если необходимо позаботиться о незавершенных делах, вызывается функ
ция handl e_event s, и только если не найдено ни одного требующего внимания
терминала, делается вызов rece ive.
Диаграмма с типами сообщений, представленная в комментариях в начале файла
t ty . с, содержит лишь наиболее распространенные типы. В ней отсутствуют мно
гие типы, требующие особой обработки драйвером терминала. Те же, которые на
ней изображены, не являются специфичными для какого-либо конкретного уст
ройства. Главный цикл t ty_t a s k проверяет общие сообщения и обрабатывает
их раньше, чем специфичные. Первая проверка относится к типу S YN_ALARM,
и если сообщение относится к нему, выполняется вызов exp i re_t irne r s , запус
кающий подпрограмму сторожевого таймера. Затем следует команда c ont i nue.
Фактически, все следующие варианты, которые мы рассмотрим, расположены
после этой команды. Скоро мы скажем об этом более подробно.
Следующий тип, соответствие которому проверяется для сообщения, HARD_
-
INT. Сообщения такого типа чаще всего обусловлены нажатием или отпускани
ем клавиши на локальной клавиатуре. Сообщения HARD_INT также генерируются
при получении байтов по последовательному порту в случае, если он включен.
В конфигурации, описываемой в книге, последовательные порты не используют
ся, однако мы сохранили в файле условный код, чтобы продемонстрировать, как
система функционировала бы при поддержке последовательных портов. Битовое
поле сообщения позволяет определить источник прерывания.
Затем проверяется тип SYS_S IG. Системные процессы (драйверы и серверы),
как правило, блокируются и ожидают сообщений. Обычные сигналы способны
получать лишь активные процессы, поэтому стандартный метод использова
ния сигналов UNIX неприменим к системным процессам. Для передачи сигнала
3.8. Терминалы 375
еще не получена хотя бы одна целая строка. Передача производится после получе
ния всей строки, потому содержимое очереди можно изменить, если, например,
пользователь ввел символ K I L L или ERASE до нажатия клавиши Enter. В некано
ническом режиме немедленный возврат имеет место, если запрошенное количе
ство символов еще недоступно.
Несколькими строками далее переменные tp - >t ty_i n l e f t и tp - >t ty_eot ct
управляют главным циклом процедуры. В каноническом режиме передача про
изводится до тех пор, пока в очереди не останется больше полностью введенных
3 . 8. Терминал ы 383
Четыре бита используются для подсчета символов, чтобы знать, сколько места
осталось для эхопечати. Условная инструкция в строке 14435 проверяет, уста
новлен ли признак конца файла (D на рисунке) . Эта проверка делается в начале
потому, что символ конца файла не должен ни передаваться программе, ни
использоваться при подсчете символов. При передаче каждого символа у него
маскируется 8 старших бит, и в локальный буфер записывается только АSСП
значение (строка 1 4437).
Существуют несколько способов сигнализировать об окончании ввода, но от спе
цифической для устройства функции ввода ожидается, что она распознает, когда
вводимый символ является переносом строки, концом файла (Ctrl+D) или одним
из подобных символов, и соответствующим образом пометит их. Функции i n_
t r ans f e r остается только проверить эту отметку, бит IN_EOT (N на рис. 3.24)
в строке 14454. Если символ опознан, значение tp - >t ty_eot c t уменьшается
на единицу. В неканоническом режиме подобным образом подсчитываются все
символы, и все они помечаются битом I N_EOT, поэтому tp - >t ty_eot c t содер
жит число символов, не удаленных из очереди. Единственное различие в работе
главного цикла процедуры в двух разных режимах работы терминала определя
ется строкой 14457. Там обнуляется переменная tp - >t ty_e o t c t , когда полу
чен символ, помеченный как разрыв строки, но делается это лишь тогда, когда
действует канонический режим. Таким образом, когда управление вновь переда
ется в начало цикла, тот корректно завершается после символа разрыва строки.
Но сказанное верно только для канонического режима - в неканоническом раз
рывы строк игнорируются.
384 Глава 3 . Ввод- вывод
Когда цикл завершается, локальный буфер символов для передачи об:р1чно час
тично полон (строки 1 446 1 - 14468). В том случае, если значение tp - > t ty_
inl e f t достигло нуля, генерируется и отправляется ответное сообщение. В кано
ническом режиме это делается всегда, а в неканоническом число символов в бу
фере сравнивается с минимальным передаваемым количеством, и если символов
недостаточно, ответное сообщение не отправляется. Если у вас достаточно хорошая
память, чтобы запомнить вызовы i n_t r ans f e r (в do_read и handl e_event s ) ,
вы, наверно, будете удивлены. Там код, следующий за вызовом, отправлял ответ
ное сообщение, когда функция i n_t rans f er передавала больше символов, чем
указано в tp - > t ty_min. И здесь именно этот случай. Причина, по которой от
ветное сообщение не отправляется непосредственно из in_t rans f e r, раскрыва
ется чуть позже при обсуждении следующей функции, вызывающей функцию
in_t r ans f e r при других обстоятельствах.
Эта следующая функция носит имя in__proc e s s (строка 14486). Она вызывается
из аппаратно-зависимого кода для выполнения общйх действий, необходимых
всегда. Ее аргументами являются указатель на структуру t ty для исходного
устройства, указатель на массив 8-разрядных символов, подлежащих обработке,
и счетчик. Новое значение счетчика возвращается в вызвавшую программу.
Функция i n__pro c e s s весьма велика, но ее работа не сложна. Она добавляет
1 6-разрядные символы во входную очередь, откуда их в дальнейшем извлекает
функция in_t rans f er.
Функцией i n_t r ans f e r символы разделяются на несколько категорий.
1. Обычные символы, расширенные до 16 бит, которые добавляются в очередь.
2. Символы, управляющие дальнейшей обработкой, модифицируют флаги, но
сами в очередь не помещаются.
3. Символы для эхопечати применяются немедленно, без занесения в очередь.
4. Символы, имеющие специальное значение, заносятся в очередь с установлен-
ными в старшем байте специальными битами, например, такими как бит БОТ.
Сначала рассмотрим совершенно стандартную ситуацию, когда обычный символ,
такой как х (АSСП-код Ох78), вводится в середине короткой строки без воздей
ствия ЕSС-кодов на терминале, •настроенном» по умолчанию. Полученный
от устройства ввода, этот символ занимает биты от О до 7 (см. рис. 3.24). В строке
14504 старший значащий бит сбрасывается в ноль, если установлен бит I S TRI P.
Но по умолчанию MINIX 3 не обнуляет старший бит, позволя;я вводить 8-раз
рядные символы. В любом случае символ х это не затронет. Расширенная обра
ботка ввода по умолчанию в M INIX 3 не разрешена, поэтому проверка бита
I EXTERN в переменной tp - > t ty_t ermi o s . c_l f lags (строка 14507) дает поло
жительный результат, но для всех последующих проверок результат отрицателен
вследствие установленных нами условий: не действует ЕSС-код (строка 1 45 1 0),
сам символ не является ЕSС-кодом (строка 145 1 7 ) и это - не символ REPRINT
(строка 14524).
Проверки в следующих нескольких строках обнаруживают, что символ не явля
ется специальным символом _PO S I X_VD I SABLE, ни CR, ни NL. Наконец, одна
3 . 8 . Терминалы 385
функции очередь все еще активна, выполняется вызов ядра sy s_s e t a l arrn, за
прашивающий очередное сообщение SYN_ALARМ. Наконец, функция s e t t irner
(строка 15089) устанавливает таймеры, определяющие срок возврата из вызова
read в неканоническом режиме. Она вызывается с двумя параметрами: t ty__ptr,
указателем на структуру t ty, и еnаЫ е, целым числом, обозначающим истину
или ложь. Библиотечные функции trnr s_s e t t irner и trnr s_c l r t irner исполь
зуются для включения и отключения таймера в соответствии со значением аргу
мента еnаЫ е. Если таймер включен, то в качестве сторожевой функции всегда
используется описанная ранее функция t ty_t irned_out .
Описание функции t ty_devnop (строка 15 125) длиннее, чем ее код, поскольку
последний попросту отсутствует. Это - пустая функция, косвенно вызываемая
в случае, если обслуживание устройству не требуется. Мы видели, что в t t у_
ini t многие указатели функций по умолчанию указывают на t ty_devnop до
тех пор, пока не выполнена процедура инициализации устройства.
Последняя функция в файле t ty . с заслуживает особого внимания - это функ
ция s e l e c t . Она представляет собой системный вызов, используемый, когда
одному процессу необходимо асинхронно обслуживать несколько устройств
ввода-вывода. Классическим примером является программа связи, работающая
с локальной клавиатурой и удаленной системой, возможно, соединенными при
помощи модема. Вызов s e l e c t дает возможность открыть несколько файлов
устройств и наблюдать за их считыванием или записью без блокирования. В от
сутствие s e l e c t для двусторонней связи необходимо использовать два отдель
ных процесса, один из которых является главным и обеспечивает связь в одном
направлении, а другой является подчиненным и обеспечивает связь в другом на
правлении. Вызов s e l e c t является примером удобной возможности, значитель
но усложняющей систему. Одной из целей разработки MINIX 3 является про
стота, достаточная для освоения операционной системы с разумными усилиями
за разумное время. По этой причине мы несколько ограничимся в повествовании
и не станем рассматривать здесь функцию do_s e l e c t (строка 1 5 1 35), а также
поддерживающие подпрограммы s e l e c t_t ry (строка 143 13) и s e l e c t_re t ry
(строка 14348).
42 35 1 63 1 70 1 8 1 46 38 1 66 38 1 66 24 1 52 57 1 85
L+ Н+ Н- L- Е+ Е- L+ L- L+ L- О+ О- SP+ SP-
54 17 145 1 82 24 1 52 1 9 1 47 38 1 66 32 1 60 28 1 56
R+ W+ W- R- О+ О- R+ R- L+ L- D+ D- CR+ CR-
Рис. 3.25. Содержимое входного буфера для строки текста, введенной с клавиатуры. Вторая
строка таблицы описывает нажатия клавиш. Символы L+, L-, R+ и R- означают соответственно
нажатие и отпускание правой и левой клавиши Shift. Код отпускания клавиши
на 1 28 больше кода нажатия
Функция kb_r ead извлекает из циклического буфера коды опроса и помещает
в свой локальный буфер АSСП-коды. Этот локальный буфер должен быть дос
таточно емким, чтобы вместить ЕSС-последовательности, генерируемые в ответ
на нажатия некоторых клавиш на цифровой клавиатуре. Затем, чтобы поместить
символы во входную очередь, вызывается функция in_pro c e s s . В строке 1 5379
значение i c ount инкрементируется. Вызов make_break возвращает АSСП-код
в виде целого числа. В этой точке специальные клавиши, например клавиши циф
ровой клавиатуры и функциональные клавиши, имеют коды большие, чем OxFF.
Коды в диапазоне от НОМЕ до INSRT (от Ох 1 0 1 до Ох 1 0 С, эти константы задаются
в файле inc lude / m i n i x / keymap . h) при помощи массива nump ad_map пре
образуются в трехсимвольные ЕSС-последовательности, показанные в табл. 3. 13.
Эти последовательности затем передаются в функцию i n_p r o c e s s (строки
1 5392 - 1 5397). Большие по величине коды в функцию i n_pr o c e s s не пере
даются, среди них ищутся коды, соответствующие комбинациям клавиш Alt+f-,
Alt+� и от Alt+F1 до Alt+ F 1 2. Если обнаруживается одна из таких комбинаций,
вызывается функция s e l e c t_c on s o l e , переключающая виртуальные консоли.
Сочетания от Ctrl+F1 до Ctrl+F1 2 также обрабатываются особо. Сочетание Ctrl+F1
показывает текущие назначения функциональных клавиш (более подробно об
этом мы скажем позже), а сочетание Ctrl+FЗ обеспечивает переключение между
программной и аппаратной прокруткой на экране консоли. Сочетания Ctrl+F7,
3 . 8 . Терминалы 393
никто не может заявить, что после сбоя, когда ожидается команда на перезагруз
ку, имеет смысл применять более эффективные методики. Внутри цикла редко
используемая неблокирующая операция приема nb_re c e i ve служит для прие
ма сообщений и проверки ввода с клавиатуры одного из вариантов, предложен
ных в сообщении:
H i t ESC to reboo t , DEL to shut down , F - keys f o r debug dumps
показывает, что поле tp - > t ty_ou t l e f t содержит нулевое значение), при по
мощи t ty_rep ly отправляется ответное сообщение (строки 1 6096- 1 6097).
В дополнение к вызовам c ons_wr i t e из handl e_event s , символы на консоль
могут выводить функции echo и rawecho в аппаратно-независимой части драй
вера терминала. Если текущим устройством вывода является консоль, косвен
ные вызовы через указатель tp - > t ty_echo перенаправляются функции cons_
echo (строка 1 6 1 05). Она делает свою работу, вызывая out_char и затем f l u sh.
Пользователь вводит данные символ за символом, и ему предпочтительно, чтобы
эхо отображалось сразу же, без видимой задержки, поэтому помещать символы
в очередь было бы неправильно.
Итак, теперь мы добрались до функции out_char (строка 1 6 1 19). Сначала она
проверяет, вводится ли ЕSС-последовательность, вызывая p ar s e_e s c ap e, и ес
ли это так, немедленно завершается (строки 1 6 1 24 - 1 6 126). В противном случае
управление передается в конструкцию swi t ch, которая проверяет различные
особые случаи: нулевой символ, символ забоя, символ звонка и т. п. Несложно
проследить, как обрабатывается большая часть этих ситуаций. Самые сложные
варианты - символы перевода строки и табуляции, поскольку они сложным об
разом меняют координаты курсора на экране и могут вызва:rь прокрутку. По
следняя проверка выполняется на код E S C . Если он обнаруживается, устанавли
вается флаг c ons - >c_e s c_s t at e (строка 1 6 1 8 1 ) и последующие вызовы out_
char перенаправляются в p ar s e_e s c ap e до тех пор, пока последовательность
не завершится. Вариант по умолчанию выполняется для печатных символов.
Если превышена ширина экрана, при необходимости делается прокрутка экрана
и вызывается f l u sh. Прежде чем поместить символ в выходную очередь, прове
ряется, заполнена ли она, и если заполнена, вызывается f l u sh. Как мы видели
ранее при описании функции c ons_wr i t e, в случае занесения символа в оче
редь необходимо учесть это, обновив значения нескольких переменных.
Далее следует функция s c r o l l_s c r e en (строка 16205). Она выполняет как про
крутку вверх, то есть нормальную прокрутку, ожидаемую при заполнении нижней
строки экрана, так и прокрутку вниз, которая необходима при попытке устано
вить курсор выше верхней границы экрана. Для каждого направления прокрутки
возможны три метода. Это проистекает из требования поддержки различных
типов видеокарт.
Мы рассмотрим случай прокрутки вверх. Сначала переменной chars присваивает
ся значение, равное размеру экрана минус 1 . Когда прокрутка делается программ
но, для ее выполнения достаточно одного вызова функции v i d_v i d_c opy, ко
торая копирует chars символов на одну строку ниже в памяти. Эта функция
умеет переходить в начало области при достижении ее конца, и наоборот. Так,
если ей указано скопировать блок памяти, начало которого выходит за верхнюю
границу памяти, то не укладывающиеся в область видеопамяти данные берутся
из ее нижней части, то есть видеопамять рассматривается как циклический мас
сив. Простота этого вызова не компенсирует низкую скорость операции. Несмот
ря на то что подпрограмма v i d_v i d_c opy написана на языке ассемблера (ее
код хранится в файле dr iver s / t ty / v i dc opy . s ) , для ее выполнения необхо
димо скопировать 3840 байт, что довольно много даже для ассемблерного кода.
3. 8 . Терми налы 40 1
c_esc_state =1
Число или ";"
Не " Г'
Вызов
do_escape
Вызов
do_escape Накопление
числовых
аргументов
Рис. 3 . 26 . Конечный автомат для обработки ЕSС-последовательностей
оказывает влияние на параметр c ons - > c_at t r. Это - байт атрибутов, который
при записи символов в видеопамять чередуется с кодами символов.
Функция s e t_6 8 4 5 (строка 1 6594) вызывается тогда, когда необходимо об
новить информацию видеоконтроллера. У контроллера 6845 есть внутренние
1 6-разрядные регистры, которые программируются по 8 бит за раз. Поэтому для
записи одного регистра требуются четыре операции с портами ввода-вывода.
В каждой из них создается массив (вектор) пар (порт, значение) и осуществляется
вызов ядра sy s_voutb, обращающийся к системному заданию для выполнения
ввода-вывода. Некоторые регистры микросхемы видеоконтроллера 6845 пере
числены в табл. 3 . 1 5 .
вызов ядра sys_g e t kme s s ag e s получает копию структуры ядра, байты ото
бражаются по одному с помощью функции putk, а последний вызов putk с ну
левым символом приводит к сбросу вывода. Хранение позиции в буфере для
различных сообщений осуществляется с помощью локальной статической пере
менной.
Функция do_di agno s t i c s (строка 1 6823) имеет назначение, схожее с do_
new_kme s s , однако обеспечивает вывод сообщений не для ядра, а для систем
ных процессов. Сообщение типа D I AGNO S T I C S может быть получено главным
циклом функции t ty_t a s k либо циклом в функции do_p an i c_dump s . В обоих
случаях производится вызов do_d i agno s t i c s . Сообщение содержит указатель
на буфер вызывающего процесса и его размер. Локальная буферизация не ис
пользуется; вместо этого текст побайтно доставляется путем многократных вы
зовов sy s_v i r c opy ядра. Это защищает драйвер терминала; в случае если про
изойдет сбой и процесс начнет генерировать большие объемы данных, проблема
переполнения буфера не сможет возникнуть. Вывод символов осуществляется
по одному функцией putk и завершается нулевым байтом.
Функция putk (строка 1 6850) печатает символы от имени кода драйвера терми
нала и используется описанными функциями для вывода текста от лица ядра
или других системных компонентов. Она просто вызывает функцию ou t_char
для каждого полученного ненулевого символа и функцию f l ush для нулевого
символа, которым заканчивается строка.
Остальные процедуры в файле c ons o l e . с просты и невелики, поэтому мы не
потратим на них много времени. Функция t o gg l e_s c r o l l (строка 1 6869 )
делает именно то, что означает ее название, она изменяет значение флага типа
прокрутки: аппаратная или программная. Помимо этого, она выводит текст в те
кущей позиции курсора, сообщая, какой режим выбран. Функция c ons_s t op
(строка 1 6869) инициализирует консоль, переводя ее в состояние, которое ожи
дает монитор начальной загрузки. Это делается перед выходом из системы или
перезагрузкой. Функция c ons_orgO (строка 1 6893) используется только тогда,
когда нажатием клавиши FЗ изменяется режим прокрутки или идет подготовка
к выходу из системы. Функция s e l ec t_cons o l e (строка 1 69 17 ) выбирает (ак
тивизирует) виртуальную консоль. При вызове ей передается индекс новой
консоли, и она дважды вызывает функцию s e t_6 8 4 5 , чтобы показать на экране
данные из соответствующей части видеопамяти.
Две последние подпрограммы в значительной степени зависят от особенностей
программного обеспечения. Функция c on_ l o a d f ont (строка 1 693 1 ) загружает
в видеоконтроллер шрифт, обеспечивая выполнение операции T I OC S FON вызова
i oc t l . Эта функция серией вызовов ga_p rogram (строка 1 697 1 ) делает так, что
становится видимой память шрифтов контроллера, которая в обычной ситуации
не адресуема. Затем, чтобы скопировать шрифт в ставшую доступной область
памяти, вызывается функция phy s_c opy, а после этого другая последователь
ность команд возвращает устройство в нормальный режим работы.
Последняя функция, c ons_i o c t l (строка 1 6987), совершает лишь одно дейст
вие: задает размер экрана. Она вызывается функцией s c r_ini t, используя зна-
Резюме 407
Рез ю ме
Вводом-выводом часто пренебрегают, хотя он заслуживает более серьезного от-
ношения. Значительная доля кода любой операционной системы связана с вво
дом-выводом. Тем не менее драйверы устройств ввода-вывода часто становятся
причиной проблем. Как правило, драйверы создают программисты, работающие
в компаниях-производителях устройств. Традиционные операционные системы
предоставляют драйверам доступ к критически важным ресурсам, таким как пре
рывания, порты ввода-вывода и память других процессов. В MINIX 3 драйверы
являются независимыми процессами с ограниченными привилегиями. По этой
причине ошибка в одном драйвере не приводит к краху всей системы.
Мы начали с рассмотрения аппаратного обеспечения ввода-вывода и связи уст
ройств ввода-вывода с контроллерами. Именно такую связь создает программ
ное обеспечение. Затем мы рассмотрели четыре уровня программного обеспече
ния ввода-вывода: обработчики прерываний, драйверы устройств, независимое
от устройств программное обеспечение и библиотеки плюс спулеры, работаю
щие в пользовательском пространстве.
Далее мы изучили проблему взаимной блокировки и инструментарий для борь
бы с ней. Взаимная блокировка возникает, когда имеется группа процессов,
получивших монопольный доступ к некоторым ресурсам, и каждому процессу
в группе необходим помимо этого другой ресурс, принадлежащий другому процес
су. В таком случае все процессы блокируются и не могут выполняться. Взаимную
блокировку можно исключить, если система построена в расчете на упреждение
подобной ситуации. Например, можно разрешить каждому процессу удерживать
не более одного ресурса в каждый момент времени. Другой способ избежать бло
кировки - проверять каждый запрос, определяя, ведет ли он к опасной ситуации
(в которой возможно возникновение блокировки) и отменять или откладывать
опасные запросы.
В MINIX 3 драйверы устройств реализованы в виде процессов, встроенных в яд
ро. Мы рассмотрели драйверы виртуального диска, жесткого диска и терминала.
У каждого из этих драйверов есть главный цикл, в котором принимаются и об
рабатываются запросы, в конечном итоге формируется и отправляется ответное
сообщение о результатах. Исходный код главных циклов и общих функций драй
веров помещен в единую библиотеку драйверов, хотя каждый драйвер компили
руется и связывается с собственными копиями библиотечных процедур. Адресные
пространства драйверов индивидуальны. Множество различных терминалов, ис
пользующих системную консоль, последовательные линии и сетевые соединения,
поддерживаются одним и тем же процессом драйвера терминала.
408 Глава 3. Ввод-вывод
В оп р осы и задани я
1 . Устройство для чтения DVD со скоростью 1х способно предоставлять 1,32 Мбайт
данных в секунду. Какова максимальная скорость устройства, которое мож
но подключить к компьютеру с помощью интерфейса U S B 2.0 без потери
данных?
2. Многие диски содержат коды исправления ошибок (ЕСС) в конце каждого
сектора. Какие действия следует предпринять, если сам код ошибочен? Какой
программный или аппаратный компонент должен это делать?
3. Что такое ввод-вывод, отображаемый на память? Для чего он используется?
4. Объясните, что такое прямой доступ к памяти (DMA) и для чего он исполь
зуется.
5. Хотя DMA не использует процессор, максимальная скорость передачи дан
ных остается ограниченной. Предположим, вы считываете блок с диска. На
зовите три фактора, ограничивающие скорость его передачи.
6. Музыка с качеством, соответствующим компакт-диску, должна иметь частоту
дискретизации сигнала 44 1 00 Гц. Предположим, что таймер генерирует пре
рывания с такой частотой, а обработка прерывю:tия занимает 1 мс на про
цессоре со скоростью 1 ГГц. Какова наименьшая частота таймера, обеспе
чивающая сохранение всех данных? Положим, что число команд обработки
прерывания постоянно, следовательно, удвоение частоты таймера удваивает
время обработки прерывания.
7. Альтернативой прерываниям является опрос. Существуют ли ситуации, в ко
торых опрос предпочтительней?
Вопросы и задания 409
30. В UNIX каждый процесс состоит из двух частей, работающих в адресном поль
зовательском пространстве и в пространстве ядра. Является ли часть в, про
странстве ядра подпрограммой или сопрограммой?
3 1 . На некотором компьютере обработчик прерываний от таймера выполняет
свои действия за 2 мс (включая накладные расходы по переключению про
цессов). Прерывания от таймера поступают с частотой 60 Гц. Какая часть вре
мени работы центрального процессора расходуется на таймер?
32. В тексте описано два варианта применения сторожевых таймеров: ожидание
запуска двигателя дисковода и выполнение возврата каретки на печатных тер
миналах. Приведите еще один пример.
33. Почему терминалы, использующие интерфейс RS-232, управляются прерыва
ниями, а терминалы с отображением на память - нет?
34. Рассмотрим работу терминала. Драйвер посылает один символ, после чего
блокируется. За передачей символа в линию следует прерывание, затем драй
вер разблокируется и посылает следующий символ и т. д. Какую часть време
ни центрального процессора занимает управление модемом, если обработка
прерывания, вывод одного символа и каждая блокировка требуют 4 мс? Бу
дет ли этот метод работать с линиями 1 1 0 бод? А что насчет линий 4800 бод?
35. Вообразите терминал, содержащий 1 200 х 800 пикселов. Для прокрутки окна
центральный процессор (или контроллер) должен переместить все строки
текста вверх, копируя их биты из одной части видеопамяти в другую. Допус
тим, в окне 66 строк по 80 символов в строке (всего 5280 символов), а каждый
символ имеет 8 пикселов в ширину и 16 пикселов в высоту. Сколько времени
займет прокрутка всего окна, если для копирования одного байта требуется
500 нс? Если все строки имеют по 80 символов в длину, чему будет равна эк
вивалентная скорость терминала в бодах? Помещение одного символа на
экран занимает 50 мкс. Подсчитайте скорость, если терминал цветной и имеет
4 бит/пиксел (в этом случае помещение символа на экран занимает 200 мкс).
36. Для чего в операционных системах нужны ЕSС-последовательности, напри
мер Ctrl+V в MINIX?
37. Получив с:и:мвол S I G INT (Ctrl+C), драйвер экрана MINIX очищает всю оче
редь на вЬiвод для этого экрана. Почему?
38. У многих терминалов, использующих интерфейс RS-232, есть ЕSС-последо
вательности для удаления текущей строки и перемещения всех нижних строк
на одну строку вверх. Как, по-вашему, реализована эта операция внутри тер
минала?
39. На оригинальном компьютере I B M РС с цветным дисплеем запись в видеопа
мять в любое время, кроме того интервала, когда электронный луч совершал
вертикальный обратный ход, вызывала появление уродливых пятен по всему
экрану. На экран выводятся 25 строк по 80 символов, каждый из которых по
мещается в квадрат 8 х 8 пикселов. Каждый ряд из 640 пикселов рисуется за
один горизонтальный проход луча, что занимает 63,6 мкс, включая горизон
тальное обратное движение луча. Экран перерисовывается 60 раз в секунду.
Вопросы и задания 41 3
4 . 1 . Б аз о вые механи з м ы
уп равлен и я пам я ть ю
Системы управления памятью можно разделить на два класса: те, в которых про
цессы при выполнении перемещаются между оперативной памятью и диском,
и те, в которых этого не происходит. Второй вариант проще, поэтому начнем с не
го, а обменом с диском, требующим либо подкачки, либо замещения страниц, мы
займемся потом. Читая главу 4, следует помнить, что варианты с подкачкой и за
мещением страниц в значительной степени являются искусственными, вызван
ными отсутствием достаточного объема оперативной памяти для одновременноm
хранения всех программ. Если когда-нибудь оперативная память настолько уве
личится в объеме, что ее будет достаточно для любых целей, аргументы в пользу
той или иной схемы управления перестанут быть актуальными.
Однако не стоит забывать, что объем программ растет так же стремительно, как
и объем памяти, поэтому не исключено, что необходимость в эффективном
управлении памятью будет требоваться всегда. В 1980-е mды во многих универ
ситетах использовались компьютеры V АХ, оснащенные системами разделения
времени и памятью объемом 4 Мбайт. С одним таким компьютером работали
десятки пользователей, получая более или менее удовлетворительное качество
обслуживания. Теперь для однопользовательского компьютера с операционной
системой Windows ХР компания Microsoft рекомендует не менее 1 28 Мбайт па
мяти. Повсеместное распространение мультимедиа еще более повышает требова
ния к памяти, так что эффективное управление памятью будет востребовано еще
как минимум лет 10.
OxFFF Драйверы
Операционная устройств
система в ПЗУ в ПЗУ
Программа
пользователя Программа
пользователя
Программа
пользователя
Операционная Операционная
система в ПЗУ система в ПЗУ
о о о
а б в
Рис. 4. 1 . Три простейшие модели организации памяти при наличии операционной системы
и одного пользовательского процесса. Существуют и другие варианты
Кроме того, операционная система может располагаться в самой верхней части
памяти (рис. 4 . 1 , б) - в постоянной памяти (ROM), или в ПЗУ (постоянное за
поминающее устройство). В третьей модели драйверы устройств могут разме
щаться в ПЗУ, а остальная часть системы - ниже в ОЗУ (рис. 4 . 1, в). Первая мо
дель раньше применялась на мэйнфреймах и мини-компьютерах, но в настоящее
время практически не употребляется. Вторая модель сейчас используется в не
которых палмтопах и встраиваемых системах, а третья модель была характерна
для ранних персональных компьютеров (например, работающих под управлением
MS-DOS), при этом часть системы, которая располагалась в ПЗУ, носила назва
ние BIOS (Basic lnput Output System - базовая система ввода-вывода).
Когда система организована таким образом, в каждый конкретный момент вре
мени может работать только один процесс. Как только пользователь набирает
команду, операционная система копирует запрашиваемую программу с диска
в память и выполняет ее, а после окончания процесса выводит на экран пригла
шение и ждет новой команды. Получив инструкции, она загружает другую про
грамму в память, записывая ее поверх предыдущей.
4 . 1 2 М ногозадачная система
. .
с фиксированными разделами
Однозадачные системы сложно использовать где-либо еще, кроме простейших
встроенных систем. Большинство современных систем поддерживает одновре
менную работу нескольких процессов. Это означает, что когда один процесс
приостановлен в ожидании завершения операции ввода-вывода, другой вправе
использовать центральный процессор. Таким образом, многозадачность увели
чивает загрузку процессора. Сетевые серверы всегда обеспечивают возможность
одновременной работы нескольких процессов (для разных клиентов), но и боль
шинство клиентских машин (то есть настольных компьютеров) в наши дни не
уступают им в этом смысле.
Самый легкий способ достижения многозадачности представляет собой простое
разделение памяти на п (возможно не равных) разделов. Такое разбиение можно
выполнить, например, вручную при запуске системы.
4. 1 . Б азовые механ измы упр а вл ения п а мят ью 41 7
Несколько
входных очередей
�----� аоо к
Раздел 4 Раздел 4
f-------1700 к
Раздел 3 Раздел 3
400 К
Раздел 2 Раздел 2
200 к
Раздел 1 Раздел 1
Операционная 1 00 к Операционная
система о система
а б
Многозадачность с фиксированными разделами памяти: - фиксированные
Рис. 4 . 2 . а
разделы с отдельными входными очередями для каждого раздела; б - фиксированные
разделы с одной общей входной очередью
Недостаток размещения входящих заданий по отдельным очередям становится
очевидным, когда к большому разделу очередь отсутствует, в то время как к ма
ленькому выстраивается довольно много заданий (в примере на рис. 4.2, а - это
разделы 1 и 3). Небольшим заданиям приходится ждать своей очереди, чтобы
попасть в память, и это при том, что память в основном свободна. Альтернатив
ная схема заключается в организации одной общей очереди для всех разделов
(рис. 4.2, б): как только раздел освобождается, задание, ближайшее к началу оче
реди и подходящее для выполнения в этом разделе, можно загрузить и присту
пить к его выполнению. Поскольку нежелательно тратить большие разделы на
маленькие задания, существует другая стратегия. Она состоит в том, что каждый
раз после освобождения раздела происходит поиск в очереди наибольшего из
приемлемых по размерам для этого раздела заданий, и именно это задание выби
рается для выполнения. Заметим, что последний алгоритм означает дискрими
нацию мелких заданий, как недостойных того, чтобы под них отводился целый
раздел, в то время как обычно небольшим программам (часто интерактивным)
крайне важно предоставлять привилегированное обслуживание.
Один из выходов из положения - создание хотя бы одного маленького раздела
памяти, который позволит выполнять маленькие задания без долгого ожидания
освобождения больших разделов.
41 8 Глава 4 . У п равл е н и е памят ь ю
4 . 1 . З . Переадресация и защита
Многозадачность вносит две существенные проблемы, требующие решения,
это переадресация для перемещения программы в памяти и защита. Из рис. 4.2 яс
но, что разные задания выполняются по разным адресам. Когда программа компо
нуется (то есть в едином адресном пространстве объединяются основной модуль,
написанные пользователем процедуры и библиотечные подпрограммы), компо
новщик должен знать, с какого адреса будет начинаться программа в памяти.
Например, предположим, что первая команда представляет собой вызов проце
дуры с абсолютным адресом 1 00 внутри двоичного файла, создаваемого компо
новщиком. Если эта программа загрузится в раздел 1 (по адресу 100 К), команда
обратится к абсолютному адресу 1 00, принадлежащему операционной системе.
А нужно вызвать процедуру по адресу 1 00 К + 1 00. Если же программа загрузит
ся в раздел 2, команду нужно переадресовать по адресу 200 К + 100 и т. д. Эта
проблема известна как проблема переадресации.
Одним из возможных решений является модификация команд во время загруз
ки программы в память. В прогр амме, загружаемой в раздел 1 , к каждому адресу
прибавляется значение 100 К, в программе, которая попадает в раздел 2, к адре
сам добавляется значение 200 К и т. д. Чтобы выполнить подобную переадреса
цию во время загрузки, компоновщик должен включить в двоичную программу
список или битовую карту с информацией о том, какие слова в программе яв
ляются адресами (и их нужно перераспределить), а какие - кодами машинных
команд, постоянными или другими частями программы, которые не нужно изме
нять. Так работает операционная система OS/MFT.
Переадресация во время загрузки не решает проблемы защиты. Вредоносные
программы всегда могут организовать какую-нибудь новую команду перехода
и с ее помощью проникнуть в память. Поскольку в такой системе использует
ся абсолютная адресация памяти, а не смещение относительно того или иного
регистра, не существует способа, который позволил бы запретить программе
обращаться к любому слову в памяти для его чтения или записи. В многопользо-
4.2. Подкачка 41 9
4 . 2 . П одка ч ка
В случае пакетных систем память с фиксированными разделами действует про
сто и эффективно. Каждое задание после ожидания в очереди загружается в раз
дел памяти и остается там до своего завершения. До тех пор пока в памяти мо
жет храниться достаточное количество заданий для обеспечения постоянной
занятости центрального процессора, нет причин что-либо усложнять.
Но совершенно другая ситуация имеет место в системах разделения времени и пер
сональных компьютерах, ориентированных на работу с графикой. Оперативной
памяти иногда оказывается недостаточно для того, чтобы вместить все текущие
420 Гл ава 4 . У п р авление памят ью
Время _____.
с с
в в в
А А А
Время _____.
с с
в
А
D D D
}
В-стек
t
} Место для роста
_ _ _ _ _ _ _ _ _ _
}
В-данные
в
используется В-программа
д••= """''"'
_ _ _ _t _ _ _ _
}
Meoro для роопо
А-стек
_ _ _ _ _
- - - - -
t
�
_ _ _ _ _
- - - - -
} Место для роста
}--",
А-данные
А
используется А-программа
Операционная Операционная
система система
а б
Рис . 4.4. Распределение памяти в случае расш ирен ия процессов: а - предоставление
пространства для роста области данн ых; б - предоставление пространства
для роста стека и области дан н ых
4 . 2 . 1 . Уп равление памятью
с помощью битовых карт
Если память выделяется динамически, этим процессом должна управлять операци
онная система. Существует два подхода к учету использования памяти: битовые
карты и списки свободных областей. В этом и следующем разделах мы по очереди
рассмотрим оба метода.
При работе с битовой картой память разделяется на блоки размером от несколь
ких слов до нескольких килобайтов. В битовой карте каждому свободному блоку
4. 2 . Подкачка 423
1 1 1 1 1 000 р о 5 н 5 з р 8 6 р 14 4
11111111
1 1 001 1 1 1
р 20 6 н 29 з х
1 1 1 1 1 000
Процесс
б в
Свободный
фрагмент
Рис . 4 . 5 . Учет испол ьзования па м яти:а обл асть па мяти с пятью процесса м и и тремя
-
в виде списка
Размер минимального выделяемого блока - весьма важный параметр системы.
Чем он меньше, тем больше битовая карта. В случае если минимальный вьще
ляемый блок памяти имеет размер 4 байта, то есть 32 бит, для него нужно 1 бит
в карте. Тогда область размером в 32п потребует п бит карты, таким образом, би
товая карта займет всего лишь 1/33 часть памяти. Если же отдать предпочтение
большим блокам, битовая карта станет меньше, но при этом может оказаться не
используемой существенная часть последнего блока каждого процесса (если раз
мер процесса не кратен размеру минимального блока).
Битовая карта предоставляет простой механизм отслеживания слов в памяти
фиксированного объема, поскольку ее размер зависит только от объема памяти
и размера минимального блока. Для этой схемы характерна проблема - при ре
шении переместить процесс из k блоков в память менеджер памяти должен найти
в битовой карте последовательность из k смежных нулевых битов. Поиск после
довательности заданной длины в битовой карте является медленной операцией
(так как искомая последовательность битов может пересекать границы слов в бито
вом массиве). Это - главный аргумент противников битовых карт.
4 . 3 . В иртуал ь на я пам я т ь
Уже достаточно давно люди столкнулись с проблемой размещения программ,
оказавшихся слишком большими и поэтому не помещавшихся в доступной фи
зической памяти. Обычно принималось решение о разделении программы на
части, называемые оверлеями (overlays). Нулевой оверлей обычно запускался
первым. По завершении своего выполнения он вызывал следующий оверлей.
Некоторые оверлейные системы были очень сложными, позволяя одновременно
находиться в памяти нескольким оверлеям. Оверлеи хранились на диске и по
мере необходимости динамически перемещались между памятью и диском сред
ствами операционной системы.
Хотя фактическая работа по загрузке оверлеев с диска и выгрузке на диск вы
полнялась системой, делить программы на части должен был программист. Раз
биение больших программ на маленькие модули поглощало много времени и бы
ло не слишком интересным занятием. Однако такая ситуация длилась недолго,
так как вскоре удалось поручить всю работу компьютеру.
Разработанный подход стал известен как виртуальная памятъ [47]. Основная
идея этого подхода состоит в том, что хотя общий размер программы, данных
и стека может превышать объем доступной физической памяти, операционная
система хранит части программы, использующиеся в настоящий момент, в опера
тивной памяти, остальные - на диске. Например, программа размером 5 1 2 Мбайт
4. 3 . В иртуальная память 427
сможет работать на машине с объемом памяти 256 Мбайт, если тщательно про
думать, какие 256 Мбайт должны находиться в памяти в каждый момент време
ни. При этом по мере необходимости части программы, находящиеся на диске,
будут меняться местами с частями в памяти.
Виртуальная память вполне работоспособна и в многозадачной системе при
наличии множества одновременно загруженных в память программ. Когда про
грамма ждет перемещения в память очередной ее части, она находится в состоя
нии ожидания ввода-вывода и не работает, поэтому центральный процессор
может быть отдан другому процессу тем же самым способом, как в любой другой
многозадачной системе.
4 . 3 . 1 . За мещение стран иц
Большинство систем виртуальной памяти опираются на прием, называемый
замещение страниц (paging). На любом компьютере существует множество адре
сов в памяти, к которым может обратиться программа. Когда программа исполь
зует следующую инструкцию, она делает это для того, чтобы скопировать содер
жимое памяти по адресу 1 000 в регистр REG (или наоборот, в зависимости от
компьютера):
MOVE REG , 1 0 0 0
Очень простой пример того, как выполняется такого рода отображение, при
веден на рис. 4.8. Мы рассматриваем компьютер, который может формировать
1 6-разрядные адреса, от О до 64 К. Это - виртуальные адреса. У данного компью
тера есть только 32 Кбайт физической памяти, поэтому, хотя программы разме
ром 64 Кбайт писать можно, их нельзя целиком загрузить в память и запустить
на выполнение. Полная копия образа памяти программы размером до 64 Кбайт
должна присутствовать на диске, но в таком виде, чтобы ее можно было по мере
надобности переносить в память по частям.
Виртуальное
адресное пространство
60 - 64 к 1------1
56- 60 к 1-----1
52 - 56 к 1------1
48 - 52 к !------!
44- 48 к !----� '\
40 - 44 к 1------1
36-40 к !----� '\ Адрес
32 - 36 к 1-----1
физической памяти
28 - 32 к ,_______,
28-32 к
24-28 к 1------1
24-28 к
20 -24 к 1------1
20-24 к
16- 20 к 1------1
1 6-20 к
12-16 К 1-----1 1------1
12- 16 к
8- 12 к 6 8- 12 к
4- 8 К 4-8 к
0-4 К 2 �---' � К -4 К
Страничный блок
Рис. 4.8. Связь между виртуальными и физическими адресами,
поддерживаемая с помощью таблицы страниц
Пространство виртуальных адресов разделено на единичные блоки, называе
мые страницами. Соответствующие блоки в физической памяти называются
страничными блоками (page frame). Размер страниц и их блоков всегда одинаков.
В этом примере они равны 4 Кбайт, но в реальных системах использовались раз
меры от 5 1 2 байт до 64 Кбайт. Имея 64 Кбайт виртуального адресного про
странства и 32 Кбайт физической памяти, мы получаем 1 6 виртуальных страниц
и 8 страничных блоков. Передача данных между ОЗУ и диском всегда происхо
дит постранично.
Пусть программа пытается получить доступ к адресу О, например, с помощью
следующей команды:
MOVE REG , O
Физическай адрес
1 1 1 1 l ol ololololololololol 1 iolol на выходе (24580)
• j�
1 5 ООО о
14 ООО о
1 3 ООО о
12 ООО о
11 111 1
10 ООО о
9 101 1
Таблица --. 8 ООО о 12 битов смещения
страницы 7 ООО о копируются прямо
6 ООО о одных данных
ИЗ ВХ
в выходные
5 011 1
4 100 1
3 ООО 1
2 110 1 -.i 110 1
1 001 1 ,,..- Бит
010 1 присутствия/
1
о
отсутствия
Виртуальная страница 2
используется как индекс
в таблице страниц
Виртуальный адрес
lolol 1 lolololololololololol 1 l o l ol на входе (81 96)
t
Рис. 4.9. Внутренняя операция бло ка управления па м ятью в систе ме из 1 6 страниц по 4 Кбайт
Таблица страниц
второго уровня
Таблица страниц
для старших
4 Мбайт памяти
Биты
10 10 1 2
1 РТ1 j Рт2 I Смещение 1
а
1 023 }1----�1
6 1-------�
5
1------<
4
1------1
3 1-------� страницам
2
1------<
К
1 1-------�
о�-----�
б
Рис. 4. 1 0 . Структура двухуровневой таблицы страниц: а 32-разрядный адрес с полями
-
Изменение Присутствие/отсутствие
Обращение Защита
Традиционная таблица
страниц с записью
для каждой
из 252 страниц
2 -1
52
1
.,;; !"' .; '"\
o�i о�
Индексирование
по виртуальной
Индексирование
.t�\
П,? хеш-коду Виртуальная
,!'
странице виртуальнои страницы страница
Страничный блок
Рис . 4. 1 2 . Сравнение обычной и инвертированной таблиц страниц
440 Глава 4. Уп равление памятью
4 . 4 . Ал горитм ы за м е ще н ия стр а н и ц
Когда происходит ошибка отсутствия страницы, операционная система должна
выбрать страницу для удаления из памяти, чтобы освободить место для затребо
ванной страницы. Если удаляемая страница была изменена за время своего при
сутствия в памяти, ее необходимо переписать на диск, обновив хранящуюся там
копию. Однако если страница не была модифицирована (например, страница
с текстом программы), копия на диске и так оказывается свежей, поэтому пере
писывать ее не надо. В этом случае затребованная страница просто считывается
на место выгружаемой.
Хотя, в принципе, при каждой ошибке отсутствия страницы для удаления мож
но выбирать случайную страницу, производительность системы заметно повы
шается, когда предпочтение отдается редко используемой странице. Если выгру
жается страница, обращения к которой происходят часто, велика вероятность,
что вскоре опять потребуется вернуть ее в память, что даст в результате допол
нительные издержки. Теме разработки алгоритмов замещения страниц было по
священо много работ, как теоретических, так и экспериментальных. Здесь м:ь1
опишем некоторые из наиболее важных алгоритмов.
Следует заметить, что проблема замещения страниц характерна и для других
компонентов компьютера. Например, большинство современных компьютеров
оснащено одним или несколькими кэшами памяти, хранящими недавно исполь
зованные блоки памяти размером 32 или 64 байт. Когда кэш заполнен, возникает
задача выбора блока для удаления. Она аналогична удалению страницы, хотя
и должна решаться быстрее (если удаление страницы можно выполнить за не
сколько миллисекунд, то при удалении блока из кэш-памяти требуется уложить
ся в несколько наносекунд). Причина состоит в том, что при кэш-промахах полу
чение данных осуществляется из основной памяти с нулевыми задержками на
перемещение головок и вращение диска.
Второй пример - веб-браузер, хранящий на диске копии страниц, к которым ра
нее имелся доступ. Обычно максимальный размер кэша фиксирован, поэтому
при интенсивном использовании браузера он с большой вероятностью заполнит
ся. Когда к веб-странице обращаются по ссылке, сначала проверяется ее наличие
в кэше, а затем копия в кэше сравнивается с оригиналом на сервере. Если копия
актуальна, она предлагается пользователю, в противном случае страница загру
жается с веб-сервера. При отсутствии копии страница загружается сразу. В случае
если кэш содержит устаревшую версию страницы, она заменяется новой, только
4.4. Алгоритмы заме щения страниц 44 1
что загруженной версией. Если оказывается, что страница (новая или обновляе
мая) не умещается в кэш, должно быть принято решение об удалении какой-ли
бо другой страницы из кэша. Методы выбора здесь аналогичны выбору страниц
в виртуальной памяти, за тем исключением, что веб-страницы никогда не моди
фицируются и не записываются обратно на веб-сервер. В системе с виртуальной
памятью страницы, находящиеся в основной памяти, могут быть «чистыми• или
«грязными•.
4 . 4 . 2 . Ал горитм N R U
Чтобы дать операционной системе возможность собирать полезные статистиче
ские данные о том, какие страницы используются, а какие - нет, большинство
компьютеров с виртуальной памятью поддерживают два статусных бита, связан
ных с каждой страницей. Бит R (от Referenced - обращение) устанавливается
всякий раз, когда происходит обращение к странице (чтение или запись). Бит М
(от Modified - изменение) устанавливается, когда страница записывается (то есть
изменяется). Биты содержатся в каждом элементе таблицы страниц (см. рис. 4. 1 1 ).
Важно реализовать обновление этих битов при каждом обращении к памяти,
поэтому необходимо, чтобы они задавались аппаратно. Если однажды бит был
установлен, то он остается равным 1 до тех пор, пока операционная система про
граммно не вернет его в состояние О.
Если аппаратное обеспечение не поддерживает эти биты, их можно смоделиро
вать следующим образом. Когда процесс запускается, все его записи в таблице
страниц помечаются как отсутствующие в памяти. Как только происходит обра
щение к странице, происходит ошибка отсутствия страницы. Затем операционная
система устанавливает бит R (в своих внутренних таблицах) ; изменяет запись
в таблице страниц так, чтобы она указывала на корректную страницу с режимом
<Полько чтение� , и перезапускает команду. Если страница позднее записывается,
происходит другая ошибка отсутствия страницы, позволяющая операционной
системе установить бит М и изменить режим на 4Чтение/запись�.
Биты R и М могут использоваться для построения простого алгоритма замещения
страниц. Когда процесс запускается, оба страничных бита для всех его страниц
операционной системой сброшены в О. Периодически (например, при каждом
прерывании от таймера) бит R очищается с целью отличить страницы, к кото
рым давно не было обращений, от тех, к которым обращения были.
При возникновении ошибки отсутствия страницы операционная система прове
ряет все страницы и делит их на четыре категории на основании текущих значе
ний битов R и М:
+ класс О - обращения и изменения не было;
+ класс 1 - обращения не было, страница изменена;
+ класс 2 - обращение было, страница не изменена;
+ класс 3 - были и обращение, и изменение.
Хотя класс 1 на первый взгляд кажется невозможным, описываемая им ситуация
случается, когда у страницы из класса 3 бит R сбрасывается во время прерыва
ния от таймера. Прерывания от таймера не затирают бит М, поскольку информа
ция, которую он несет, необходима, чтобы понять, нужно переписывать страницу
на диске или нет. Поэтому если бит R сбрасывается, а М остается установлен
ным, страница попадает в класс 1 .
Алгоритм NR U (Not Recently Used не использовавшаяся в последнее время
-
4 . 4 . З . Ал горитм FI FO
Другим требующим небольших издержек алгоритмом является FIFO (First- In,
First- Out первым пришел, первым ушел). Чтобы проиллюстрировать его рабо
-
Страница,
загруженная Последняя
первой загруженная
страница
а
А трактуется
как заново
загруженная
страница
б
Рис. 4. 1 3 . Иллюстрация работы алгоритма второго шанса:а - страницы, отсортированные
в порядке FIFO; б список страниц, если ошибка отсутствия страницы произошла
-
4 . 4 . 5 . Ал горитм часов
Хотя алгоритм второго шанса является корректным, он слишком неэффективен,
так как постоянно тасует страницы по списку. Поэтому лучше хранить все стра
ничные блоки в кольцевом списке в форме часов (рис. 4. 14, стрелка указывает на
старейшую страницу).
4 . 4 . Алгоритмы заме щения страни ц 445
R = О: страница выгружается
4 . 4 . 6 . Ал горитм LRU
В основе этой неплохой аппроксимации оптимального алгоритма лежит на
блюдение, что страницы, к которым наблюдалось многократное обращение в не
скольких последних командах, вероятно, также будут часто востребованы в сле
дующих. И наоборот, можно полагать, что страницы, к которым ранее не было
обращений, не потребуются в течение долгого времени. Эта идея привела к сле
дующему реализуемому алгоритму: когда происходит ошибка отсутствия стра
ницы, выгружается из памяти страница, которая не использовалась дольше все
го. Такая стратегия замещения страниц называется LR U ( Least Recently Used -
дольше всего не использовавшаяся страница).
Хотя алгоритм LRU теоретически реализуем, он не дешев. Для полной реализации
алгоритма LRU необходимо поддерживать список всех содержащихся в памяти
страниц, такой, где последняя использовавшаяся страница находится в начале
списка, а та, к которой дольше всего не было обращений, - в конце. Сложность
заключается в том, что список должен обновляться при каждом обращении к па
мяти. Поиск страницы, ее удаление, а затем вставка в начало списка - это опера
ции, поглощающие очень много времени, даже если они выполняются аппаратно
(предположим, что необходимое оборудование можно сконструировать).
Существуют и другие способы реализации алгоритма LRU с помощью специ
ального оборудования. Для первого метода требуется оснащение компьютера
64-разрядным аппаратным счетчиком С, который автоматически инкрементируется
446 Глава 4. Уп ра вление памятью
после каждой команды. Кроме того, каждая запись в таблице страниц должна
иметь поле, достаточно большое для хранения значения счетчика. После каждого
обращения к памяти текущая величина счетчика С запоминается в записи табли
цы, соответствующей той странице, к которой произошла ссылка. А если возни
кает ошибка отсутствия страницы, операционная система проверяет все значе
ния счетчиков в таблице страниц и ищет наименьшее. Эта страница и является
дольше всего не использовавшейся.
Рассмотрим второй вариант аппаратной реализации алгоритма LRU. На машине
с п страничными блоками оборудование LRU может поддерживать матрицу разме
ром п х п бит, изначально равных нул ю . Всякий раз при доступе к страничному
блоку k аппаратура сначала присваивает всем битам строки k единицу, а затем
приравнивает нулю все биты столбца k. В любой момент времени строка, двоич
ное значение которой наименьшее, является дольше всего не использовавшейся.
Работа этого алгоритма продемонстрирована на рис. 4. 15, где рассматриваются
четыре страничных блока и следу ющий порядок обращения к страницам:
0 1 232 1 0323
После ссылки на страницу О мы получаем ситуацию, показанную на рис. 4. 1 5, а;
после обращения к странице 1 на рис. 4. 1 5, б и т. д.
-
о о о о 1 о 1 1 1 о о 1 1 о о о 1 о о о
2 о о о о о о о о 1 1 о 1 1 1 о о 1 1 о 1
з о о о о о о о о о о о о 1 1 1 о 1 1 о о
а б в г д
о о о о о 1 1 1 о 1 1 о о 1 о о о 1 о о
1 о 1 1 о о 1 1 о о 1 о о о о о о о о о
1 о о 1 о о о 1 о о о о 1 1 о 1 1 1 о о
1 о о о о о о о 1 1 1 о 1 1 о о 1 1 1 о
е ж з и к
интервале времени. Все, что мы можем сделать, - это выгрузить страницу 3, так
как к странице 5 также обращались двумя тактами раньше, а к странице 3 - нет.
Биты R для Биты R для Биты R для Биты R для Биты R для
страниц 0-5, страниц 0-5, страниц 0-5, страниц 0-5, страниц 0-5,
такт О такт 1 такт 2 такт З такт 4
11 1°11 1°11 11 1 11 11 1°1°1 1 1°1 l1 !1 lol 1 lol 1 I 11 1°1°1°1 1 1°1 1°11 11 1°1°1°1
Страница
о 10000000 11000000 11100000 11110000 01111000
00000000 10000000 11000000 01100000 10110000
2 10000000 01000000 00100000 00100000 10001000
3 00000000 00000000 10000000 01000000 00100000
4 10000000 11000000 01100000 10110000 01011000
5 10000000 01000000 10100000 01010000 00101000
а б в г д
Рис . 4 . 1 6 . Алгоритм старения программно моделирует алгоритм LRU. Показаны шесть
страниц после пяти тактов часов
Второе отличие между алгоритмом LR U и алгоритмом старения заключается
в том, что в последнем счетчик имеет конечное число разрядов, например 8.
Предположим, что каждая из двух страниц получила нулевое значение счетчика.
В данной ситуации мы лишь случайным образом можем выбрать одну из них.
На самом деле не исключено, что к одной странице в последний раз обращались
9 тактов назад, а к другой - 1 000 тактов назад. И мы не имеем возможности уви
деть это. На практике, однако, обычно достаточно 8 бит при такте системных ча
сов около 20 мс. Если к странице не обращались в течение 1 60 мс, очень вероят
но, что она не нужна.
k
Рабочий набор - это множество страниц, использованных при последних
Рис . 4. 1 7 .
k обращениях к памяти. Функция w(k, t) представляет собой размер рабочего
набора в момент времени t
Быстрый рост кривой вначале и его последующее резкое замедление говорят
о том, что программы, как правило, имеют доступ к большинству своих страниц,
однако рабочий набор не подвержен значительным изменениям во времени. На
пример, если программа исполняет цикл, занимающий 2 страницы памяти, и ис
пользует данные, расположенные на 4 других страницах, то, возможно, за 1000 ко
манд осуществляется обращение ко всем 6 страницам, а последнее обращение,
например, к странице 7 случилось миллион команд назад на этапе инициализа
ции программы. Из-за такого асимптотического поведения содержимое рабочего
набора нечувствительно к выбранному значению k. Другими словами, существу
ет большое количество значений k, для которых рабочие наборы одинаковы. Это
позволяет, на основе знаний о страницах, использованных при последнем завер
шении программы, разумно спрогнозировать множество страниц, которые по
требуются на начальной стадии работы программы при следующем ее запуске.
4.5. Разработка систем заме ще н ия стран иц 45 1
Возраст
АО 10 АО АО
А1 7 А1 А1
А2. 5 А2. А2.
АЗ 4 АЗ АЗ
А4 6 А4 А4
А5 з СЕ;О) А5
во 9 во во
В1 4 В1 В1
В2 6 В2 В2
вз 2 вз СЕ;О)
В4 5 В4 В4
В5 6 В5 В5
В6 12 В6 В6
С1 з С1 С1
С2 5 С2 С2
сз 6 сз сз
а б в
4 . 5 . З . Раз м ер страницы
Зачастую размер страницы является параметром, выбираемым операционной
системой. Даже если аппаратное обеспечение предусматривает, например, раз
мер страницы в 5 1 2 байт, операционная система может просто рассматривать
страницы О и 1, 2 и 3, 4 и 5 и т. д. как страницы размером 1 Кбайт, всегда предо
ставляя для них два смежных страничных блока.
Определение оптимального размера страницы требует учета нескольких взаимо
связанных факторов. Поэтому не существует абсолютного лучшего решения.
Прежде всего, есть два довода в пользу маленького размера страниц. Случайно
выбранный текст, данные или сегмент стека не заполняют страницы целиком.
В среднем половина последней страницы оказывается пустой, и это дополнитель
ное пространство пропадает. Такие потери называют внутренней фрагментаци
ей. Если в памяти п сегментов, а размер страницы равен р байт, то в результате
внутренней фрагментации пр/2 байт будет потрачено впустую. Это - разумный
аргумент в пользу страниц небольшого размера.
Другой довод становится очевидным, если мы представим себе программу, вы
полняемую за 8 шагов, по 4 Кбайт каждый. При размере страницы 32 Кбайт про
грамме должно быть постоянно выделено 32 Кбайт. При размере страницы
16 Кбайт ей необходимо только 16 Кбайт. При размере страницы 4 Кбайт или
меньше программа требует всего лишь 4 Кбайт в любой момент времени. То есть
большой размер страницы скорее, чем маленький, станет причиной того, что в па
мяти окажется неиспользуемая часть страницы.
Однако небольшой размер страницы означает, что программам потребуется мно
го страниц, для которых нужна огромная таблица страниц. Программа размером
32 Кбайт требует всего 4 страницы по 8 Кбайт или целых 64 страницы по 5 1 2 байт.
Как правило, страница за раз переносится на диск и с него, при этом большая
часть времени уходит на поиск цилиндра и задержку вращения, так что переме
щение маленькой страницы занимает почти столько же времени, сколько и боль
шой. То есть нужно 64 х 10 мс, чтобы загрузить 64 страницы размером 5 1 2 байт,
и всего лишь 4 х 1 0, 1 мс для загрузки четырех страниц по 8 Кбайт.
На некоторых машинах таблица страниц должна записываться в аппаратные ре
гистры каждый раз, когда процессор переключается с одного процесса на другой.
Если на таком компьютере страница имеет маленький размер, то время, требуе
мое для загрузки таблицы, растет пропорционально уменьшению размера стра
ницы. Более того, пространство, занятое таблицей страниц, также возрастает
с уменьшением страницы.
4.5. Разработка систем замеще н ия стран иц 455
4 . 6 . Сегм е нтаци я
Обсуждавшаяся до сих пор виртуальная память представляла собой одномерное
пространство, в котором виртуальные адреса идут один за другим от О до некото
рого максимума. Для решения многих задач наличие двух и более отдельных
виртуальных адресных пространств может быть лучше, чем одно. Например, по
мере трансляции формируются несколько структур данных компилятора.
1. Исходный текст, сохраненный для печати листинга (в пакетных системах).
2. Символьная таблица с именами и атрибутами переменных.
3. Таблица со всеми используемыми константами: целыми и с плавающей точкой.
4. Дерево грамматического разбора с результатами синтаксического анализа про-
граммы.
5. Стек, используемый для процедурных вызовов внутри компилятора.
Во время компиляции каждая из первых четырех структур непрерывно растет.
Стек при компиляции непредсказуемо увеличивается или уменьшается. В одно
мерной памяти эти пять структур должны размещаться в смежных частях вирту
ального адресного пространства (рис. 4.20).
Рассмотрим, что происходит, если программа имеет исключительно большое
число переменных и обычное количество всего остального. Область адресного
пространства, предоставленная для символьной таблицы, может заполниться, но
в других структурах, скорее всего, останется пустым множество ячеек. Конечно,
4.6. Сегме нтация 457
! }
Стек вызовов
} Свободно
Адресное пространство, "m�мв11111RВ11
Дерево Пространство, в данный
предоставленное синтаксического момент использУе мое
для дерева синтаксического анализа деревом синтаксического
пространства анализа
}
Таблица кодировки символов
достигла таблицы
с исходным текстом
Рис. 4.20. В одномерном адресном пространстве при росте таблиц
одна может упереться в другую
При другом подходе можно поиграть в Ра бин Гуда, забирая пространство у струк
тур с излишками места и передавая их структурам с их недостатком. Такая пере
тасовка реализуема, но она аналогична управлению собственными оверлеями, что
в лучшем случае неудобно, а в худшем случае требует большого объема скучной
и непродуктивной работы.
На самом деле нужно найти подход, освобождающий программиста от управле
ния расширяющим ися и сокращающим ися структурами данных, так же как вир
туальная память избавляет программы от возни с оверлеями.
Простое и предельно обобщенное решение заключается в том, чтобы обеспечить
машину множеством полностью независимых адресных пространств, называемых
сегм ентами. Каждый сегмент содержит линейную последовательность адресов
от О до некоторого максимума. Длина каждого сегмента может быть любой от
нуля до разрешенного максимума. Различные сегменты могут быть различной
длины. Более того, длины сегментов могут меняться во время выполнения про
граммы. Длина сегмента стека может увеличиваться всякий раз, когда что-либо
помещается в стек, и уменьшаться при выборке данных из стека.
Поскольку каждый сегмент образует отдельное адресное пространство, разные
сегменты могут расти или сокращаться независимо друг от друга. Если стек,
находя щийся в определенном сегменте, нуждается в увеличении адресного про
странства, он может получить его, потому что в его адресном пространстве нет
458 Глава 4. Уп равление памятью
больше ничего, что может стать препятствием для роста. Конечно, сегмент мо
жет заполниться, но сегменты обычно очень большие, поэтому такие инциденты
редки. Чтобы определить адрес в такой сегментированной, или двухмерной,
памяти, программа должна указать адрес, состоящий из двух частей: номера сег
мента и адреса внутри сегмента. Рисунок 4.2 1 иллюстрирует сегментированную
память, использующуюся для обсуждавшихся ранее структур данных компиля
тора. Здесь показаны 5 независимых сегментов.
2 о к �---�
16 к - 16 к
12 к - 1 2 к�----, 12 к - 12 к
Таблица
кодировки
Дерево
8 к -символов 8 к- 8 К синтаксического вк-
Исходный анализа Стек
текст вызовов
4 к ,_. 4 К- 4К- 4К-
Таблица 4. 2 ( пр одолжение )
Вопрос Замещение страниц Сегментация
Облегчен ли совместный доступ Нет Да
пользователей к процедурам?
Зачем была придумана эта техника? Чтобы получить Чтобы иметь возможность
большое линейное разбивать программы
адресное пространство и данные на логически
без дополнительных независимые адресные
затрат на физическую пространства, а также
память упростить совместный
доступ и защиту
Содержимое страниц в известной степени случайно. Программист не осведомлен
даже о том факте, что происходит замещение страниц. Хотя добавление несколь
ких битов в каждую запись таблицы страниц для определения режима доступа
в принципе возможно, однако, чтобы использовать такой подход, программисту
пришлось бы отслеживать, где находятся границы страниц в его адресном про
странстве. Это представляет собой в точности тот вид администрирования, для
устранения которого была придумана технология замещения страниц. Посколь
ку пользователь сегментированной памяти имеет дело с иллюзией постоянного
нахождения всех сегментов в оперативной памяти (то есть он может адресовать
ся к ним так, как будто они существуют), он может защищать сегменты по от
дельности, не заботясь об управлении их загрузкой в память.
4 . 6 . 2 . Сегментация с замещением
стран иц в l ntel Penti u m
Pentium поддерживает 16 К независимых сегментов по 232 байт виртуальной памя
ти каждый. Операционная система может настроить Pentium на использование
сегментации, замещения страниц, либо того и другого вместе. Большинство опе
рационных систем, включая Windows ХР и все семейство UNIX, поддерживают
4.6. Сегментация 46 1
Сегмент 4 Сегмент 4
(7 К) (7 К) Сегмент 5
(4 К)
Сегмент 3 Сегмент 3 Сегмент 3 Сегмент 5
(8 К) (8 К) (8 К) (4 К)
Сегмент б
Сегмент 2 Сегмент 2 Сегмент 2 (4 К)
(5 К) (5 К) (5 К) Сегмент 2
(5 К)
Сегмент 1
(8 К) Сегмент 7 Сегмент ? Сегмент ? Сегмент ?
(5 К) (5 К) (5 К) (5 К)
Сегмент а Сегмент а Сегмент а Сегмент а Сегмент а
(4 К) (4 К) (4 К) (4 К) (4 К)
а б в г д
Рис. 4 . 2 2 . Решение проблемы фрагментации: а-гразвитие внешней фрагментации;
-
Биты 13 2
Индекс
)1 � Уровень
а = GDT/1 = LDT привилегированности (0-3)
Рис. 4 . 2 3 . Селектор в системе Peпtium
462 Глава 4 . Уп равление памятью
Относительная
адресация
Рис. 4.24. Дескриптор программного сегмента в системе Peпtium. Сегменты данных
немного отличаются
Формат селектора сознательно продуман так, чтобы упростить определение ме
стоположения дескриптора. Сначала выбирается локальная или глобальная таб
лица дескрипторов, основываясь на бите 2 селектора. Затем селектор копируется
во внутренний рабочий регистр и 3 младших бита сбрасываются в нули. Нако
нец, к нему прибавляется адрес одной из таблиц, с целью получить прямой ука
затель на дескриптор. Например, селектор 72 ссылается на запись 9 в глобальной
таблице дескрипторов, расположенную по адресу GDT + 72.
Теперь проследим, как пара селектор-смещение преобразуется в физический ад
рес. Как только микропрограмма узнает, какой сегментный регистр использует
ся, она может найти в своих внутренних регистрах полный дескриптор, соответ
ствующий этому селектору. Если сегмент не существует (селектор равен О) или
в данный момент выгружен, происходит прерывание.
Затем микропрограмма проверяет, выходит ли смещение за пределы сегмента,
в этом случае также возникает прерывание. Логически, в дескрипторе просто
должно существовать 32-разрядное поле размера сегмента, но там доступны толь
ко 20 бит, поэтому действует другая схема. Если поле G ( Granularity - глубина
4 . 6. Сегментация 463
Селектор Смещение
Дескриптор
Базовый адрес
�---<-1
�
Предел
Другие поля
32-разрядный
линейный адрес
Рис. 4 . 2 5 . Преобразование пары селектор-смещение в физический адрес
Если режим замещения страниц отключен (за счет бита в глобальном управляю
щем регистре), линейный адрес интерпретируется как физический адрес и посы
лается в память для чтения или записи. Таким образом, при отключении режима
замещения страниц мы получаем чистую схему сегментации с базовым адресом
каждого сегмента, выдаваемым его дескриптором. Сегментам разрешено пере
крываться случайным образом, возможно потому, что реализация контроля за
тем, чтобы они не пересекались, была бы слишком трудоемкой и заняла бы слиш
ком много времени.
В то же время в режиме замещения страниц линейный адрес интерпретируется
как виртуальный адрес и отображается на физический адрес с помощью таблицы
страниц практически так же, как в наших предыдущих примерах. Единственная
серьезная трудность заключается в том, что при 32-разрядном виртуальном адресе
и странице размером 4 Кбайт сегмент может содержать 1 млн страниц, поэтому
имеет место двухуровневое отображение с целью уменьшения размера таблицы
страниц для маленьких сегментов.
У каждой работающей программы есть странwтый каталог, состоящий из 32-раз
рядных записей в количестве 1 024. Он расположен по адресу, хранящемуся в гло
бальном регистре. Каждая запись в каталоге ссылается на таблицу страниц, так
же содержащую 1 024 записей (тоже 32-разрядных). Записи в таблицах страниц,
в свою очередь, указывают на страничные блоки. Эта организация продемонст
рирована на рис. 4.26.
464 Глава 4. Уп равление памятью
Линейный адрес
Биты 10 10 12
Каталог Страница Смещение
а
i
выбранное
......
1024
записей t
Смещение
t
i
Каталог f-------1
• >------< +
Запись каталога Запись в табnице
указывает на страниц указывает
табnицу каталога на слово
б
Рис. 4.26. Отображение линейного адреса на физический
На рис. 4.26, а мы видим линейный адрес, разделенный на три поля: каталога,
страницы и смещения. Поле каталога используется как индекс в страничном
каталоге, определяющий расположение указателя на правильную таблицу стра
ниц. Затем обрабатывается поле страницы в качестве индекса в таблице страниц,
с целью найти физический адрес страничного блока. И наконец, чтобы получить
физический адрес требуемого байта или слова, к адресу страничного блока при
бавляется последнее поле - поле смещения.
Каждая запись в таблице имеет размер 32 бита, двадцать из которых содержат
номер страничного блока. Остальные биты - это биты доступа и �грязный• бит,
задаваемые аппаратно для операционной системы, биты защиты и другие полез
ные биты.
Каждая таблица страниц включает в себя записи для 1 024 страничных блоков
размером по 4 Кбайт, таким образом, одна таблица страниц обеспечивает управ
ление памятью размером 4 Мбайт. Сегмент, размер которого меньше 4 Мбайт,
будет иметь страничный каталог с единственной записью - указателем на его
единственную таблицу страниц. Следовательно, в случае короткого сегмента на
поддержку таблиц страниц расходуется только две страницы вместо миллиона
в случае одноуровневой таблицы страниц.
Чтобы избежать повторных обращений к памяти, система Pentium имеет неболь
шой буфер быстрого преобразования адреса (TLB), который напрямую отобра
жает наиболее часто используемые комбинации полей каталога и страницы на
физический адрес страничного блока. Только когда текущая комбинация от
сутствует в TLB, действительно выполняется процедура, которую иллюстрирует
4. 6 . Сегментация 465
рис. 4.26, после чего TLB обновляется. Система обладает хорошей производи
тельностью до тех пор, пока обращения к отсутствующим в TLB страницам про
исходят относительно редко.
Если немного поразмыслить над механизмом замещения страниц, можно прий
ти к выводу о том, что смысла в использовании нулевого значения поля базы
нет. Единственное, для чего нужно это поле, - обеспечить смещение, позволяющее
использовать записи, находящиеся в середине, а не в начале страничного катало
га. Фактически база требуется лишь для поддержки «чистой• (без замещения
страниц) сегментации, а также для совместимости с процессором 286, в котором
режим замещения страниц всегда отключен.
Также следует отметить, что даже если приложение не требует сегментации, а до
вольствуется единым разбитым на страницы 32-разрядным адресным простран
ством, эта модель все равно работает. Все сегментные регистры могут быть на
строены тем же самым селектором, в дескрипторе которого поле базы равно О,
а поле лимита установлено на максимум. Тогда при использовании единого ад
ресного пространства смещение команды будет линейным адресом - в сущно
сти, это обычное замещение страниц. Фактически все современные операцион
ные системы для компьютера Pentium работают таким образом. Система OS/2
была единственной, в которой были задействованы все возможности архитекту
ры блока управления памятью (MMU) компании Intel.
В конце концов, кто-то должен похвалить разработчиков Pentium. При постав
ленных перед ними противоречивых задачах - реализовать «чистое• замещение
страниц памяти, «чистую• сегментацию и страничные сегменты и в то же время
обеспечить совместимость с процессором 286, а кроме того, сделать все это эф
фективно - то, что у них получилось, на удивление просто и понятно.
Мы, хотя и кратко, но целиком описали архитектуру виртуальной памяти про
цессоров Pentium и теперь следует сказать несколько слов о защите, так как эта
тема тесно связана с виртуальной памятью. Pentium поддерживает четыре уров
ня защиты, где уровень О является наиболее привилегированным, а уровень 3 -
наименее привилегированным (рис. 4.27). В каждый момент времени работаю
щая программа находится на определенном уровне, что отмечается 2-разрядным
полем в его слове состояния программы (PSW). Каждый сегмент в системе так
же имеет свой уровень.
До тех пор пока программа сама ограничивает использование сегментов на своем
собственном уровне, система прекрасно работает. Разрешаются попытки получе
ния доступа к данным более высокого уровня. Попытки доступа к данным более
низкого уровня запрещены и вызывают прерывания. Попытки вызвать процеду
ры различного уровня (более высокого или низкого) позволяются, но тщательно
контролируются. Чтобы сделать межуровневый вызов, инструкция CALL должна
содержать селектор вместо адреса. Этот селектор определяет дескриптор, назы
ваемый шлюзом вызова ( call gate) и передающий адрес вызываемой процедуры.
Таким образом, попасть в середину произвольного сегмента кода другого уровня
невозможно, открыты лишь официальные точки входа.
466 Гла в а 4 . Уп ра влен ие памятью
Уровень
Рис. 4.27. Защита в системе Pentium
Рисунок 4.27 иллю стрирует типичное применение этого механизма. На уровне О мы
находим ядро операционной системы, занимающееся обработкой операций ввода
вывода, управлением памятью и другими первоочередными задачами. На уров
не 1 находится обработчик системных вызовов. Пользовательские программы
этого уровня могут обращаться к процедурам для вьmолнения системных вызовов,
но только к определенному и защищенному списку процедур. Уровень 2 содер
жит библиотечные процедуры, возможно, совместно используемые несколькими
работающими программами. Пользовательские программы вправе вызывать эти
процедуры и читать их данные, но не могут их изменять. И наконец, пользова
тельские программы работают на наименее защищенном уровне 3.
В программные и аппаратные прерывания заложен механизм, аналогичный шлю
зам вызовов. Они тоже обращаются к дескрипторам, а не к абсолютным адресам,
а эти дескрипторы указывают на определенные процедуры. Поле типа на рис. 4.24
позволяет различать программные сегменты, сегменты данных и шлюзы вызовов
различных видов.
4 . 7 . Знакомство с ме н еджер ом
про цессов в M I N IX 3
В MINIX 3 управление памятью реализовано элементарно: ни замещение стра
ниц, ни подкачка попросту не используются. Тем не менее код поддержки под
качки входит в полную версию операционной системы и позволяет применять
MINIX 3 в условиях нехватки физической памяти. На практике объемы памяти
таковы, что к подкачке приходится прибегать достаточно редко.
4.7. З наком ство с менеджером п роцессов в M I N IX З 467
4 . 7 . 1 . Распределение памяти
Программы в MINIX 3 могут быть скомпилированы так, чтобы использовать
обьединенное пространство данных и кода. В этом случае под все составные час
ти процесса (текст, данные и стек) выделяется единый блок памяти. Этот блок
используется ими совместно и освобождается единовременно. Такая схема распре
деления памяти применялась по умолчанию в исходной версии MINIX. В MINIX 3,
напротив, по умолчанию принято компилировать программы с раздельными про
странствами данных и кода. Для ясности м ы сначала рассмотрим более простую
модель с общей памятью. Процессы с раздельными пространствами данных и ко
да позволяют расходовать память эффективнее, но при этом возникают сложно
сти, которые мы изучим позднее.
В обычном режиме выделение памяти в MINIX 3 происходит в двух ситуациях.
Во-первых, когда процесс разветвляется, дочернему процессу предоставляется
необходимая ему память. Во-вторых, когда процесс при помощи системного
вызова ехес заменяет свой образ, старый образ памяти процесса возвращается
в список свободных блоков памяти, а новая память выделяется на новом месте.
Положение нового образа процесса в памяти зависит от того, где найден первый
подходящий по размеру блок. Кроме того, когда процесс завершается (самостоя
тельно или принудительно, по сигналу), занятая им память освобождается. Име
ет место и третий случай, в котором системный процесс запрашивает память под
4. 7. Знакомство с менеджером п роцессов в M I N IX 3 469
собственные нужды. Например, драйвер памяти может запросит память под вир
туальный диск. Это возможно лишь на этапе инициализации системы.
На рис. 4.28 показаны оба варианта выделения памяти. На рис. 4 . 28, а мы ви
дим в памяти два процесса, А и В. Если процесс А разветвляется, мы попадаем
в ситуацию, представленную на рис. 4.28, б. Дочерний процесс является точной
копией процесса А. Если теперь дочерний процесс выполнит файл С, память
придет в состояние, показанное на рис. 4.28, в. Образ дочернего процесса был
заменен образом С.
Предел
верхней
памяти
А А А
Выделение памяти:
Рис. 4 . 2 8 . исходное состояние; б состояние после
а - -
т Символы
Размер Данные
файла
на диске 1--_Код
_j_ ___-1
за гол овок
а б
Рис. 4.29. Распределение памяти дл я программы:а программа хранится на диске в виде
-
Если программист знает, что общий объем памяти, необходимый для стека и дан
ных программы в файле а . ou t , не превышает 10 Кбайт, то при помощи следую
щей команды он может изменить поле заголовка исполняемого файла:
chmem = 1 0 2 4 0 a . ou t
После этого вызов е х е с будет выделять только 1 0 240 байт дополнительной па
мяти. Так, для описанного примера будет выделено 1 6 Кбайт памяти. Из этой
памяти верхний килобайт отводится под стек, а 9 Кбайт образуют свободную об
ласть для будущего роста стека и (или) области данных.
Для программ с раздельными адресными пространствами кода и данных (у кото
рых компоновщик устанавливает специальный бит в заголовке программы) по
ле общего размера в заголовке относится только к стеку и данным. Так, при за
грузке программы с 4 Кбайт кода, 2 Кбайт данных, 1 Кбайт стека и суммарным
размером 64 Кбайт будет выделено 68 Кбайт памяти ( 4 Кбайт на код, 64 Кбайт
образуют адресное пространство данных, а 61 Кбайт останется для роста стека
и данных). Граница сегмента данных может быть изменена только при помощи
системного вызова brk. При выполнении этого вызова проверяется, не упирает
ся ли новая граница сегмента данных в нижнюю границу стека, и соответствую
щие изменения вносятся во внутренние таблицы. Это делается исключительно
внутри памяти, выделенной процессу, поскольку у операционной системы не за
прашивается никаких новых блоков. Если же после изменения границы сегмент
данных будет пересекаться со стеком, вызов завершается ошибкой.
Тут нужно упомянуть небольшую семантическую сложность. Когда мы говорим
4:Сегмент� , мы имеем в виду область памяти, определяемую операционной систе
мой. Но у процессоров Intel 80х86 есть специальные внутренние сегментные ре
гистры и (у более новых из них) таблицы дескрипторов сегментов, обеспечи
вающие аппаратную поддержку 4Сегментов�. Концепция сегмента в архитектуре
Intel сходна с тем, как сегменты определяются в MINIX 3, но это - не одно и то
же. Все ссылки на сегменты в этом тексте следует рассматривать в контексте их
определения в MINIX 3. Когда мы будем говорить об аппаратных сегментах, мы
явно укажем сегментные регистры и дескрипторы сегментов.
Это предупреждение может быть обобщено. Разработчики аппаратного обеспече
ния часто целенаправленно стараются реализовать поддержку на своем оборудова
нии конкретных операционных систем. Поэтому терминология описания регистров
и других аспектов архитектуры процессора обычно отражает то, как все это будет
использоваться. Подобные возможности часто полезны для разработчиков опера
ционной системы, но практика не обязательно соответствует идеям производителя
оборудования . В результате термины, звучащие одинаково, но имеющие разное зна
чение для операционной системы и оборудования, моrут привести к непониманию.
4 . 7 2 Обработка сообщени й
. .
обратно, чтобы сообщить о выполнении или ошибке. Этот механизм подобен ме
ханизму обработки системных вызовов (шаг 7 на рис. 1 . 1 2), но только в адрес
ном пользовательском пространстве, а не в пространстве ядра.
менеджера процессов
У менеджера процессов есть две ключевые структуры данных: таблица процес
сов и таблица свободных блоков памяти.
Из табл. 2 . 1 видно, что одни поля таблицы процессов необходимы ядру, дру
гие нужны для управления процессами, а третьи требуются файловой системе.
В MINIX 3 каждая из трех частей операционной системы поддерживает собст
венную таблицу процессов, содержащую только те поля, которые интересны ей.
Записи всех трех таблиц соответствуют друг другу, чтобы не усложнять дело.
Так, ячейка k таблицы процессов менеджера процессов соответствует тому же
процессу, что и ячейка k таблицы процессов файловой системы. При создании
или уничтожении процесса необходимо обновлять записи во всех трех таблицах,
чтобы поддерживать их в согласованном состоянии.
Исключения составляют процессы, не видимые за пределами ядра. К ним от
носятся встроенные в ядро таймерное и системное задания ( CLOCK и SYSTEM ) ,
а также �заполнители� I DLE и KERNEL. В таблице процессов ядра их номера отри
цательны, а в таблицах менеджера процессов и файловой системы соответствую
щих им записей вообще нет. Таким образом, строго говоря, утверждение о ячейках
таблиц с номером k справедливо лишь при значении k, большем или равном О.
П роцессы в памяти
Таблица процессов менеджера процессов называется mp r o c , она определена
в файле src / serve rs / pm/mproc . h. В этой таблице содержатся поля, связанные
с выделением памяти, а также некоторые дополнительные сведения. Самым важ
ным полем является массив mp_s eg, у которого есть три записи, для сегмента
текста (кода), данных и стека. Все его элементы представляют собой структуры,
содержащие виртуальный и физический адреса, а также длину сегмента, причем
эти величины измеряются не в байтах, а в кликах. Размер клика (минимального
блока памяти) зависит от реализации. В ранних версиях MINIX используется
значение 256 байт, а в MINIX 3 - 1 024 байта. Все сегменты начинаются на гра
нице клика и содержат целое число кликов.
Способ записи информации о выделении памяти иллюстрирует рис. 4.30. На ри
сунке показан процесс с такой структурой: 3 Кбайт кода, 4 Кбайт данных, зазор
имеет величину 1 Кбайт, а после него следует стек объемом 2 Кбайт. Всего вы
делено 1 О Кбайт памяти. На рис. 4.30, б показано, что хранится в полях длины
и виртуального и физического адресов для этих сегментов при условии, что
процесс не разделяет адресные пространства кода и данных. В этой модели
размер сегмента кода всегда считается равным нулю, а сегмент данных содержит
и данные, и код. Когда показанный на рисунке процесс обращается к виртуаль-
4 .7. Знакомст в о с м енеджер ом пр оце ссо в в M I NIX 3 475
Общий код
При выполнении процесса содержимое его областей данных и стека может ме
няться, но код не меняется никогда. Часто случается, что несколько процессов
выполняют одну и ту же программу, например, несколько пользователей могут
работать с одной оболочкой. Поэтому общий код повышает эффективность памя
ти. Когда системный вызов е х е с собирается загрузить процесс, он открывает
файл с образом этого процесса и считывает заголовок. Если у процесса раздель
ные адресные пространства кода и данных, среди всех ячеек таблицы mproc осу
ществляется поиск по полям mp_dev, mp_i no, mp_c t ime. Эти поля содержат
информацию о номере индексного узла и времени модификации образов, испол
няемых другими процессами. Если обнаруживается процесс, который уже вы
полняет нужную программу, то выделять память под еще одну копию кода не
нужно. Вместо этого в карту памяти нового процесса в поле mp_seg [ Т ] записы
вается указатель на ту область памяти, где уже хранится код, а память выделяет
ся только под данные и стек (рис. 4.3 1 ). Если загруженного образа найдено не
было или адресные пространства кода и данных объединены, память выделяется
согласно рис. 4.30 и заполняется данными с диска.
4 .7. Знакомство с менеджером пр оцессов в M I N IX 3 477
J 1 •S
:а •S
::i: s
..а ""
t:; (,)
Q)
� 7 С\1
s ::i:
"' s
s s
a:i & .§:
Ох5 Oxf5 Ох2 Стек
о OxfO Ох4 Данные
о Охс8 ОхЗ Код
•S
:а
::i:
•S
s
Процесс 2
..а "" в
t:; (,)
Q)
�
7 С\1
s ::i:
"' s
s s
a:i & .§:
Стек Ох5 OxdO Ох2
Данные о ОхсЬ Ох4
Код о Охс8 ОхЗ
Процесс 1
а
Ох32000
1 r
б
Использование общего кода:
Ри с . 4 . 3 1 . карта памяти для раздельных адресных
а -
пространств кода и данных, как на предыдущем рисунке; б распределение памяти после
-
запуска второго процесса, выполняющего тот же код; в карта памяти второго процесса
-
\О t s а 52 \О t s а 81 88 \О t s а 8188
Массив 1 r s u 48 1 r s u 8184 1 r s u 8184
переменных Е м =
44 =
Е м 81 80 =
Е м 81 80
окружения 1
с
1 1
о
о Н \О 40 о Н \О с 81 76 о Н \О с 81 76
g \О с 36 g \О с 81 72 g \О с 81 72
с ____ _,
". f \О 1 32 f \О 1 81 68 f \О 1 81 68
НОМЕ /usr/ast
=
- \О s 1 28 - \О s 1 81 64 - \О s 1 81 64
о 24 о 81 60 о 81 60
42 20 81 78 81 56 81 78 81 56
о 16 о 81 52 о 81 52
38 12 81 74 8148 81 74 8148
Массив 34 8 81 70 8144 81 70 8144
аргументов 31 4 81 67 8140 81 67 8140
с 28 о 81 64 81 36 81 64 81 36
�� епvр
81 56
81 36
81 32
81 28
-1
ls argv 4 8124
argc returп 81 20
а б в г
Если программист в конце кода функции rna i n не сделал вызов exi t, то после
ее завершения управление передается обратно в подпрограмму runt irne. Опять
же, с точки зрения компилятора, rna i n обычная функция, и для возврата из
-
4 . 7. 7 . Обработка си гналов
В главе 1 сигналы были определены как средство передачи информации процес
су, который не обязательно ждет ввода. Задается набор сигналов, и у каждого
сигнала есть действие по умолчанию: либо завершить процесс, которому сигнал
адресован, либо игнорировать сигнал. Если бы других альтернатив не бьmо, обра
ботку сигналов было бы просто понять и реализовать. Но при помощи системных
вызовов процессы способны менять это поведение. Процесс может потребовать,
чтобы любой сигнал (за исключением особого сигнала s i gki l l ) игнорировался.
Более того, процесс может перехватить сигнал, предписав, чтобы вместо дейст
вия по умолчанию был вызван указанный им обработчик сиzнала (опять же, это
не относится к сигналу s i gki l l ). Таким образом, с точки зрения программиста
есть два этапа работы с сигналами: подготовительная фаза, когда определяется
ответная реакция на будущий сигнал, и ответная, когда сигнал генерируется и об
рабатывается. Ответным действием может быть выполнение собственной подпро
граммы-обработчика. В действительности есть и третья фаза. Когда пользова
тельский обработчик завершается, специальный системный вызов восстанавли
вает нормальную работу получившего сигнал процесса. Программисту об этой
третьей фазе знать не нужно, он пишет обработчики сигналов как обычные
функции, а заботу о вызове и завершении обработчиков и управлении стеком
берет на себя операционная система.
4. 7. Знакомство с менеджером пр оцессов в M I N IX 3 485
Таблица 4.4. Сигналы MINIX 3, регламентированные POSIX. Знак (*) означает, что сигнал
зависит от аппаратной помержки, сигналы с пометкой (М) не описаны в POSIX и введены
в MINIX 3 для помержания совместимости с устаревшим кодом. Сигналы ядра являются
специфичными для MINIX 3 и предназначены для информирования системных процессов
о событиях системы. В таблицу не попали несколько устаревших имен и синонимов
Сигнал Описание Источни к
SIGHUP Отбой Системный вызов kill
SIGINT Прерывание Ядро
SIGQUIT Завершение Ядро
SIGILL Недопустимая инструкция Ядро (*)
4 .7. Знакомство с менеджером пр оцессов в M I N IX 3 487
Структура Локальные
sigframe переменные
- - - - - - - - -
Адрес sigreturп
возврата 1
Локальные
переменные
обработчика
}т·�-
Фрейм стека Фрейм стека Фрейм стека Фрейм стека
(регистры (регистры (регистры (регистры
процессора) процессора) процессора) процессора) процессов
(исходные) (изменены, (изменены, (исходные)
ip = обработчик) ip = обработчик)
Исходное Во время работы Выполняется Возврат в исходное
состояние обработчика sigгetuгп состояние
а б в г
Рис . 4.33.Стек процесса (сверху) и кадр стека (снизу), соответствующие различным фазам
обработки сигнала: а состояние, в котором процесс приостанавливается; б состояние
- -
на каждом этапе выполнения стек выглядит как обычный стек процесса с собст
венными локальными переменными после адреса возврата.
Главное, что должен сделать вызов s igreturn, это вернуть все в исходное со
-
4 . 8 . Уп равление пам я ть ю в M I N IX
В общих чертах разобравшись в том, как работает менеджер процессов, давайте
обратимся к самому коду. Менеджер процессов полностью написан на языке С,
его код прост и снабжен множеством комментариев, поэтому мы, как правило, не
будем слишком глубоко вдаваться в детали. Сначала мы изучим заголовочные
файлы, затем - главную программу, а потом - файлы с кодом описанных ранее
системных вызовов.
Поле mp_f l ags, как показано в конце файла, необходимо для хранения разно�
образных битовых сочетаний. В нем хранится беззнаковое целое, 16-разрядное
для самых старых процессоров и 32-разрядное для процессоров 386 и выше.
Последнее поле таблицы процессов называется mp_procargs. Когда запускаетоя
новый процесс, строится стек, подобный показанному на рис. 4.32, и указатель
на массив argv нового процесса сохраняется в этой переменной. Например, на
рис. 4.32 в поле будет сохранено значение 8 1 64, благодаря чему, пока выполняется
команда l s , команда p s может вывести содержимое командной строки:
ls -l f . c g . c
Это - тот же самый механизм, который мы могли наблюдать в коде ядра. Как
уже было отмечено, переменная core_name объявлена в файле g l o . h с ключе
вым словом ext e rn, а не EXTERN. Теперь становится ясно, почему: core_name
объявляется со строкой инициализации, а инициализация в определении ext ern
невозможна.
Еще один важный элемент файла t аЫ е . с - массив c a l l_ve c (строка 17815).
О н также инициализирован, а потому в g l o . h его нельзя было бы объявлять
с ключевым словом EXTERN. С его помощью номер системного вызова преобра
зуется в адрес выполняющей его функции, номер вызова играет роль индекса
в массиве. Если в сообщении указан несуществующий номер системного вызова,
управление передается функции no_sy s , которая просто возвращает код ошиб
ки. Несмотря на то что при объявлении массива c a l l_vec применяется макрос
_PROTOTYPE, в действительности это - описание не прототипа, а инициализи
рованного массива. Но так как он же массив указателей на функции, проще всего
получить код, компилируемый как классическим (Керниган и Ричи), так и стан
дартным компилятором С при помощи макроса _PROTOTYPE.
И наконец, последнее замечание о заголовочных файлах. Поскольку MINIX 3 до
сих пор находится в стадии активной разработки, некоторые <1:острые углы� до
сих пор не <1:сглажены�. Один из них состоит в том, что некоторые исходные файлы
в каталоге pm / включают заголовочные файлы из каталога ядра. Если не знать
об этом, можно столкнуться с проблемами при поиске некоторых важных опреде
лений. Вероятно, определения, используемые более чем одним из основных компо
нентов MINIX 3, следует разместить в заголовочных файлах каталога inc lude / .
4 . 8 . 2 . Главная п рограмма
Менеджер процессов компилируется и компонуется независимо от ядра и фай
ловой системы. Следовательно, у него имеется собственная главная процедура,
которая запускается после того, как ядро заканчивает свою инициализацию. Она
расположена в файле ma i n . с (строка 1 804 1 ) . В ней менеджер процессов сначала
выполняет собственную инициализацию (функция pm_i n i t ) , а затем входит
в цикл (строка 1 805 1 ) . В этом цикле сначала, чтобы дождаться входящего сооб
щения, делается вызов get_work. Затем вызывается одна из функций do_XXX,
498 Глава 4. Уп равление памятью
После запуска MINIX 3 вы можете получить эту информацию при помощи ко
манды sys env или клавиши F5 . Разумеется, числа, которые вы увидите, могут
отличаться от приведенных в этом примере.
Здесь мы видим два блока свободной памяти. Кроме того, два блока памяти
заняты: ниже адреса Ох800 находятся данные BIOS, главная загрузочная запись
и загрузочный блок. Не имеет значения, как используется эта память, важно, что
на момент запуска монитора загрузки она недоступна. Память, начинающаяся
с адреса Ох800, является •базовой памятью� для I В М-совместимых компьюте
ров. В данном примере свободный блок с началом по адресу Ох800 (2048) имеет
размер Ох923е0 (599008) байт. Далее следует блок • верхней области памяти�
с 640 Кбайт до 1 Мбайт, который недоступен обычным программам. Он зарезер
вирован под память для чтения и выделенную память адаптеров ввода-вывода.
Начиная с адреса Ох 1 00000 ( 1 Мбайт), свободно Ox3df0000 байт. Как правило,
этот участок называют расширенной памятью. В показанном примере компью
тер оснащен в общей сложности 64 Мбайт оперативной памяти.
Если вы внимательно следили за числами, то заметили, что сумма свободной
базовой памяти составляет менее 638 Кбайт, как •должно бы быть�. Загрузочный
монитор MINIX 3 загружает себя как можно выше в данном диапазоне и в рас
сматриваемом случае занимает около 52 Кбайт. Таким образом, свободными ока
зываются приблизительно 584 Кбайт памяти. Следует отметить, что механизм
использования памяти может быть сложнее, чем описано здесь. Например, один
из методов запуска M INIX, к моменту написания книги еще не перенесенный
в MINIX 3, предполагает применение D ОS-файла для имитации диска MINIX.
Этот метод требует загрузки некоторых компонентов M S - D O S до запуска мо
нитора загрузки MINIX 3. Если компоненты окажутся загруженными в области
памяти, несмежные с уже занятыми, число областей свободной памяти будет
больше двух.
Когда монитор загрузки помещает загрузочный образ в память, информация о его
компонентах отображается на экране консоли. Часть экрана показана на рис. 4.34.
В этом примере (типичном, но, вероятно, отличающемся от вашего экрана, по
скольку для его создания использовалась рабочая редакция MINIX 3) монитор
загрузки поместил ядро в свободную область памяти, начиная с адреса Ох800.
500 Глава 4. Уп равление памятью
Строго говоря, sys_ge t irnage является не вызовом ядра, а одним из более 10 мак
росов, определенных в файле i n c l ude / rn i n i x / sys l i b . h и обеспечивающих
простой интерфейс к вызову ядра sys_ge t i n f o . Процессы ядра невидимы из
пользовательского пространства, и части таблицы процессов, принадлежащие
менеджеру процессов и файловой системе, не нуждаются в инициализации со
стороны компонентов ядра. Фактически место под записи процессов ядра не ре
зервируется. Каждый из них имеет отрицательный номер (индекс в таблице про
цессов) и игнорируется при проверке в строке 1 8202. Кроме того, вызывать
функцию pat ch_rnern_chunks для процессов ядра не обязательно; при выделе
нии памяти под ядро потребности его процессов учитываются.
Как системные, так и пользовательские процессы необходимо добавить в табли
цу процессов, хотя работа с ними ведется по-раз ному (строки 1 82 1 0- 1 82 1 9 ) .
Единственным пользовательским процессом, включенным в состав загрузочного
образа, является ini t , поэтому в строке 1 82 1 0 выполняется проверка для INIT_
PROC_NR. Все остальные процессы, входящие в загрузочный образ, - системные.
Системные процессы являются особыми: они не могут быть вытеснены, каждый
из них обладает собственной записью в таблице p r i v ядра и набором привиле
гий, задаваемым флагами. Для каждого процесса определены надлежащие пара
метры обработки сигналов по умолчанию, при этом между системными про
цессами и ini t имеются определенные различия. Далее карта памяти каждого
процесса извлекается из ядра при помощи функции get_rnern_rnap, совершаю
щей вызов ядра sys_ge t i n f o, и pat ch_rnern_rnap , соответствующим образом
изменяющей массив rnern_chunk s (строки 1 8225 - 1 8230).
Наконец, файловой системе передается сообщение, с помощью которого каждый
процесс инициализируется в принадлежащей ей части таблицы процессов ( стро
ки 1 8233- 1 8236). Сообщение содержит только номер и идентификатор процесса;
этого достаточно, чтобы инициализировать запись в таблице файловой системе,
поскольку все процессы загрузочного образа принадлежат суперпользователю
и могут получить одинаковые значения по умолчанию. Каждое сообщение от
правляется при помощи операции s end, поэтому ответа на него не ожидается.
После передачи сообщения имя процесса отображается на консоли (строка 18237):
Bui l d ing pro c e s s t аЫ е : pm fs r s tty memory log driver i n i t
NONE в качестве номера процесса указывает файловой системе на то, что все сис
темные процессы инициализированы, можно выйти из цикла и послать синхрони
зирующее сообщение для снятия блокирования с менеджера процессов.
После этого файловая система может продолжить собственную инициализацию,
а инициализация менеджера процессов почти завершена. В строке 1 8253 вызы
вается функция mem_ini t. Она инициализирует связанный список свободных
областей памяти и нужные переменные, которые будут использованы для управ
ления памятью в процессе работы системы, на основе данных массива mem_
chunks . Управление памятью в обычном режиме начинается после того, как на
консоль выводится сообщение, содержащее общий объем памяти, память, заня
тую MINIX 3, и объем свободной памяти:
Phy s i c a l memory : t o t a l 6 3 9 9 6 КВ , sy s t em 1 2 8 3 4 КВ , f r e e 5 1 1 6 2 КВ
Ожидание
а б
Рис. 4.35. Иллюстрация механизма завершения процесса: а процесс 1 2 собирается
-
При этом @олшебная• строка сценария указывает, что его следует интерпрети
ровать с помощью оболочки Bourne:
#! / Ь in / sh
Массив \О t 52
переменных s а 1 r 48
окружения s u 1 44
=
о \О t 40 о Е М о н 40
s а 1 r 36 \О 1 f \О 36
С-----1•• s u 1 32 =
с_____,"
. h s s 32
НОМЕ /usr/ast Е
=
м о н 28 НОМЕ /usr/ast
=
\О h s 1 28
\О 1 f \О 24 п i ь 1 24
h s s 20 о 20
о 16 Действующий 40 16
32 12 массив о 12
о 8 аргументов 37 8
25 4 32 4
20 о f1 24 о
s.sh
/Ьiп/sh
а б
Рис. 4.36.Обработка сценария: массивы, переданные вызову execve, и стек, созданный
а -
при исполнении сценария; б - вид массивов и стека после обработки функцией patch_stack.
Имя сценария передается программе, интерпретирующей сценарий
Следующая функция, определенная в файле е х е с . с , - это функция rw_seg
( строка 1 9208). При каждом вызове е х е с она исполняется один или два раза.
Обязательный вызов выполняет загрузку сегмента данных, а необязательный
вызов - сегмента кода. Файловая система прибегает :к специальному трюку, что
бы поместить сразу весь сегмент в пользовательское пространство, а не считы
вать и копировать файл блок за блоком. Суть в том, что вызов особым образом
декодируется файловой системой и выглядит та�<, как будто сам пользователь
ский процесс считывает весь сегмент. Лишь несколько первых строк процедуры
считывания файловой системы знают о том, как в действительности обстоит де
ло. Подобный маневр значительно ускоряет процесс загрузки сегмента.
Последняя подпрограмма в файле ехе с . с называется f i nd_share (строка 19256).
Она по номеру индексного узла, номеру устройства и времени модификации ищет
в таблице процессов процесс, с которым можно разделить код. Это - простой
последовательный поиск подходящего поля в таблице mproc. Конечно, при про
смотре необходимо игнорировать сам процесс, для которого выполняется поиск.
4 . 8 . 6 . Реализация сигналов
С сигналами связаны 8 системных вызовов, перечисленных в табл. 4 . 5 . Как сами
сигналы, так и эти системные вызовы обрабатываются кодом из файла s i gna l . с .
стандарту POSIX, необходимо использовать вторую функцию. Код do_s igact ion
(строка 1 9544) начинается с проверок правильности номера сигнала и отсутст
вия попыток изменить реакцию на сигнал s i gk i l l (строки 19550- 1 955 1 ) . Сиг
нал s i gk i l l нельзя ни игнорировать, ни блокировать, ни обрабатывать. Это то
исключительное средство, при помощи которого пользователь может контро
лировать собственные процессы, а системный оператор - пользователей. При
вызове s i gac t ion передаются указатели на структуру типа s i gac t i on, по ад
ресу s ig_o s a помещаются старые значения атрибутов, а по адресу s i g_ns a -
новый набор атрибутов.
На первом шаге, чтобы скопировать текущие значения атрибутов по указателю
s i g_o s a , вызывается системное задание. Далее, при вызове s igac t i on указа
тель s i g_ns a может иметь значение NULL. Это означает, что требуется считать
текущие значения атрибутов, не меняя их. В таком случае s i gac t ion немедлен
но возвращает управление (строка 19560). Если указатель s i g_n s a не равен
NULL, в пространство менеджера процессов копируется новая структура, описы
вающая действие сигнала.
Код в строках 19567 - 1 9585 модифицирует битовые карты rnp_cat ch, rnp_ignore
и rnp_s i gp ending, чтобы указанный сигнал либо игнорировался, либо обраба
тывался так, как предлагается по умолчанию, либо вызывал обработчик. Поле
s a_handl er структуры s i ga c t i on используется для передачи указателя на про
цедуру в исполняемую функцию, если сигнал вызывает обработчик, либо одного
из специальных кодов S I G_ I GN и S I G_DFL, значения которых понятны, если вы
ориентируетесь в рассмотренных ранее стандартах обработки сигналов POSIX.
Кроме того, может использоваться код S I G_ME S S , специфичный для MINIX 3;
мы рассмотрим его позже.
Библиотечные функции s i gadd s e t и s i gde l s e t модифицируют битовые кар
ты сигналов, хотя те же действия можно реализовать и при помощи макроса, как
и другие простые манипуляции с битами. Тем не менее эти функции требуются
по стандарту P O S I X с целью упростить перенос программ на другие системы,
в том числе те, в которых общее число сигналов превышает число битов в целом
значении. Использование библиотечных функций упрощает и перенос самой
системы MINIX 3 на различные платформы.
Ранее мы упомянули особый случай - код S I G_ME S S . Этот код, проверяемый
в строке 1 9576, доступен только для привилегированных (системных) процессов.
Как правило, такие процессы блокируются, ожидая сообщений-запросов. Это оз
начает, что обычный метод получения сигнала, при котором менеджер процессов
просит ядро выставить кадр сигнала на стек приемника, будет отложен до мо
мента, когда сообщение активизирует приемник. Код S I G_ME S S предписывает
менеджеру процессов доставить уведомление, имеющее более высокий приори
тет, чем обычные сообщения. Уведомление содержит набор активных сигналов
в качестве аргумента, допуская передачу нескольких сигналов в одном сообщении.
В завершение заполняются другие относящиеся к сигналам поля той части
таблицы процессов, которая принадлежит менеджеру процессов. Для каждого
512 Глава 4 . Уп равление памятью
Оповещения и таймеры
Системный вызов a l arrn выполняется функцией do_a l a rrn (строка 19769). Она
вызывает следующую функцию, s e t_a l arrn, указав нулевое время оповещения.
Код s e t_a l arrn вынесен в отдельную функцию потому, что он также использу
ется для отключения таймера, когда процесс завершается, а таймер еще работает.
Функция s i g_a l a rrn работает с таймерами, поддерживаемыми внутри менед
жера процессов. Сначала она определяет, установлен ли таймер от имени за
прашивающего процесса, и, если да, истек ли он. Такие проверки позволяют сис
темному вызову вернуть оставшееся время предыдущего оповещения в секундах
или нуль, если таймер не установлен. Комментарий описывает некоторые про
блемы, связанные с большими тайм-аутами. В строке 19818 весьма неприятный
на вид код преобразует время в тики, умножая аргумент, переданный при вызове
(время в секундах), на константу нz - число тактов таймера в секунду. Для того
чтобы привести результат к требуемому типу c l o ck_t , нужно трижды преобра
зовать его тип. В следующей строке тип c l o c k_t переменной t i ck s преобразу
ется обратно в uns i gn e d l ong. Затем результат сравнивается с преобразова
нием исходного значения аргумента в uns i gned l ong. Если обнаруживается
несовпадение, то запрошенное время вызывает выход за пределы значений одно
го из используемых типов данных, и вместо него подставляется значение, указы
вающее бесконечное время. Наконец, вызывается одна из функций prn_set_
t irner или prn_c anc e l_t irner, соответственно добавляющая и удаляющая тай
мер из очереди менеджера процессов. Ключевым аргументом последнего вызова
является c au s e_s i g a l arrn
- сторожевая функция, которая должна быть вы
полнена по истечении таймера.
Взаимодействие с таймерами, поддерживаемое в пространстве ядра, скрыто в вы
зовах подпрограмм prn_XXX_t irner. Любой запрос оповещения, в конечном сче
те, вызывающий его генерацию, обычно приводит к запросу установки таймера
в пространстве ядра. Единственным исключением является ситуация, в которой
несколько запросов оповещения возникают одновременно. Однако процессы
могут отменять оповещения или завершать работу до истечения установленных
ими таймеров. Вызов ядра, устанавливающий таймер в пространстве ядра, дол
жен выполняться лишь при изменении таймера, находящегося во главе очереди
таймеров менеджера процессов.
Когда таймер, стоящий в очереди в пространстве ядра и установленный от имени
менеджера процессов, истекает, системное задание информирует об этом менедже
ра процессов, посылая ему уведомление, а тот обнаруживает его в своем главном
514 Глава 4. Уп равлен ие памятью
.--�����-----,
Уровень
Рис. 4.37. Сообщения при работе таймера. Самые главные из них: 1 пользователь
-
.._
1
1
1
1
1
1
1
Регистры процессора
1
1
1
t�
(64 байта ) t�
1
1
1
1
1
1
1
Маска
Структура sigcoпtext Флаги
.,,,
....
�
Указатель на sigпcoпtext
Структура sigframe
Адрес возврата
'
Указатель фрейма
'
Указатель на sigпcoпtext
'
'
'
'
Код (плавающая запятая)
'
'
'
<111
Адрес структуры sigreturп '
Этот вызов означает, что указанный сигнал должен быть отправлен всем процессам
в текущей группе (то есть всем процессам, запущенным с того же терминала).
Сигналы, исходящие от ядра и системного вызова rebo o t , также могут затраги
вать несколько процессов. По этой причине check_s i g в цикле перебирает все
процессы из таблицы процессов, выбирая из них потенциальных получателей
(строки 1 9996-20026). В цикле содержится много тестов, и только если все они
пройдены, при помощи s i g_proc отправляется сигнал (строка 20023 ).
Еще одна функция, которая несколько раз вызывается в рассмотренном нами ко
де, называется check_p ending (строка 20036). Она перебирает все биты в би
товой карте mp_s i gp ending процесса, сверяясь с битовыми картами с помо
щью функций do_s i gma sk, do_s i gr e t run и do_s igsuspend, и смотрит, не
была ли снята блокировка с одного из задержанных сигналов. Обнаружив пер
вый такой сигнал, она отправляет его. Так как все обработчики событий со вре
менем вызывают функцию do_s i greturn, все разблокированные активные сиг
налы в конце концов доставляются.
Процедура unpau s e (строка 20065) необходима для отправки сигналов про
цессам, приостановленным на одном из вызовов pau s e, wai t , read, wr i t e или
s i gsuspend. Выяснить, обусловлена ли остановка вызовом p au s e , wa i t или
s i gsu spend, можно, сверившись с таблицей процессов менеджера процессов.
Если выясняется, что ни один из этих вызовов не является причиной остановки,
запрос передается файловой системе, которая при помощи собственной функции
do_ unpaus e проверяет, был ли процесс приостановлен для чтения или записи.
В любом случае результат одинаков: незаконченный вызов завершается с ошиб
кой, а процесс вновь запускается и может обработать сигнал.
Последняя процедура в этом файле называется dump_c or e (строка 20093). Она
записывает на диск дампы памяти. Дамп состоит из заголовка, содержащего ин
формацию о размере занимаемых процессом сегментов, всей информации состоя
ния процесса (это копия записи процесса из таблицы процессов ядра) и образов
всех сегментов. Отладчик может прочитать эту информацию, чтобы помочь про
граммисту определить, что пошло не так в работе программы.
Код записи в файл прост. Здесь снова возможна проблема, упомянутая в предьщу
щем разделе, но теперь в несколько иной форме. Чтобы гарантировать, что записы
ваемый в дамп сегмент стека содержит самую последнюю информацию, вызывает
ся функция adj u s t (строка 200 10). Из-за проверки границы безопасности этот
вызов может �провалиться�. Правда, дамп записывается в любом случае, незави
симо от успеха вызова, но информация о стеке может оказаться неправильной.
Рез ю ме
В этой главе были проанализированы как общие принципы управления памя
тью, так и их реализация в M INIX 3. Мы увидели, что в простейших системах
вообще не поддерживается подкачка или замещение страниц. Программа, загру
женная в память, остается там до своего завершения. Некоторые операционные
системы позволяют находиться в памяти одновременно только одному процессу,
в то время как другие поддерживают многозадачность.
Следующим шагом вперед является подкачка (то есть загрузка и выгрузка целых
процессов). Благодаря подкачке система может обрабатывать большее количест
во процессов, чем то, для которого достаточно пространства в памяти. Процессы,
для которых в ней нет места, целиком выгружаются на диск. Свободные области
в памяти и на диске можно отслеживать с помощью битового массива или спи
ска свободных участков.
Современные компьютеры часто поддерживают некоторую форму виртуальной
памяти. В простейшем виде адресное пространство каждого процесса делится на
части постоянного размера, называемые страницами, которые могут размещаться
в любом доступном страничном блоке в памяти. Существует множество алгорит
мов замещения страниц, два наилучших - это алгоритмы •старения� и •второго
шанса� . Для хорошей работы систем замещения страниц выбрать хороший алго
ритм недостаточно; необходимо также обратить внимание на такие вопросы, как
определение рабочего набора, стратегию предоставления памяти и размер страниц.
Сегментация помогает в управлении структурами данных, изменяющими свой
размер во время выполнения, и упрощает процессы компоновки и совместного
доступа. Она также облегчает предоставление различных видов защиты разным
сегментам. Иногда механизмы сегментации и замещения страниц комбинируют
ся, что позволяет организовать двухмерную виртуальную память. Системы Intel
Pentium поддерживают сегментацию и замещение страниц памяти.
Управление памятью в MINIX 3 реализовано просто. Процессу выделяется па
мять, когда он делает системный вызов f or k или ехе с . После того как область
памяти выделена, она никогда не меняет своих размеров, пока работает процесс.
На машинах с процессорами Intel система MINIX 3 поддерживает для процессов
две модели памяти. У маленьких программ инструкции и данные могут разме
щаться в одном сегменте. В более сложных программах адресные пространства
данных и кода могут быть разными. Такие процессы могут иметь общий код,
Во п росы и задани я 525
поэтому при вызове f or k им выделяется память лишь под данные и стек. Такое
не исключено и при вызове ехе с , если окажется, что в памяти уже находится
процесс, использующий тот же код, который нужен новой программе.
По большей части работа менеджера процессов связана не с отслеживанием памя
ти, что делается при помощи списка свободных блоков и алгоритма выбора первого
подходящего блока, а с обслуживанием системных вызовов, относящихся к управ
лению памятью. Некоторые из системных вызовов обеспечивают работу сигналов
в стиле POSIX, а поскольку по умолчанию большинство таких сигналов завершают
процесс, имеет смысл обрабатывать их в менеджере процессов, инициирующем за
вершение всех процессов. Отдельные системные вызовы напрямую к работе с па
мятью не относятся, но также обрабатываются менеджером процессов в основном
из-за того, что он меньше файловой системы по объему и поместить их здесь удобнее.
В опросы и задания
1 . Компьютерная система имеет достаточно места для того, чтобы содержать в опе
ративной памяти четыре программы. Эти программы простаивают в ожида
нии ввода-вывода половину времени. Какая часть времени работы централь
ного процессора пропадает?
2. Рассмотрим систему подкачки, когда в памяти содержатся свободные участки
следующих размеров и в следующем порядке: 1 0 Кбайт, 4 Кбайт, 20 Кбайт,
18 Кбайт, 7 Кбайт, 9 Кбайт, 1 2 Кбайт и 15 Кбайт. Какой из них будет выбран
по алгоритму первого соответствия для успешного удовлетворения запроса
сегмента следующего размера:
1 ) 12 Кбайт;
2) 10 Кбайт;
3) 9 Кбайт.
Ответьте на тот же самый вопрос для алгоритмов наилучшего соответствия,
наихудшего соответствия и следующего соответствия.
3. У компьютера есть 1 Гбайт оперативной памяти, выделяемой блоками по
64 Кбайт. Сколько килобайтов занимает битовая карта, хранящая данные о сво
бодных блоках?
4. Рассмотрите предыдущий вопрос для случая, когда вместо битовой карты ис
пользуется список свободных блоков. Сколько памяти займет список в луч
шем и худшем случаях? Считайте, что операционная система занимает пер
вые 5 1 2 Кбайт памяти.
5. В чем разница между физическим адресом и виртуальным?
6. Опираясь на таблицу страниц на рис. 4.8, сосчитайте физический адрес, соот
ветствующий каждому из следующих виртуальных адресов:
1) 20;
2 ) 4 1 00;
3) 8300.
526 Глава 4 . Уп р авление памятью
7. На рис. 4.9 поле страницы виртуального адреса имеет разрядность 4 бита, а по
ле страницы физического адреса - 3 бита. Может ли число страничных битов
виртуального адреса в общем случае быть больше, меньше и равно числу битов
физического адреса? Объясните ответ.
8. Процессор Intel 8086 не поддерживает виртуальную память. Тем не менее не
которые компании ранее продавали системы, содержащие стандартный про
цессор 8086 и выполняющие замещение страниц. Предположите, как они это
делали. Подсказка: подумайте о логическом расположении блока управления
памятью (MMU).
9. Считая, что команда выполняется за 1 мкс, а ошибка отсутствия страницы
требует дополнительно п мкс, напишите выражение для фактического време
ни выполнения команды с учетом того, что ошибки происходят через каждые
k инструкций.
10. Компьютер имеет 32-разрядное адресное пространство и страницы размером
8 Кбайт. Таблица страниц целиком поддерживается аппаратно, на запись в ней
отводится одно 32-разрядное слово. При запуске процесса таблица страниц
копируется из памяти в аппаратуру, одно слово требует 1 00 нс. Если каждый
процесс работает в течение 1 00 мс (включая время загрузки таблицы страниц),
какая доля времени процессора жертвуется на загрузку таблицы страниц?
1 1 . Компьютер с 32-разрядным адресом использует двухуровневую таблицу стра
ниц. Виртуальные адреса расщепляются на 9-разрядное поле таблицы верх
него уровня, 1 1 -разрядное поле таблицы страниц второго уровня и смещение.
Чему равен размер страниц и сколько их в адресном пространстве?
12. Далее представлен алгоритм фрагмента программы для компьютера с разме
ром страницы 5 1 2 байт. Программа расположена по адресу 1 020, указатель
стека равен 8 1 92 (стек увеличивается по направлению к нулю). Напишите
последовательность страничных обращений, создаваемую этой программой.
Каждая инструкция занимает 4 байта (1 слово), включая непосредственные
константы. В последовательности обращений учитываются обращения как
к инструкциям, так и к данным.
Загрузить слово 6 1 44 в регистр О.
Поместить содержимое регистра О в стек.
Вызвать процедуру по адресу 5 1 20, поместив в стек адрес возврата.
Вычесть константу 16 из указателя стека.
Сравнить полученный результат с константой 4.
При равенстве перейти на адрес 5 152.
13. Предположим, что 32-разрядный виртуальный адрес разбивается на четыре
поля. Первые три используются для трехуровневой системы таблиц страниц.
Четвертое поле - это смещение. Зависит ли количество страниц от размера
всех четырех полей? Если нет, какие из полей имеют значение, а какие нет?
14. Компьютер, процессы которого имеют 1 024 страницы в своем адресном про
странстве, хранит таблицы страниц в памяти. На чтение слова из таблицы
Во п росы и задания 527
5 . 1 . Ф айлы
В следующих нескольких разделах файлы рассматриваются с точки зрения поль
зователя, то есть обсуждаются их использование и свойства.
5 . 1 . 1 . И м енование файлов
Файлы являются объектами абстрактного механизма. Они предоставляют сред
ство сохранения информация на диске и ее последующего считывания. При этом
от пользователя должны скрываться такие подробности, как способ и место хра
нения информации, а также детали работы дисков.
Вероятно, наиболее важной характеристикой любого абстрактного механизма
является то, как именуются управляемые объекты, поэтому мы начнем изучение
файловой системы с именования файлов. При создании файла процесс дает фай
лу имя. Когда процесс завершает работу, файл продолжает свое существование,
и по его имени к нему могут получить доступ другие процессы.
Правила именования файлов варьируются от системы к системе, но все совре
менные операционные системы поддерживают использование в качестве имен
файлов 8-символьных текстовых строк. То есть идентификаторы andrea, bruce
и c a thy являются допустимыми именами файлов. Часто в именах файлов также
разрешается употребление цифр и специальных символов, поэтому допустимы
и такие имена, как 2 , urgent ! и F i g . 2 - 1 4 . Многие файловые системы поддер
живают имена файлов длиной до 255 символов.
В некоторых файловых системах, например UNI X, различаются прописные
и строчные буквы, тогда как в других, таких как MS- DOS, нет. Таким образом,
имена mar i a , Mar i a и MARI A в системе UNIX указывают на три различных
файла, и в то же время в MS- DOS все три имени относятся к одному файлу.
532 Глава 5 . Файловые систем ы
5 . 1 . 2 . Структура файла
Файлы могут быть структурированы несколькими способами. Три типа струк
тур показаны на рис. 5 . 1 . Файл на рис. 5. 1 , а представляет собой неструктуриро
ванную последовательность байтов. В данном случае операционная система не
интересуется содержимым файла. Все, что она видит, - это байты. Значения этим
байтам присваиваются программами пользовательского уровня. Такой подход
характерен как для UNIX, так и для Windows 98.
Трактовка операционной системой файлов как просто последовательностей бай
тов обеспечивает максимальную гибкость. Пользовательские программы могут
помещать в файлы все что угодно и именовать их любым удобным для них спо
собом. Операционная система не вмешивается в э.тот процесс, что особенно цен
но для пользователей, собирающихся сделать что-либо необычное.
Первый шаг по направлению к структуризации иллюстрирует рис. 5 . 1 , б. В дан
ной модели файл представляет собой последовательность · эаписей фиксирован
ной длины, каждая со своей внутренней структурой. Для файлов, состоящих
534 Глава 5. Файловые систем ы
и з записей, важным является то, что операция чтения возвращает одну запись,
а операция записи обновляет или дополняет одну запись. Несколько десяти
летий назад, когда вовсю применялись перфокарты, состоящие из 80 колонок
отверстий, многие операционные системы (на мэйнфреймах) оперировали фай
лами, состоящими из 80-символьных записей - образов перфокарт. Этими опе
рационными системами поддерживались также файлы, составленные из 1 3 2 -
символьных записей, предназначенные для линейных принтеров (которые в те
дни печатали по 132 символа в строке). В результате программы читали из вход
ных файлов 80-символьные блоки и тут же расширяли их до 132 -символьных
блоков. Ни одна современная универсальная система не работает подобным
образом.
1 Байт 1 Запись
5 . 1 . З . Тип ы файлов
Многие операционные системы поддерживают различные типы файлов. Напри
мер, в системах UNIX и Windows проводится различие между обычными файла
ми и каталогами. Кроме того, в UNIX различают символьные и блочные специ
альные файлы. Windows ХР также использует файлы метаданных, которые мы
рассмотрим позднее. К обычным (regular) файлам относятся все файлы, содер
жащие пользовательскую информацию. Все файлы на рис. 5. 1 являются просто
файлами. Каталоzи - это системные файлы, обеспечивающие структуризацию
файловой системы. Позже мы рассмотрим их подробнее. Символьные специаль
ные файл ы имеют отношение к вводу-выводу и используются для моделирова
ния последовательных устройств ввода-вывода, таких как терминалы, принтеры
и сети. Блочные специальные файлы находят применение при моделировании
дисков. В данной главе в основном рассматриваются обычные файлы.
Обычные файлы, как правило, являются либо АSСП-файлами, либо двоичны
ми файлами. ASCII -файлы содержат текстовые строки. В некоторых системах
каждая АSСП -строка завершается символом возврата каретки. В других (на
пример, UNIX) используется символ перевода строки. Есть системы (напри
мер, Windows), где требуются оба символа. Строки не обязаны иметь одну и ту
же длину.
Главным преимуществом АSСП-файлов является то, что они могут отображать
ся на экране и выводиться на печать «как есты" без какого-либо преобразования,
и редактироваться любым текстовым редактором. Более того, если несколько
программ использует АS С П - файлы для ввода и вывода, несложно соединить
вход одной программы с выходом другой, как это делается в конвейерах оболоч
ки. ( Обмен данными между процессами не становится проще, но интерпретация
информации облегчается, если ее представление стандартизировано.)
Помимо АSСП-файлов существуют двоичные файлы. При выводе их на принтер
получается невразумительный набор символов. Но в действительности у них
есть некая внутренняя структура, известная использующей их программе.
Например, на рис. 5.2, а показан простой исполняемый двоичный файл, входя
щий в одну из версий UNIX. Хотя технически любой файл представляет собой
всего лишь последовательность байтов, операционная система станет исполнять
его только в том случае, если он имеет соответствующий формат. Файл состоит
из пяти разделов: заголовка, текста, данных, данных переадресации и символь
ной таблицы. Заголовок начинается с так называемого маzическоzо числа, и:ден
тифицирующего файл как исполняемый (чтобы предотвратить случайный «За
пуск• файла другого формата). Следом за сигнатурой в заголовке располагаются
поля с размерами различных частей файла, адресом точки входа файла и некото
рые флаги. За заголовком следуют текст программы и данные. Они загружаются
в оперативную память и настраиваются на работу по адресу загрузки при помо
щи битов переадресации. Символьная таблица используется для отладки.
Второй пример двоичного файла представляет собой архив в системе UNIX. Он
состоит из набора библиотечных процедур (модулей), откомпилированных, но
536 Глава 5. Файловые системы
«Магическое» число
/ Имя модуля
т
Заголовки
Размер текста
Размер данных Дата
s
" Размер
111
о релокационного блока Владелец
еС\1 Размер таблицы Объектный
С') символов модуль Защита
1
Точка входа Размер
Флаги Заголовки
Текст
l l
Объектный
модуль
Данные Заголовки
I Биты релокации I
I Таблица
символов
I Объектный
модуль
1 J
а б
Рис. 5 . 2 . Структура двоичного файла: а - исполняемый файл; б архив
-
5 . 1 4 Доступ к файлам
. .
5 . 1 . 5 . Атрибуты файлов
У каждого файла есть имя и данные. Помимо этого, все операционные системы
связывают с каждым файлом другую информацию, например дату и время со
здания файла, а также его размер. Мы будем называть эти дополнительные све
дения атрибутами файлов, хотя их иногда обозначают термином метаданные.
Список атрибутов значительно варьируется от системы к системе. В табл. 5.2
показаны некоторые возможные атрибуты, однако существуют и другие. На
практике ни в одной операционной системе не используются сразу все приве
денные в таблице атрибуты файлов, но каждый из них можно встретить в той
или иной системе.
резервирование
Флаг АSСll/двоичный О ASCll; 1 двоичный
- -
пользователь должен для получения доступа к файлу указать пароль. В этом слу
чае пароль должен входить в атрибуты файла.
Флаги представляют собой отдельные биты или короткие битовые поля, управляю
щие некоторыми специфическими свойствами. Например, скрытые файлы не по
являются в перечне файлов при распечатке каталога. Флаг архивации представляет
собой бит, следящий за тем, была ли создана для файла резервная копия. Этот
флаг очищается программой архивирования и устанавливается операционной
системой при изменении файла. Таким образом, программа архивирования мо
жет определить, какие файлы следует архивировать. Временный файл можно ав
томатически удалить по окончании работы создавшего файл процесса.
Атрибуты длины записи, позиции ключа и длины ключа присутствуют только
у тех файлов, записи которых могут искаться по ключу.
Различные атрибуты, хранящие значения времени, позволяют следить за тем,
когда файл был создан, когда в последний раз он был изменен, когда к нему в по
следний раз предоставлялся доступ. Эти сведения можно использовать в различ
ных целях. Например, если исходный файл программы был модифицирован по
сле создания соответствующего ему объектного файла, данный исходный файл
должен быть перекомпилирован.
В качестве текущего размера файла указывается количество байтов в файле в на
стоящий момент. В некоторых старых операционных системах мэйнфреймов
при создании файла требовалось указать также максимальную длину файла, что
позволяло операционной системе зарезервировать достаточно места для его по
следующего увеличения. Современные операционные системы, работающие на
персональных компьютерах, умеют обходиться без подобного резервирования.
5 . 1 6 Операци и с файлами
. .
Создание файла. Файл создается без данных. Этот системный вызов объявля
ет о появлении нового файла и позволяет установить некоторые его атрибуты.
de l e t e
Удаление файла. Когда файл уже более н е нужен, его удаляют, чтобы освобо
дить пространство на диске. Этот системный вызов поддерживается во всех
операционных системах.
open
Открытие файла. Прежде чем использовать файл, процесс должен его открыть.
Системный вызов open позволяет системе считать в оперативную память ат
рибуты файла и список дисковых адресов для быстрого доступа к содержимо
му файла при последующих вызовах.
540 Глава 5. Файловые системы
close
lock
5 . 2 . Каталоги
В файловых системах файлы обычно организуются в каталоzи, или папки, ко
торые, в свою очередь, в большинстве операционных систем также являются
файлами. В данном разделе мы рассмотрим каталоги, их организацию, свойства
и действия, которые могут быть выполнены с ними.
5 . 2 . 1 . П ростые каталоги
Обычно каталог содержит некоторое число записей, по одной записи на файл.
Один из вариантов показан на рис. 5.3, а, где каждая запись каталога включает
в себя имя файла, его атрибуты и адрес данных файла на диске. Другой вариант
представлен на рис. 5.3, б. Здесь запись каталога хранит имя файла и указатель
на структуру данных с атрибутами и дисковыми адресами. Широко применяют
ся оба этих варианта.
а б
Структура данных,
содержащая атрибуты
Рис. 5 . 3 . Организация каталогов:
а - атрибуты хранятся в каталоге;
б - атрибуты хранятся отдельно
Когда открывается файл, операционная система ищет его запись в каталоге. Затем
она извлекает и загружает в память атрибуты и дисковые адреса либо из самой
записи, либо из структуры, на которую запись ссылается. При всех последую
щих обращениях к файлу используется информация из памяти.
Количество каталогов меняется от системы к системе. В простейшем варианте име
ется один каталог, в котором хранятся все файлы всех пользователей (рис. 5.4, а ) .
Подобные системы бьши распространены в ранних персональных компьютерах,
отчасти потому, что компьютеры были однопользовательскими.
542 Глава 5. Файл овые с и стемы
О Каталог Q Файл
а б в
5 . 2 . 3 . Пути
При организации файловой системы в виде дерева каталогов требуется некий
способ указания файла. Для этого обычно используют два метода. В первом слу
чае обращение к файлу выполняется по абсолютному пути, составленному из
имен всех каталогов от корневого до того, в котором содержится файл, и имени
самого файла. Например, путь / u s r / a s t / m a i lbox означает, что корневой ка
талог содержит подкаталог u s r, в который, в свою очередь, вложен подкаталог
a s t , где находится файл mai lbox. Абсолютные пути всегда начинаются от кор
невого каталога и являются уникальными. В UNI X компоненты пути разделяют
ся косой чертой ( / ). В Windows в качестве разделителя принята обратная косая
черта ( \ ) . Таким образом, одно и то же имя пути в этих операционных системах
будет выглядеть следующим образом:
+ Windows:
\ u s r \ a s t \mai lbox
+ UNIX:
/ u s r / a s t / ma i lbox
Относительная форма задания пути часто оказывается более удобной, хотя она
подразумевает то же, что и абсолютная.
Некоторым программам требуется доступ к файлам независимо от того, какой
каталог является в данный момент текущим. В этом случае они всегда должны
указJ>Iвать абсолютные имена. Например, программе проверки правописания может
понадобиться для выполнения работы прочитать файл / u s r / l i Ь / di c t i onary.
В этом случае она должна использовать абсолютное имя файла, поскольку за
ранее неизвестно, каким будет рабочий каталог при ее вызове. Абсолютное
имя файла будет работать всегда, независимо от того, какой каталог является
текущим.
Если программе проверки правописания понадобится большое количество фай
лов из каталога /usr / l ib, она может, обратившись к операционной системе, поме
нять рабочий каталог на / us r / l ib, после чего указывать просто имя di c t i onary
в качестве первого аргумента системного вызова op en. Явно указав свой рабо
чий каталог, программа может использовать в дальнейшем относительные име
на, поскольку точно знает, где она находится в дереве каталогов.
У каждого процесса есть свой рабочий каталог, поэтому, когда процесс меняет
свой рабочий каталог и потом завершает работу, это не влияет на работу других
процессов, и в файловой системе не остается никаких следов от подобных изме
нений. Таким образом, процесс может без опасений менять свой рабочий ката
лог, когда это ему удобно. С другой стороны, если библиотечная процедура по
меняет свой рабочий каталог и не восстановит его при возврате управления,
программа, вызвавшая такую процедуру, может оказаться не в состоянии про
должать свою работу, так как ее предположения о текущем каталоге окажутся
неверными. По этой причине библиотечные процедуры редко меняют рабочие
каталоги, а когда все-таки меняют, обязательно восстанавливают старое имя пе
ред возвратом управления.
Большинство операционных систем, поддерживающих иерархические катало
ги, имеют специальные записи в каждом каталоге, означающие текущий ( ) .
Корневой каталог
5 . 2 . 4 . Операции с каталогами
Системные вызовы, управляющие каталогами, значительно отличаются о т сис
темы к системе (в отличие от системных вызовов для работы с файлами). Чтобы
дать представление о том, что они собой представляют и как выполняются, при
ведем следующий пример (взятый из UNI X).
c re a t e
Удаление каталога. Может бьпь удален только пустой каталог. Записи точка ( )
.
opendi r
Открытие каталога. После этой операции каталог может быть прочитан. На
пример, для распечатки всех файлов каталога программа, создающая список,
открывает каталог, чтобы прочитать имена всех содержащихся в нем файлов.
Прежде чем каталог может быть прочитан, его следует открыть, подобно от
крытию и чтению файла.
c l o sedir
Закрытие каталога. Когда каталог прочитан, его следует закрыть, чтобы осво
бодить место во внутренней таблице системы.
readd i r
un l i nk
Н еразрывные файлы
Простейшей схемой выделения файлам определенных блоков на диске являет
ся система, в которой файлы представляют собой наборы смежных блоков диска.
Тогда на диске с блоками по 1 Кбайт файл размером в 50 Кбайт будет занимать
50 последовательных блоков. У неразрывных файлов есть два существенных пре
имущества. Во-первых, такую модель легко реализовать, так как системе, чтобы
определить, какие блоки принадлежат тому или иному файлу, нужно следить всего
лишь за двумя числами: номером первого блока файла и числом блоков в файле.
Зная первый блок файла, любой другой его блок легко получить при помощи
простой операции сложения.
Во-вторых, при работе с неразрывными файлами производительность просто
превосходна, так как весь файл может быть прочитан с диска за одну операцию.
Требуется только одна операция позиционирования (для первого блока). После
этого более не нужно искать цилиндры и тратить время на ожидание поворота
диска, поэтому данные могут считываться с максимальной скоростью, на какую
способен диск. Таким образом, непрерывные файлы легко реализуются и для
них характерна высокая производительность.
К сожалению, неразрывные файлы имеют и серьезный недостаток: их использо
вание ведет к фрагментации дисков. Поначалу фрагментация не является про
блемой, поскольку каждый новый файл можно записать сразу следом за преды
дущим. Однако в конечном счете диск заполнится, и возникнет необходимость
550 Глава 5 . Файловые системы
Связанные списки
Второй метод размещения файлов состоит в представлении каждого файла в ви
де связанного списка блоков диска (рис. 5.7). Первое слово каждого блока явля
ется указателем на следующий блок. В остальной части блока хранятся данные.
Файл А
Физический
блок
о
1
2 10
3 11
4 7 ..__ Файл А начинается здесь
5
6 3 ..__ Файл В начинается здесь
7 2
8
9
10 12
11 14
12 -1
13
14 -1
15 � Неиспользуемый блок
Рис . 5 . 8 . Таблица размещения файлов
552 Глава 5. Файловые систем ы
При такой организации все блоки доступны для данных. Кроме того, значитель
но упрощается произвольный доступ. Хотя для обращения к какому-либо блоку
файла все равно понадобится проследовать по цепочке всех ссылок вплоть до
требуемого блока, в данном случае вся цепочка ссылок уже хранится в памяти и
ее прохождение не требует дополнительных дисковых операций. Как и в преды
дущем случае, для доступа ко всем частям файла в каталоге достаточно хранить
один целый индекс (номер начального блока файла).
Основной недостаток этого метода состоит в том, что вся таблица должна по
стоянно находиться в памяти. Для 20-гигабайтного диска с блоками размером
1 Кбайт потребовалась бы таблица из 20 ООО ООО записей, по одной для каждого
из 20 ООО ООО блоков диска. Каждая запись должна состоять как минимум из
3 байт. Для ускорения поиска размер записей должен быть увеличен до 4 байт.
Таким образом, резидентная таблица будет занимать 60 или 80 Мбайт опера
тивной памяти. Таблица, конечно, может быть размещена в виртуальной памяти,
но и в этом случае она продолжит занимать большой объем виртуальной па
мяти и дискового пространства, а кроме того, приведет к генерации страничного
трафика. Операционные системы M S - D O S и Windows 98 используют только
файловые системы F АТ; более поздние версии Windows также предоставляют
их поддержку.
И ндексные узл ы
Последний метод соотнесения блоков диска файлам заключается в связывании
с каждым файлом структуры данных, называемой индексным узлом (index node),
или i-узлом (i-node), содержащей атрибуты файла и адреса блоков файла. Про
стой пример индексного узла показан на рис. 5.9. При наличии индексного узла
можно найти все блоки файла. Большое преимущество такой схемы перед хра
нящейся в памяти таблицей из списков состоит в том, что индексный узел ока
зывается в памяти только тогда, когда открыт соответствующий ему файл. Если
каждый индексный узел занимает п байт, а одновременно открыть можно k фай
лов, для массива индексных узлов в памяти потребуется всего kn байт.
Обычно эта величина значительно меньше, чем размер таблицы F АТ. Это легко
объясняется. Размер таблицы, хранящей список всех блоков диска, пропорцио
нален емкости самого диска. Для диска из п блоков потребуется п записей в таб
лице. Таким образом, размер таблицы линейно растет с ростом размера диска.
Для схемы индексных узлов, напротив , требуется массив в памяти с разме
ром, пропорциональным максимальному количеству файлов, которые можно
открыть одновременно. При этом не важно, какой именно размер диска, 1, 1 0
или 1 0 0 Гбайт.
С такой схемой связана проблема, суть которой в том, что при выделении каждо
му файлу фиксированного количества дисковых адресов этого количества может
не хватить. Одно из решений заключается в резервировании последнего дис
кового адреса не для блока данных, а для адреса косвенноzо блока, содержащего
адреса блоков диска. Этот принцип можно расширить и ввести блоки с двойным
и тройным уровнем косвенности, как показано на рис. 5.9.
5. 3 . Реализация файловой системы 553
1-узел
Атрибуты Однократный
Адреса
блоков
С этой проблемой тесно связан вопрос хранения атрибутов файла. Каждая фай
ловая система поддерживает различные атрибуты файла, такие как дату созда
ния файла, имя владельца и т. д" и всю эту информацию нужно где-то хранить.
Один из очевидных вариантов - поместить эти сведения непосредственно в за
пись каталога. В простейшем случае каталог представляет собой список записей
фиксированного размера, по одной записи на файл, содержащих имя файла фик
сированной длины, структуру атрибутов и один или несколько дисковых адре
сов (не более определенного максимума), определяющих расположение блоков,
как мы видели на рис. 5.3, а.
Системы с индексными узлами могут хранить атрибуты в индексных узлах, а не
в записях каталога, как на рис. 5.3, б. В этом случае запись каталога короче: она
содержит только имя файла и номер индексного узла.
Общие файл ы
В главе 1 мы кратко упомянули о связях между файлами, например, одного проекта,
упрощающих совместную работу с ними нескольких пользователей. На рис. 5. 1 О
показана файловая система с рис. 5.4, в, однако теперь один из файлов пользова
теля С присутствует также в одном из каталогов пользователя В.
Общий файл
Ри с . 5. 1 О. Файловая система, содержащая общий файл
на индексный узел другой файловой системы. Кроме того, файл может иметь
только одного владельца и один набор разрешений. Если владелец совместно ис
пользуемого файла удалит его запись из своего каталога, не исключено, что дру
гой пользователь лишится возможности удалить этот файл из своего каталога
(при отсутствии соответствующего разрешения).
Альтернативным способом совместного использования файлов является созда
ние нового типа файла, содержимое которое представляет собой путь к другому
файлу. Такой вид связи работает для монтируемых файловых систем. Более то
го, если в путях существует возможность указывать сетевые адреса, можно орга
низовать связь с файлом, расположенным на другом компьютере. В UNIX этот
вид связи называется символьной связью, в Windows - ярлыком, а в Мае OS фир
мы Apple - псевдонимом. Символьные связи могут применяться в системах, где
атрибуты хранятся в записях каталогов. Несложно понять, что синхронизация
множества записей каталогов, которые содержат атрибуты, - непростая задача.
Любое изменение, внесенное в файл, затрагивает все соответствующие ему за
писи каталогов. Недостатком символьных связей является то, что при удалении
и даже при переименовании целевого файла они становятся недействительными.
Катало г и в Wi ndows 98
Файловая система в начальной редакции Windows 95 была идентична файловой
системе MS-DOS, однако уже во второй редакции была организована поддержка
длинных имен файлов и файлов большего объема. Мы будем ссылаться на вторую
версию файловой системы как на файловую систему Windows 98, хотя ее можно
найти и на некоторых компьютерах, работающих под управлением Windows 95 .
В Windows 98 поддерживаются два типа записей каталогов; первую из них
(рис. 5. 1 1 ) мы будем называть базовой записью.
Байты 8 3 1 1 1 4 2 2 4 2 4
Базовое имя Расш. NT Дата/время Последний Дата/время Размер
создания доступ последней записи файла
Атрибуты�
Десятые доли t t
Старшие 1 6 бит t
Младшие 1 6 бит
времени создания начального блока начального блока
Рис. 5 . 1 1 . Базовая запись каталога в Windows 98
Байты 1 10 1 1 1 12 2 4
11 5 символов 1111 6 символов 1 1 2 символа
Последовательность
1 Атрибуты
1 \Контрольная
сумма
Рис. 5 . 1 2 . Запись (частичная) для длинного имени файла в Windows 98
Если все это кажется сложным, мы, пожалуй, согласимся с вами. Обеспечение
обратной совместимости с более ранними и простыми системами в сочетании с
новыми возможностями приводит к хаосу. Несомненно, борцы за чистоту идей
выступят против хаоса, но едва ли смогут разбогатеть на новых версиях операци
онных систем.
Катало г и в U N IX
В UNIX применяется исключительно простая структура каталогов (рис. 5. 13).
Здесь каждая запись состоит из имени файла и номера индексного узла. Вся ос
тальная информация, о размере файла, его типе, владельцах, времени изменения
и занимаемых им дисковых блоках, хранится в индексном узле. В некоторых
UNIХ-подобных системах применяется другая схема, но, в любом случае, за
пись каталога состоит исключительно из АSСП-строки и номера индексного узла.
Байты 2 14
Имя файла
Номер
i-узла
Рис. 5 . 1 З. Запись каталога в UNIX версии 7
Когда открывается файл, файловая система должна найти на диске указанное ей
имя файла. Рассмотрим, как будет происходить поиск файла / u s r / a s t / rnbox.
5. 3 . Реализаци я файл о в о й системы 557
1-узел 26
1-узел 6 содержит
содержит Блок 1 32 данные Блок 406
данные содержит о каталоге содержит
Корневой каталог о каталоге /usг каталог 1 32 /usг/ast каталог /usr/ast
1 .
Режимный код 6 .
Режимный код 26 .
1 . . Размер 1 . . Размер 6 . .
Катало г и в NTFS
Текущей файловой системой для продуктов Microsoft на сегодняшний день явля
ется NТFS (New Technology File System - файловая система новой технологии).
Рамки этой книги не предусматривают ее детального описания, однако некото
рые проблемы, с которыми сталкивается NТFS, и их решениями мы ознакомимся.
Одна из проблем - длинные имена файлов и путей. NТFS поддерживает длин
ные имена файлов (до 255 символов) и путей (до 32 767 символов). Поскольку
предшествующие версии Windows в любом случае не способны читать файло
вую систему NТFS, сложная структура каталогов с обратной совместимостью не
нужна, и поле имени имеет переменную длину. Также предоставляется поддерж
ка второго имени в формате 8 + 3, позволяющая устаревшим системам получать
доступ к NТFS-файлам по сети.
NТFS предусматривает использование в именах файлов различных алфавитов
с помощью кодировки Unicode. В Unicode каждый символ занимает 16 бит; это
го достаточно для представления множества языков с очень большими алфави
тами (например, японского языка). Однако помимо представления алфавитов,
многоязычности присущи и другие проблемы. Даже среди языков, использующих
латиницу, имеются свои тонкости. Так, в некоторых языках (к примеру, в испан
ском) определенные комбинации двух символов при сортировке считаются од
ним символом. Слова, начинающиеся с префиксов �ch� и �н�, должны следовать
после слов, начинающихся соответственно с префиксов �cz� и �1z� . Еще сложнее
проблема чувствительности к регистру. Если по умолчанию имена файлов чув
ствительны к регистру, иногда может возникать необходимость в организации
нечувствительного к регистру поиска. Для языков на основе латиницы решение
проблемы очевидно, по крайней мере, их носителям. Если поддерживается только
один язык, правила очевидны, однако Unicode позволяет смешивать различные
языки. В многонациональной организации один и тот же каталог может содер
жать имена файлов на греческом, русском и японском языках. В качестве реше
ния проблемы в NТFS введен атрибут файла, определяющий соглашения о реги
стре для языка, на котором написано его имя файла.
С помощью дополнительных атрибутов в NТFS решено много задач. Если в UNIX
файл представляет собой последовательность байтов, то в NТFS - коллекцию
атрибутов, где каждый атрибут является потоком байтов. Базовая структура дан
ных NТFS - главная таблица файлов (Master File ТаЫе, MFT). Она поддержи
вает 16 атрибутов, каждый из которых может иметь длину до 1 Кбайт. Если этого
недостаточно, атрибут можно использовать в качестве заголовка, указывающего
на дополнительный файл с расширенными значениями атрибута. Такой атрибут
называется нерезидентным. Сама таблица MFT представляет собой файл и со
держит запись для каждого файла и каталога файловой системы. Поскольку ее
объем может значительно вырасти, при создании NТFS около 1 2,5 % пространст
ва раздела резервируется под MFT. Благодаря резервированию MFT не фраг
ментируется как минимум до тех пор, пока все зарезервированное пространст
во не будет исчерпано. В последнем случае для MFT резервируется еще одна
5.3 . Реализация файловой системы 559
область. Таким образом, даже если таблица MFT фрагментирована, она состоит
из очень небольшого числа крупных блоков.
Как же в NTFS обстоит дело с данными? Данные попросту представляют собой
один из атрибутов файла. На самом деле, NТFS-файл может содержать несколь
ко потоков данных. Изначально эта возможность позволяла Windows-cepвepaм
обслуживать файлы клиентов Apple Maclntosh. В исходной операционной систе
ме Maclntosh (до Мае OS 9) все файлы имели два потока данных. Эти потоки
назывались <1:ветвь ресурсов• и <1:ветвь данных• . Множественные потоки данных
имеют и другие применения; например, для большого графического файла можно
хранить его уменьшенный эскиз. Максимальный объем потока составляет 264 бай
та. В то же время система NTFS способна хранить содержимое небольших файлов
(до нескольких сотен байтов) в заголовке атрибута. Такие файлы называются
непосредственными [9 1 ) .
М ы лишь слегка затронули несколько подходов, позволяющих NTFS решать про
блемы, не решенные более старыми и простыми файловыми системами. NTFS
также предоставляет и другие возможности: сложную систему защиты, шифро
вание и сжатие данных. Их описание, как и описание их реализации, занимает
гораздо больше места, чем мы можем позволить себе в этой книге. Более деталь
ное рассмотрение NTFS вы найдете в [ 1 1 5 ) . Кроме того, дополнительную инфор
мацию можно поискать в Интернете.
Размер блока
После принятия решения о хранении файлов блоками фиксированного размера
возникает вопрос о размере блоков. Учитывая организацию дисков, очевидными
кандидатами на роль блоков являются сектор, дорожка и цилиндр диска (недос
татком такого выбора является зависимость этих параметров от устройств). В сис
теме управления страницами памяти страницы также входят в число основных
560 Глава 5. Файловые системы
кандидатов. Если выбрать большую единицу хранения, такую как цилиндр, это
будет означать, что любой файл, даже состоящий из одного байта, займет как ми
нимум целый цилиндр.
В то же время при маленьких единицах хранения каждый файл будет состоять
из большого числа блоков. Для чтения каждого блока файла обычно требуется
операция поиска нужного цилиндра и ожидание поворота диска, поэтому чтение
файла, состоящего из большого числа блоков, окажется медленным.
Например, представьте себе диск, в котором каждая дорожка содержит 131 072 байт
( 128 Кбайт), период вращения составляет 8,33 мс, а среднее время поиска - 1 0 мс.
При этом время, требующееся для чтения блока из k байт, равно сумме времен
поиска, поворота и переноса данных:
10 + 4 , 1 65 + (k/13 1 072) х 8,33.
Сплошная кривая на рис. 5 . 1 5 показывает зависимость скорости передачи дан
ных от размера блока.
Использование \
\ cli
�Ф � 800 дискового пространства \
\
\ 80 ф
111
!3
>S \ :s; :i::
� со :i:: со
,_ ' со а.
'8 � 600 ' 60 111
!3
�
.11 - '
'
t3 �:Jj ' 8.
о •, ' § i::
g- � 400 ,
,
40 i:: е
U o
:s: 111
с) � �
200 20 u
:s;
i::[
O L_,�
�d::==�====I...�--1.��J_�_L��l___J O
о 128 256
1К 2К 51 2
4К 8К 1 6К О
Размер блока, в байтах
Рис. 5 . 1 5 . Зависимость скорости чтения/записи данных диска (сплошная линия, левая
шкала) и эффективности использования дискового пространства (штриховая линия,
правая шкала) от размера блоков. Все файлы по 2 Кбайт
Чтобы вычислить эффективность использования дискового пространства, нам
необходимо сделать предположение о среднем размере файла. Одно из старых
исследований показало, что средний размер файла в системе UNIX составляет
около 1 Кбайт [9 1 ) . В 2005 году в отделе, где работает один из авторов, был про
изведен подсчет для более чем 1 млн дисковых UNIX -файлов и 1 ООО пользова
телей. Медианный размер составил 2475 байт; это означает, что половина фай
лов имеет меньший размер, а половина - больший. Медианный размер является
лучшим показателем, чем средний, поскольку на среднее значение могут оказы
вать влияние всего лишь несколько файлов (например, руководства для аппа
ратных устройств размером по 100 Мбайт или демонстрационные видеоролики),
а на медианное - нет.
5.3. Реал изация файловой системы 561
1 052 689 блоков, чтобы охватить все 2 2 8 дисковых блока. Часто список свобод
ных блоков хранится в самих свободных блоках.
�
, :� :� :� :� :�
Резервные копии
Большинство пользователей считают создание резервных копий файлов просто
потерей времени. Однако когда в один прекрасный день диск внезапно отказы
вается работать, они диаметрально меняют свои привычки. Компании, напротив,
обычно хорошо осознают ценность своей информации и выполняют резервное
копирование один раз в сутки, чаще всего на магнитную ленту. Современные
магнитные ленты вмещают десятки и иногда даже сотни гигабайтов при стоимо
сти в несколько центов за гигабайт. Однако создание резервных копий является
далеко не столь тривиальным делом, как это может показаться, поэтому мы кос
немся некоторых аспектов данной темы.
Как правило, резервирование на магнитную ленту осуществляется для решения
одной из двух потенциальных проблем: восстановления после аварии и вос
становления после глупой ошибки. В первом случае требуется вернуть компью
тер в работоспособное состояние после отказа диска, пожара, потопа или другой
природной катастрофы. На практике такие вещи происходят довольно редко,
и именно поэтому многие пользователи не заботятся о резервировании. Как
правило, в силу той же причины они не страхуют свое имущество от пожара.
Второй случай наступает тогда, когда пользователи случайно удаляют нужные
им файлы. Это происходит настолько часто, что разработчики Windows придума
ли специальный каталог, называемый корзиной (гесусlе Ьin), куда на самом деле
перемещается удаляемый файл и где он впоследствии может быть легко обнаружен
и восстановлен. Резервные копии являются развитием этого принципа и позво
ляют восстанавливать файлы, удаленные несколько дней или даже недель назад.
Создание резервной копии отнимает много времени и требует большого про
странства, поэтому важно, чтобы этот процесс был эффективным и удобным.
Возникает ряд вопросов, и первый из них - следует резервировать файловую
систему целиком или лишь ее часть? Зачастую исполняемые (двоичные) про
граммы содержатся в ограниченной части дерева файловой системы; резервиро
вать их не обязательно, поскольку такие файлы можно восстановить с компакт
дисков производителей. Кроме того, большинство систем имеют каталог времен
ных файлов, и резервировать его также не имеет смысла. В UNIX все специаль
ные файлы (устройства ввода-вывода) содержатся в каталоге / dev / . Резерви
рование этого каталога не только не обязательно, а попросту опасно, поскольку
программа резервирования при попытке считывания файлов зависнет. Короче
говоря, чаще всего предпочтительнее создавать резервные копии содержимого
отдельных каталогов, нежели копировать всю файловую систему.
5.3 . Реализация файловой системы 565
Номер блока
о 1 2 3 4 5 6 7 8 9 1 0 11 121 3141 5
Занятые
l 1 l 1 l o l 1 l o l 1 l 1 l 1 l 1 l o l o l 1 l 1 l 1 l o l o l блоки
Свободные
l o l o l 1 l o l 1 l o l o l o l o l 1 l 1 l o l o l o l 1 l 1 I блоки
а
Номер блока
о 1 2 3 4 5 6 7 8 9 1 0 11 1 21 3141 5
Занятые
l 1 l 1 l o l 1 l o l 1 l 1 l 1 l 1 l o l o l 1 l 1 l 1 l o l o l блоки
Свободные
l o l o l o l o l 1 l o l 0 J o l o l 1 l 1 l o l o l o l 1 l 1 I блоки
б
о 1 2 3 4 5 6 7 8 9 1 0 1 1 121 3141 5
Занятые
1l l 1 l o l 1 l o l 1 l 1 l 1 l 1 l o l o l 1 l 1 l 1 l o l o J блоки
Свободные
l o l o l 1 l o l 2 l o l o l o l o l 1 l 1 l o l o l o l 1 l 1 I блоки
в
о 1 2 3 4 5 6 7 8 9 1 0 11 121 3141 5
l 1 l 1 l o l 1 l o l 2 l 1 l 1 l 1 l o l o l 1 l 1 l 1 l o l o l Занятые
блоки
l o l o l 1 l o l 1 l o l o l o l o l 1 l 1 l o l o l o l 1 l 1 I Свободные
блоки
г
Тогда программа rrn удалит все файлы в текущем каталоге, после чего сообщит,
что не может найти файл с расширением о. В системе MS-D O S и некоторых дру
гих системах при удалении файла устанавливается всего лишь один бит в ката
логе или индексном узле, отмечая, что файл удален. Блоки диска не возвращаются
в список свободных блоков до тех пор, пока они не понадобятся. Таким образом,
если пользователь быстро обнаружит ошибку, он сможет восстановить удален
ные файлы. В Windows удаленные файлы обычно помещаются в корзину, откуда
их можно при необходимости извлечь. При этом свободное пространство на дис
ке не увеличивается до тех пор, пока корзина не будет очищена.
Подобные механизмы не являются безопасными. В безопасной системе при уда
лении с диска блоки данных заполняются нулями или случайными числами,
чтобы не дать возможность другому пользователю восстановить информацию.
Многие пользователи даже не подозревают, насколько �живучими• могут быть
данные. Конфиденциальные или важные данные зачастую удается восстановить
даже с утилизированных дисков [48] .
Кэширование
Для минимизации количества обращений к диску применяется блочный, или бу
ферный, кэш. (Термин �кэш• происходит от французского слова cacher, что зна
чит �скрывать•.) В данном контексте кэшем называется набор блоков, логически
принадлежащих диску, но хранящихся в оперативной памяти по соображениям
производительности.
Существуют различные алгоритмы кэширования. Обычная практика заключается
в перехвате всех запросов чтения к диску и поиске требующихся блоков в кэше.
Если блок присутствует в кэше, то запрос чтения блока может быть удовлетворен
572 Глава 5. Файловые систем ы
Более того, к некоторым блокам, таким как блоки индексных узлов, программы
редко обращаются дважды в течение короткого интервала времени. Исходя из
этих соображений, мы приходим к модифицированной схеме LRU, принимая во
внимание два вопроса.
1. Насколько велика вероятность того, что данный блок скоро снова понадобится?
2. Важен ли данный блок для непротиворечивости файловой системы?
Для ответа на каждый из поставленных вопросов блоки можно разделить на ка
тегории, такие как блоки индексных узлов, �косвенные• блоки (блоки косвен
ной адресации), блоки каталогов, блоки, целиком заполненные данными, и бло
ки, частично заполненные данными. Блоки, которые, вероятно, не потребуются
снова в ближайшее время, помещаются в начало LR U-списка, чтобы занимаемые
ими буферы могли вскоре освободиться. Блоки, вероятность повторного исполь
зования которых в ближайшее время высока (например, частично заполненные
записываемые блоки), заносятся в конец LRU-списка, что позволяет им дольше
оставаться в кэше.
Второй вопрос не связан с первым. Если блок представляет важность для непро
тиворечивости файловой системы (обычно это все блоки, кроме блоков данных)
и такой блок модифицируется, то его следует немедленно сохранить на диске,
независимо от его положения в LRU-списке. Своевременно записывая критиче
ски важные блоки, мы значительно снижаем вероятность того, что сбой компью
тера повредит файловую систему. Пользователь вряд ли будет рад потере одного
из своих файлов из-за какого-то сбоя. Еще сильнее он огорчится, если при этом
испорченной окажется вся файловая система.
Даже при принятии всех перечисленных мер предосторожности по поддержанию
в рабочем состоянии файловой системы слишком долгое хранение в кэше блоков
с данными является нежелательным. Представьте себе автора будущей книги,
подготавливаемой на персональном компьютере. Даже если наш писатель перио
дически велит текстовому редактору сохранять редактируемый файл на диске,
есть большая вероятность, что все блоки останутся в кэше. Если произойдет сбой,
структура файловой системы не пострадает, но труд целого дня будет потерян.
Эта ситуация случается не слишком часто, и если случается, то только с очень
невезучими пользователями. Для решения данной проблемы обычно применяет
ся два метода. В системе UNIX есть вызов sync , принуждающий сохранить все
модифицированные блоки кэша на диске. При загрузке операционной системы
запускается фоновая программа, обычно под названием upda t e, вся работа
которой заключается в периодическом (обычно через каждые 30 с) обращении
к системному вызову sync . В результате при любом сбое будет потеряно не бо
лее полминуты работы.
В Windows практикуется другой подход, состоящий в том, что каждый модифи
цированный блок записывается на диск сразу же. Кэш, в котором все модифици
рованные блоки немедленно записываются на диск, называется сквозным кэшем ,
или кэшем со сквозной записью. При использовании сквозного кэша количество
обращений ввода-вывода к диску больше, чем при применении обычного кэша.
Чтобы лучше понять разницу в этих двух подходах, представьте себе программу,
574 Глава 5. Файловые системы
а б
Уменьшение количества перемещений головки диска:
Рис. 5 . 1 9 . индексные узлы,
а -
5 . 3 . 7. Файловые системы
с жу рнал ьной структурой
Изменения в технологии оказывают влияние на современные файловые систе
мы. В частности, центральные процессоры становятся все быстрее, диски - все
вместительнее и дешевле (при этом скорость доступа хотя и растет, но мед
ленно), а размеры оперативной памяти растут экспоненциально. Единственным
параметром, не меняющимся столь стремительно, является время поиска цилин
дра диска. В результате это становится узким местом многих файловых систем.
В университете Беркли были проведены исследования, направленные на сни
жение остроты проблемы. В результате родилась совершенно новая файловая
система с журнальной структурой ( Log-structured File System, LFS). В этом
разделе мы кратко опишем, как она работает, а дополнительные сведения можно
получить в [99 ] .
В основе файловой системы с журнальной структурой лежит идея, что п о мере
ускорения центральных процессоров и экстенсивного расширения оперативной
памяти растет и выгода от кэширования дисков. Поэтому становится возмож
ным удовлетворить весьма существенную часть всех дисковых запросов прямо
из кэша файловой системы без обращения к диску. Из этого следует, что в буду
щем большинство обращений к диску будут составлять обращения записи, по
этому алгоритм опережающего чтения, применявшийся в некоторых файловых
системах, уже не дает большого выигрыша производительности.
Ситуация усложняется тем, что в большинстве файловых систем операции запи
си выполняются над очень маленькими блоками данных. Такие операции оказы
ваются крайне неэффективными, поскольку самой физической записи, занимаю
щей 50 мкс, часто предшествует поиск цилиндра в течение 1 О мс и его поворот
в течение 4 мс. При таких параметрах эффективность диска падает до 1 %.
Чтобы понять, из чего складываются все эти мелкие операции записи, рассмот
рим создание файла в операционной системе UNIX. Здесь необходимо произ
вести запись в индексный узел каталога, блок каталога, индексный узел файла
и, наконец, блок самого файла. В принципе, эти операции записи могут быть от
ложены на некоторое время, но тем самым не исключаются серьезные проблемы
непротиворечивости файловой системы в случае сбоя компьютера прежде, чем
запись на диск будет выполнена. По этой причине индексные узлы обычно со
хранятся на диск без промедления.
5 . 3 . Реализация файловой системы 577
5 . 4 . Безопасность
Многие компании располагают ценной информацией, которую они тщательно
охраняют. Таким образом, защита информации от несанкционированного досту
па является главной заботой всех операционных систем. В следующих разделах
мы рассмотрим различные вопросы, связанные с безопасностью и защитой, рав
но относящиеся как к системам разделения времени, так и к персональным ком
пьютерам, связанным локальной сетью.
5 . 4 . 1 . Безопасное окружение
Термины «безопасность• и «защита• иногда смешивают. Однако часто полез
но провести границу между техническими, административными, юридическими
и политическими аспектами безопасности, с одной стороны (то есть с гарантией
того, что файлы не читаются и не модифицируются неавторизованными лица
ми), и специфическими механизмами операционной системы, привлекаемыми
для обеспечения безопасности, с другой стороны. Чтобы избежать путаницы, мы
будем применять термин безопасность для обозначения общей проблемы и тер
мин защита при описании специфических механизмов операционной системы,
используемых для обеспечения информационной безопасности в компьютерных
системах, хотя в реальности граница между этими двумя терминами достаточно
размыта. Сначала мы познакомимся с вопросами безопасности, чтобы понять
природу проблемы. Затем мы рассмотрим механизмы защиты и модели, способ
ствующие обеспечению безопасности.
5. 4 . Безо п асность 579
Уг розы
С точки зрения безопасности компьютерные системы ставят три общие цели, ка
ждой из которых соответствует своя категория угроз (табл. 5.3). Первая, конфи
денциальность данных, подразумевает, что данные, не подлежащие разглашению,
остаются тайными. Говоря точнее, если владелец данных разрешил доступ к ним
лишь ограниченному кругу лиц, то система должна гарантировать невозможность
несанкционированного доступа к ней. Как минимум, пользователь должен иметь
возможность указывать, кому и что разрешено просматривать, а система обязана
претворять эти указания в жизнь.
Злоумышленники
Большинство людей совершенно безвредно и законопослушно. Так зачем же бес
покоиться о безопасности? Затем, что есть небольшая группа людей, которая от
нюдь не безвредна и жаждет причинять неприятности другим (возможно, для
собственной коммерческой выгоды). В литературе по безопасности злоумышленни
ком называют человека, сующего свой нос в чужие дела. Злоумышленники подраз
Вредоносные программы
Еще одну угрозу безопасности представляют собой вредоносные программы.
В определенном смысле автора программы следует считать злоумышленником,
зачастую обладающим хорошо развитыми техническими навыками. Различие ме
жду традиционным злоумышленником и вредоносной программой заключается
5. 4 . Безо пасность 581
5 . 4 . 3 . П ри н ципы разработки
механизмов безопасности
В 1975 году исследователи определили несколько общих принципов, которых
необходимо придерживаться при разработке безопасных систем [ 1 02] . Приве
дем краткий обзор некоторых из этих идей на основе опыта работы с систе
мой MUL ТICS.
+ Устройство системы не должно быть секретом. Предположение, что взлом
щики не знают, как работает система, - это лишь ненужные иллюзии разра
ботчиков.
+ По умолчанию доступ не должен предоставляться. Об ошибках, в результате
которых пользователям было отказано в законном доступе, сообщат значи
тельно быстрее, чем о случаях ошибочного предоставления несанкциониро
ванного доступа.
+ Необходимо проверять текущее состояние прав доступа. Система не должна,
проверив наличие прав доступа и убедившись, что доступ разрешен, затем со
хранять эту информацию для последующего использования. Многие системы
проверяют разрешение доступа при открытии файла, но не после открытия.
Это означает, что пользователь, открывший файл и держащий его открытым
неделями, будет продолжать обладать доступом к файлу, даже если владелец
файла с тех пор уже давно изменил права доступа файла.
+ Предоставляйте каждому процессу как можно меньше привилегий. Если у про
граммы-редактора есть доступ только к редактируемому файлу (указанному
при вызове), то редакторы в виде троянских коней с ахейцами в брюхе вряд
ли смогут причинить много вреда. Применение этого принципа предполагает
схему защиты высокой степени детализации. Подобные схемы рассматрива
ются позднее в данной главе.
+ Механизм защиты должен быть простым, одинаковым для всех и встроенным
в самые нижние уровни системы. Попытка установить механизмы безопас
ности на существующую небезопасную систему практически невыполнима.
Безопасность, как и правильность, не является свойством, которое можно до
бавить потом.
+ Выбранная схема должна быть психологически приемлемой. Если пользова
тели почувствуют, что для защиты файлов требуется тратить слишком много
усилий, они не станут их защищать. В то же время они будут громко жало
ваться, если что-либо пойдет не так. Ответы типа •это ваша вина�, как прави
ло, восприниматься не будут.
586 Глава 5. Файловые системы
Пароли
В наиболее широко применяемой форме аутентификации пользователю предла
гается ввести имя и пароль. Парольная защита легко реализуется. В UNIX это
происходит следующим образом: программа входа в систему просит пользовате
ля ввести имя и пароль, который немедленно шифруется. Затем программа чита
ет файл паролей, представляющий собой последовательность АSСП-строк, где
каждая строка соответствует одному пользователю. Когда нужный пользователь
найден, введенный шифрованный пароль сравнивается с шифрованным паролем
из файла. В зависимости от результата сопоставления пользователю выдается
разрешение или отказ в доступе.
Парольная аутентификация легко уязвима. Зачастую можно видеть публикации
о том, как школьники старших и даже средних классов с домашних компьютеров
взламывают сверхсекретные системы крупных корпораций и правительственных
организаций. Почти всегда взлом происходит вследствие угадывания комбина
ции имени пользователя и пароля.
Несмотря на более свежие исследования, классический труд по вопросу безопас
ности паролей был написан аж в 1979 году на основе исследований систем UNIX
[90]. Авторы скомпилировали список вероятных паролей: имена и фамилии, на
звания улиц, городов, слова из словарей среднего размера (в частности, написан
ные задом наперед), автомобильные номера и короткие строки случайных сим
волов. Затем они сравнили свой полученный таким образом список с системным
файлом паролей, чтобы посмотреть, есть ли совпадения. Как выяснилось, более
86 % от общего количества паролей в файле оказались в их списке.
Если бы все пароли состояли из 7 символов, случайным образом выбранных из
95 печатных символов набора ASCII, их количество было бы равно 95 7 , что при
мерно равно 7 х 10 1 3 . Если выполнять 2000 операций шифрования в секунду, на
построение списка для сверки пароля потребуется около 2000 лет. Более того,
под хранение такого списка ушло бы 20 млн магнитных лент. Даже требование
того, чтобы пароли содержали как минимум один символ нижнего регистра, один
символ верхнего регистра, один специальный символ и имели бы как минимум
семь или восемь символов в длину, заметно улучшает ситуацию по сравнению
с тем случаем, когда пароль выбирается пользователем без всяких ограничений.
Даже для случая, когда по политическим причинам невозможно заставить поль
зователей выбирать разумные пароли, в [90] описана технология, делающая пред
лагаемый авторами метод атаки (заранее зашифровать большое число паролей)
практически бесполезным. Идея состоит в том, чтобы ассоциировать с каждым
5 . 4. Безо пасн ость 587
паролем п-разрядное случайное число. Это случайное число меняется при каж
дом изменении пароля. Оно хранится в файле паролей в незашифрованном виде,
и каждый может его видеть. Пароль же сначала объединяется со случайным чис
лом, а только затем шифруется и записывается в файл.
Рассмотрим, к каким последствиям приведет эта техника для злоумышленника,
пытающегося составить список вероятных паролей, зашифровать их и сохранить
в отсортированном виде в файле f, где их затем легко будет найти. Если злоумыш
ленник считает, что слово Marilyn может быть паролем, ему теперь недостаточно
закодировать только это слово и записать его в f. Он должен зашифровать и за
писать 2п строк, Mar i lyn O O O O , Mar i lyn0 0 0 1 , Mar i lyn 0 0 0 2 и т. д. Благодаря
этой технике, называемой добавлением соли в файл паролей, размер файла f уве
личивается в 2п раз. В UNIX применяется значение п, равное 12. В некоторых
версиях UNIX сам файл паролей сделан недоступным для чтения, а для работы
с ним предоставлена программа, которая просматривает запрошенные записи,
внося дополнительную задержку, достаточную, чтобы сильно замедлить атаку.
Добавление случайных чисел к файлу паролей защищает систему от взломщи
ков, пытающихся заранее составить большой список зашифрованных паролей
и таким образом взломать несколько паролей сразу. Однако данный метод бесси
лен помочь в том случае, когда пароль легко отгадать, например, если пользователь
David использует пароль Dav id. Взломщик может просто попытаться отгадать
пароли один за другим. Обучение пользователей в данной области помогает, но
оно редко проводится. Однако помимо обучения пользователей в вашем распо
ряжении помощь компьютера. На некоторых системах устанавливается програм
ма, формирующая случайные, легко произносимые бессмысленные слова, такие
как f o t a l ly, garbungy или Ьip i t ty, подходящие в качестве паролей (жела
тельно с чередованием прописных и строчных букв и с разбавлением специаль
ными символами).
Некоторые операционные системы требуют от пользователей регулярной смены
паролей, чтобы ограничить ущерб в ситуации, когда пароль становится извест
ным взломщику. Крайность здесь одноразовые пароли. В этом случае пользо
-
ватель получает блокнот, содержащий список паролей. Для каждого входа в сис
тему используется следующий пароль в списке. В итоге, если даже взломщику
удастся узнать уже отработавший пароль, он ему не пригодится. ( Предполагает
ся, что пользователь не потеряет выданный ему блокнот. )
Еще одна вариация н а тему паролей предполагает, что для каждого нового поль
зователя создается длинный список вопросов и ответов, который хранится на
сервере в надежном виде (например, в зашифрованном). Вопросы должны выби
раться так, чтобы пользователю не нужно было их записывать. Примеры:
+ Как зовут сестру Марджолин?
+ На какой улице расположена ваша начальная школа?
+ Что преподавала мисс Воробьофф?
При регистрации сервер задает один из этих вопросов, выбирая его в списке слу
чайным образом, и проверяет ответ.
588 Глава 5. Файловые системы
Физическая идентификация
Совершенно иным подходом к авторизации является проверка наличия у поль
зователя некоторого предмета, как правило, пластиковой карты с нанесенной
магнитной полосой. Обычно пользователь должен не только вставить карту, но
и ввести пароль; таким образом, доступ к системе обеспечивается при соблюде
нии двух условий - наличия у пользователя карты и знания им пароля. Обычно
на этом принципе основана работа банкоматов.
Другой метод проверки подлинности пользователя основан на измерении его
физических характеристик, которые трудно подделать. Например, для иденти
фикации пользователя может применяться специальное устройство считывания
отпечатков пальцев или распознавания тембра голоса. Поиск можно значительно
ускорить, если пользователь при этом будет сообщать системе, кто он; в этом
случае системе будет достаточно выполнить сравнение для одного отпечатка паль
цев, нежели искать предоставленный отпечаток во всей базе данных. Визуальная
идентификация пока не встречается, но со временем и она может появиться.
Еще один метод идентификации заключается в анализе подписи. Пользователь
ставит подпись специальным пером, соединенным с терминалом, и компьютер
сверяет ее с оригиналом. Еще лучше сравнивать не подпись, а движения, выпол
няемые при ее написании. Хороший специалист по подделке подписей может на
рисовать довольно точную копию подписи, но не обязательно угадает, в каком
порядке выполняются движения.
На удивление часто на практике используется измерение длины пальцев. При
этом каждый терминал оснащается устройством вроде показанного на рис. 5.20.
Пользователь засовывает в него руку, и устройство измеряет длину его пальцев
и сравнивает с информацией, хранящейся в базе данных.
Подобные примеры измерения биометрических характеристик можно приводить
еще и еще, но мы остановимся только на двух, которые помогут отметить кое-что
важное. Кошки и другие животные мочой метят свои владения по периметру.
Очевидно, кошки могут идентифицировать друг друга подобным образом. Пред
ставьте себе, что кому-нибудь удастся создать небольшое устройство, способное
производить мгновенный анализ мочи, обеспечивая, таким образом, надежную
идентификацию. Раз так, значит, каждый терминал можно снабдить подобным
устройством, вывесив табличку: •для регистрации помочитесь сюда, пожалуй
ста� . Возможно, таким образом удалось бы создать абсолютно надежную систе
му, хотя она вряд ли понравилась бы пользователям. То же самое можно сказать
о системе, состоящей из иголки и небольшого спектрометра и предлагающей поль
зователю проколоть палец иголкой, предоставив таким образом каплю крови для
анализа. Дело в том, что любая схема аутентификации должна быть психологи-
5.4. Безо пасност ь 589
Пружина
5 . 5 . М еханизм ы за щ иты
В предыдущих разделах мы рассмотрели множество проблем, некоторые из них
были техническими, тогда как другие - нет. В следующих разделах мы скон
центрируемся на некоторых технических деталях методов защиты файлов, ис
пользуемых в операционных системах. Во всех этих методах проводится четкое
разграничение между политикой (от кого и чьи данные должны защищаться)
и механизмом (как система проводит данную политику). Отделение политики от
механизма обсуждается в [ 104] . Мы уделим особое внимание именно механизму,
а не политике.
В некоторых системах защита реализуется при помощи программы, называю
щейся монитором обращений. При каждой попытке доступа к некоторому ресур
су система сначала просит монитор обращений проверить законность данного
доступа. Монитор обращений смотрит в таблицы политик и принимает решение.
Рассмотрим окружение, в котором работает монитор обращений.
5 . 5 . 1 . Домены защиты
Компьютерная система подразумевает множество �объектов� , которые требует
ся защищать. Это может быть аппаратура (например, центральный процессор,
память, диски или принтеры) или программное обеспечение (процессы, файлы,
базы данных или семафоры).
У каждого объекта есть уникальное имя, по которому к нему позволено обра
щаться, и набор операций, которые вправе выполнять с объектом процессы. Так,
к файлу применимы операции read и wri t e, к семафору - операции up и down.
5 . 5 . Механиз мы за щиты 59 1
Файл 1 [R]
Файл 2 [RW]
Объект
Чтение
2 Чтение Заnись
Чтение
Заnись
Заnись
Исnолнение
Чтение
з Заnись Заnись Заnись
Исnолнение
Объект
Плоттер 2 Домен 2
домен Файл 1 Файл 2 Файл З Файл 4 Файл 5 Файл 6 При нтер 1 Домен 1 Домен З
Чтение
Чтение Enter
Заnись
Чтение
Чтение
2 Чтение Заnись Заnись
Заnись
Исnолнение
Чтение
з Заnись Заnись Заnись
Исnолнение
Процесс
'(3"
Пространство
пользователя
}"��-
Файл ____. 0 ----./ А: RW; В: А 1 ACL
0 ----./ А: R; B : RW; C : R 1/
0 ----./ B : RWX; С: RX 1
'----�����---'
Запись подобного вида дает пользователю t ana доступ к файлу паролей незави
симо от того, в какой группе он находится в текущий момент.
Еще одна возможность заключается в предоставлении пользователю доступа
к объекту при условии, что надлежащим правом обладает хотя бы одна группа,
в которую он входит. В этом случае пользователю, состоящему в нескольких
группах, не нужно у1<азывать текущую группу при входе в систему. В любой мо
мент времени учитываются все группы, членом которых он является. Недоста
ток такого подхода - меньшая изолированность: t ana имеет возможность ре
дактировать файл паролей во время общения с любителями голубей.
Применение групп и масок позволяет выборочно блокировать доступ пользова
телей к файлам. Например:
virgi l , *: ( nог.е ) ; * . * : RW
Эта запись дает возможность всем, кроме пользователя vi rgi l , читать и писать
в файл. Такой эффект достигается потому, что записи сканируются в порядке
перечисления и применяется первая подходящая (остальные же записи даже не
проверяются) . Для v i rg i l такой записью является первая; в ней указано отсут
ствие каких-либо прав (none ) . На этом поиск заканчивается, и то, что все ос
тальные пользователи имеют права доступа, остается •за кадром• .
Другой способ работы с группами предполагает, что в АСL-записях задействова
ны не пары (UID, GID), а один из этих идентификаторов. Например, для файла
p i ge on_dat a запись может выглядеть следующим образом:
debbi e : RW ; phi l : RW ; p i g fan : RW
Она означает, что пользователи debЬ i e , phi l и все члены группы p i g fan име
ют право чтения и записи.
Иногда владелец файла хочет отметить разрешения, назначенные пользователю
или группе. Списки управления доступом позволяют относительно легко отме
нить назначенные ранее права. Все, что нужно сделать, - это отредактировать
их. Тем не менее если список проверяется лишь при открытии файла, то измене
ния возымеют действие лишь при следующем вызове open. К любому открыто
му файлу применяются права, актуальные на момент открытия, даже если позд
нее доступ пользователю запрещается.
5 . 5 . З . М андаты
Матрица, показанная на рис. 5.23, может также храниться по рядам. Здесь с каж
дым процессом ассоциирован список разрешенных для доступа объектов вместе
с информацией о том, какие операции разрешены, другими словами, это - домен
защиты объекта. Такой список называется списком мандатов ( Capabllity List,
C-list, рис. 5.25), а его элементы - мандатами [36, 44) .
\j
596 Глава 5. Файловые систем ы
П �ц
0 0 Пространство
пользователя
}
1 1 1
1 1 1
� �
� F1 :R
R F2:RW RX
П �mpa"cmo ""ра
§]
§]
FЗ:RWX " \
Список мандатов
Рис . 5 . 25 . У каждого процесса имеется список мандатов
5 . 5 . 4 . Секретн ые канал ы
Даже при наличии списков управления доступом и мандатов в системе безопасно
сти могут существовать бреши. В данном разделе мы поговорим о существовании
утечек информации в системах, для которых строго математически доказано, что
подобные утечки невозможны. Изложенные здесь идеи впервые высказаны в [72].
5.5 . Механизм ы за щ иты 599
Ядро Тайный
канал
а б
Проблема изоляции:
Рис . 5 . 27 . а клиент, сервер и сообщник сервера; б даже от
- -
Сервер ___...
Сервер Сервер
блокирует разблокирует
файл, чтобы файл, чтобы
послать 1 послать О
О � Передаваемый
битовый поток
Сообщник ___...
Время •
Рис. 5 . 28 . Секретный канал, основанный на блокировке файлов
5 . 6 . 1 . Сообщения
Файловая система понимает 39 типов сообщений, запрашивающих различные
действия. Все они, кроме двух, соответствуют системным вызовам MINIX 3. Ис
ключения составляют два сообщения, генерируемые другими компонентами
MINIX 3. Что касается системных вызовов, то 31 из них принимаются от пользо
вательских процессов, 6 сообщений соответствуют системным вызовам, обраба
тываемым сначала менеджером памяти, который затем, чтобы завершить работу,
вызывает файловую систему. Еще 2 сообщения также обрабатываются файловой
системой. Все эти сообщения перечислены в табл. 5.5.
Загрузочный СуnеР,бnок
бnок
1-уэлы Один бnок диска
,--'---,
Данные
Битовая Битовая
карта i-уэлов карта зон
Рис. 5 . 29 . Структура дискеты или небольшого жесткого диска с 64 индексными узлами
и размером блока 1 Кбайт (то есть два подряд идущих сектора по 5 1 2 байт
рассматриваются как один блок)
Любая файловая система начинается с заzрузачноzо блока. Этот блок содержит
исполняемый код. Размер загрузочного блока всегда составляет 1 024 байта (два
сектора диска), хотя в других случаях в MINIX 3 могут использоваться блоки
большего размера (что и имеет место по умолчанию). При включении компьютера
его аппаратное обеспечение считывает содержимое загрузочного блока в память
и исполняет его. Код в загрузочном блоке инициирует процесс загрузки самой
операционной системы. После того как система загружена, загрузочный блок боль
ше не используется. Для загрузки системы подходит не каждый дисковый накопи
тель, но ради единообразия структуры на каждом блочном устройстве резерви
руется загрузочный блок. Худшее, к чему может привести такая стратегия, - это
потеря одного блока. Чтобы аппаратное обеспечение не пыталось загрузиться с уст
ройства, не предназначенного для загрузки, в известное заранее место загрузочно
го блока записывается сигнатура ( -«маzическое» число) в том и только том случае,
если блок содержит исполняемый код. Аппаратура (а в действительности, код
BIOS) откажется загружаться с устройства, если загрузочный блок не имеет такой
сигнатуры. Таким образом, случайный «мусор� в качестве программы не запустится.
Суперблок содержит информацию, описывающую структуру файловой системы.
Его размер, как и размер загрузочного блока, составляет 1 024 байта независимо
от размера блоков, используемых в остальной части файловой системы. Струк
тура суперблока показана на рис. 5.30.
5 . 6 . Обзор файловой систем ы M I N IX 3 605
Число i-узлов
(не используется)
Число блоков битовой карты i-узлов
Число блоков битовой карты зон
Первая зона данных
Log, (количество блоков в зоне)
Присутствуют
и на диске, Замещение страниц
и в памяти Максимальный размер файла
Количество зон
Магическое число
Замещение страниц
Размер блока (в байтах)
Подверсия ФС �
Указатель на i-узел для корня,
смонтированной файловой системы
Указатель на i-узел,
смонтированный выше
1-узлов на блок
Номер устройства
Есть в памяти, Флаг только чтение
но отсутствуют Флаг направления байтов в ФС
на диске Версия ФС
Прямых зон на индексный узел
Косвенных зон на косвенный блок
Первый свободный бит в битовой
карте i-узлов
Первый свободный бит в битовой
карте зон
Рис. 5 . 30 . Структура суперблока в MINIX
карты. Так как каждый индексный узел занимает 64 байта, блок размером 1 Кбайт
может содержать до 16 индексных узлов. При наличии 64 используемых индекс
ных узлов для их хранения потребуется 4 дисковых блока.
Позже мы подробно объясним различие между дисковыми блоками и зонами,
сейчас же достаточно сказать, что место на диске может вьщеляться частями (зона
ми) из 1, 2, 4, 8 или, в общем случае, 2п блоков. Битовая карта зон позволяет от
слеживать свободное пространство в зонах, а не в блоках. Для стандартных гибких
дисков, используемых MINIX 3, размер зоны совпадает с размером блока ( 1 Кбайт),
поэтому для таких устройств в первом приближении можно считать, что зона -
это то же самое, что и блок. Пока мы позже в этой главе не приступим к обсужде
нию деталей выделения места, вы можете считать, что эти понятия эквивалентны.
Обратите внимание, что количество блоков в зоне не хранится в суперблоке, так
как оно нигде не требуется. Все, что нужно, - это логарифм по основанию два от
этого числа, который используется как значение сдвига при преобразовании
блоков в зоны, и наоборот. Например, если зона содержит 8 блоков, log2 8 3. =
То есть, чтобы найти зону, содержащую блок 1 28, нужно сдвинуть 1 28 на три бита
вправо (получится зона 1 6).
Битовая карта зон содержит только зоны, занимаемые данными (то есть в нее не
попадают блоки, хранящие битовые карты и индексные узлы), причем первая зо
на данных соответствует биту 1 в битовой карте. Как и в случае с картой индекс
ных узлов, нулевой бит не используется, а значит, первый блок битовой карты
описывает 8 1 9 1 зон, а последующие - 8 1 92 каждый. Если вы посмотрите на бито
вые 1<арты только что отформатированного диска, вы увидите, что в обеих бито
вых картах (зон и индексных узлов) установлено два бита. Первый из них соот
ветствует несуществующей 0-й зоне или индексному узлу. Второй соответствует
индексному узлу и зоне корневого каталога устройства, которая создается при
создании файловой системы.
Информация, хранящаяся в суперблоке, избыточна, так как иногда она требует
ся в одной форме, а иногда в другой. Так как на размещение суперблока отводит
ся 1 Кбайт места, имеет смысл хранить информацию во всех необходимых пред
ставлениях, а не преобразовывать ее в ходе работы. Например, номер первой
зоны данных на диске можно вычислить, исходя из размера блока, размера зоны,
числа индексных узлов и числа зон, но удобнее просто хранить это значение в су
перблоке. Оставшаяся часть суперблока все равно не используется, потому вы
деление в нем одного лишнего слова ничего не стоит.
Когда загружается MINIX 3, суперблок с корневого устройства считывается в таб
лицу в памяти. Аналогичным образом, при монтировании других файловых сис
тем их суперблоки также помещаются в память. В этой таблице есть несколько
полей, которых нет на диске. Среди них флаг, индицирующий, что разрешено
только чтение, флаг, позволяющий установить нестандартный порядок следова
ния байтов, а также поля, предназначенные для ускорения доступа. Они указы
вают положение в битовых картах, ниже которого все биты установлены (то есть
заняты). Кроме того, здесь есть поле, описывающее устройство, с которого при
шел данный суперблок.
5.6. Обзор файловой системы M I N IX 3 607
Такая команда создаст файловую систему из 1440 блоков н а гибком диске в при
воде 1 . Ей можно указать файл-прототип с перечислением каталогов и файлов,
подлежащих включению в созданную файловую систему. Эта же команда запи
сывает в суперблок необходимую сигнатуру, идентифицирующую файловую
систему как файловую систему MINIX. MINIX развивается, и в ранних версиях
некоторые атрибуты файловой системы (например, размер индексного узла) бы
ли другими. При попытке монтировать дискету, имеющую другой формат, на
пример дискету MS-DOS, системный вызов mount , проверяющий суперблок на
наличие сигнатуры, сообщит об ошибке.
5 . 6 . З . Битовые карты
MINIX 3 следит за свободными и занятыми индексными узлами и зонами при
помощи двух битовых карт. Когда удаляется файл, несложно подсчитать, какой
бит в битовой карте соответствует освободившемуся индексному узлу, и найти
его при помощи обычного механизма кэширования. В найденном блоке бит, со
ответствующий освободившемуся индексному узлу, сбрасывается. Зоны освобо
ждаются точно так же, только используется битовая карта зон.
Логически, при создании файла файловая система должна последовательно про
смотреть битовые карты, чтобы найти первый свободный индексный узел, кото
рый будет выделен новому файлу. Фактически же, хранящийся в памяти супер
блок содержит поле, указывающее на следующий свободный индексный узел,
поэтому требуется искать свободный индексный узел, начиная с этого положе
ния (зачастую свободным оказывается следующий узел). Аналогичным образом,
когда индексный узел освобождается, проверяется, есть ли перед ним другие
свободные, и при необходимости обновляется значение указателя. Если оказалось,
что все индексные узлы на диске заняты, процедура поиска указывает на 0-й эле
мент. Именно поэтому 0-й индексный узел не используется (другими словами,
он является индикатором заполнения диска). ( Когда программа mk f s создает
новую файловую систему, она обнуляет индексный узел О и устанавливает млад
ший бит в битовой карте, соответственно, файловая система никогда не пытается
выделить этот блок.) Все, что только что было сказано для индексных узлов, от
носится и к зонам. Когда необходимо дисковое пространство, логически ищется
первая свободная зона, начиная с начала, а чтобы избежать ненужного последо
вательного поиска, поддерживается указатель на первую свободную зону.
Теперь мы можем объяснить разницу между зонами и блоками. В основе идеи
зон лежит попытка гарантировать, что блоки одного файла расположены на одном
цилиндре - это дает возможность повысить производительность за счет после
довательного чтения. Для этого за один раз выделяется несколько блоков. Если,
608 Глава 5 . Файловые системы
например, размер блока равен 1 Кбайт, а зоны - 4 Кбайт, битовая карта зон от
слеживает зоны, а не блоки. Диск объемом 20 Мбайт будет разбит на 5 К зон по
4 Кбайт, и в битовой карте зон, таким образом, будет 5 Кбит.
Большинство файловых систем работают с блоками. Обмен данными с диском
всегда производится целыми блоками, кэш также оперирует блоками. Только та
небольшая часть файловой системы, которая работает с физическим адресом
(то есть с битовой картой зон и индексными узлами), знает о зонах.
В процессе разработки файловой системы MINIX 3 необходимо было принять
некоторые решения о ее структуре. В 1 985 году, когда была задумана операцион
ная система MINIX, диски имели небольшой объем, и ожидалось, что у многих
пользователей будет только дисковод. Поэтому было решено в первой версии
файловой системе ограничить дисковый адрес значением 16 бит, чтобы впоследст
вии хранить большую их часть в блоках косвенной адресации. При 1 6-разрядном
номере зоны и размере зоны в 1 Кбайт такая система позволяла работать с диска
ми объемом до 64 Мбайт. В те дни это бьm огромный объем, и казалось, что если
диски станут больше, будет несложно переключиться на зоны размером 2 Кбайт
или 4 Кбайт, не меняя размер блока. Благодаря 1 6-разрядному номеру зоны раз
мер индексного узла был ограничен значением 32 байта.
Когда широко распространились диски значительно большей емкости, стало оче
видно, что желательны изменения. Многие файлы имеют объем менее 1 Кбайт,
поэтому увеличение размера блока привело бы к бесполезному расходованию
объема диска из-за того, что записываются и считываются почти пустые блоки,
и к бесполезной трате драгоценной оперативной памяти на кэш. Можно было бы
увеличить размер зоны, но большие зоны означают менее эффективное использова
ние свободного места на диске, при этом все равно желательно было бы сохранить
эффективность работы с дисками маленького объема. Другой разумной альтерна
тивой было бы задание разного размера зоны для больших и маленьких дисков.
В конце концов, было принято решение увеличить разрядность дискового ука
зателя до 32 бит. Благодаря этому файловая система MINIX 2 могла бы работать
с дисками объемом до 4 Тбайт при размере зоны и блока 1 Кбайт и с дисками
объемом до 16 Тбайт при размере блока и зоны 4 Кбайт (в настоящее время
принятом по умолчанию). Однако другие факторы заставили урезать этот раз
мер (к примеру, 32-разрядные указатели не позволяют выйти за предел 4 Гбайт).
Вместе с увеличением размера индексных узлов требуется увеличивать разряд
ность дисковых указателей. Это не обязательно плохо: индексный узел MINIX 2
(а теперь и M INIX 3 ) совместим со стандартными индексными узлами UNIX
и имеет пространство для хранения трех значений времени, дополнительных зон
с одинарным и двойным уровнем косвенности, а также место для будущего рас
ширения зонами с тройным уровнем косвенности.
Зоны приводят еще к одной неожиданной проблеме, которую можно проиллюст
рировать следующим простым примером, опять же, с зонами размером 4 Кбайт
и блоками 1 Кбайт. Предположим, что имеется файл размером 1 Кбайт, для
которого выделена одна зона. Последние три блока зоны содержат случайный
<1:мусор� , оставшийся от предыдущих файлов, но ничего плохого в этом нет, так
5 . 6 . Обзор файловой системы M I N IX 3 609
как в индексном узле четко указано, что размер файла равен 1 Кбайт. Фактиче
ски, этот мусор не попадет даже в дисковый кэш, так как чтение производится
блоками, а не зонами. Попытки прочитать информацию после конца файла все
гда возвращают О вместо данных.
Предположим, что кто-то установил файловый указатель на 32 768 и дописал
1 байт. Теперь размер файла станет равным 32 769. Если после этого установить
файловый указатель на 1 К и выполнить чтение, удастся получить данные, кото
рые были в данном блоке ранее, что является серьезной угрозой безопасности.
Решение состоит в том, чтобы в ситуации, когда производится запись после кон
ца файла, явно обнулять все еще не выделенные блоки в зоне, которая ранее бы
ла последней. Хотя такая ситуация встречается достаточно редко, система долж
на ее отслеживать, в результате ее код несколько усложняется.
5 . 6 . 4 . И ндексные узл ы
Схема индексного узла MINIX показана на рис. 5.3 1 . Она практически совпадает
со строением индексного узла в UNIX. Имеются девять 32-разрядных указателей
на зоны диска, из которых семь прямых и два косвенных. В MINIX 3 индексный
узел занимает 64 байта, как и в стандартной системе UNIX, поэтому остается ме
сто для дополнительного десятого указателя (тройного уровня косвенности), хотя
в текущей версии файловой системы он не поддерживается. Время последнего
доступа, модификации и изменения индексного узла в MINIX 3 хранятся стан
дартным образом, как в UNIX. Последний из этих параметров обновляется прак
тически при каждой операции, за исключением чтения файла.
Когда файл открывается, его индексный узел считывается в память и помещает
ся в таблицу индексных узлов, где остается до закрытия файла. Записи в этой
таблице имеют несколько дополнительных полей, которых нет на диске. Напри
мер, благодаря номеру индексного узла и номеру устройства, откуда он считан,
файловая система знает, куда перезаписать индексный узел, если он изменен
в памяти. Кроме того, у каждого индексного узла имеется счетчик. Если файл
открывается дважды, вторая копия индексного узла в память не копируется,
вместо этого увеличивается на единицу значение счетчика. При закрытии файла
счетчик декрементируется, и только тогда, когда он достигает нуля, индексный
узел удаляется из таблицы в памяти. Если за время нахождения в памяти он бьm
изменен, он записывается на диск.
Главное предназначение индексного узла в том, чтобы хранить сведения о положе
нии блоков файла на диске. Первые семь номеров зон записываются в индексный
узел напрямую. Таким образом, при стандартных параметрах, когда зоны и блоки
имеют размер 1 Кбайт, файлы размером до 7 Кбайт не требуют использования
блоков косвенной адресации. После 7 Кбайт применяются косвенные блоки при
мерно так, как это показано на рис. 5.8, за тем исключением, что это только бло
ки первого и второго уровней косвенности. Если блоки и зоны имеют размер
1 Кбайт, блок первого уровня косвенности содержит 256 записей, что соответствует
61 О Глава 5 . Файловые систем ы
1 6 бит
Режим ...._ Тип файла и биты rwx
Число ссылок ...._ Записи в директориях для этого файла
Uid ...._ Идентифицирует владельца файла
Gid ...._ Группа владельца
- Размер файла ...._Количество байт в файле
1
- Время доступа
Время модификации Время измеряется в секундах
,.._
с 1 января 1 970 года
Время изменения состояния
,.._
- зона о
- Зона 1
64 байта
- Зона 2
- Зона 3 � Номера семи первых зон
- Зона 4
,_ Зона 5
,_ Зона 6
}
- Косвенная зона Используются для файлов,
Косвенная зона второго уровня
,_..
занимающих больше семи зон
- Не используется Можно использовать для косвенных зон
� третьего уровня вложенности
Кроме того, индексный узел хранит информацию о типе файла (обычный файл,
каталог, специальный блочный файл, специальный символьный файл, канал
ввода-вывода) и биты защиты, а также биты S ETU I D и S ETGI D. В поле l i nk
5.6 . Обзор файловой системы M I NIX 3 61 1
5 . 6 . 5 . Кэш блоков
Для повышения производительности файловой системы в MINIX 3 применяет
ся кэширование блоков. Кэш реализован в виде массива буферов, каждый из ко
торых состоит из заголовка, содержащего указатели, счетчики и флаги, и тела -
области памяти для хранения одного блока. Все свободные буферы связаны друг
с другом в двунаправленный список, отсортированный в направлении от послед
них использовавшихся ( Most Recently Used, MRU) к дольше всего не использо
вавшимся ( Least Recently Used, LRU). Это иллюстрирует рисунок 5.32.
При вызове get_Ь l o c k ей передается как номер блока, так и номер устройства,
и при поиске оба эти параметра сравниваются с соответствующими полями
буферов из цепочки. Если нужный блок найден, увеличивается на единицу зна
чение счетчика в его заголовке и возвращается указатель на него. Если затребо
ванный буфер в кэше не обнаруживается, выбирается первый из LRU-списка; он
гарантированно не используется, и содержащийся в нем блок может быть удален
из оперативной памяти.
Когда удаляемый из памяти блок выбран, проверяется один из флагов в его заго
ловке, означающий, что блок был модифицирован после считывания. Если флаг
установлен, блок записывается на диск. Затем с диска считывается нужный блок,
для этого отправляется сообщение драйверу диска. До тех пор пока запрошен
ный блок не прочитан, файловая система приостанавливается, а после этого воз
вращает указатель на прочитанный блок.
По окончании работы запросившей блок процедуры, чтобы освободить блок, она
вызывает другую процедуру, put_Ы o c k. Обычно блок используется сразу по
сле выделения и затем освобождается, но так как существует вероятность того,
что перед освобождением блока будут сделаны дополнительные запросы, функ
ция put_Ы o c k сначала уменьшает на единицу счетчик использования и поме
щает блок обратно в LRU-список в том и только том случае, если счетчик достиг
нуля. Если он имеет ненулевое значение, блок не освобождается.
Один из аргументов функции put_Ы o c k описывает, к какому классу принадле
жит освобождаемый блок (индексные узлы, каталог, данные). В зависимости от
этого значения принимаются два ключевых решения.
1. Поместить блок в начало или в конец LRU-списка.
2. Записать блок на диск немедленно (если он был модифицирован).
Почти все блоки присоединяются в конец списка в полном соответствии с идеей
сортировки по частоте использования. Исключение составляют блоки виртуаль
ного диска; поскольку они уже находятся в памяти, хранение их в кэше практи
чески бессмысленно.
Модифицированный блок не записывается до тех пор, пока не произойдет одно
из двух следующих событий.
1. Блок достиг начала LRU-списка и удаляется из памяти.
2. Выполнен системный вызов sync .
Вызов sync не перебирает элементы LRU-списка. Вместо этого он обрабатывает
массив буферов и записывает модифицированные буферы на диск даже в том
случае, если они еще используются.
Однако есть одно исключение. В старой версии MINIX суперблок модифициро
вался при монтировании системы, поэтому, чтобы снизить вероятность повреж
дения файловой системы по причине неожиданного сбоя, он сохранялся без про
медления. Сейчас суперблок модифицируется лишь в случае, если необходимо
изменить размер виртуального диска во время запуска системы потому, что он
оказался больше, чем размер устройства. Тем не менее чтение и запись супер
блока отличаются от аналогичных операций для обычного блока, поскольку размер
5.6 . Обзор файловой системы M I N IX 3 61 3
5 . 6 . 6 . Каталоги и пути
Другим важным компонентом файловой системы является подсистема управле
ния каталогами и путями. Многие системные вызовы, такие как open, в качестве
аргумента получают имя файла. Но в действительности им нужен номер индекс
ного узла этого файла, поэтому файловая система должна просмотреть дерево
каталогов и найти нужный индексный узел.
В предыдущих версиях M INIX каталог представлял собой файл, содержащий
1 6-байтовые записи, где первые два байта отводились под номер индексного
узла, а оставшиеся 14 - под имя файла. Такая структура ограничивала число
файлов раздела значением 2 16 , а длину имени - 14 символами, как и в UNIX
версии 7. Вместе с объемом дисков имена файлов также выросли. В MINIX 3
новая версия файловой системы поддерживает записи каталога длиной 64 байта,
где 4 байта занимает номер индексного узла и 60 байт - имя файла. Четыре мил
лиарда файлов в одном разделе, по сути, является бесконечно большим числом,
а любого программиста, называющего файлы именами длиной более 60 симво
лов, следует отправить на медицинское освидетельствование.
Обратите внимание на то, что пути не имеют 60-символьного ограничения на
длину:
/ u s r / a s t / cours e " ma t er i a l " f o r " t hi s " y e ar / opera t i ng " sy s t ems / examinat ion - 1 . ps
/ast/f1 /ast/f2
а б в /usr/ast/f2
Механизм монтирования:
Рис. 5 . 3 3 . а корневая файловая система; б немонтированная
- -
5 . 6 . 7 . Дескрипторы файлов
После того как файл открыт, пользователю возвращается дескриптор этого фай
ла, который впоследствии может использоваться в системных вызовах r ea d
или wr i t е. В данном разделе мы рассмотрим, как файловая система обращается
с дескрипторами.
Подобно ядру и менеджеру процессов, файловая система поддерживает в своем
адресном пространстве собственную часть таблицы процессов. Особенно интерес
ны три поля этой таблицы. Первые два из них содержат указатели на индексные
узлы корневого и рабочего каталогов. Поиск файла всегда начинается с одного
из указанных каталогов, в зависимости от того, задан абсолютный или относи
тельный путь. Значения этих указателей можно обновить при помощи систем
ных вызовов chroot и chdir, которые изменяют соответственно текущие кор
невой и рабочий каталоги.
Третье интересное нам сейчас поле представляет собой массив, индексами в ко
тором являются номера файловых дескрипторов. Этот массив служит для того,
чтобы по данному дескриптору определить соответствующий ему файл. На
первый взгляд, достаточно, чтобы элементы этого массива представляли собой
указатели на индексный узел файла. В конце концов, индексный узел загружает
ся в память при открытии файла и хранится там до закрытия файла, то есть ин
дексный узел гарантированно доступен.
К несчастью, этот простой план обречен на провал, так как в MINIX 3 (как
и в UNIX) можно совместно работать с файлом. Возникающая проблема связа
на с 32-разрядным числом, индицирующим, какой байт считывается следующим.
Это тот самый номер, называемый файловым указателем (или указателем по
зиции в файле), который меняется системным вызовом l s eek. Проблема выра
жается следующим вопросом: « Где должен храниться файловый указатель? �
Первый вариант - поместить его в индексный узел. Но, к сожалению, если два
(или более) процесса будут в одно и то же время держать файл открытым, им
придется завести собственные указатели, так как иначе вызов l s eek, сделанный
одним процессом, будет влиять на следующую операцию чтения другого процес
са. Вывод: файловый указатель нельзя хранить в индексном узле.
А что насчет того, чтобы поместить его в таблицу процессов? Почему бы не
взять второй массив, параллельный массиву файловых дескрипторов, и хранить
в нем файловый указатель для каждого файла? Эта идея также не работает, хотя
и по более тонкой причине. Основная подоплека проблемы кроется в семантике
системного вызова f o rk. Когда процесс ветвится, то и родительский, и дочерний
процессы должны использовать единый указатель для всех открытых файлов.
Чтобы лучше понять проблему, представим себе сценарий оболочки, в котором
стандартный вывод перенаправлен в файл. Когда оболочка ответвляет от себя
первую программу, позиция в файле стандартного вывода для нее равна О. Это
значение наследуется потомком, который направляет в стандартный вывод,
предположим, 1 Кбайт данных. После завершения потомка значение указателя
должно быть равно 1 К.
5.6. Обзор файло в ой системы M I N IX 3 617
Таблица filp
Таблица
процессов Таблица i-узлов
Указатель положения
в файле для i-узла
Родитель
Потомок
r r r r
Рис. 5 . 34 . Совместное использование файловых указателей родительским
и дочерним процессами
Единственным обязательным значением, которое необходимо хранить в таблице
f i lp, является значение файлового указателя, но для удобства туда же записы
вается и указатель на индексный узел. Массив файловых дескрипторов в табли
це процессов при этом содержит указатели на записи в массиве f i lp. Кроме то
го, в таблице f i lp находятся значения битов управления доступом, некоторые
флаги, которые могут указывать, что файл открыт в каком-либо специальном режи
ме, и счетчик количества процессов, использующих данный указатель. Счетчик
необходим для того, чтобы файловая система могла определить, когда завершит
ся последний процесс, обращающийся к данной ячейке, и освободить ее.
5 . 7 2 Табл ицы
. .
Управление блоками
С кэшем блоков работают подпрограммы из файла c ache . с . Он содержит де
вять процедур, перечисленных в табл. 5.6. Первая из них, get_Ы ock (строка
22426), реализует стандартный способ получения блока данных. Когда процеду
ре файловой системы необходимо прочитать блок пользовательских данных, ка
талог, суперблок или блок любого другого типа, она вызывает функцию get_
Ы о сk, указывая ей номер блока и устройство.
NR_BUF _НASH - 1 . Если имеется 256 списков, маска равна 255, и все блоки, в но
мерах которых совпадают последние 8 бит, попадают в один список. Получается
256 списков для номеров 00000000, 0000000 1 , ... , 1 1 1 1 1 1 1 1 .
При поиске блока на первом шаге выясняется, в какой из цепочек хеш-таблицы
блок находится, хотя есть один особый случай, когда считывается свободное ме
сто из разреженного файла и поиск пропускается. Это - причина проверки, вы
полняемой в строке 22454. Если данный особый случай не обнаружен, следую
щие две строки устанавливают указатель Ьр на начало той цепочки, в которой
оказался бы нужный блок, если бы он был в кэше, для чего на номер блока на
кладывается маска НАSН_МАSК. В следующем далее цикле перебираются элемен
ты цепочки в поисках запрошенного блока. Если блок найден и в данный момент
не используется, он исключается из LR U-списка. Если он используется, то в LR U
списке его уже нет. Затем вызывающей программе возвращается указатель на
найденный блок (строка 22463).
Если в списке нужный блок не обнаружен, то и в кэше его нет, потому из LRU
списка выбирается дольше всех не использовавшийся блок. Выбранный блок ис
ключается из хеш-цепочки, так как ему будет назначен новый номер, и он попа
дет в другую цепочку. Если информация в блоке изменена, она записывается на
диск (строн:а 22495). Если это делать при помощи вызова f lu sha l l , будут со
хранены все измененные блоки с того же устройства. Большинство блоков запи
сываются именно так. Применяемые в текущий момент блоки никогда не могут
быть отданы для другого запроса, так как они отсутствуют в LRU-списке. Одна
ко блоки почти никогда не находятся в работе, и процедура put_Ы o c k обычно
освобождает блок сразу по окончании использования.
Как только получен новый буфер, во все его поля, включая поле b_dev, записы
ваются новые значения (строки 22499-22504), и можно считывать данные блока
с диска. Есть только два случая, в которых считывать диск с блока необязатель
но. Функция get_Ы o c k может быть вызвана с параметром only_search. Это
может означать, что выполняется упреждающее выделение блока. Упреждающее
выделение подразумевает, что содержимое обнаруженного буфера при необхо
димости перезаписывается на диск и ему назначается новый номер, но в поле Ь_
dev заносится значение NO_DEV, как свидетельство того, что блок не содержит
данных. Пример мы увидим, когда станем обсуждать функцию rw_s c a t t ered.
Кроме того, параметр only_search может использоваться тогда, когда блок ну
жен файловой системе для полной перезаписи его содержимого. Тогда считыва
ние старых данных было бы пустым расточительством. В том и другом случа
ях параметры блока обновляются, но реальное чтение не выполняется (строки
22507-225 13). Когда новый блок готов и при необходимости считан, get_Ы o c k
возвращает указатель н а него в вызывающую программу.
Предположим, что файловой системе временно, чтобы найти имя файла, нужен
блок каталога. Тогда, чтобы получить этот блок, она вызывает функцию get_
Ы о сk. Обнаружив имя файла, она, чтобы вернуть блок в кэш, вызывает функ
цию put_Ыo ck (строка 22520), освобождая буфер про запас, в расчете, что позд
нее он понадобится для другого блока.
5.7. Реали зация файл овой систем ы MINIX 3 627
Код rw_i node несколько сложнее, чем подразумевает приведенная схема, так
как от него требуются некоторые дополнительные действия. Во-первых, поскольку
определение текущего времени требует вызова ядра, все поля индексного узла,
поддежащие обновлению значением времени, только помечаются путем установки
соответствующих битов в поле индексного узла в памяти i_update. Если это поле
будет иметь ненулевое значение, при записи вызывается функция updat e_t ime s.
Во-вторых, дополнительную сложность вносит история MINIX. В старой версии
файловой системы (в версии 1 ) индексные узлы на диске имели структуру, от
личную от структуры в версии 2. Поэтому о преобразовании заботятся две функ
ции, o l d_ic opy (строка 23 1 68) и new_ i c opy (строка 232 14). Первая из них
преобразует представление индексного узла в памяти в формат версии 1 . Вторая
делает то же самое для версий 2 и 3. Обе функции используются только в преде
лах этого файла, поэтому они объявлены как PRIVATE. Обе они выполняют пре
образование в двух направлениях, как из памяти на диск, так и обратно.
Предшествующие версии MINIX были перенесены на системы, где расположе
ние байтов в слове отличается от такового в процессорах Intel. В будущем анало
гичный перенос предполагается и для M INI X 3. В каждой реализации инфор
мация на диске хранится в том порядке, какой принят в системе. А что это за
порядок, система узнает из поля sp - >nat ive в суперблоке. Поэтому функции
o l d_ i c opy и new_i c opy при необходимости вызывают подпрограммы c onv2
и c onv4 с целью изменить порядок следования байтов. Разумеется, многое из
того, что мы описали, не используется в MINIX 3, поскольку эта система не под
держивает файловую систему версии 1 в степени, достаточной ддя использования
дисков с этой файловой системой. На момент написания книги никто не перенес
MINIX 3 на платформу с другим порядком следования байтов. Тем не менее эти
биты и поля сохраняются на случай, если кто-нибудь захочет расширить область
применения операционной системы.
Процедура dup_inode (строка 23257) просто увеличивает на единицу счетчик
использования индексного узла. Она вызывается при повторном открытии фай
ла, при этом индексный узел не нужно еще раз считывать с диска.
Управление суперблоками
В файле super . с находятся процедуры для работы с суперблоками и битовыми
картами. Эти шесть процедур перечислены в табл. 5.8.
Как мы уже отмечали, когда требуется индексный узел или зона, вызывается
функция a l l o c_inode или a l l o c_z one. Каждая из них, в свою очередь, вызы
вает функцию a l l o c_Ь i t (строка 2332 4 ) , чтобы найти неустановленный бит
в битовой карте. Поиск включает в себя три вложенных цикла, работающих сле
дующим образом.
1. Внешний цикл перебирает все блоки битовой карты.
2. Промежуточный цикл перебирает все слова блока.
3. Внутренний цикл проверяет все биты в слове.
В промежуточном цикле выясняется, является ли текущее слово дополнением
нуля, то есть состоит ли оно целиком из единиц. Если да, значит, в этом слове
нет •свободных� бит о в, и проверяется следующее слово. Когда обнаруживается
другое значение, где по крайней мере один бит равен О, запускается внутренний
цикл, который определяет его позицию в слове. Если оказалось, что проверены
все блоки, но нулевых битов не нашлось, значит, свободных индексных узлов
или зон на диске нет, и возвращается код NO_B I T ( О ) . Подобный поиск может
потребовать много процессорного времени, но благодаря указателям на первый
свободный индексный узел (или зону), передаваемый из суперблока в a l l oc_
Ьi t в качестве начальной позиции для поиска, его удается сократить.
Обнулить •занятый� бит проще, чем установить, так как не требуется выполнять
поиск. Функция f ree_Ь i t (строка 23400) вычисляет, какой блок битовой кар
ты содержит сбрасываемый бит, и дальше вызывает функцию get_Ь l o c k, обну
ляет бит и завершает операцию вызовом put_Ь l ock.
При помощи следующей процедуры, ge t_sup e r (строка 23445), в таблице су
перблоков ищется запись для заданного устройства. Например, когда монтиру
ется файловая система, нужно проверить, не делается ли это повторно. Для этого
можно вызовом get_sup e r попробовать найти устройство, на котором файло
вая система расположена. Если устройство не найдено, то и файловая система
еще не смонтирована.
В MINIX 3 сервер файловой системы способен работать с файловыми система
ми, размеры блоков которых различны, хотя в каждом разделе диска использует
ся один и тот же размер. Функция get_Ь l o c k_s i z e (строка 23467) выясняет,
какой размер имеет блок в файловой системе. Она ищет заданное устройство в таб
лице суперблоков и возвращает размер блока, если устройство смонтировано.
В противном случае возвращается минимальный размер блока, MIN_BLOCK_S I Z E.
Функция mount ed (строка 23489) вызывается только при закрытии блочного
устройства. Обычно при закрытии такого устройства все данные, сохранен
ные в кэше, сбрасываются. Но если оказалось, что устройство смонтировано, это
нежелательно. Функции mounted передается указатель на индексный узел уст
ройства. Она проверяет, является ли устройство корневым или смонтированным,
и если устройство смонтировано, возвращает TRUE.
Наконец, перейдем к функции re ad_sup e r (строка 23509). Она отчасти похожа
на функции rw_Ь l o c k и rw_inode, но выполняет только чтение. Суперблок не
считывается в кэш; обращение к устройству происходит для прямого считыва
ния 1024 байт, расположенных со смещением 1 024 байта от начала устройства.
5.7. Реал изация файловой системы MINIX 3 633
Блокировка файлов
Функции POSIX для блокировки файлов перечислены в табл. 5.9. Область фай
ла можно заблокировать на запись и чтение или только на запись при помощи
системного вызова f cnt l с запросом F _S ETLK или F_SETLKW. Узнать, заблоки
рована ли та или иная область файла, можно с помощью запроса F _GETLК.
5 . 7 . З . Главная програм м а
Код главного цикла файловой системы находится в файле main . с (строка 24040).
Вход в него осуществляется после обращения к функции f s_i ni t за инициали
зацией. По своей структуре он очень похож на главный цикл менеджера процес
сов и драйверов устройств ввода-вывода. В нем вызывается функция get_work,
ожидающая прибытия следующего запроса на обслуживание (если не может
быть обслужен процесс, ранее приостановленный на чтении из канала или с тер
минала). Она же устанавливает значение глобальной переменной who, куда за
писывается номер ячейки в таблице процессов, принадлежащей вызывающему
процессу, а также заполняет другую глобальную переменную, c a l l_nr, записы
вая в нее номер сделанного системного вызова.
Как только управление возвращается в главный цикл, устанавливаются следую
щие флаги: fp указывает на запись вызывающего процесса в таблице процессов,
а super_u s e r говорит, принадлежит ли этот процесс суперпользователю. Уве
домления имеют наивысший приоритет, поэтому в первую очередь проверке
подлежит сообщение SYS_S I G, чтобы выяснить, собирается ли система завершить
работу. Вторым проверяется сообщение SYN_ALARМ, указывающее на то, что ус
тановленный файловой системой таймер истек. Сообщение NOT I F Y_ME S SAGE
означает, что драйвер устройства готов к обслуживанию, и передается на обра
ботку функции dev_s t a t u s . Затем начинается главное действо: на передний
план выходит процедура, выполняющая системный вызов. Адрес процедуры вы
бирается в таблице c a l l_ve c s указателей на процедуры, где в качестве индекса
выступает значение c a l l_nr.
При возврате управления в главный цикл проверяется значение флага dont_
reply. Если он установлен, значит, ответное сообщение не требуется (то есть
процесс заблокирован по причине чтения из пустого канала). Иначе отправляет
ся ответное сообщение при помощи функции rep ly (строка 24087 ). Последняя
команда в цикле должна распознавать последовательное чтение файла и, соот
ветственно, для повышения производительности пытаться загрузить следующий
блок до того, как в действительности придет запрос.
5.7. Реал изация файловой системы MINIX 3 635
Две следующие функции файла играют важную роль в главном цикле файловой
системы. Функция get_wo rk (строка 24099) проверяет, имеются ли ранее за
блокированные процедуры, которые могут продолжить работу. Если такие есть,
они считаются приоритетнее новых сообщений. Только тогда, когда у файловой
системы нет отложенных задач, она отправляет ядру запрос на получение сле
дующего сообщения (строка 24 1 24 ) . Несколькими строками далее находится
функция rep ly (строка 24 1 59), запускаемая после завершения системного вы
зова (успешного или неуспешного ). Процесс может быть завершен по сигналу,
и код состояния, возвращаемый ядром, игнорируется. В этом случае все равно
ничего больше не сделаешь.
Начало Конец
NULL
о
k c=J-------. NULL
.
п c=J-------. NULL
а
Начало Конец
NULL
о
п c=J-------. NULL
б
Начало Конец
NULL
о
п c=J-------. NULL в
где все блоки связаны друг с другом в LRU-список и хешированы. Полезно ра
зобраться в том, как возникла ситуация, показанная на рисунке. Сразу после
инициализации процедурой bu f_p o o l все буферы находятся в списке и все они
связаны в нулевую хеш-цепочку (рис. 5.35, а). Когда запрашивается буфер,
структура приходит в состояние, показанное на рис. 5.35, б, и остается в нем, пока
буфер используется. На этом рисунке мы можем видеть, что блок исключен из
LRU-списка и помещен в отдельную хеш-цепочку.
Обычно же блок освобождается и возвращается в LRU-список немедленно
(рис. 5.35, в). Здесь блок, хотя и не используется более, все еще содержит инфор
мацию и при необходимости может быть извлечен из хеш-цепочки. После того
как система поработает некоторое время, почти все блоки, скорее всего, окажут
ся случайно распределенными между различными цепочками. LR U-список при
этом будет выглядеть так, как показано на рис. 5.32.
Следующую функцию, bu i l d_dmap, мы опишем позже, когда пойдет речь о функ
циях, работающих с файлами устройств. После этого вызьшается функция l o ad_
ram, которая, в свою очередь, использует функцию iget env (строка 264 1 ). По
следняя получает от ядра численный идентификатор, передавая ему в качестве
аргумента параметр загрузки. Если вы пользовались командой sy s env для про
смотра параметров загрузки работающей системы MINIX 3, вы видели, что ин
формация отображалась в виде строк, подобных следующей:
r o o t dev= 9 1 2
осуществляет запись в суперблок, однако, как и при чтении последнего, кэш бло
ков не используется и данные пишутся непосредственно на устройство с помо
щью функции dev_io.
Сейчас два момента заслуживают комментария. Первый - код в строках 2429 1 -
24307, обрабатывающий вариант загрузки с компакт-диска. В нем используется
функция cdp robe, не рассматриваемая в этой книге. Заинтересованным читате
лям мы предлагаем обратиться к коду файла f s / cdprobe . с, который можно
найти на компакт-диске и веб-сайте MINIX 3. Второй момент: независимо от ис
пользуемого MINIX 3 размера обычных блоков, размер загрузочного блока всегда
равен 1 Кбайт, а суперблок загружается из второго килобайта дискового устрой
ства. Любые другие варианты оказались бы сложными, поскольку размер блока
можно узнать, лишь загрузив суперблок.
Функция l oad_rarn выделяет пространство под пустой виртуальный диск, если
указан ненулевой размер rarns i z e, при этом виртуальный диск не используется
в качестве корневой файловой системы. Виртуальный диск будет можно задей
ствовать как файловую систему лишь после инициализации командой rnk f s ,
поскольку структуры файловой системы не скопированы в него. В качестве аль
тернативы такой виртуальный диск можно сделать вторичным кэшем, если соот
ветствующая поддержка интегрирована в файловую систему.
Последняя функция файла rna i n . с, функция l oad_sup e r (строка 24426), ини
циализирует таблицу суперблоков и считывает в нее суперблок корневого уст
ройства.
индексный узел и делает для него запись каталога. Фактически, большую часть
работы выполняет функция new_node (строка 24797). Если индексный узел уже
существует, возвращается код ошибки. Код ошибки тот же самый, который бьm
приемлемым при открытии файла. Однако в данном случае код возвращается
в вызывающую программу, которая, предположительно, подобающим образом его
интерпретирует. Подробный анализ отдельных случаев, проводимый в c ommon_
open, здесь не нужен.
Функция do_rnkdi r (строка 24805) выполняет системный вызов rnkd i r. Как
и в случае с предыдущими системными вызовами, важную роль здесь играет
функция new_node. Каталоги в отличие от файлов никогда не бывают пустыми,
так как любой каталог содержит, по крайней мере, две записи, точку ( . ) и две
точки ( . . ), первая из которых ссьmается на сам каталог, а вторая - на вышестоя
щий. Количество ссылок на один файл ограничено константой L INК_МAX (в файле
inc l ude / l irni t s . h для стандартной конфигурации MINIX 3, предназначенной
для платформы lntel, она определена как SHRT_МAX и ее значение равно 32767).
Поэтому, раз дочерний каталог содержит ссылку на родительский, функция do_
rnkdi r сначала проверяет, можно ли добавить новую ссылку на родительский ка
талог (строки 24819-24820). Когда эта проверка пройдена, вызывается функция
new_node. Если и этот вызов удался, для каталогов создаются записи . и . .
(строки 2484 1 -24842). Описанный алгоритм прямолинеен, но учитывает возмож
ность сбоев (например, переполнение диска). Чтобы ничего не испортить, обес
печивается откат к исходному состоянию, если процесс не может быть завершен.
Закрыть файл всегда проще, чем открыть. Поэтому функции do_c l o s e (стро
ка 24865) для обычных файлов, фактически, требуется только уменьшить значе
ние счетчика в f i lp и, если оно достигло нуля, возвратить индексный узел при
помощи функции put_i node. (Каналам же и специальным файлам требуется
особое внимание.) На последнем шаге аннулируются все блокировки, связанные
с этим файлом, и пробуждаются все процессы, приостановленные по факту бло
кировки.
Заметьте, что возврат индексного узла означает только, что уменьшается счетчик
в таблице индексных узлов, следовательно, в конце концов, он может быть уда
лен из таблицы. Эта операция не имеет ничего общего с освобождением индекс
ного узла (то есть со сбросом бита в битовой карте индексных узлов). Объект
индексного узла освобождается только тогда, когда файл больше не находится
ни в одном из каталогов.
Последняя процедура в файле open . с - процедура do_l s eek (строка 24939).
Она вызывается, когда осуществляется переход на заданную позицию в файле. При
этом блокируется упреждающее чтение (строка 24968), поскольку явное переме
щение на заданную позицию в файле несовместимо с последовательным доступом.
Чтение файла
Открыв файл, его можно читать или записывать в него данные. Функций для
этого больше, чем достаточно, - все связанные с чтением функции можно найти
в файле read . с. Мы обсудим сначала их, а затем перейдем к следующему файлу,
642 Гла ва 5. Файло в ые систем ы
Номера байтов
о 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 ... Блок Блок •1
я позиция = 1
�- Порция данных б
Текущая позиция = 6
t
1 1 J 1 � Порция данных 2
Текущая позиция = 9
t
1 1 1 1 � Порция данных 1
Рис . 5 . 36 . Три примера того, как для 1 О-байтового файла определяется размер первого
фрагмента данных. Размер блока равен 8 байт, запрашивается 6 байт.
Фрагмент отмечен штриховкой
Процедура rw_chunk (строка 2525 1 ) получает на входе индексный узел и пози
цию в файле, преобразует эти значения в физический номер блока на диске и за
прашивает передачу этого блока (или его части) в область пользовательских
данных. Преобразование относительной позиции в файле в физический адрес на
диске выполняется функцией read_rnap, которая осведомлена о структуре ин
дексных узлов и блоков косвенной адресации. Для обычного файла переменные
Ь и dev в строках 25280 и 25281 содержат соответственно физический номер
блока и номер устройства. Вызов get_Ы o c k (строка 25303) запрашивает у об
работчика кэша блоков нужный блок, считывая его при необходимости. Затем
вызов rahead (строка 25295) убеждается в том, что блок считан в кэш.
После того как указатель на блок получен, вызов sys_vi rc opy ядра в строке
253 1 7 обеспечивает копирование данных в пользовательское пространство. За
тем блок освобождается, чтобы позже он мог быть удален из кэша. ( После того
как вызов get_Ы oc k находит нужный блок, тот исключается из LRU-списка
и пребывает вне его до тех пор, пока счетчик использования в заголовке буфера
не обнулится. Вызов put_Ыock уменьшает значение этого счетчика и, если наста
ло время, возвращает буфер в LRU-список.) Код в строке 25327 определяет, запол
нился ли блок при записи. Правда, на данном этапе это уже не принципиально,
так как функция put_Ыock теперь игнорирует значение, передаваемое ей во вто
ром аргументе, и всегда добавляет освободившиеся блоки в конец LR U-списка.
Функция read_rnap (строка 25337) преобразует логическое смещение в файле
в физический номер блока, пользуясь для этого информацией индексного узла.
Те блоки, которые достаточно близки к началу файла, попадут в одну из первых
семи зон (то есть в одну из зон, хранящихся в самом индексном узле). При этом
чтобы узнать, какая из зон необходима, требуется только несложная арифметика.
644 Глава 5. Файловые систем ы
Для блоков, расположенных дальше, может понадобиться считать один или боль
ше блоков косвенной адресации.
Функция rd_i ndi r (строка 25400) вызывается, когда необходимо считать кос
венный блок. Комментарии к ней несколько устарели; во-первых, код поддержки
процессора 68000 удален, во-вторых, файловая система MINIX 1 больше не ис
пользуется и соответствующий ей код также можно исключить. Тем не менее
следует отметить, что в случае организации поддержки других файловых систем
или платформ, проблемы иных форматов сохранения данных на диске, типов дан
ных и порядка следования байтов можно решить в этом файле. Если без труд
ных для понимания преобразований данных не обойтись, то совершив их здесь,
вы обеспечите единую форму представления данных во всей файловой системе.
Функция read_ahead (строка 25432 ) преобразует логическое положение в фи
зический адрес блока, вызывает функцию get_Ы ock, в результате чего блок
оказывается в кэше, и немедленно возвращает его. В конце концов, сделать с ним
она все равно ничего не может. Задача read_ahead лишь в том, чтобы повысить
вероятность найти данные в кэше, если они скоро понадобятся.
Обратите внимание, что функция read_ahead вызывается только из главного
цикла в rna in. Ее вызов не является частью вызова re ad. Важно понять, что эта
функция вызывается после того, как пользователю отправлен ответ, чтобы он
мог продолжать свою работу, пока файловая система дожидается завершения
упреждающего чтения.
Сама функция r ead_ahead написана так, чтобы запрашивать всего один блок.
Реально трудится вызываемая ею подпрограмма rahead. В rahead (строка 2545 1 )
заложена та жизненная концепция, что если немного больше - хорошо, а намно
го больше - еще лучше. Так как дискам и прочим накопителям часто требуется
много времени, чтобы найти первый запрошенный блок, но зато они могут быст
ро считать несколько смежных блоков, делается ставка на то, что получится счи
тать много последовательных блоков ценой небольших дополнительных затрат.
Запрос на упреждающую выборку передается функции get_Ь l ock, подготавли
вающей кэш блоков к получению нескольких блоков за раз. Затем вызывается
функция rw_scatt ered, которой передается список блоков. Работу этой функции
мы уже обсуждали. Вспомните, что rw_s c a t t e r e d передает запрос драйверу
устройства, который в ответ имеет право обслужить столько запросов, сколько
он способен выполнить эффективно. Все это звучит довольно витиевато, но зато
позволяет на нужное •много� повысить быстродействие приложений, считываю
щих с диска ожидаемое •больше� данных.
На рис. 5.37 показаны взаимосвязи между основными подпрограммами, участ
вующими в чтении файла. В том числе указано, кто кого вызывает.
Зап ис ь
Код, обеспечивающий запись, находится в файле wri t e . с. Запись в файл в боль
шинстве своем сходна с чтением, и функция do_wr i t e (строка 25625) просто
вызывает read_wri t e с флагом WRITING. Основное отличие записи в том, что
здесь может потребоваться выделение дополнительных блоков. Функция wri t e_
5.7. Реализаци я файло вой системы MINIX 3 645
map (строка 25635) аналогична read_map с той разницей, что вместо поиска
физического адреса блока по индексному узлу и косвенным блокам она добавля
ет номер новой зоны, а не блока.
Точки входа
�
Определение�
дискового адреса
, Возврат
блока
�
�
В КЭШ
Доступ к косвенному
блоку Поиск в кэше
(если нужно )
Опять же, если бы в случае неудачи можно было просто сообщить о фатальной
ошибке ядра, код был бы намного компактнее. Однако с точки зрения пользовате
ля, гораздо лучше, когда при переполнении диска wr i t e возвращает код ошибки
вместо того, чтобы провоцировать крах, к тому же с разрушением файловой системы.
Функция wr_indi r (строка 25726) записывает новый номер зоны в косвенный
блок, а чтобы преобразовать данные в нужный формат (порядок следования бай
тов), она вызывает подпрограмму преобразования c onv4 . Здесь мы снова имеем
дело с устаревшим кодом, работающим с файловой системой версии 1 ; на самом
деле, используется лишь код, работающий с версией 2. Пусть имя этой функции
не вводит вас в заблуждение. Помните, что действительную запись данных на
диск выполняют функции, обслуживающие кэш блоков.
Далее в файле wr i t e . с следует функция c l e ar_z one (строка 25747). Она за
нимается очисткой блоков, оказавшихся в середине файла. Такое может слу
читься, если записать некоторый объем данных после конца файла. К счастью,
это случается не очень часто.
Функция new_Ы ock (строка 25787) вызывается из rw_chunk, когда требуется
новый блок. На рис. 5.38 показаны шесть последовательных этапов увеличения
файла. В этом примере размер блока равен 1 Кбайт, а зоны 2 Кбайт. -
Свободные зоны: 1 2 20 3 1 36 . . .
в
j 24 j 2s j 40 j
г
l 24 l 2s l 40 l 4 1 1
д
l фs l 40 l • 1 l 02 I
2 r Номор бл<жо
е
l 24 l 2s l 40 l 4 1 j в2 I�
Рис. 5 . 38 . Последовательное выделение блоков размером 1 Кбайт при размере зоны 2 Кбайт
Здесь при первом своем вызове функция new_Ы o ck выделяет зону 12 (блоки
24 и 25). Затем она задействует блок 25, который уже выделен, но еще не исполь
зован. При третьем вызове выделяется зона 20 (блоки 40 и 4 1 ) и т. д.
Функция z ero_Ы ock (строка 25839) очищает блок, стирая его предыдущее со
держимое. Честно говоря, это описание длиннее, чем сам код.
5 . 7 . 5 . Каталоги и пути
Итак, мы завершили обзор функций записи и чтения файлов. Наша следующая
задача - разобраться, как обрабатываются пути к файлам и каталоги.
get_iпode Загрузка
i-узла
по компонентам
пути
Определение Поиск бпока Возврат бпока
адресов в кэше в кэш
на диске
Рис . 5 . 3 9 . Некоторые из процедур, участвующих в поиске файла по его пути
Хотя может показаться, что нет смысла бесконечно повторять проверки, практи
ка показывает, что в реальных операционных системах значительная часть кода
выполняет рутинную работу, которая не слишком интересна, но имеет ключевое
значение для системы. Если пользователь иногда случайно будет пытаться мон
тировать поврежденную дискету, это приведет к тотальной порче файловой сис
темы, и он решит, что система ненадежна, в чем виноватым, естественно, окажет
ся не пользователь, а разработчик.
Томас Эдисон сделал одно замечание, которое применимо и к нашему случаю.
Он сказал, что гений - это 1 % вдохновения и 99 % труда. Различие между хоро
шей и посредственной системой состоит не в превосходном алгоритме планиро
вания, а в том внимании, которое уделено деталям.
Демонтировать файловую систему проще, чем монтировать. Эту задачу в два
этапа решает функция do_umount (строка 26828). Она убеждается, что вызов
бьш сделан суперпользователем, преобразует имя в номер устройства, а затем
обращается к подпрограмме unmount (строка 26846), завершающей операцию.
Единственная проблема в том, что все файлы на демонтируемой файловой сис
теме должны быть закрыты, и ни у одного процесса не должно быть текущего
каталога на ней. Проверка осуществляется тривиально: сканируется вся табли
ца индексных узлов на предмет поиска в памяти хотя бы одного индексного
узла, принадлежащего демонтируемой файловой системе. Если да, umount рапор
тует об ошибке.
Последняя подпрограмма в файле mount . с носит имя name_t o_dev (строка
26893). Она определяет главный и вспомогательный номера устройства по пере
даваемому ей имени специального файла. Эти номера хранятся в самом индекс
ном узле, там, где у обычных файлов хранится информация о первой зоне. Это
место пустует, поскольку у специальных файлов нет зон.
Вот некоторые из возможных ошибок, которые могут произойти при этом вызове:
+ файл f i l e_name не существует или недоступен;
+ у файла f i l e_name уже есть максимальное количество ссьшок;
+ файл f i l e_name является каталогом (создавать такие ссылки имеет право
только суперпользователь);
+ файл l ink_name уже существует;
+ файлы l ink_name и f i l e_name расположены на разных устройствах.
Если все в порядке, в каталоге создается новая запись с именем l ink_name и но
мером индексного узла f i l e_name . В коде имя name l соответствует f i l e_
name, а name 2 - l ink_name. Вносит новую запись в каталог функция s e arch_
dir, вызываемая из do_l ink в строке 27086.
5.7. Реализация файловой системы MINIX 3 65 1
З ащита
Механизм защиты в MINIX 3 основан на битах rwx. Это три набора битов, каж
дый из которых определяет доступность файла для его владельца, группы и для
остальных. Значениями этих битов можно управлять при помощи системного
вызова chmod, инициируемого функцией do_chmod из файла pro t e c t с (стро .
ка 27824). Она сначала делает ряд проверок, а затем меняет режим доступа к фай
лу (строка 27850).
Вызов chown подобен вызову chrnod в том, что он тоже меняет значения внут
ренних полей индексного узла некоторого файла. Поэтому их реализация тоже
достаточно схожа, хотя do_chown (строка 27862) позволяет менять владельца
файла только суперпользователю. Обычные пользователи вправе применять этот
вызов, чтобы менять принадлежность их собственных файлов к группе.
Вызов urnask позволяет задать маску (хранящуюся в таблице процессов), которая
маскирует биты разрешений при последующих вызовах creat. Весь код уместил
ся бы в одну строку (27907), если бы не потребность в восстановлении старого
значения маски. Это дополнительное требование утраивает объем кода ( стро
ки 27906-27908).
При помощи системного вызова ac c e s s процесс может выяснить, разрешен ли
ему определенный способ доступа к файлу (например, на чтение). Этот вызов
реализуется функцией do_ac c e s s (строка 279 14), которая считывает индекс
ный узел файла, а затем вызывает вспомогательную функцию f orЬi dden (стро
ка 27938). Та, в свою очередь, проверяет U I D и GID процесса, а также инфор
мацию в индексном узле и в зависимости от этих данных принимает решение
о том, разрешен доступ или запрещен.
Небольшая процедура re ad_only проверяет файловую систему, в которой распо
ложен переданный ей индексный узел, и определяет, смонтирована ли она с дос
тупом только на чтение. Эта функция необходима для предотвращения попыток
записи в такую файловую систему.
654 Глава 5 . Файловые системы
Первое нулевое значение указывает на то, что запись относится к драйверу, ко
торый не обязан быть в загрузочном образе. По умолчанию при попытке откры
тия устройства первый указатель вызывает функцию no_dev, возвращающую
вызвавшему процессу ошибку ENODEV (нет такого драйвера). Следующие два
нулевых значения также используются по умолчанию: поскольку устройство
невозможно открыть, нет необходимости вызывать функцию для фактического
ввода-вывода. Нуль в элементе таблицы процессов интерпретируется как отсут
ствие процесса. Значение DМAP_МUTABL E указывает на то, что изменения этой
записи разрешены (обратите внимание, что отсутствие такого флага в записи
драйвера памяти означает невозможность ее модификации после инициализа
ции). Система MINIX 3 может быть сконфигурирована как на наличие, так и на
отсутствие драйвера дисковода для дискет в загрузочном образе. Если драйвер
присутствует и определен параметром загрузки l abe l FLOPPY как дисковое
=
В ремя
Каждому файлу сопоставлены три 32-разрядных числа, связанные со временем.
Первые два хранят время последнего доступа к файлу и момент его последнего
изменения. В третьем фиксируется время последнего изменения состояния са
мого индексного узла. Это время меняется практически при каждом обращении
к файлу, за исключением вызовов read и ехе с . Все значения хранятся в индекс
ном узле. При помощи системного вызова ut irne владелец файла или суперполь
зователь может изменить время доступа и изменения. Это делается процедурой
do_u t irne (строка 288 18) из файла t irne . с, которая получает индексный узел
и записывает в него значения времени. Затем сбрасываются флаги, индицирующие,
660 Глава 5. Файловые системы
что требуется обновить время (строка 28848), с целью избежать затратного и не
нужного здесь вызова c l oc k_t ime.
Как мы знаем из предыдущей главы, реальное время рассчитывается как сумма
времени, отсчитанного от последнего запуска системы и поддерживаемого таймер
ным заданием, и реального времени запуска. Возврат значения реального времени
осуществляет вызов s t ime. Большую часть его работы делает менеджер процессов,
однако глобальная переменная boo t t ime, хранящая время запуска системы, под
держивается файловой системой. Каждый раз при поступлении вызова s t ime
менеджер процессов посылает файловой системе сообщение, благодаря кото
рому ее функция do_s t ime (строка 28859) обновляет переменную boo t t ime .
Табл ица 5. 1 О . Параметры запроса системного вызова FCNTL согласно стандарту POSIX
Действие Значение
F_DU PFD Дублирование дескриптора
F_G EТFD Считывание флага закрытия файла при системном вызове ехес
F_S EТFD Установка флага закрытия файла при системном вызове ехес
F_G EТFL Считывание флагов состояния файла
F_SEТFL Установка флагов состояния файла
F_GEТLK Считывание состояния блокирования файла
F_SEТLK Блокирование чтения и записи в файл
F_SEТLКW Блокирование записи в файл
Функция do_f cn.t l также занимается обработкой блокирования файлов. Вызов
с командой F_GETLK, F_SETLK или F_SETLKW преобразуется в вызов l o ck_op,
рассмотренный в предыдущем разделе.
Следующий системный вызов, sync, копирует все блоки и индексные узлы, изме
ненные со времени записи на диск. Его обработкой занимается функция do_sync.
Она просто выполняет поиск измененных записей во всех таблицах. Индексные
узлы должны быть обработаны первыми, поскольку функция rw_inode сохраня
ет свои результаты в кэше блоков. После записи в кэш блоков всех модифициро
ванных индексных узлов все модифицированные блоки сбрасываются на диск.
Системные вызовы f o rk, ехе с , exi t и s e t принадлежат менеджеру процессов,
однако их результаты должны быть доступны и здесь. При создании процесса
посредством f ork необходимо, чтобы ядро, менеджер процессов и файловая сис
тема знали об этом. Эти «системные вызовы� поступают не от пользовательских
процессов, а от менеджера процессов. Процедуры do_f ork, do_exi t и do_s et
фиксируют соответствующую информацию в части таблицы процессов, принадле
жащей файловой системе. Процедура do_exe c с помощью процедуры do_
c l o s e ищет и закрывает файлы, которые должны быть закрыты при вызове ехе с .
Последняя функция в файле rni s с . с не является системным вызовом, однако
обрабатывается похожим образом. Функция do_revi ve вызывается, когда драй
вер устройства завершает работу, затребованную файловой системой, которую
он был не в состоянии выполнить ранее (например, предоставить пользова
тельскому процессу введенные данные). Файловая система возобновляет про
цесс и посылает ему ответное сообщение.
Существует системный вызов, поддержка которого осуществляется отдельными
заголовочным и исходным С-файлами. Это - вызов s e l e c t , поддерживаемый
файлами s e l e c t . h и s e l e c t . с. Вызов s e l ec t используется тогда, когда одно
му процессу (к примеру, сетевому приложению или программе взаимодействия)
требуется работать с несколькими потоками ввода-вывода. Детальное его описа
ние выходит за рамки темы данной книги.
662 Глава 5. Файловые системы
5 . 7. 1 О. П роч ие компоненты M I N IX 3
Менеджер процессов, описанный в предыдущей главе, и файловая система, рас
смотренная в этой главе, являются серверами пользовательского пространства,
предоставляющими поддержку, которая в традиционных операционных системах
интегрирована в ядро. Конечно же, в MINIX 3 существуют и другие серверные
процессы. Они находятся в пользовательском пространстве, имеют системные
привилегии и должны рассматриваться как компоненты операционной системы.
Рез ю ме 663
Р ез юм е
Со стороны файловая система представляется как коллекция файлов, каталогов
и инструментов для действий над ними. Можно считывать или записывать фай
лы, создавать и уничтожать каталоги и перемещать файлы из одного каталога
в другой. В большинстве современных файловых систем поддерживается иерар
хическая структура каталогов, когда в один каталог может быть вложен второй
и т. д., до бесконечности.
Если же смотреть изнутри, открывается совершенно другая картина. Разработ
чики файловой системы должны заботиться о том, как выделяется место, и от
слеживать, какой блок какому файлу соответствует. Мы увидели, что в разных
файловых системах структуры каталогов различаются. Надежность и произво
дительность файловой системы тоже имеют существенное значение.
Исключительно важны как для пользователей, так и для разработчиков системы
вопросы безопасности и защиты. Мы обсудили известные уязвимости старых
664 Глава 5. Файловые системы
систем и общие проблемы, волне вероятные для многих других. Размышляя о за
щите, мы рассмотрели аутентификацию, с паролем и без, списки управления
доступом, мандатные системы, а также матричную моде.ль защиты.
Наконец, мы подробно изучили файловую систему MINIX 3. Ее код весьма объ
емен, но не очень сложен. Файловая система принимает запросы от пользователь
ских процессов, находит в таблице системных вызовов адреса процедур и вызы
вает эти процедуры, чтобы обслуживать запросы. Благодаря модульной структуре
и тому, что файловая система вынесена из ядра, ее можно легко выделить из
MINIX 3, превратив в самостоятельный сетевой файловый сервер, внеся лишь
незначительные поправки.
При обращении к файлу MINIX 3 буферизует блоки в кэше и пытается делать
упреждающее чтение при последовательном режиме работы с файлом. Если кэш
достаточно велик, то при многократных обращениях к одному и тому же набору
программ· (например, в процессе компиляции) нужный файл с высокой вероят
ностью окажется в памяти.
В опросы и задания
1 . В файловой системе NTFS для именования файлов используется кодировка
Unicode, поддерживающая 1 6-разрядные символы. В чем преимущество име
нования файлов в Unicode по сравнению с ASCII?
2. Некоторые файлы начинаются с �магического• числа. Для чего оно исполь
зуется?
3. В табл. 5.2 перечислены некоторые атрибуты файлов, однако в ней отсутству
ет атрибут четности. Является ли четность полезным атрибутом для файла?
Если да, то как ее можно использовать?
4. Создайте пять различных путей к файлу / e t c / p a s swd. Подсказка: исполь
зуйте в каталоге записи точка ( . ) и две точки ( . . ).
5. В системах, поддерживающих последовательный доступ, всегда имеется опе
рация �перемотки• файлов. Нужна ли такая операция в системах, поддержи
вающих файлы произвольного доступа?
6. В некоторых операционных системах предоставляется системный вызов rename,
позволяющий сменить имя файла. Есть ли разница между использованием
этого системного вызова и копированием файла с новым именем с последую
щим удалением старого файла?
7. Рассмотрите дерево каталогов на рис. 5.5. Если / u s r / j im является рабочим
каталогом, как будет выглядеть абсолютный путь для файла с относительным
путем . . / a s t / x?
8. Предположим, у файловой системы нет единого корневого каталога, а вместо
этого у каждого пользователя имеется собственный корневой каталог. Делает
ли это файловую систему более гибкой? Обоснуйте ответ.
Вопросы и з адан и я 665
16. Было предложено хранить первую часть каждого файла системы UNIX в том
же дисковом блоке, что и его индексный узел. Каковы преимущества такого
подхода?
17. Производительность файловой системы зависит от процента блоков, которые
удается в нем найти. Напишите формулу для среднего времени удовлетво
рения запроса блока при частоте успешных обращений, равной h, если об
служивание запроса с помощью кэша занимает 1 мс, а для считывания блока
с диска требуется 40 мс. Нарисуйте график этой зависимости для значений h
в интервале от О до 1 ,0.
1 8. В чем разница между жесткой связью и символической связью? Назовите
преимущества каждой из них.
19. Назовите три «ловушки�, которых необходимо избегать при резервном копи
ровании файловой системы.
20. У гибкого диска 4000 цилиндров, каждый из которых содержит 8 штук
5 1 2-блочных дорожек. Время установки составляет 1 мс на одно перемеще
ние между цилиндрами. Если не пытаться разместить блоки файла впритирку,
666 Глава 5. Файловые систем ы
36. Напишите две программы на языке С или в виде сценария интерпретатора, пе
редающие и принимающие сообщение по тайному каналу в системе MINIX 3.
Подсказки: во-первых, бит разрешения видим, даже если другие способы
доступа к файлу запрещены, во-вторых, команда или системный вызов s l eep
гарантирует задержку фиксированной длительности, заданную аргументом.
Измерьте скорость обмена данными в простаивающей системе, затем создай
те искусственную высокую нагрузку, запустив множество фоновых процес
сов, и снова измерьте скорость обмена данными.
37. Реализуйте в MINIX 3 непосредственные файлы (маленькие файлы, храни
мые в индексном узле и экономящие время доступа к диску).
Гл ава 6
Б и б л и о гр аф и я
В предыдущих пяти главах нами были затронуты разнообразные темы. Эта глава
призвана помочь читателям, желающим заняться углубленным изучением опе
рационных систем. В пункте 6. 1 приведен список рекомендуемой литературы,
а в пункте 6.2 - еще один список, в котором в алфавитном порядке перечислены
все публикации, цитаты из которых использованы в этой книге.
Полезными источниками публикаций об операционных системах являются сбор
ники докладов Симпозиума по принципам операционных систем ( Symposium
оп Operatiпg Systems Priпciples ), проводимого раз в два года, Международной
конференции по распределенным компьютерным системам (Iпternatioпal Соп
fеrепсе оп Distributed Computiпg Systems), проводимой IEEE ежегодно, а также
Симпозиума U S ENIX по проектированию и реализации операционных сис
тем. Кроме того, в журналах АСМ Traпsactioпs оп Computer Systems и Operatiпg
Systems Review периодически публикуются статьи, имеющие отношение к дан
ной тематике.
6 . 1 . 2 . П роцессы
+ Andrews and Schneider, « Concepts and Notations for Concurrent Programming�.
Учебное пособие по процессам и взаимодействию между процессами, вклю
чая активное ожидание, семафоры, мониторы, обмен сообщениями и прочие
методы. В данной статье также показано, как эти концепции поддерживаются
встроенными средствами различных языков программирования.
672 Глава 6. Библ иография
6 . 1 . З . Ввод-вы вод
+ Chen et al., «RAID: Нigh Performance ReliaЫe Secondary Storage� .
Параллельное использование нескольких жестких дисков для ускорения вво
да -вывода характерно для высокопроизводительных систем. Авторы рас
сматривают эту концепцию и исследуют различные варианты ее организации
с точки зрения производительности, стоимости и надежности.
+ Coffman et al., «System Deadlocks�.
Краткий обзор взаимных блокировок, их причин, способов обнаружения и пре
дотвращения.
+ Corbet et al., Linux Device Drivers, Зrd Ed.
Если вы действительно хотите понять, как работает ввод-вывод, попробуйте
написать драйвер устройства. Эта книга поможет вам сделать это для опера
ционной системы Linux.
+ Geist and Daniel, «А Continuum of Disk Scheduling Algorithms� .
Описан обобщенный алгоритм планирования головки диска, а также пред
ставлены многочисленные экспериментальные данные и результаты модели
рования.
+ Holt, «Some Deadlock Properties of Computer Systems� .
Рассматриваются взаимные блокировки. Автор представляет модель н а осно
ве направленных графов, с помощью которой можно анализировать некото
рые ситуации взаимных блокировок.
6. 1 . Рекоме ндуемая литература 673
6 . 1 . 4 . Управление памятью
+ Bic and Shaw, Operating System Principles.
Три главы этой книги посвящены управлению памятью, а также физической,
виртуальной и общей памяти.
+ Denning, « Virtual Memory•.
Классическая публикация по многим аспектам виртуальной памяти. Автор
был одним из пионеров в данной области и создателем концепции рабочего
множества.
+ Denning, « W orking Sets Past and Present•.
Полезный обзор множества алгоритмов управления памятью и замещения
страниц. Сопровождается объемной библиографией.
+ Denning, «The Locality Principle• .
Новый взгляд на историю принципа локальности и обсуждение его примене
ния к различным проблемам, не относящимся к замещению страниц.
+ Halpem, «VIM: Taming Software with Hardware• .
В этой провокационной статье автор доказывает, что н а создание, отладку
и поддержку программного обеспечения с оптимизированным использованием
674 Глава 6. Библиография
6 . 1 . 5 . Ф айловые систем ы
+ Denning, «The United States vs. Craig Neidorf� .
Когда молодой хакер получил и опубликовал информацию о принципах ра
боты системы телефонной связи, ему было предъявлено обвинение в компью
терном мошенничестве. Данная статья посвящена этому случаю, поднявшему
множество фундаментальных проблем, в том числе свободу слова. Статья
вызвала массу неоднозначных откликов, а сам автор впоследствии выступил
с опровержением.
+ Ghemawat et al., «The Google File System� .
Предположим, вы задались целью разместить дома весь Интернет, чтобы
всегда иметь любую информацию под рукой. Каким будет ваш первый шаг?
Вероятно, купить много персональных компьютеров, скажем, 200 ООО штук.
Никаких особых возможностей от этих компьютеров не потребуется. Ваш
второй шаг - прочитать эту статью и узнать, как этот подход реализован в сис
теме Google.
+ Hafner and Markoff, Cyberpunk: Outlaws and Hackers on the Computer Frontier.
Три замечательные истории о молодых хакерах, взламывающих компьютеры
по всему миру, рассказанные компьютерным репортером газеты New York
Times и его соавтором. Ранее из-под пера этого репортера вышла история об
интернет-черве.
+ Harbron, File Systems: Structures and Algorithms.
Книга, посвященная проектированию файловой системы, приложениям и про
изводительности. Содержит описания структур и алгоритмов.
+ Harris et al., Gray Hat Hacking: The Ethical Hacker's Handbook.
В этой книге рассматриваются юридические и этические аспекты тестирова
ния компьютерных систем на наличие уязвимостей, а также техническая ин
формация об их возникновении и обнаружении.
6.2. Алфави тн ый с п исок литературы 675
5. Bala, К., Kaashoek, M.F., and Weihl, W.: «Software Prefetching and Caching for
Translation Lookaside Buffers,» Proc. First Symp. on Oper. Syst. Design and Imp
lementation, USENIX, рр. 243--,-254, 1 994.
6. Basili, V.R., and Perricone, В.Т.: «Software errors and Complexity: An Empirical
Investigation,» Commun. of the АСМ, vol. 27, рр. 43-52, Jan. 1984.
7. Bays, С.: «А Comparison of Next-Fit, First-Fit, and Best-Fit, » Commun. of the
АСМ, vol. 20, рр. 1 9 1 - 192, March 1977.
8. Ben-Ari, М: Principles of Concurrent and Distributed Programming, Upper Saddle
River, NJ: Prentice Hall, 1990.
9. Bic, L.F., and SHAW, А. С.: Operating System Principles, Upper Saddle River, NJ:
Prentice Hall, 2003.
10. Boehm, H.-J.: «Threads Cannot Ье Implemented as а Library,» Proc. 2004 АСМ
SIGPLAN Conf. on Prog. Lang. Design and Impl., АСМ, рр. 2 6 1 -268, 2005.
1 1 . Bovet, D.P., and CESAТI, М.: Understanding the Linux Kernel, 2nd Ed., Sebastopol,
СА, O'Reilly, 2002.
12. Brinch Hansen, Р.: Operating System Principles Upper Saddle River, NJ: Prentice
Hall, 1973.
13. Brinch Hansen, Р.: Classic Operating Systems, New York: Springer-Verlag, 200 1 .
1 4 . Brooks, F . Р . , Jr.: The Mythical Man-Month: Essays o n Software Engineering,
Anniversary Ed., Boston: Addison-Wesley, 1995.
15. Cerf, V.G.: «Spam, Spim, and Spit,» Commun. of the АСМ, vol. 48, рр. 39-43,
April 2005.
16. Chen, Н, Wagner, D., and Dean, D.: «Setuid Demystified,» Proc. 1 1th USENIX
Security Symposium, рр. 171 - 1 90, 2002.
17. Chen, Р.М., Lee, Е.К., Gibson, G.A., Katz, R.Н., and Patterson, D.A.: «RAID: Нigh
Performance ReliaЫe Secondary Storage,» Computing Surveys, vol. 26, рр. 145-
185, June 1994.
18. Cheriton, D.R.: «An Experiment Using Registers for Fast Message- Based Inter
process Communication,» Operating Systems Review, vol. 18, рр. 12-20, Oct. 1984.
19. Chervenak, А., Vellanski, V., and Kurmas, Z . : «Protecting File Systems: А Survey
of Backup Techniques,» Proc. 1 5th Symp. on Mass Storage Systems, I EEE, 1998.
20. Chou, А., Yang, J. -F ., Chelf, В., and Hallem, S.: «An Empirical Study of Operating
System Errors,» Proc. 18th Symp. on Oper. Syst. Prin., АСМ, рр. 73-88, 200 1 .
2 1 . Coffman, E.G., Elphick, M.J ., and Shoshani, А.: «System Deadlocks,» Computing
Surveys, vol. 3, рр. 67-78, June 197 1 .
22. Corbato', F.J .: «On Building Systems That Will Fail,» Commun. of the АСМ, vol.
34, рр. 72�8 1 , Sept. 199 1 .
23. Corbato', FJ., Merwin-Daggett, М., and Daley, R.C: «An Experimental Time-Sharing
System,» Proc. AFIPS Fall Joint Computer Conf., AFIPS, рр. 335-344, 1962.
24. Corbato', FJ., Saltzer, J.H., and Clingen, С.Т.: «MULТI CS - The First Seven
Years,» Proc. AFIPS Spring Joint Computer Conf., AFIPS, рр. 57 1 -583, 1972.
6. 2. Алфавитн ь1й список литературы 677
25. Corbato', FJ., and Vyssotsky, V.A.: •lntroduction and Overview of the MULТICS
System,• Proc. AFIPS Fall Joint Computer Conf., AFIPS, рр. 1 85 - 1 96, 1965.
26. Corbet, ]., Rublni, А., and Kroah-Hartrnan, G. : Linux Device Drivers, 3rd Ed.
Sebastopol, СА: O'Reilly, 2005.
27. Courtois, Р.]., Heyrnans, F., and Parnas, D.L.: • Concurrent Control with Readers
and Writers, • Cornmun. of the АСМ, vol. 10, рр. 667-668, Oct. 197 1 .
28. Daley, R . C . , and Dennis, ] . В . : •Virtual Mernory, Processes, and Sharing in
MULТICS,• Cornrnun. of the АСМ, vol. 1 1 , рр. 306-3 12, Мау 1968.
29. Deitel, Н.М., Deitel, Р. ]., and Choffnes, D. R.: Operating Systerns, 3rd Ed., Upper
Saddle River, NJ: Prentice- Hall, 2004.
30. Denning, D.: •The United states vs. Craig Neidorf,• Cornrnun. of the АСМ, vol. 34,
рр. 22 -43, March 199 1 .
3 1 . Denning, P.J.: •The Working Set Model for Prograrn Behavior,• Cornrnun. of the
АСМ, vol. 1 1 , рр. 323-333, 1968а.
32. Denning, P.J.: •Thrashing: Its Causes and Prevention, • Proc. AFIPS National
Cornputer Conf., AFIPS, рр. 9 1 5-922, 1968Ь.
33. Denning, P.J .: •Virtual Mernory,• Cornputing Surveys, vol. 2, рр. 1 53- 189, Sept.
1970.
34. Denning, P.J .: •Working Sets Past and Present,• IEEE Trans. on Software Engi
neering, vol. SE-6, рр. 64-84, Jan. 1980.
35. Denning, P.J .: •The Locality Principle,• Cornrnun. of the АСМ, vol. 48, рр. 19-24,
July 2005.
36. Dennis, J.B., and Van Horn, Е.С.: • Prograrnrning Sernantics for Multiprograrnrned
Cornputations,• Cornrnun. of the АСМ, vol. 9, рр. 143 - 1 55, March 1 966.
37. DiВona, С., Ockrnan, S., and Stone, М. eds.: Open Sources: Voices frorn the Open
Source Revolution, Sebastopol, СА: O' Reilly, 1999.
38. Dijkstra, E.W.: • Co-operating Sequential Processes, • in Prograrnrning Languages,
Genuys, F. (Ed.), London: Acadernic Press, 1965.
39. Dijkstra, E.W.: •The Structure of ТНЕ Multiprograrnrning System,• Cornrnun. of
the АСМ, vol. 1 1 , рр. 34 1 -346, Мау 1 968.
40. Dijkstra, E.W.: •Му Recollections of Operating Systern Design,» Operating Systerns
Review, vol. 39, рр. 4-40, April 2005.
4 1 . Dodge, С., Irvine, С., and Nguyen, Т.: •А Study of Initialization in Linux and
OpenBSD,• Operating Systerns Review, vol. 39, рр. 79-93 April 2005.
42. Engler, D., Chen, D.Y., and Chou, А.: • Bugs as Inconsistent Behavior: А General
Approach to Inferring Errors in Systerns Code, • Proc. 18th Syrnp. on Oper. Syst.
Prin., АСМ, рр. 57-72, 200 1 .
4 3 . Engler, D.R., Kaashoek, M.F., and О'Тооlе, ]. Jr.: •Exokemel: An Operating Systern
Architecture for Application-Level Resource Managernent,• Proc. 15th Syrnp. on
Oper. Syst. Prin., АСМ, рр. 2 5 1 -266, 1995.
678 Глава 6. Библиография
63. Hutchinson, N. C., Manley, S., Federwisch, М., Harris, G., Hitz, D, Kleiman, S, and
O' Malley, S.: •Logical vs. Physical File System Backup,• Proc. Third USENIX
Symp. on Oper. Syst. Design and Implementation, USENIX, рр. 239-249, 1999.
64. IEEE: Information technology - PortaЫe Operating System Interface (POSIX),
Part 1: System Application Program Interface (API ) [ С Language] , New York:
IEEE, 1990.
65. Jacob, В., and Mudge, Т.: •Virtual Memory: Issues of Implementation, • IEEE
Computer, vol. 31, рр. 33-43, June 1998.
66. Johansson, ]., and Riley, S: Protect Your Windows Network: From Perimeter to
Data, Boston: Addison-Wesley, 2005.
67. Kernighan, B.W., and Ritchie, D . M . : The С Programming Language, 2nd Ed.,
Upper Saddle River, NJ: Prentice Hall, 1988.
68. Кlein, D.V.: • Foiling the Cracker: А Survey of, and Improvements to, Password
Security,• Proc. UNIX Security Workshop 11, USENIX, Aug. 1990.
69. Кleinrock, L.: Queueing Systems, Vol. 1 , New York: John Wiley, 1975.
70. Knuth, D.E.: The Art of Computer Programming, Volume 1 : Fundamental Algo
rithms, 3rd Ed., Boston: Addison-Wesley, 1997.
7 1 . Lampson, B.W.: •А Scheduling Philosophy for Multiprogramming Systems, •
Commun. o f the АСМ, vol. 1 1 , рр. 347-360, Мау 1968.
72. Lampson, B.W.: •А Note on the Confinement ProЬlem,• Commun. of the АСМ,
vol. 10, рр. 6 1 3-615, Oct. 1973.
73. Lampson, B.W.: •Hints for Computer System Design, • IEEE Software, vol. 1,
рр. 1 1 -28, Jan. 1984.
74. Ledin, G., Jr.: •Not Teaching Viruses and Worms is Harmful,• Commun. of the
АСМ, vol. 48, р. 144, Jan. 2005.
75. Leschke, Т.: •Achieving Speed and Flexibllity Ьу Separating Management from
Protection: Embracing the Exokernel Operating System, • Operating Systems
Review, vol. 38, рр. 5 - 1 9, Oct. 2004.
76. Levine, G.N.: •Defining Deadlocks,• Operating Systems Review vol. 37, рр. 54-64,
Jan. 2003а.
77. Levine, G.N.: •Defining Deadlock with FungiЬle Resources,• Operating Systems
Review, vol. 37, рр. 5- 1 1 , July 2003Ь.
78. Levine, G.N . : •The Classification of Deadlock Prevention and Avoidance is
Erroneous, • Operating Systems Review, vol. 39, 47-50, April 2005.
79. Lewine, D.: POSIX Programmer's Guide, Sebastopol, СА: O' Reilly & Associates,
1 99 1 .
80. Li, К., and Hudak, Р.: • Memory Coherence i n Shared Virtual Memory Systems,•
АСМ Trans. on Computer Systems, vol. 7, рр. 32 1 -359, Nov. 1989.
8 1 . Linde, R.R.: •Operating System Penetration,• Proc. AFIPS National Computer
Conf., AFIPS, рр. 361 -368, 1975.
680 Глава 6. Библиография
82. Lions, ].: Lions' Commentary on Unix 6th Edition, with Source Code, San Jose,
СА: Peer-to-Peer Communications, 1996.
83. Marsh, B.D., Scott, M.L., LeЬlanc, T.J ., and Markatos, Е.Р.: «First- Class User
Level Threads,� Proc. 13th Symp. on Oper. Syst. Prin" АСМ, рр. 1 1 0- 1 2 1 , 199 1 .
84. McHugh, J.A.M., and Deek, F.P.: «An Incentive System for Reducing Malware
Attacks, � Commun. of the АСМ, vol. 48, рр. 94-99, June 2005.
85. McKusick, М.К., Joy, W.N., Leffler, S.J., and Fabry, R.S.: «А Fast File System for
UNIX,� АСМ Trans. on Computer Systems, vol. 2, рр. 1 8 1 - 1 97, Aug. 1984.
86. McKusick, М.К., and Neville-Neil, G.V.: The Design and Implementation of the
FreeBSD Operating System, Addison-Wesley: Boston, 2005.
87. Milo, D " Douglis, F" Paindaveine, У, Wheeler, R" and Z hou, S.: « Process
Migration, � АСМ Computing Surveys, vol. 32, рр. 24 1 -299, July-Sept. 2000.
88. Milojicic, D.: «Operating Systems: Now and in the Future,� IEEE Concurrency,
vol. 7, рр. 1 2 -2 1 , Jan.-March 1999.
89. Moody, G.: Rebel Code Cambridge, МА: Perseus, 200 1 .
90. Morris, R " and Thompson, К.: « Password Security: А Case Нistory,� Commun. of
the АСМ, vol. 22, рр. 594-597, Nov. 1 979.
9 1 . Mullender, S.J" and Tanenbaum, A. S.: «lmmediate Files,� Software - Practice
and Experience, vol. 14, рр. 365-368, April 1984.
92. Naughton, ].: А Brief History of the Future, Woodstock, NY: Overlook Books,
2000.
93. Nemeth, Е" Snyder, G" Seebass, S" and Hein, Т. R.: UNIX System Administation,
3rd Ed" Upper Saddle River, NJ, Prentice Hall, 2000.
94. Organick, Е.1.: The Multics System, Cambridge, МА: М.1.Т. Press, 1972.
95. Ostrand, T.J " Weyuker, E.J" and Bell, R. M.: «Where the Bugs Are,� Proc. 2004
АСМ Symp. on Softw. Testing and Analysis, АСМ, 86-96, 2004.
96. Peterson, G.L.: «Myths about the Mutual Exclusion ProЬlem,� Information Proces
sing Letters, vol. 12, рр. 1 1 5- 1 1 6, June 198 1 .
97. Prechelt, L.: «An Empirical Comparison of Seven Programming Languages,� IEEE
Computer, vol. 33, рр. 23-29, Oct. 2000.
98. Ray, D.S" and Ray, E.J .: Visual Quickstart Guide: UNIX, 2nd Ed" Berkeley, СА:
Peachpit Press, 2003.
99. RosenЬlum, М" and Ousterhout, J.К.: «The Design and Implementation of а Log
Structured File System,� Proc. 13th Symp. on Oper. Syst. Prin" АСМ, рр. 1 - 15,
199 1 .
100. Russinovich, М.Е" and Solomon, D.A.: Microsoft Windows Internals, 4th Ed"
Redmond, WА: Microsoft Press, 2005.
101. Saltzer, J.H.: « Protection arrd Control of Information Sharing in M U LTICS,�
Commun. of the АСМ, vol. 17, рр. 388-402, July 1974.
102. Saltzer, J.H" and Schroeder, M.D.: «The Protection of Information in Computer
Systems,� Proc. IEEE, vol. 63, рр. 1278- 1308, Sept. ·1975.
6 . 2. Алфави тн ы й с п исок литературы 68 1
122. Uhlig, R" Nagle, D" Stanley, Т, Mudge, Т" Secrest, S" and Brown, R: «Design
Tradeoffs for Software-Managed TLBs,• АСМ Trans. on Cornputer Systerns, vol. 12,
рр. 175-205, Aug. 1994.
123. Uppuluri, Р" Joshi, U" and Ray, А.: «Preventing Race Condition Attacks on File
Systerns,• Proc. 2005 АСМ Syrnp. on Applied Cornputing, АСМ, рр. 346-353,
2005.
124. Vahalia, U.: UNIX Internals - The New Frontiers, 2nd Ed" Upper Saddle River,
NJ: Prentice Hall, 1996.
1 25. Vogels, W.: « File Systern Usage in Windows NT 4.0,• Proc. АСМ Syrnp. on
Operating Systern Principles, АСМ, рр. 93- 1 09, 1999.
126. Waldspurger, С.А" and Weihl, W.E.: « Lottery Scheduling: FlexiЬle Proportional
Share Resource Managernent, • Proc. First Syrnp. on Oper. Syst. Design and
Irnplernentation, USENIX, рр. 1 - 1 1 , 1 994.
127. Weiss, А.: «Spyware Ве Gone,• NetWorker, vol. 9, рр. 18-25, March 2005.
128. Wilkes, J" Golding, R" Staelin, С, and Sullivan, Т.: «The НР AutoRAID Нierarchical
Storage Systern,• АСМ Trans. on Cornputer Systerns, vol. 1 4 , рр. 1 08- 1 36,
Feb. 1996.
129. Wulf, W.A" Cohen, E.S" Corwin, W. M " Jones, А. К" Levin, R" Pierson, С" and
Pollack, FJ.: «HYDRA: The Kernel of а Multiprocessor Operating Systern,• Corn
rnun. of the АСМ, vol. 17, рр. 337-345, June 1974.
130. Yang, J" Twohey, Р" Engler, D. and Musuvathi, М.: «Using Model Checking to
Find Serious File Systern Errors,• Proc. Sixth Syrnp. on Oper. Syst. Design and
lrnplernentation, USENIX, 2004.
13 1 . Zekauskas, MJ" Sawdon, W.A" and Bershad, B.N.: «Software Write Detection for
а Distributed Shared Mernory, • Proc. First Syrnp. on Oper. Syst. Design and
Irnplernentation, USENIX, рр. 87- 1 00, 1994.
132. Zwicky, E.D.: «Torture-Testing Backup and Archive Prograrns: Things You Ought
to Кnow but ProbaЬly Would Rather Not,• Prof. Fifth Conf. on Large Installation
Systerns Adrnin" USENIX, рр. 1 8 1 - 1 90, 199 1 .
П ри л ожение А
Ус та н о в к а M I N IX 3
В данном приложении рассматриваются вопросы установки операционной систе
мы MINX 3. Для полной установки требуются компьютер с процессором Pentium
(или совместимым), не менее 16 Мбайт оперативной памяти, 1 Гбайт свободного
дискового пространства, C D - R O M с интерфейсом I D E и жесткий диск с ин
терфейсом IDE. Минимальная установка (без исходных файлов команд) требует
8 Мбайт оперативной памяти и 50 Мбайт дискового пространства. Поддержка
Serial АТА, USB и SСSI-дисков в настоящий момент отсутствует. За информа
цией о CD-RO M с интерфейсом USB обращайтесь на сайт www . minixЗ.org.
А . 1 . П одготовка к установке
Если в вашем распоряжении имеется компакт-диск (например, приложенный
к этой книге), вы можете пропустить шаги 1 и 2, однако желательно осведомить
ся о наличии более новой версии операционной системы на сайте www . minixЗ.org.
Если вы хотите использовать MINIX 3 на симуляторе, сначала обратитесь к пунк
ту А.5. Если вы не располагаете IDЕ-устройством CD-RO M, получите специаль
ный загрузочный USВ-образ CD-RO M или воспользуйтесь симулятором.
1. Загрузка образа компакт-диска MINIX 3 из Интернета.
Загрузите образ компакт-диска MINIX 3 с веб-сайта www . minixЗ .org.
2. Создание загрузочного компакт-диска MINIX 3.
Разархивируйте загруженный файл. Вы получите поразрядный файл образа
компакт-диска с расширением . iso и данное руководство. Запишите его на ком
пакт-диск. Это и будет загрузочный компакт-диск.
Если вы пользуетесь программой Easy CD Creator 5, в меню File (Файл ) выбе
рите команду Record CD from CD image (З аписать CD из образа) и в появив
шемся диалоговом окне измените расширение файлов с cif на iso.
При использовании Nero Express 5 выберите команду Disk lmage or Saved Project
(Образ диска или сохраненный проект ) и измените тип на l mage Files (Файлы
образов), далее выберите файл образа и щелкните на кнопке Open (Открыть ).
Выберите устройство CD-RW и щелкните на кнопке Next (Далее).
684 Приложение А. У становка M I N IX 3
чтобш оставить место под MINIX. Во всех остальных случаях читайте упомя
нутое интерактивное руководство по адресу www . minixЗ .org/doc/partitions . html.
Если размер вашего диска превышает 1 28 Гбайт, раздел MINIX 3 должен
быть полностью размещен в первых 1 28 гигабайтах (из-за механизма адреса
ции дисковых блоков).
ВНИ МАН И Е ������
Если вы сделаете ошибку во время создания раздела, то можете потерять данные на диске,
поэтому сохраните их на CD или DVD перед началом установки. Разбиение на разделы тре
бует большой осторожности по причине опасности потери данных.
А. 2 . Загрузка
На данном этапе у вас должен иметься некоторый объем свободного пространст
ва на вашем диске. Если вы еще не освободили требуемого пространства, сделай
те это сейчас. Раздел, предназначенный для MINIX 3, должен существовать.
1 . Загрузка с CD-ROM.
Вставьте CD-ROM в накопитель и загрузите с него компьютер. Если компью
тер имеет не менее 16 Мбайт оперативной памяти, выберите вариант Regular
(Обычная загрузка), если есть только 8 Мбайт - вариант Small ( Ко мпактная
загрузка). Если компьютер загружается с жесткого диска вместо CD-ROM,
запустите еп� снова, войдите в программу настройки BIOS и установите та
кой порядок загрузки, при котором сначала идет обращение к CD-ROM, а по
том к жесткому диску.
2. Вход в качестве пользователя root.
Когда появится запрос на вход в систему, войдите как пользователь root .
После успешного входа в ы увидите приглашение оболочки ( # ). С этого мо
мента вы работаете в полнофункциональной операционной системе MINIX 3.
Если вы введете следующую команду, то сможете увидеть, какое программ
ное обеспечение доступно:
ls / u s r / b i n / 1 mo re
Нажмите пробел для прокрутки списка. Чтобы узнать, что делает программа
f oo, наберите команду man f o o . Страницы руководств также доступны по
адресу http ://www . m i n ixЗ .org/manpages/.
3. Запуск сценария установки.
Для запуска сценария установки MINIX 3 на жесткий диск введите команду
s e t up. После этой и всех последующих команд не забудьте нажимать клавишу
Enter. Когда сценарий установки выведет на экран строки с текстом, нажмите
клавишу Enter для продолжения. Если экран внезапно погаснет, нажмите кла
виши Ctrl+FЗ для <1:программной прокрутки• (может понадобиться только на
очень старых компьютерах). Обозначение Сtrl+кла в иша указывает на то, что
нужно нажать клавишу Ctrl и, удерживая ее, нажать указанную клавишу.
686 При ложение А. Установка M I N IX 3
Для первых двух вариантов введите номер раздела. Для третьего варианта
введите команду de l e t e, а при появлении запроса введите номер раздела.
Этот раздел запишется заново, а его предыдущее содержимое будет поте
ряно навсегда.
3) Confirm your choices (Подтвердите свой выбор).
В данный момент мы достигли того этапа, после выполнения которого
«пути назад• уже нет. Появится запрос о том, желаете ли продолжать.
Если да, то все данные в выбранной области будут потеряны. Если вы увере
ны, введите команду y e s и нажмите клавишу Enter. Для выхода из сцена
рия установки без изменения таблицы разделов нажмите клавиши Ctrl+C.
5. Reinstall Choice ( Переустановка).
Если вы выбрали существующий раздел MINIX 3, на этом шаге вам будет
предоставлен выбор между полной установкой (Full install), которая сотрет все
на разделе, и переустановкой ( Reinstall), которая не затронет ваш существую
щий раздел / home . Это означает, что вы можете поместить свои персональ
ные файлы в / home и заменить старую систему новой версией MINIX 3 без
потери своих файлов.
6. Select the size of /home (Выберите размер/hоmе ) .
Выбранный раздел будет разделен на три подраздела: r oot, / u s r и / home.
Последний предназначен для ваших персональных файлов. Определитесь,
сколько дискового пространства должно быть выделено для ваших файлов.
Выбор нужно будет подтвердить.
7. Select а Ыосk size (Выбор размера блока).
Поддерживаются блоки размерами 1 , 2, 4 и 8 Кбайт, но для использования
размера более 4 Кбайт нужно изменить константу и перекомпилировать систе
му. Если объем оперативной памяти составляет 16 Мбайт или более, выберите
стандартное значение (4 Кбайт); в противном случае задайте 1 Кбайт.
8. Wait for bad Ыосk detection ( Проверка п оврежденных блоков).
Сценарий установки будет сканировать каждый раздел для поиска повреж
денных блоков. Это может занять несколько минут, возможно 10 минут и бо
лее на больших разделах; проявите терпение. Если вы абсолютно уверены,
что неисправных блоков нет, можно прекратить сканирование любого из раз
делов, нажав клавиши Ctrl+C.
9. Wait for files to Ье copied (Ко п ирован ие файлов).
Когда закончится сканирование, файлы будут автоматически скопированы
с CD-RO M на жесткий диск. Вы увидите каждый копируемый файл. Когда
копирование завершится, система M INIX 3 окажется установленной. Вы
ключите систему, набрав команду shut down. Всегда останавливайте MINIX 3
этим способом для предотвращения потери данных, так как MINIX 3 хра
нит некоторые файлы на виртуальном диске и копирует их на жесткий диск
только при завершении работы.
688 П риложение А. Установка M I N IX 3
А . 4 . Тести рование
В этом разделе рассказывается, как проверить установленную систему, заново
собрать систему после модификации и затем загрузить ее. Для начала загрузите
вашу новую систему MINIX 3. К примеру, если вы используете контроллер О,
диск О, раздел 3, введите команду boot с О dОрЗ и войдите как пользователь root .
По некоторым причинам номер диска, видимый BIOS (и используемый монито
ром загрузки), может не совпадать с применяемым MINIX 3. Сначала попробуйте
задействовать номер, предложенный сценарием установки. Это хороший момент
для создания пароля пользователя root (справку вы можете получить с помо
щью команды man pas swd) .
1 . Компиляция набора тестов.
Для проверки MINIX 3 наберите в командной строке следующую пару команд:
cd / u s r / s rc / t e s t
make
Если необходимо компилировать набор программ как root, а выполнять, как Ьiп, проверьте,
что бит setuid установлен корректно.
3. Повторная сборка всей операционной системы.
Если все тесты работают правильно, вы можете собрать систему заново пря
мо сейчас. После установки новой системы это вряд ли необходимо, но если
вы планируете модифицировать систему, вам нужно знать, как собрать ее по
вторно. Кроме того, это хороший способ ознакомиться с тем, как работает
система. Для просмотра доступных параметров введите две команды:
cd / u s r / s r c / t o o l s
make
�голом• компьютере. Для этой цели имеется ряд виртуальных машин, симулято
ров и эмуляторов. Вот наиболее популярные:
+ VMware (www .vmware . com);
+ Bochs (www . bochs.org);
+ QEMU (www .qemu . org).
Ознакомьтесь с соответствующей документацией. Запуск программы на симуля
торе аналогичен ее запуску на реальном компьютере, поэтому следует вернуться
к пункту А. 1 , получить компакт-диск с последней версией операцио н ной систе
мы и продолжить работу согласно данному руководству.
П ри л ожение Б
Сп и с о к фай л ов M I N IX 3
н а ко м п а кт- ди с ке
З а голово ч н ы е фай лы
00000 inc l ude / an s i . h
00200 inc lude / e rrno . h
00900 inc l ude / f cnt l . h
00100 inc lude / l imi t s . h
00700 inc l ude / s igna l . h
00600 inc lude / s t r ing . h
01000 inc lude / t ermi o s . h
01300 i n c l u de / t imers . h
00400 inc lude / u n i s t d . h
04400 inc lude / ibm/ i n t e rrupt . h
043 0 0 inc lude / ibm / p o r t i o . h
04500 inc lude / ibm / po r t s . h
03500 inc lude / m i n i x / c a l lnr . h
03600 inc lude /minix / c om . h
02 3 0 0 inc l ude / m i n i x / c o n f i g . h
02 6 0 0 inc lude /min i x / c ons t . h
04100 inc lude / m i n i x / devi o . h
042 0 0 inc lude /min i x / dmap . h
022 00 inc lude / m i n i x / i o c t l . h
03000 inc lude / m i n ix / ipc . h
02 5 0 0 inc l u d e / m i n i x / sy s ! c o n f i g . h
03200 inc lude / m i n i x / sy s l ib . h
03400 inc l ude / m i n i x / sysut i l . h
02800 i n c l u d e / m i n i x / type . h
01800 inc lude / sy s / d i r . h
02100 inc lude / sy s / i o c ! d i s k . h
02000 inc lude / sy s / i o c t l . h
01600 i n c l u de / sy s / s i g c ontext . h
01700 inc lude / sy s / s t a t . h
01400 inc lude / sy s / type s . h
01900 inc lude / sy s / wa i t . h
Д рай в ер ы
1 0 8 0 0 drive r s / dr ivers . h
1 2 1 0 0 driver s / a t wini / a t wini . c
1 2 0 0 0 drive r s / a t ! w in i / a t wini . h
692 При л ожение Б. С п исок фай л о в M I N IX 3 на компакт-диске
Sl д po
1 0 4 0 0 kerne l / c l o c k . c
0 4 7 0 0 kerne l / c o n f i g . h
0 4 8 0 0 kerne l / c on s t . h
0 8 0 0 0 kerne l / except i on . c
0 5 3 0 0 kerne l / g l o . h
0 8 1 0 0 kerne l / i 8 2 5 9 . c
0 5 4 0 0kerne l / ipc . h
0 4 6 0 0 kerne l / kerne l . h
0 8 7 0 0 kerne l / k l ib . s
0 8 8 0 0 kerne l / k l iЬ3 8 6 . s
0 7 1 0 0 kerne l / ma i n . c
0 6 2 0 0 kerne l / mpx . s
0 6 3 0 0 k e rne l / mpx3 8 6 . s
0 5 7 0 0 kerne l / pr i v . h
0 7 4 0 0 kerne l / proc . c
0 5 5 0 0 kerne l / proc . h
0 8 3 0 0 kerne l / pr o t e c t . c
0 5 8 0 0 kerne l / prot e c t . h
0 5 1 0 0 kerne l / pro t o . h
0 5 6 0 0 kerne l / s c ons t . h
0 6 9 0 0 kerne l / s t a r t . c
0 9 7 0 0 kerne l / sy s t em . c
0 9 6 0 0 kerne l / sy s t em . h
1 0 3 0 0 kerne l / sy s t em / do ехес . с
1 0 2 0 0 kerne l / sy s t em / do s e t a l a rm . c
0 6 0 0 0 kerne l / t aЫ e . c
0 4 9 0 0 ke rne l / type . h
0 9 4 0 0 kernel / u t i l i t y . c
Ф айло в ая систем а
21600 s e rvers / f s / bu f . h
22400 s erver s / f s / cache . c
21000 s e rvers / f s / c o n s t . h
28300 s erve r s / f s / devi c e . c
28100 s e rvers / f s / dmap . c
21700 s e rver s / f s / f i l e . h
23700 s e rver s / f s / f i l edes . c
21500 s erve rs / f s / fproc . h
20900 s erver s / f s / f s . h
Менедже р про цессов 693
21400 s e rvers / f s / g l o . h
22900 s erve r s / f s / inode . c
21900 s e rvers / f s / inode . h
27000 s e rve r s / f s / l i nk . c
23800 s e rve r s / f s / l o c k . c
21800 s e rve r s / f s / l o c k . h
24000 s e rvers / f s / ma i n . c
26700 s e rve rs / f s / mount . c
24500 s e rve r s / f s / open . c
22000 s e rvers / f s / param . h
26300 s e rvers / f s / p a t h . c
25900 s e rve r s / f s / p ipe . c
27800 s e rvers / f s / p r o t e c t . c
21200 s e rvers / f s / p r o t o . h
25000 s e rvers / f s / read . c
27500 s e rvers / f s / s t ad i r . c
23300 s e rvers / f s / super . c
22100 s e rve r s / f s / super . h
22200 s e rver s / f s / t aЫ e . c
28800 s e rvers / f s / t ime . c
21100 s e rvers / f s / type . h
25600 s e rvers / f s / wr i t e . c
А н
ACL, 593 НТТР, 62
ANS I, 1 58, 353
АТА, 329
1/0, 1 9
в
ШЕ, 313
BIOS, 323, 4 1 6 шт, 1 90, 2 1 7
BSD, 32
IEEE, 32
ЮРL, 1 75
с IPC, 92
C-list, 595 I P L, 547
CMS, 70 IS, 140, 397, 660
cookie, 582 ISA, 1 9
СР/М, 33 i-узел , 6 1
CRC, 3 1 7
C-Threads, 90
CTSS, 30
J
JVM, 7 1
D
DDOS, 58 1 L
DMA, 258 LAMP, 39
DOS, 34, 58 1 LBA, 330
LBA, 48, 33 1
Е LDT, 2 1 7, 461
LFS, 576
ЕСС, 255
ЕШЕ, 326 lock file, 295
EOF, 308 LRU, 445, 6 1 1
LSI, 33
F
FAT, 551
м
FCFS, 3 1 7 М.1.Т. , 30
FIFO, 443 Мае OS Х, 34
FMS, 27 M B R, 142, 547
FORTRAN, 25 M FT, 4 1 8, 553, 558
FS, 139 MINIX, 36
FTP, 62 ммu, 427
Motif, 35
G MPI, 1 1 3
GDT, 1 90, 2 1 6, 461 MRU, 6 1 1
GID, 42 MS-DOS, 34
GUI, 34 M U LТICS, 30
Алф а витн ы й у казатель 695
N А
NFU, 447 абсолютный путь, 543
NRU, 442 аварийный сигнал, 4 1
NТFS, 532, 558 автоконфигурирование, 258
автономный режим, 26
адаптер
о Ethernet, 292
OS/360, 28 ввода-вывода, 323
понятие, 254
сетевой, 1 53
р
адрес
PFF, 453 виртуальный, 427
PID, 50, 145 линейный, 463
РМ, 139, 467 физический, 176
POSIX, 32 адресация блоков
линейная, 330
PPI D, 145
логическая, 3 1 4
PSW, 1 75, 4 1 9
адресное пространство, 40
Р- Threads, 90
активное ожидание, 97, 257
активный раздел, 1 42
R алгоритм
wsclock, 451
RAID, 3 1 5
банкира
RAM, 4 1 4
для нескольких видов ресурсов, 283
ROM, 3 4 , 323, 4 1 4 для одного вида ресурсов, 281
R S , 1 40, 656 быстрого соответствия, 426
второго шанса, 444
s замещения страниц, 440
наилучшего соответствия, 425
SATA, 327
наихудшего соответствия, 425
SLED, 3 1 5 первого соответствия, 424
S P, 67 планирования, 1 1 8
SPOOL, 30 вытесняющий, 120
SSF, 3 1 8 карусельного, 128
System V, 32 невытесняющий, 1 20
приоритетного, 129
циклического, 1 28
т следующего соответствия, 424
TLB, 436 старения, 447
TSS, 196, 2 1 7 часов, 445
элеваторный, 3 1 8
аппаратная прокрутка, 365
u аппаратное прерывание, 1 49
UART, 343 архивация
U I D , 42 инкрементная, 565
UNIX, 32 полная, 565
USB, 297 архитектура
компьютера, 2 1
UTC, 235
набора команд, 1 9
теговая, 596
w асинхронная передача, 262
wsclock, 45 1 асинхронное событие, 240
ассоциативная память, 436
атака
х отказа в обслуживании, 579, 58 1
Х Windows, 34 с черного хода, 584
696 Алфавитн ы й указатель
демон защита
печати, 93, 268 от дурака, 537
понятие, 8 1 , 1 4 1 от несанкционированного доступа, 578
дескриптор понятие, 578
глобальный, 190, 2 1 6 защищенный режим, 1 68
локальный, 2 1 6 злоумышленник, 580
прерывания, 87, 190 зомби, 479
сегмента, 47 1
файла, 44, 6 1 6
шлюза прерывания, 196
и
джиттер, 1 24 идентификатор
ДИСК группы, 42
виртуальный, 142 пользователя, 42
загрузочный, 142 процесса, 50
добавление соли, 587 иерархия памяти, 4 1 4
добровольная блокировка файлов, 6 1 7 ИМЯ
домен защиты, 59 1 пути, 43
доступ файла, 43
последовательный, 537 инверсия приоритета, 100
произвольный, 537 инвертированная таблица страниц, 438
доступность системы, 579 индексный узел, 6 1 , 552
дочерний процесс, 4 1 инициализируемая переменная, 177
драйвер устройства, 139, 254, 263
инкрементная архивация, 565
дружественный интерфейс, 34
инкрементная резервная копия, 565
интерпретатор команд, 40
Е интерфейс
единообразное именование, 2 6 1 графический, 34
дружественный, 34
жестких дисков с интегрированной
ж
электроникой, 325
жесткая связь, 546, 554 командной строки, 34
жесткая система реального времени, 1 34 передачи сообщений, 1 1 3
жидкокристаллический дисплей, 34 1 системного вызова, 32
информационный сервер, 140, 397
3 исключение, 149, 205
зависание, 1 1 5
заголовок к
процедуры, 536
канал, 45
сектора, 255
ввода-вывода, 255
файла, 192, 475, 535
секретный, 599
заголовочный файл, 1 57
канонический режим, 345
загрузочный блок, 185, 547, 604
карта
загрузочный диск, 142
активных сигналов, 148
загрузочный образ, 142, 1 86, 498
;,�адание активных уведомлений, 148
программное, 25 источников прерываний, 1 48
с наименьшим временем завершения, 126 клавиш, 368
системное, 1 38, 222 карусельное планирование, 128
таймерное, 138 каталог, 42, 54 1
замещение страниц, 427 корневой, 43
глобальное, 45 1 рабочий, 43, 544
локальное, 45 1 спулера, 93
опережающее, 450 спулинга, 268
по запросу, 449 страничный, 463
запрос-отзыв, 588 текущий, 544
зарезервированный суффикс, 162 квант, 1 28
698 Алфавитный указатель
переменная
о инициализируемая, 177
оболочка, 46 условная, 1 07
обработка ошибок, 2 6 1 перехват
обработчик исключения, 53
прерываний, 2 1 5 клавиатурного ввода, 58 1
сигнала, 484 сигнала, 484
образ периодические события, 134
загрузочный, 142, 1 86, 498 пиксел, 34 1
памяти, 40 планирование
системный, 186 в системах реального времени, 1 34
общие права, 597 вытесняющее, 120
общий код, 470, 476 гарантированное, 132
объединение пространств данных и кода, 468 карусельное, 1 28
объект, 593 лотерейное, 132
объявление, 158 механизм, 1 35
оверлей, 426 невытесняющее, 1 2 0
ограничительный регистр, 4 1 9 политика, 135
одноразовый пароль, 587 приоритетное, 1 29
однородный ресурс, 2 7 1 справедливое, 133
операционная система, 1 8 циклическое, 128
многоуровневая, 67 планировщик, 1 1 8
монолитная, 65 допуска, 1 26
распределенная, 35 памяти, 127
сетевая, 35 процессора, 127
опережающее замещение страниц, 450 планируемая система реального времени, 1 34
определение функции, 1 58 поврежденный блок, 320
опрос, 257 подкачка, 29
отказ в обслуживании, 579, 581 подтверждение приема, 1 1 1
открытый исходный код, 39 поиск с перекрытием, 3 1 4
отладочный дамп, 179 поколения компьютеров
относительный путь, 544 второе, 25
ошибка отсутствия страницы, 429 первое, 24
четвертое, 33
п политика планирования, 135
полное имя файла, 43
пакетная обработка, 25 пользовательский режим, 20, 139
палмтоп, 4 1 5 порт ввода- вывода, 256
память последовательный доступ, 537
ассоциативная, 436 постоянная память, 34
виртуальная, 420, 426 почтовый ящик, 1 1 2
иерархия, 4 1 4 право доступа, 59 1
постоянная, 34 преамбула
сжатие, 420 битового потока, 255
уплотнение, 420 управляющей последовательности, 366
папка, 54 1 прерывание, 1 95, 2 1 5
параметр загрузки, 1 86, 325 аппаратное, 149
пароль, 587 программное, 149
первым пришел - первым обслужен, 124 префикс расширенных клавиш, 394
переадресация, 418 префиксный символ, 349
передача приватность, 579
асинхронная, 262 примитив
синхронная, 262 взаимодействия между процессами, 223
сообщений, 1 1 О сообщения, 223
переключение принцип наименьшего уровня привилегий, 598
контекста, 128, 1 77 принципал, 593
процессов, 128 приоритетное планирование, 129
700 Алфавитн ы й указатель
проблема
р
изоляции, 599
инверсии приоритета, 1 00 рабочая станция
обедающих философов, 1 1 3 бездисковая, 1 87
ограниченности буфера, 1 0 1 рабочий каталог, 43, 544
переадресации, 4 1 8 рабочий набор, 449
производителя и потребителя, 1 0 1 раздел
читателей и писателей, 1 1 7 активный, 142
пробуксовка, 449 главный, 548
программа диска, 62, 142
вредоносная, 580 логический, 548
начальной загрузки, 142 расширенный, 548
троянская, 582 фиксированный, 4 1 6
шпионская, 582 разделение
программная независимость от устройств, 2 6 1 времени, 30
программная прокрутка, 365 пространств данных и кода, 468
программное прерыв;щие, 149 процессора, 248
программный поток, 89 разделяемое устройство, 262
произвольный доступ, 537 рандеву, 1 1 3, 147
прокрутка, 365 раскладка клавиатуры, 368
аппаратная, 365 распределенная общая память, 456
программная, 365 распределенная операционная система, 35
промежуточное программное обеспечение, 32 распределенная система, 32
пропорциональность, 123 распределенный отказ в обслуживании, 581
пропускная способность, 122 расширение имени файла, 532
пространство расширенная машина, 22
адресное, 40 расширенный раздел, 548
дисковое, 37 расщепление данных, 3 1 6
оперативной памяти, 23
реальное время, 236
прототип функции, 158
регистр
процедура
базовый, 4 1 9
библиотечная, 544
ограничительный, 4 1 9
понятие, 1 5 1
сегментный, 47 1
процесс, 40
устройства, 1 9
блокировка, 84
режим
дочерний, 4 1
автономный, 26
завершение, 82
без обработки, 345
клиентский, 73
защищенный, 1 68
концепция, 78
канонический, 345
легковесный, 89
локальный, 35 1
модель, 78
ограниченный возможностями неканонический, 345
ввода-вывода, 1 1 9 однократного срабатывания, 234
ограниченный вычислительными пользовательский, 20, 139
возможностями, 1 1 9 с обработкой, 345
реализация, 86 с прерыванием, 352
серверный, 73 супервизора, 20
системный, 140 тактового меандра, 234
создание, 80 ядра, 20
состояние, 84 резервная копия
прямой доступ к памяти, 258 инкрементная, 565
псевдоним, 555 полная, 565
псевдопараллелизм, 78 ресурс, 270
псевдотерминал, 356 выгружаемый, 2 7 1
путь, 6 1 3 невыгружаемый, 2 7 1
абсолютный, 543 однородный, 2 7 1
относительный, 544 роль, 594
Ал фави тны й указатель 70 1
ф я
файл, 530 ядро
атрибуты, 538 MINIX, 138
блокировки, 295 минимальное, 73
блочный, 535 язык
включаемый, 1 57 ассемблера, 19, 25
заголовочный, 1 57 машинный, 19
непосредственный, 559 программирования, 24
последовательного доступа, 537 ярлык, 555
Ко м п а кт - ди с к M I N IX 3
Ап паратное обеспечение
Операционная система MINIX 3 предъявляет следующие требования к аппарат
ному обеспечению:
+ персональный компьютер с процессором Pentium или другим совместимым
с ним процессором;
+ 16 Мбайт или более оперативной памяти;
+ 200 Мбайт или более свободного пространства на жестком диске;
+ драйвер CD-ROM с интерфейсом IDE;
+ жесткий диск с интерфейсом IDE.
Диски с интерфейсами Serial АТА, USB и SCSI не поддерживаются. За альтер
нативными конфигурациями обратитесь на сайт http ://www . minixЗ.org.
Установка
Установка может быть полностью выполнена без подключения к Интернету, однако
некоторые специальные документы доступны только на сайте http://www. minixЗ.org.
Исчерпывающие инструкции по установке имеются на компакт-диске в формате
Adobe Acrobat PDF.
Поддержка п родукта
За дополнительной технической информацией о программном обеспечении MINIX,
содержащемся на данном диске, обратитесь на официальный веб-сайт MINIX по
адресу http ://www . minixЗ .org.
Эндрю Таненбаум, Альберт Вудхалл
Операционные системы
Разработка и реализация (+CD)
Классика CS
3-е издание
Перевел с английского А . Кузнецов
Подписано в печать 26. 1 2.06. Формат 70х 1 00/ 1 6. Усл. п. л. 56,76. Тираж 3000. Заказ 36 25.
ООО «Питер Пресс», 198206, Санкт-Петербург, Петергофское шоссе, 73, лит. А29.
Налоговая льгота - общероссийский классификатор продукции ОК 005-93, том 2; 95 3005 - литература учебная.
Отпечатано по технологии CtP в ОАО «Печатный двор» им. А. М. Горького.
1 97 1 1 0, Санкт-Петербург, Чкаловский пр., 1 5 .
В бол ь ш и н стве се р ьезн ых к н и г, посвя ще н н ых о пера цион н ы м с и сте м а м , тео р и и
уделя ется го ра здо бол ь ше в н и м а н ия , ч е м п р а ктике. В это м с м ы сле труды классика
IТ-л ите ратуры Эндрю Та н е н баума сове р ш е н н о у н и к ал ь н ы . Тео р и я в н их все гда
пода ется в хо р о ш е м а ка де м ическом стиле , а п р а ктические зада н ия соста вле н ы
та к и м обра з о м , чтобы ч итател ь м о г почувствовать себя разработч и к о м , р е ш а ю щ и м
реал ь н ы е зада ч и .
C D - R O M П РИ Л А ГАЕТСЯ
1 1 1 11 1
9 785469 01 4034