ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 24.12.2021
Просмотров: 12215
Скачиваний: 10

Примеры операционных систем 493
ны. («Сборка мусора» — это автоматическое удаление неиспользуемых структур
данных.) «Куча» в NT сходна с функцией
malloc
в системах UNIX, но в NT, в отли-
чие от UNIX, может быть несколько независимых «куч».
Примеры виртуального ввода-вывода
Основной задачей любой операционной системы является предоставление служб
для пользовательских программ. Главным образом, это службы ввода-вывода для
чтения и записи файлов. И UNIX, и NT предлагают широкий спектр служб ввода-
вывода. Для большинства системных вызовов UNIX в NT имеется эквивалентный
вызов, но обратное не верно, поскольку NT содержит гораздо больше вызовов и
каждый из них гораздо сложнее соответствующего вызова в UNIX.
Виртуальный ввод-вывод в системе UNIX
Система UNIX пользовалась большой популярностью во многом благодаря своей
простоте, которая, в свою очередь, является прямым результатом организации си-
стемы файлов. Обычный файл представляет собой линейную последовательность
8-битных байтов
1
от 0 до максимум 2
32
-1 байтов. Сама операционная система не
сообщает структуру записей в файлах, хотя многие пользовательские программы
рассматривают текстовые файлы в коде ASCII как последовательности строк, каж-
дая из которых завершается переводом строки.
С каждым открытым файлом связан указатель на следующий байт, который
нужно считать или записать. Системные вызовы
read
и
write
считывают и записы-
вают данные, начиная с позиции, которую определяет указатель. После операции
оба вызова перемещают указатель в другую позицию, передвигая его ровно на
столько байтов, сколько было считано или записано. Возможен и случайный до-
ступ к файлам, когда указатель файла устанавливается на определенное значение.
Кроме обычных файлов, система поддерживает специальные файлы, которые
используются для доступа к устройствам ввода-вывода. С каждым устройством
ввода-вывода обычно связан один или несколько специальных файлов. Считывая
информацию из этих файлов и записывая информацию в эти файлы, программа
может считывать информацию с устройства ввода-вывода и записывать информа-
цию на устройство ввода-вывода. Так происходит работа с дисками, принтерами,
терминалами и многими другими устройствами.
Основные системные вызовы для файлов в UNIX приведены в табл. 6.9. Вызов
creat
(без
е
на конце) используется для создания нового файла. В настоящее время
он не является обязательным, поскольку вызов
open
тоже может создавать новый
файл. Вызов
unlink
удаляет файл (предполагается, что файл находится только в од-
ной директории).
Вызов
open
используется для открытия существующих файлов, а также для
создания новых. Флаг
mode
сообщает, как его открыть (для чтения, для записи
и т. д.). Вызов возвращает небольшое целое число, которое называется дескрипто-
ром файла. Дескриптор файла определяет файл в последующих вызовах. Сам про-
1
Для многих сейчас слова про 8-битные байты могут показаться странными, однако на самом деле рань-
ше байт мог быть и 5-битным, и 7-битным, и 8-битным. Теперь мы по умолчанию считаем байт состо-
ящим из 8 битов. —
Примеч. научн. ред.

