Литмир - Электронная Библиотека
Содержание  
A
A

{

 превратить имя файла в идентификатор индекса (алгоритм namei);

 if (файл не существует или к нему не разрешен доступ) return
 (код ошибки);

 выделить для индекса запись в таблице файлов, инициализировать счетчик, смещение;

 выделить запись в таблице пользовательских дескрипторов файла, установить указатель на запись в таблице файлов;

 if (режим открытия подразумевает усечение файла)
 освободить все блоки файла (алгоритм free);

 снять блокировку (с индекса); /* индекс заблокирован выше, в алгоритме namei */

 return (пользовательский дескриптор файла);

}

Рисунок 5.2. Алгоритм открытия файла

Предположим, что процесс, открывая файл «/etc/passwd» дважды, один раз только для чтения и один раз только для записи, и однажды файл «local» для чтения и для записи[15], выполняет следующий набор операторов:

fd1 = open("/etc/passwd", O_RDONLY);

fd2 = open("local", O_RDWR);

fd3 = open("/etc/passwd", O_WRONLY);

На Рисунке 5.3 показана взаимосвязь между таблицей индексов, таблицей файлов и таблицей пользовательских дескрипторов файла. Каждый вызов функции open возвращает процессу дескриптор файла, а соответствующая запись в таблице пользовательских дескрипторов файла указывает на уникальную запись в таблице файлов ядра, пусть даже один и тот же файл ("/etc/passwd") открывается дважды. Записи в таблице файлов для всех экземпляров одного и того же открытого файла указывают на одну запись в таблице индексов, хранящихся в памяти. Процесс может обращаться к файлу «/etc/passwd» с чтением или записью, но только через дескрипторы файла, имеющие значения 3 и 5 (см. Рисунок). Ядро запоминает разрешение на чтение или запись в файл в строке таблицы файлов, выделенной во время выполнения функции open. Предположим, что второй процесс выполняет следующий набор операторов:

fd1 = open("/etc/passwd", O_RDONLY);

fd2 = open("private", O_RDONLY);

Архитектура операционной системы UNIX (ЛП) - pic_31.png

Рисунок 5.3. Структуры данных после открытия

На Рисунке 5.4 показана взаимосвязь между соответствующими структурами данных, когда оба процесса (и больше никто) имеют открытые файлы. Снова результатом каждого вызова функции open является выделение уникальной точки входа в таблице пользовательских дескрипторов файла и в таблице файлов ядра, и ядро хранит не более одной записи на каждый файл в таблице индексов, размещенных в памяти.

Запись в таблице пользовательских дескрипторов файла по умолчанию хранит смещение в файле до адреса следующей операции ввода-вывода и указывает непосредственно на точку входа в таблице индексов для файла, устраняя необходимость в отдельной таблице файлов ядра. Вышеприведенные примеры показывают взаимосвязь между записями таблицы пользовательских дескрипторов файла и записями в таблице файлов ядра типа «один к одному». Томпсон, однако, отмечает, что им была реализована таблица файлов как отдельная структура, позволяющая совместно использовать один и тот же указатель смещения нескольким пользовательским дескрипторам файла (см. [Thompson 78], стр.1943). В системных функциях dup и fork, рассматриваемых в разделах 5.13 и 7.1, при работе со структурами данных допускается такое совместное использование.

Архитектура операционной системы UNIX (ЛП) - pic_32.png

Рисунок 5.4. Структуры данных после того, как два процесса произвели открытие файлов

Первые три пользовательских дескриптора (0, 1 и 2) именуются дескрипторами файлов: стандартного ввода, стандартного вывода и стандартного файла ошибок. Процессы в системе UNIX по договоренности используют дескриптор файла стандартного ввода при чтении вводимой информации, дескриптор файла стандартного вывода при записи выводимой информации и дескриптор стандартного файла ошибок для записи сообщений об ошибках. В операционной системе нет никакого указания на то, что эти дескрипторы файлов являются специальными. Группа пользователей может условиться о том, что файловые дескрипторы, имеющие значения 4, 6 и 11, являются специальными, но более естественно начинать отсчет с 0 (как в языке Си). Принятие соглашения сразу всеми пользовательскими программами облегчит связь между ними при использовании каналов, в чем мы убедимся в дальнейшем, изучая главу 7. Обычно операторский терминал (см. главу 10) служит и в качестве стандартного ввода, и в качестве стандартного вывода и в качестве стандартного устройства вывода сообщений об ошибках.

5.2 READ

Синтаксис вызова системной функции read (читать):

number = read(fd, buffer, count)

где fd — дескриптор файла, возвращаемый функцией open, buffer — адрес структуры данных в пользовательском процессе, где будут размещаться считанные данные в случае успешного завершения выполнения функции read, count — количество байт, которые пользователю нужно прочитать, number — количество фактически прочитанных байт. На Рисунке 5.5 приведен алгоритм read, выполняющий чтение обычного файла. Ядро обращается в таблице файлов к записи, которая соответствует значению пользовательского дескриптора файла, следуя за указателем (см. Рисунок 5.3). Затем оно устанавливает значения нескольких параметров ввода-вывода в адресном пространстве процесса (Рисунок 5.6), тем самым устраняя необходимость в их передаче в качестве параметров функции. В частности, ядро указывает в качестве режима ввода-вывода «чтение», устанавливает флаг, свидетельствующий о том, что ввод-вывод направляется в адресное пространство пользователя, значение поля счетчика байтов приравнивает количеству байт, которые будут прочитаны, устанавливает адрес пользовательского буфера данных и, наконец, значение смещения (из таблицы файлов), равное смещению в байтах внутри файла до места, откуда начинается ввод-вывод. После того, как ядро установит значения параметров ввода-вывода в адресном пространстве процесса, оно обращается к индексу, используя указатель из таблицы файлов, и блокирует его прежде, чем начать чтение из файла.

алгоритм read

входная информация:

 пользовательский дескриптор файла

 адрес буфера в пользовательском процессе

 количество байт, которые нужно прочитать

выходная информация: количество байт, скопированных в пользовательское пространство

{

 обратиться к записи в таблице файлов по значению пользовательского дескриптора файла;

 проверить доступность файла;

 установить параметры в адресном пространстве процесса, указав адрес пользователя, счетчик байтов, параметры ввода-вывода для пользователя;

 получить индекс по записи в таблице файлов;

вернуться

15

В описании вызова системной функции open содержатся три параметра (третий используется при открытии в режиме создания), но программисты обычно используют только первые два из них. Компилятор с языка Си не проверяет правильность количества параметров. В системе первые два параметра и третий (с любым «мусором», что бы ни произошло в стеке) передаются обычно ядру. Ядро не проверяет наличие третьего параметра, если только необходимость в нем не вытекает из значения второго параметра, что позволяет программистам указать только два параметра.

30
{"b":"96903","o":1}