- •Лекция 1. 7.02.2014
- •Монтирование файловой системы.
- •Лекция 2. 10.02.2014
- •Лекция 3. 17.02.2014
- •Открытые файлы.
- •Лекция 4. 24.02.2014
- •Лекция 5. 3.03.2014 Файлы.
- •Лекция 6. 17.03.2014
- •Организация виртуальной файловой системы (vfs)
- •Регистрация и дерегистрация фс
- •Функции для работы с элементами фс proc.
- •Лекция 7. 24.03.2014
- •Файловая система specfs.
- •Терминалы.
- •Терминальный ввод-вывод.
- •Лекция 8. 31.03.2014
- •Типы флагов структуры termios.
- •Принятые соглашения и стандарты.
- •Простые способы открытия псевдотерминалов.
- •Лекция 9. 7.04.2014
- •Лекция 10. 14.04.2014
- •Реализация доступа к устройствам.
- •Структура контроллера внешнего устройства.
- •Южный и северный мосты.
- •Последовательные и параллельные интерфейсы.
- •Лекция 11. 21.04.2014
- •Управление вводом-выводом.
- •Прерывания.
- •Лекция 12. 28.04.2014 Контроллер прерывания.
- •Лекции 13-14. 5.05.2014, 12.05.2014
- •Проблемы прямого доступа к памяти.
- •Управление устройствами.
- •Многослойная модель системы ввода-вывода.
- •Пространство имен устройств.
- •Доступ к драйверу символьного устройства.
- •Доступ к драйверу блочного устройства.
- •Дополнительная информация о драйверах.
- •Лекция 15. 19.05.2014
- •Типичные точки входа в драйвер устройства.
- •Файлы устройств.
- •Буферизация ввода-вывода.
- •Схемы обменной буферизации
- •Обслуживание прерываний.
- •Лекция 16. 26.05.14
- •Лекция 17. 02.06.14
Лекция 4. 24.02.2014
Файловая система долговременно хранит всю ту информацию, с которой пользователь может работать длительное время.
Современные тенденции: сделать современные ОС максимально гибкими. Главный интерес пользователя - сохранять информацию в различных форматах. Одна современная система может поддерживать несколько файловых систем.
Открытый файл — файл, с которым в настоящее время работает процесс или несколько процессов. Система обеспечивает процесс работы с файлами через понятие (абстракцию) «открытый файл».
На рисунке показана проблема: один процесс открывает два файловых дескриптора для одного и того же файла. Причина проблемы файловых дескрипторов. Пусть есть файл, открытый для чтения и записи, и в него уже успели что-то записать. После этого мы хотим выполнить fork и затем exec, в котором хотим вызвать stream editor (SED) — потоковый текстовый редактор, выполняющий копирование файлов на стандартный выход и редактирующий их в соответсвии со своими командами, которые могут быть указаны, например, в командном файле. Одним из решений является закрытие стандартного ввода, а затем новое открытие файла. Здесь начинают работать особенности получения файловых дескрипторов. Мы закроем stdin и тут же откроем (reopen). Начнут работать свойства системного вызова open, который всегда возвращает наименьший неоткрытый дескриптор файла.
#include <unistd.h>
int dup(int fg);
int dup2(int fg; int fd2);
fd = open ("mf", O_ROW R|O CREATE, 0644);
//...
// что-то записали в файл
//...
close(STDIN_FILENO);
open("mf", O_RDONLY);
if (fork() == 0) {
execlp("sed", "sed", (char*)0);
perror("sed");
}
Распараллеливание: Функции редактирования передаются потомку. Потомок наследует stdin. Но поскольку в предке выполнено закрытие и открытие нового файла (stdin идентифицируется в программе как другой открытый файл), stdin не наследуется.
//...
fd = open("mf", O_RDWR|O_CREAT, 0644);
//...
// что-то записали в файл
//...
if (fork() == 0) {
close(STDI_FILENO);
open("mf", O_RDONLY);
execlp("sed", "sed", (char*)0);
perror("sed");
}
В родителе stdin остался открытым, а в потомке он закрыт. Этот пример показывает, как отделить создание файла от исполнения. Данный пример показывает, как заменять файловые дескрипторы у нового процесса — процесса-потомка.
Что делать, если потомок не знает имя файла?
Это возможно в том случае, если процесс-родитель сам не открывает файл, а наследует его дескриптор от своего родителя. Очевидно, что может действовать «методом тыка», осуществляя поиск в таблицах ядра, но гораздо проще дублировать дескриптор следующим образом:
// CODE 3
//...
if (fork() == 0) {
close(STDIN_FILENO);
dup(fd); // fd duplicated in stdin
execlp("sed", "sed", (char*)0);
perror("sed");
}
У предложенного варианта имеется два недостатка:
Перед закрытием стандартного ввода сначала необходимо убедиться, что дескриптор fd не задействован. Это необходимо для того, чтобы fd стал дескриптором stdin. Иначе он будет закрыт.
Последовательность close, dup не атомарна. Возможно, что после того, как процесс закрыл stdin возник сигнал, система перешла на обработчик этого сигнала и выполнение процесса было прервано. В результате возможна ситуация, в которой системный вызов dup обнаружит, что stdin уже занят и вернет другой наименьший файловый дескриптор. Это можно расценивать, как поражение exec'a.
Использование dup2 решает обе проблемы. Dup2 заботится о закрытии, ничего не делает, если его аргументы одни и те же и, в результате закрытия дублированной последовательности, будет атомарным. Таким образом лучшее решение будет следующим:
// CODE 4
//...
if (fork() == 0) {
dup2(fd, STDIN_FILEN0);
execlp("sed", "sed", (char*)0);
perror("sed");
}
Такой подход называется «дублируем и уходим».
Возможны такие ситуации, когда необходимо проверить режим работы процесса-потомка (что потомок желает сделать). Для этого существует системный вызов
#include <fcntl.h>
int fcntl(int fildes, int command, …)
fcntl — сокращенно от file control
Для нас имеет значение только три задачи:
Дублирование дескриптора открытого файла в поле fildes. Для того, чтобы это выполнить, необходимо указать в команде константу F_DUPFD. В отличие от dup2, если файл уже был открыт (openfcntl), его не закроет, и повторное дублирование будет возможно. Затем с помощью этой функции можно получить открыте файловые дескрипторы. Для этого необходимо использовать константу F_GETFL. Для установки режима открытия файлового дескриптора необходимо использовать константу F_SETFL. Установка режима открытия файловых дескрипторов используется только в режиме O_APPEND.
Пример
make = fcntl(fildes, F_GETFL);
if (mode & O_APPEND)
//...
mode = fcntl(fildes, F_GETFL);
if (mode & O_RDONLY)
//...
работать не будет. Причины исторические. В ранних версиях Юникс константы read only, wrtite only и readwrite имели значения 0, 1, 2. Когда стало ясно, что лучше иметь битовое представление, было написано слишком много ПО. В результате комитет POSIX принес жертву Bckwrdcmptblty и ввел константу O_ACCMODE, которая является AND bitmask.
Пример
mode = fcntl(fildes, F_GETFL);
if (mod == -1)
exit(1);
else if(mode & O_ACCMODE == ORDONLY)
//...
else if (mode & O_ACCMODE == OWRONLY)
//...
else if (mode & O_ACCMODE == O_RDWR)
//...
int main()
{
int fd = open("foo.txt", O_RDONLY); //IO system call
FILE *fs = fopen("bar.txt", "w"); // c standart library IO
//...
}