4 9 4
Глава 6. Уровень операционной системы
цесс ввода-вывода осуществляется с помощью процедур
read
и
write,
каждая из
которых содержит дескриптор файла (он указывает, какой файл использовать),
буфер для данных и число байтов, которое сообщает, какое количество данных
нужно передать. Вызов
Iseek
используется для перемещения указателя файла, что
делает возможным случайный доступ к файлам.
Stat
выдает информацию о файле (размер, время последнего доступа, имя вла-
дельца и т. п.).
Chmod
изменяет режим защиты файла (например, разрешает или,
наоборот, запрещает каким-нибудь пользователям читать его). Наконец,
fcntl
выпол-
няет различные действия над файлами, например блокирование и разблокирование.
Таблица 6.9.
Основные системные вызовы UNIX
Системный вызов Значение
creat(name, mode) Создает файл;
mode
определяет тип защиты
unlink(name) Удаляет файл (предполагается, что есть только 1 связь)
open(name, mode) Открывает или создает файл и возвращает дескриптор файла
close(fd) Закрывает файл
read (fd, buffer, count) Считывает байты в количестве
count
в
buffer
write(fd, buffer, count) Записывает в файл
count
байтов из
buffer
lseek(fd, offset, w) Перемещает указатель файла на
offset
и
w
stat(name, buffer) Возвращает информацию о файле
chmod(name, mode) Изменяет тип защиты файла
fcntl(fd, cmd, j) Производит различные операции управления (например, блокирует
файл или его часть)
В листинге 6.3 показано, как происходит процесс ввода-вывода. Эта программа
минимальна и не включает в себя проверку ошибок. Перед тем как войти в цикл,
программа открывает существующий файл
data
и создает новый файл
newf.
Каж-
дый вызов возвращает дескриптор файла
infd
и
outfd
соответственно. Следующий
параметр в обоих вызовах — биты защиты, которые определяют, что файлы нужно
считать и записать соответственно. Оба вызова возвращают дескриптор файла. Если
не удалось произвести
open
или
creat,
то возвращается отрицательный дескриптор
файла, который сообщает, что вызов не удался.
Листинг 6.3.
Фрагмент программы для копирования файла с использованием
системных вызовов UNIX. Этот фрагмент написан на языке С,
поскольку в языке Java не показываются системные вызовы
низкого уровня, а нам нужно их показать
/* Открытие дескрипторов файла. */
infd = openC'data", 0);
outfd = creat("newf", ProtectionBits);
/* Цикл копирования. */
do{
count = readCinfd. buffer, bytes);
if (count > 0) write(outfd, buffer, count):
} while (count > 0):
/* Закрытие файлов.*/
close(infd):
ciose(outfd);

Примеры операционных систем 495
Вызов
read
имеет три параметра: дескриптор файла, буфер и число байтов. Дан-
ный вызов должен считать нужное число байтов из указанного файла в буфер.
Число считанных байтов помещается в
count. Count
может быть меньше, чем
bytes,
если файл был слишком коротким. Вызов
write
копирует считанные байты в вы-
ходной файл. Цикл продолжается до тех пор, пока входной файл не будет прочи-
тан полностью. Тогда цикл завершается, а оба файла закрываются.
Дескрипторы файлов в системе UNIX представляют собой небольшие целые
числа (обычно до 20). Дескрипторы файлов 0, 1 и 2 соответствуют
стандартному
вводу,
стандартному выводу
и
стандартной ошибке
соответственно. Обычно пер-
вый из них обращается к клавиатуре, а второй и третий — к дисплею, но пользо-
ватель может перенаправить их к файлам. Многие программы UNIX получают
входные данные из стандартного устройства ввода и записывают выходные дан-
ные в стандартное устройство вывода. Такие программы называются фильтрами.
С системой файлов тесно связана система директорий. Каждый пользователь
может иметь несколько директорий, а каждая директория может содержать фай-
лы и поддиректории. Система UNIX обычно конфигурируется с главной директо-
рией, так называемым
корневым каталогом,
который содержит поддиректории
bin
(для часто используемых программ),
dev
(для специальных файлов устройств вво-
да-вывода),
lib
(для библиотек) и
usr
(для пользовательских директорий, как пока-
зано на рис. 6.27). В нашем примере директория
usr
содержит поддиректории
ast
и
jim.
Директория
ast
включает в себя два файла
(data
и/оо.с) и поддиректорию
bin,
в которую входят 4 игры.
Чтобы назвать файл, нужно указать его путь из корневого каталога. Путь со-
держит список всех директорий от корневого каталога к файлу, для разделения
директорий используется слэш. Например, путь к файлу
game2
будет таким: /usr/
ast/bin/game2. Путь, который начинается с корневого каталога, называется
абсо-
лютным путем.
В каждый момент времени каждая работающая программа имеет текущий
ка-
талог.
Путь может быть связан с текущим каталогом. В этом случае в начале пути
слэш не ставится (чтобы отличить такой путь от абсолютного пути). Такой путь
называется
относительным
путем. Если /usr/ast — текущий каталог, то можно
получить доступ к файлу game3, используя путь bin/game3. Пользователь может
создать связь с чужим файлом, используя для этого системный вызов
link.
В на-
шем примере пути /usr/ast/bin/game3 и /usr/jim/jotto приводят к одному и тому
же файлу. Не разрешается применять связи к директориям, чтобы предотвратить
циклы в системе директорий. Вызовы
open
и
creat
используют и абсолютные, и
относительные пути.
Основные вызовы для оперирования с директориями в системе UNIX приведе-
ны в табл. 6.10.
Mkdir
создает новую директорию, a
rmdir
удаляет существующую
пустую директорию. Следующие три вызова применяются для чтения элементов
директорий. Первый открывает директорию, второй считывает элементы из нее,
а третий закрывает директорию.
Chdir
изменяет текущую директорию.
Link
создает элемент директории, который указывает на уже существующий
файл. Например, элемент /usr/jim/jotto можно создать с помощью вызова
Iink("/usr/ast/bin/game3", "/usr/jim/jotto")
или с помощью эквивалентного вызова, используя относительные пути, которые
зависят от текущей директории.
Unlink
удаляет элемент директории. Если файл

