- •Морис Дж. Бах Архитектура операционной системы 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 Упражнения
- •Приложение системные операции
- •Библиография
10.1.2.2 Closе
Процесс разрывает связь с открытым устройством, закрывая его. Однако, ядро запускает определяемую типом устройства процедуру close только в последнем вызове функции close для этого устройства, и то только если не осталось процессов, которым устройство необходимо открытым, поскольку процедура закрытия устройства завершается разрывом аппаратного соединения; отсюда ясно, что ядру следует подождать, пока не останется ни одного процесса, обращающегося к устройству. Поскольку ядро запускает процедуру открытия устройства при каждом вызове системной функции open, а процедуру закрытия только один раз, драйверу устройства неведомо, сколько процессов используют устройство в данный момент. Драйверы могут легко выйти из строя, если при их написании не соблюдалась осторожность: когда при выполнении процедуры close они приостанавливают свою работу и какой-нибудь процесс открывает устройство до того, как завершится процедура закрытия, устройство может стать недоступным для работы, если в результате комбинации вызовов open и close сложилась нераспознаваемая ситуация.
алгоритм close /* для устройств */
входная информация: дескриптор файла
выходная информация: отсутствует
выполнить алгоритм стандартного закрытия (глава 5ххх);
if (значение счетчика ссылок в таблице файлов не 0) goto finish;
if (существует еще один открытый файл, старший и младший номера которого совпадают с номерами закрываемого устройства)
goto finish; /* не последнее закрытие */
if (устройство символьного типа)
использовать старший номер в качестве указателя в таблице ключей устройства посимвольного ввода-вывода;
вызвать процедуру закрытия, определяемую типом драйвера и передать ей в качестве параметра младший номер устройства;
if (устройство блочного типа)
if (устройство монтировано) goto finish;
переписать блоки устройства из буферного кеша на устройство;
использовать старший номер в качестве указателя в таблице ключей устройства ввода-вывода блоками;
вызвать процедуру закрытия, определяемую типом драйвера и передать ей в качестве параметра младший номер устройства;
сделать недействительными блоки устройства, оставшиеся в буферном кеше;
finish:
освободить индекс;
Рисунок 10.4. Алгоритм закрытия устройства
Алгоритм закрытия устройства похож на алгоритм закрытия файла обычного типа (Рисунок 10.4). Однако, до того, как ядро освобождает индекс, в нем выполняются действия, специфичные для файлов устройств.
1. Просматривается таблица файлов для того, чтобы убедиться в том, что ни одному из процессов не требуется, чтобы устройство было открыто. Чтобы установить, что вызов функции close для устройства является последним, недостаточно положиться на значение счетчика ссылок в таблице файлов, поскольку несколько процессов могут обращаться к одному и тому же устройству, используя различные точки входа в таблице файлов. Так же недос таточно положиться на значение счетчика в таблице индексов, поскольку одному и тому же устройству могут соответствовать несколько файлов устройства. Например, команда ls -l покажет, что одному и тому же устройству символьного типа ("c" в начале строки) соответствуют два файла устройства, старший и младший номера у которых (9 и 1) совпадают. Значение счетчика связей для каждого файла, равное 1, говорит о том, что имеется два индекса.
crw-w-w- 1 root vis 9, 1 Aug 6 1984 /dev/tty01
crw-w-w- 1 root unix 9, 1 May 3 15:02 /dev/tty01
Если процессы открывают оба файла независимо один от другого, они обратятся к разным индексам одного и того же устройства.
2. Если устройство символьного типа, ядро запускает процедуру закрытия устройства и возвращает управление в режим задачи. Если устройство блочного типа, ядро просматривает таблицу результатов монтирования и проверяет, не располагается ли на устройстве смонтированная файловая система. Если такая система есть, ядро не сможет запустить процедуру закрытия устройства, поскольку не был сделан последний вызов функции close для устройства. Даже если на устройстве нет смонтированной файловой системы, в буферном кеше еще могут находиться блоки с данными, оставшиеся от смонтированной ранее файловой системы и не переписанные на устройство, поскольку имели пометку "отложенная запись". Поэтому ядро просматривает буферный кеш в поисках таких блоков и переписывает их на устройство перед запуском процедуры закрытия устройства. После закрытия устройства ядро вновь просматривает буферный кеш и делает недействительными все буферы, которые содержат блоки для только что закрытого устройства, в то же вре мя позволяя буферам с актуальной информацией остаться в кеше.
3. Ядро освобождает индекс файла устройства. Короче говоря, процедура закрытия устройства разрывает связь с устройством и инициализирует заново информационные структуры драйвера и аппаратную часть устройства с тем, чтобы ядро могло бы позднее открыть устройство вновь.
