- •Морис Дж. Бах Архитектура операционной системы unix предисловие
- •Глава 1. Общий обзор особенностей системы
- •1.1 История
- •1.2 Структура системы
- •1.3 Обзор с точки зрения пользователя
- •1.3.1 Файловая система
- •1.3.2 Среда выполнения процессов
- •1.3.3 Элементы конструкционных блоков
- •1.4 Функции операционной системы
- •1.5 Предполагаемая аппаратная среда
- •1.5.1 Прерывания и особые ситуации
- •1.5.2 Уровни прерывания процессора
- •1.5.3 Распределение памяти
- •1.6 Выводы
- •Глава 2. Введение в архитектуру ядра операционной системы
- •2.1 Архитектура операционной системы uniх
- •2.2 Введение в основные понятия системы
- •2.2.1 Обзор особенностей подсистемы управления файлами
- •2.2.2 Процессы
- •2.2.2.1 Контекст процесса
- •2.2.2.2 Состояния процесса
- •2.2.2.3 Переходы из состояния в состояние
- •2.2.2.4 «Сон» и пробуждение
- •2.3 Структуры данных ядра
- •2.4 Управление системой
- •2.5 Выводы и обзор последующих глав
- •2.6 Упражнения
- •Глава 3. Буфер сверхоперативной памяти (кеш)
- •3.1 Заголовки буфера
- •3.2 Структура области буферов (буферного пула)
- •3.3 Механизм поиска буфера
- •3.4 Чтение и запись дисковых блоков
- •3.5 Преимущества и неудобства буферного кеша
- •3.6 Выводы
- •3.7 Упражнения
- •Глава 4. Внутреннее представление файлов
- •4.1 Индексы
- •4.1.1 Определение
- •4.1.2 Обращение к индексам
- •4.1.3 Освобождение индексов
- •4.2 Структура файла обычного типа
- •4.3 Каталоги
- •4.4 Превращение составного имени файла (пути поиска) в идентификатор индекса
- •4.5 Суперблок
- •4.6 Назначение индекса новому файлу
- •4.7 Выделение дисковых блоков
- •4.8 Другие типы файлов
- •4.9 Выводы
- •4.10 Упражнения
- •Глава 5. Системные операции для работы с файловой системой
- •5.1 Open
- •5.2 Read
- •5.3 Wriте
- •5.4 Захват файла и записи
- •5.5 Указание места в файле, где будет выполняться ввод-вывод — lseeк
- •5.6 Closе
- •5.7 Создание файла
- •5.8 Создание специальных файлов
- •5.9 Смена текущего и корневого каталога
- •5.10 Cмена владельца и режима доступа к файлу
- •5.11 Stat и fstат
- •5.12 Каналы
- •5.12.1 Системная функция pipе
- •5.12.2 Открытие поименованного канала
- •5.12.3 Чтение из каналов и запись в каналы
- •5.12.4 Закрытие каналов
- •5.12.5 Примеры
- •5.14 Монтирование и демонтирование файловых систем
- •5.14.1 Пересечение точек монтирования в маршрутах поиска имен файлов
- •5.14.2 Демонтирование файловой системы
- •5.15 Linк
- •5.16 Unlinк
- •5.16.1 Целостность файловой системы
- •5.16.2 Поводы для конкуренции
- •5.17 Абстрактные обращения к файловым системам
- •5.18 Сопровождение файловой системы
- •5.19 Выводы
- •5.20 Упражнения
- •Глава 6. Структура процессов
- •6.1 Состояния процесса и переходы между ними
- •6.2 Формат памяти системы
- •6.2.1 Области
- •6.2.2 Страницы и таблицы страниц
- •6.2.3 Размещение ядра
- •6.2.4 Пространство процесса
- •6.3 Контекст процесса
- •6.4 Сохранение контекста процесса
- •6.4.1 Прерывания и особые ситуации
- •6.4.2 Взаимодействие с операционной системой через вызовы системных функций
- •6.4.3 Переключение контекста
- •6.4.4 Сохранение контекста на случай аварийного завершения
- •6.4.5 Копирование данных между адресным пространством системы и адресным пространством задачи
- •6.5 Управление адресным пространством процесса
- •6.5.1 Блокировка области и снятие блокировки
- •6.5.2 Выделение области
- •6.5.3 Присоединение области к процессу
- •6.5.4 Изменение размера области
- •6.5.5 Загрузка области
- •6.5.6 Освобождение области
- •6.5.7 Отсоединение области от процесса
- •6.5.8 Копирование содержимого области
- •6.6 Приостановка выполнения
- •6.6.1 События, вызывающие приостанов выполнения, и их адреса
- •6.6.2 Алгоритмы приостанова и возобновления выполнения
- •6.7 Выводы
- •6.8 Упражнения
- •Глава 7. Управление процессами
- •7.1 Создание процесса
- •7.2 Сигналы
- •7.2.1 Обработка сигналов
- •7.2.2 Группы процессов
- •7.2.3 Посылка сигналов процессами
- •7.3 Завершение выполнения процесса
- •7.4 Ожидание завершения выполнения процесса
- •7.5 Вызов других программ
- •7.6 Код идентификации пользователя процесса
- •7.7 Изменение размера процесса
- •7.8 Командный процессор shell
- •7.9 Загрузка системы и начальный процесс
- •7.10 Выводы
- •7.11 Упражнения
- •Глава 8. Диспетчеризация процессов и ее временные характеристики
- •8.1 Планирование выполнения процессов
- •8.1.1 Алгоритм
- •8.1.2 Параметры диспетчеризации
- •8.1.3 Примеры диспетчеризации процессов
- •8.1.4 Управление приоритетами
- •8.1.5 Планирование на основе справедливого раздела
- •8.1.6 Работа в режиме реального времени
- •8.2 Системные операции, связанные со временем
- •8.3 Таймер
- •8.3.1 Перезапуск часов
- •8.3.2 Внутренние системные тайм-ауты
- •8.3.3 Построение профиля
- •8.3.4 Учет и статистика
- •8.3.5 Поддержание времени в системе
- •8.4 Выводы
- •8.5 Упражнения
- •Глава 9. Алгоритмы управления памятью
- •9.1 Свопинг
- •9.1.1 Управление пространством на устройстве выгрузки
- •9.1.2 Выгрузка процессов
- •9.1.2.1 Выгрузка при выполнении системной функции fork
- •9.1.2.2 Выгрузка с расширением
- •9.1.3 Загрузка (подкачка) процессов
- •9.2 Подкачка по запросу
- •9.2.1 Структуры данных, используемые подсистемой замещения страниц
- •9.2.1.1 Функция fork в системе с замещением страниц
- •9.2.1.2 Функция exec в системе с замещением страниц
- •9.2.2 "Сборщик" страниц
- •9.2.3 Отказы при обращениях к страницам
- •9.2.3.1 Обработка прерываний по отказу из-за недоступности данных
- •9.2.3.2 Обработка прерываний по отказу системы защиты
- •9.2.4 Замещение страниц на менее сложной технической базе
- •9.3 Система смешанного типа со свопингом и подкачкой по запросу
- •9.4 Выводы
- •9.5 Упражнения
- •Глава 10. Подсистема управления вводом-выводом
- •10.1 Взаимодействие драйверов с программной и аппаратной средой
- •10.1.1 Конфигурация системы
- •10.1.2 Системные функции и взаимодействие с драйверами
- •10.1.2.1 Open
- •10.1.2.2 Closе
- •10.1.2.3 Read и Writе
- •10.1.2.4 Стратегический интерфейс
- •10.1.2.5 Ioctl
- •10.1.2.6 Другие функции, имеющие отношение к файловой системе
- •10.1.3 Программы обработки прерываний
- •10.2 Дисковые драйверы
- •10.3 Терминальные драйверы
- •10.3.1 Символьные списки
- •10.3.2 Терминальный драйвер в каноническом режиме
- •10.3.3 Терминальный драйвер в режиме без обработки символов
- •10.3.4 Опрос терминала
- •10.3.5 Назначение операторского терминала
- •10.3.6 Драйвер косвенного терминала
- •10.3.7 Вход в систему
- •10.4 Потоки
- •10.4.1 Более детальное рассмотрение потоков
- •10.4.2 Анализ потоков
- •10.5 Выводы
- •10.6 Упражнения
- •Глава 11. Взаимодействие процессов
- •11.1 Трассировка процессов
- •11.2 Взаимодействие процессов в версии V системы
- •11.2.1 Сообщения
- •11.2.2 Разделение памяти
- •11.2.3 Семафоры
- •11.2.4 Общие замечания
- •11.3 Взаимодействие в сети
- •11.4 Гнезда
- •11.5 Выводы
- •11.6 Упражнения
- •Глава 12. Многопроцессорные системы
- •12.1 Проблемы, связанные с многопроцессорными системами
- •12.2 Главный и подчиненный процессоры
- •12.3 Семафоры
- •12.3.1 Определение семафоров
- •12.3.2 Реализация семафоров
- •12.3.3 Примеры алгоритмов
- •12.3.3.1 Выделение буфера
- •12.3.3.2 Wait
- •12.3.3.3 Драйверы
- •12.3.3.4 Фиктивные процессы
- •12.4 Система tunis
- •12.5 Узкие места в функционировании многопроцессорных систем
- •12.6 Упражнения
- •Глава 13. Распределенные системы
- •13.1 Периферийные процессоры
- •13.2 Связь типа newcastlе
- •13.3 "Прозрачные" распределенные файловые системы
- •13.4 Распределенная модель без передаточных процессов
- •13.5 Выводы
- •13.6 Упражнения
- •Приложение системные операции
- •Библиография
5.14.1 Пересечение точек монтирования в маршрутах поиска имен файлов
Давайте повторно рассмотрим поведение алгоритмов namei и iget в случаях, когда маршрут поиска файлов проходит через точку монтирования. Точку монтирования можно пересечь двумя способами: из файловой системы, где производится монтирование, в файловую систему, которая монтируется (в направлении от глобального корня к листу), и в обратном направлении. Эти способы иллюстрирует следующая последовательность команд shell'а.
mount /dev/dsk1 /usr
cd /usr/src/uts
cd ../../..
По команде mount после выполнения некоторых логических проверок запускается системная функция mount, которая монтирует файловую систему в дисковом разделе с именем «/dev/dsk1» под управлением каталога «/usr». Первая из команд cd (сменить каталог) побуждает командный процессор shell вызвать системную функцию chdir, выполняя которую, ядро анализирует имя пути поиска, пересекающего точку монтирования в «/usr». Вторая из команд cd приводит к тому, что ядро анализирует имя пути поиска и пересекает точку монтирования в третьей компоненте «..» имени.
Рисунок 5.24. Структуры данных после монтирования
Для случая пересечения точки монтирования в направлении из файловой системы, где производится монтирование, в файловую систему, которая монтируется, рассмотрим модификацию алгоритма iget (Рисунок 5.25), которая идентична версии алгоритма, приведенной на Рисунке 4.3, почти во всем, за исключением того, что в данной модификации производится проверка, является ли индекс индексом точки монтирования. Если индекс имеет соответствующую пометку, ядро соглашается, что это индекс точки монтирования. Оно обнаруживает в таблице монтирования запись с указанным индексом точки монтирования и запоминает номер устройства монтируемой файловой системы. Затем, используя номер устройства и номер индекса корня, общего для всех файловых систем, ядро обращается к индексу корня монтируемого устройства и возвращает при выходе из функции этот индекс. В первом примере смены каталога ядро обращается к индексу каталога «/usr» из файловой системы, в которой производится монтирование, обнаруживает, что этот индекс имеет пометку «точка монтирования», находит в таблице монтирования индекс корня монтируемой файловой системы и обращается к этому индексу.
алгоритм iget
входная информация: номер индекса в файловой системе
выходная информация: заблокированный индекс
do
if (индекс в индексном кеше)
if (индекс заблокирован)
sleep (до освобождения индекса);
continue; /* цикл с условием продолжения */
/* специальная обработка для точек монтирования */
if (индекс является индексом точки монтирования)
найти запись в таблице монтирования для точки монтирования;
получить новый номер файловой системы из таблицы монтирования;
использовать номер индекса корня для просмотра;
continue; /* продолжение цикла */
if (индекс в списке свободных индексов) убрать из списка свободных индексов;
увеличить счетчик ссылок для индекса;
return (индекс);
/* индекс отсутствует в индексном кеше */
убрать новый индекс из списка свободных индексов;
сбросить номер индекса и файловой системы;
убрать индекс из старой хеш-очереди, поместить в новую;
считать индекс с диска (алгоритм bread);
инициализировать индекс (например, установив счетчик ссылок в 1);
return (индекс);
Рисунок 5.25. Модификация алгоритма получения доступа к индексу
Для второго случая пересечения точки монтирования в направлении из файловой системы, которая монтируется, в файловую систему, где выполняется монтирование, рассмотрим модификацию алгоритма namei (Рисунок 5.26). Она похожа на версию алгоритма, приведенную на Рисунке 4.11. Однако, после обнаружения в каталоге номера индекса для данной компоненты пути поиска ядро проверяет, не указывает ли номер индекса на то, что это корневой индекс файловой системы. Если это так и если текущий рабочий индекс так же является корневым, а компонента пути поиска, в свою очередь, имеет имя «..», ядро идентифицирует индекс как точку монтирования. Оно находит в таблице монтирования запись, номер устройства в которой совпадает с номером устройства для последнего из найденных индексов, получает индекс для каталога, в котором производится монтирование, и продолжает поиск компоненты с именем «..», используя только что полученный индекс в качестве рабочего. В корне файловой системы, тем не менее, корневым каталогом является «..»
алгоритм namei /* превращение имени пути поиска в индекс */
входная информация: имя пути поиска
выходная информация: заблокированный индекс
if (путь поиска берет начало с корня) рабочий индекс = индексу корня (алгоритм iget);
else рабочий индекс = индексу текущего каталога (алгоритм iget);
do (пока путь поиска не кончился)
считать следующую компоненту имени пути поиска;
проверить соответствие рабочего индекса каталогу и права доступа;
if (рабочий индекс соответствует корню и компонента имени «..») continue; /* цикл с условием продолжения */
поиск компоненты:
считать каталог (рабочий индекс), повторяя алгоритмы bmap, bread и brelse;
if (компонента соответствует записи в каталоге (рабочем индексе))
получить номер индекса для совпавшей компоненты;
if (найденный индекс является индексом корня и рабочий индекс является индексом корня и имя компоненты «..»)
/* пересечение точки монтирования */
получить запись в таблице монтирования для рабочего индекса;
освободить рабочий индекс (алгоритм iput);
рабочий индекс = индексу точки монтирования;
заблокировать индекс точки монтирования;
увеличить значение счетчика ссылок на рабочий индекс;
перейти к поиску компоненты (для «..»);
освободить рабочий индекс (алгоритм iput);
рабочий индекс = индексу с новым номером (алгоритм iget);
else /* компонента отсутствует в каталоге */ return (нет индекса);
return (рабочий индекс);
Рисунок 5.26. Модификация алгоритма синтаксического анализа имени файла
В вышеприведенном примере (cd «../../..») предполагается, что в начале процесс имеет текущий каталог с именем «/usr/src/uts». Когда имя пути поиска подвергается анализу в алгоритме namei, начальным рабочим индексом является индекс текущего каталога. Ядро меняет текущий рабочий индекс на индекс каталога с именем «/usr/src» в результате расшифровки первой компоненты «..» в имени пути поиска. Затем ядро анализирует вторую компоненту «..» в имени пути поиска, находит корневой индекс смонтированной (перед этим) файловой системы — индекс каталога «usr» — и делает его рабочим индексом при анализе имени с помощью алгоритма namei. Наконец, оно расшифровывает третью компоненту «..» в имени пути поиска. Ядро обнаруживает, что номер индекса для «..» совпадает с номером корневого индекса, рабочим индексом является корневой индекс, а «..» является текущей компонентой имени пути поиска. Ядро находит запись в таблице монтирования, соответствующую точке монтирования «usr», освобождает текущий рабочий индекс (корень файловой системы, смонтированной в каталоге «usr») и назначает индекс точки монтирования (каталога «usr» в корневой файловой системе) в качестве нового рабочего индекса. Затем оно просматривает записи в каталоге точки монтирования «/usr» в поисках имени «..» и находит номер индекса для корня файловой системы («/»). После этого системная функция chdir завершается как обычно, вызывающий процесс не обращает внимания на тот факт, что он пересек точку монтирования.