496 Глава 6. Урсень операционной системы
имеет только одну связь, он удаляется. Если он имеет две и более связей, то он не
удаляется. Не имеет никакого значения, была ли удаленная связь изначально со-
зданной, или это копия. Вызов
unlink("/usr/ast/bin/game3")
делает файл
game3
доступным только через путь /usr/jim/jotto. Вызовы
link
и
unlink
могут использоваться для перемещения файлов из одной директории в другую.
Корневой
каталог
Файлы данных
Рис. 6.27. Часть системы директорий в операционной системе UNIX

Примеры операционных систем
497
С каждым файлом (а также с каждой директорией, поскольку директория —
это тоже файл) связано битовое отображение, которое сообщает, кому разрешен
доступ к этому файлу. Отображение содержит три поля RWX (Read, Write, eXecute —
чтение, запись, выполнение). Первое из них контролирует разрешение на чтение,
запись и выполнение файлов для их владельца, второе — для других пользователей
из группы владельца, а третье — для любых пользователей. Поля RWX R-X —X
означают, что владелец файла может читать этот файл, записывать что-либо в него
и выполнять его (очевидно, файл является выполняемой программой, иначе не было
бы разрешения на его выполнение), другие члены группы могут читать и выпол-
нять его, а посторонние люди — только выполнять. Таким образом, посторонние
люди могут использовать эту программу, но не могут ее украсть (скопировать),
поскольку им запрещено чтение. Отнесение пользователей к тем или иным группам
осуществляется системным администратором, которого обычно называют
привиле-
гированным пользователем.
Привилегированный пользователь имеет право действо-
вать вопреки механизму защиты и считывать, записывать и выполнять любой файл.
Таблица 6.10.
Основные вызовы для работы с директориями в системе UNIX
Системный вызов Значение
mkdir(name, mode) Создает новую директорию
rmdir(name) Удаляет пустую директорию
Opendir(name) Открывает директорию для чтения
readdir(dirpointer) Читает следующий элемент директории
Closedir(dirpointer) Закрывает директорию
chdir(dirname) Изменяет текущий каталог на
dirname
Iink(name1, name2) Создает элемент директории
пате2,
указывающий на
пате 1
unlink(name) Удаляет
пате
из директории
Теперь рассмотрим, как файлы и директории реализованы в системе UNIX.
Более детальное описание см. в [152]. С каждым файлом (и с каждой директорией,
поскольку директория — это тоже файл) связан блок информации в 64 байта, ко-
торый называется
индексным дескриптором (i-node).
I-node сообщает, кто владе-
ет файлом, что разрешено делать с файлом, где найти данные и т. п. Индексные
дескрипторы для файлов расположены или последовательно в начале диска, или,
если диск разделен на группы цилиндров, — в начале цилиндра. Индексные де-
скрипторы снабжены последовательными номерами. Таким образом, система UNIX
может обнаружить i-node просто путем вычисления его адреса на диске.
Элемент директории состоит из двух частей: имени файла и номера индексного
дескриптора. Когда программа выполняет команду
openC'foo.c", 0),
система ищет текущий каталог для файла «foo.c», чтобы найти номер индексного
дескриптора для этого файла. Обнаружив номер индексного дескриптора, програм-
ма может считать его и узнать всю информацию об этом файле.
При большей длине пути файла основные шаги, изложенные выше, повторя-
ются несколько раз, пока не будет пройден весь путь. Например, чтобы найти но-
мер индексного дескриптора для пути /usr/ast/data, система сначала ищет корне-