Студопедия.Орг Главная | Случайная страница | Контакты | Мы поможем в написании вашей работы!  
 

Регионы в виртуальном адресном пространстве



Вначале все виртуальное адресное пространство процесса свободно. Оно начинает заполняться по мере выполнения программы. Чтобы воспользоваться какой-либо частью этого пространства, в нем нужно создать регион, зарезервировав определенный диапазон адресов. Такая схема позволяет поддерживать разреженные адресные пространства.Совокупность регионов описывается структурой VAD, которая организована в виде двоичного дерева и хранится в PCB (структура EPROCESS, см. лекцию 5) процесса. Для вновь создаваемого региона можно запросить любой диапазон адресов с учетом уже существующих регионов. Первые регионы для кода, стека, стандартной кучи процесса и ряд других создает операционная система в момент загрузки процесса. Последующие регионы приложение создает самостоятельно (см. рис. 9.4).

2)Алгоритм открытия файла в UNIX файловой системе

алгоритм open /* для драйверов устройств */ входная информация: имя пути поиска режим открытия выходная информация: дескриптор файла { преобразовать имя пути поиска в индекс, увеличить значе- ние счетчика ссылок в индексе; выделить в таблице файлов место для пользовательского дескриптора файла, как при открытии обычного файла; выбрать из индекса старший и младший номера устройства; сохранить контекст (алгоритм setjmp) в случае передачи управления от драйвера; если (устройство блочного типа) { использовать старший номер устройства в качестве ука- зателя в таблице ключей устройств ввода-вывода бло- ками; вызвать процедуру открытия драйвера по данному индек- су: передать младший номер устройства, режимы откры- тия; } в противном случае { использовать старший номер устройства в качестве ука- зателя в таблице ключей устройств посимвольного вво- да-вывода; вызвать процедуру открытия драйвера по данному индек- су: передать младший номер устройства, режимы откры- тия; } если (открытие в драйвере не выполнилось) привести таблицу файлов к первоначальному виду, уменьшить значение счетчика в индексе;

Билет 21.

1) алгоритм создания дирректории в UNIX файловой системе

Когда регистрируется новый пользователь в операционной системе UNIX, то обычно создается каталог /u/username, который будет начальным для этого пользователя. Вам необходимо будет организовать свою структуру каталогов. Как и с файлами, для создания каталогов можно использовать относительные или абсолютные имена. Если текущим каталогом является /u/guhas, то

mkdir temp

создаст подкаталог с названием temp в каталоге guhas и его абсолютный путь будет /u/guhas/temp.

mkdir /u/guhas/temp

можно также использовать для получения того же эффекта, что дала предыдущая команда. mkdir../temp

позволит создать каталог /u/temp. Данный пример использует.. (две последовательные точки) как часть относительного пути для указания, что каталог temp будет создан в каталоге на один уровень выше, то есть в каталоге /и. Используя mkdir, можно создать более чем один каталог сразу. Например, из текущего каталога выдайте следующую команду:

mkdir testdirl /u/guhas/temp/testdir2

которая создаст testdirl в текущем каталоге и testdir2 в каталоге /u/guhas/temp (предполагается, что такой каталог существует.) В данном примере testdirl использует относительный путь, a /u/guhas/testdir2 использует абсолютный путь.

Если каталог уже есть, то UNIX сообщит об ошибке, предупредив, что каталог уже существует.

Для создания каталога у вас должно быть право на запись в родительском каталоге, в котором вы создаете подкаталог, и родительский каталог должен существовать. Однако многие системыUNIX с mkdir обеспечивают опцию -р. При указании данной опции, если родительского каталога не существует, то он также будет создан.

Если работа с каталогом окончена или вы израсходовали все пространство на диске и хотите каталог удалить, используйте команду rmdir

Если текущий каталог р /н/guhas и temp находится в нем, то для удаления каталога temp используйте команду

rmdir temp

При выполнении команды может появиться сообщение об ошибке, утверждающее Directory temp is not empty (Каталог temp не пуст), что означает наличие в temp файлов и каталогов. Удалить каталог можно только тогда, когда он пуст (все файлы и каталоги в нем удалены ранее). Командой rmdir удалять файлы нельзя. Для этой цели существует команда rm

2) алгоритм создания дирректории в UNIX файловой системе

Каждый файл идентифицируется именем, которое представляет собой последовательность символов. Старые версии UNIX имели ограничение на количество символов в имени файла. Все новые версии UNIX такого ограничения уже не имеют. Тем не менее при именовании файлов следует быть внимательным. Хотя UNIX и позволяет большинству символов использоваться в имени файла, но некоторые из символов в UNIX имеют специальное значение и их использование в имени может вызвать определенные проблемы.

Например, символ > используется как оператор перенаправления вывода. Если необходимо создать файл с именем х>у, то, по идее, нужно использовать команду touch:

touch x>y

Но при этом получилось бы два файла: один с именем х, другой с именем у.

Для обхода проблемы используйте специальный символ (\) (в оболочках Кот и С), а команду touch применяйте следующим образом:

touch x\>y

Билет 22

1)Алгоритм чтения файла в UNIX файловой системе

mode чтение или запись
count количество байт для чтения или записи
offset смещение в байтах внутри файла
address адрес места, куда будут копироваться данные, в памяти пользователя или ядра
flag отношение адреса к памяти пользователя или к памяти ядра
Рисунок 5.6. Параметры ввода-вывода, хранящиеся в пространстве процесса

Затем в алгоритме начинается цикл, выполняющийся до тех пор, пока операция чтения не будет произведена до конца. Ядро преобразует смещение в байтах внутри файла в номер блока, используя алгоритм bmap, и вычисляет смещение внутри блока до места, откуда следует начать ввод-вывод, а также количество байт, которые будут прочитаны из блока. После считывания блока в буфер, возможно, с продвижением (алгоритмы bread и breada) ядро копирует данные из блока по назначенному адресу в пользовательском процессе. Оно корректирует параметры ввода-вывода в адресном пространстве процесса в соответствии с количеством прочитанных байт, увеличивая значение смещения в байтах внутри файла и адрес места в пользовательском процессе, куда будет доставлена следующая порция данных, и уменьшая число байт, которые необходимо прочитать, чтобы выполнить запрос пользователя. Если запрос пользователя не удовлетворен, ядро повторяет весь цикл, преобразуя смещение в байтах внутри файла в номер блока, считывая блок с диска в системный буфер, копируя данные из буфера в пользовательский процесс, освобождая буфер и корректируя значения параметров ввода-вывода в адресном пространстве процесса. Цикл завершается, либо когда ядро выполнит запрос пользователя полностью, либо когда в файле больше не будет данных, либо если ядро обнаружит ошибку при чтении данных с диска или при копировании данных в пространство пользователя. Ядро корректирует значение смещения в таблице файлов в соответствии с количеством фактически прочитанных байт; поэтому успешное выполнение операций чтения выглядит как последовательное считывание данных из файла. Системная операция lseek (раздел 5.6) устанавливает значение смещения в таблице файлов и изменяет порядок, в котором процесс читает или записывает данные в файле.

#include ‹fcntl.h›
main() {
int fd;
char lilbuf[20], bigbuf[1024];
fd = open("/etc/passwd", O_RDONLY);
read(fd, lilbuf, 20);
read(fd, bigbuf, 1024);
read(fd, lilbuf, 20);
}
Рисунок 5.7. Пример программы чтения из файла

Рассмотрим программу, приведенную на Рисунке 5.7. Функция open возвращает дескриптор файла, который пользователь засылает в переменную fd и использует в последующих вызовах функции read. Выполняя функцию read, ядро проверяет, правильно ли задан параметр «дескриптор файла», а также был ли файл предварительно открыт процессом для чтения. Оно сохраняет значение адреса пользовательского буфера, количество считываемых байт и начальное смещение в байтах внутри файла (соответственно: lilbuf, 20 и 0), в пространстве процесса. В результате вычислений оказывается, что нулевое значение смещения соответствует нулевому блоку файла, и ядро возвращает точку входа в индекс, соответствующую нулевому блоку. Предполагая, что такой блок существует, ядро считывает полный блок размером 1024 байта в буфер, но по адресу lilbuf копирует только 20 байт. Оно увеличивает смещение внутри пространства процесса на 20 байт и сбрасывает счетчик данных в 0. Поскольку операция read выполнилась, ядро переустанавливает значение смещения в таблице файлов на 20, так что последующие операции чтения из файла с данным дескриптором начнутся с места, расположенного со смещением 20 байт от начала файла, а системная функция возвращает число байт, фактически прочитанных, т. е. 20.
При повторном вызове функции read ядро вновь проверяет корректность указания дескриптора и наличие соответствующего файла, открытого процессом для чтения, поскольку оно никак не может узнать, что запрос пользователя на чтение касается того же самого файла, существование которого было установлено во время последнего вызова функции. Ядро сохраняет в пространстве процесса пользовательский адрес bigbuf, количество байт, которые нужно прочитать процессу (1024), и начальное смещение в файле (20), взятое из таблицы файлов. Ядро преобразует смещение внутри файла в номер дискового блока, как раньше, и считывает блок. Если между вызовами функции read прошло непродолжительное время, есть шансы, что блок находится в буферном кеше. Однако, ядро не может полностью удовлетворить запрос пользователя на чтение за счет содержимого буфера, поскольку только 1004 байта из 1024 для данного запроса находятся в буфере. Поэтому оно копирует оставшиеся 1004 байта из буфера в пользовательскую структуру данных bigbuf и корректирует параметры в пространстве процесса таким образом, чтобы следующий шаг цикла чтения начинался в файле с байта 1024, при этом данные следует копировать по адресу байта 1004 в bigbuf в объеме 20 байт, чтобы удовлетворить запрос на чтение.
Теперь ядро переходит к началу цикла, содержащегося в алгоритме read. Оно преобразует смещение в байтах (1024) в номер логического блока (1), обращается ко второму блоку прямой адресации, номер которого хранится в индексе, и отыскивает точный дисковый блок, из которого будет производиться чтение. Ядро считывает блок из буферного кеша или с диска, если в кеше данный блок отсутствует. Наконец, оно копирует 20 байт из буфера по уточненному адресу в пользовательский процесс. Прежде чем выйти из системной функции, ядро устанавливает значение поля смещения в таблице файлов равным 1044, то есть равным значению смещения в байтах до места, куда будет производиться следующее обращение. В последнем вызове функции read из примера ядро ведет себя, как и в первом обращении к функции, за исключением того, что чтение из файла в данном случае начинается с байта 1044, так как именно это значение будет обнаружено в поле смещения той записи таблицы файлов, которая соответствует указанному дескриптору.
Пример показывает, насколько выгодно для запросов ввода-вывода работать с данными, начинающимися на границах блоков файловой системы и имеющими размер, кратный размеру блока. Это позволяет ядру избегать дополнительных итераций при выполнении цикла в алгоритме read и всех вытекающих последствий, связанных с дополнительными обращениями к индексу в поисках номера блока, который содержит данные, и с конкуренцией за использование буферного пула. Библиотека стандартных модулей ввода-вывода создана таким образом, чтобы скрыть от пользователей размеры буферов ядра; ее использование позволяет избежать потерь производительности, присущих процессам, работающим с небольшими порциями данных, из-за чего их функционирование на уровне файловой системы неэффективно (см. упражнение 5.4).
Выполняя цикл чтения, ядро определяет, является ли файл объектом чтения с продвижением: если процесс считывает последовательно два блока, ядро предполагает, что все очередные операции будут производить последовательное чтение, до тех пор, пока не будет утверждено обратное. На каждом шаге цикла ядро запоминает номер следующего логического блока в копии индекса, хранящейся в памяти, и на следующем шаге сравнивает номер текущего логического блока со значением, запомненным ранее. Если эти номера равны, ядро вычисляет номер физического блока для чтения с продвижением и сохраняет это значение в пространстве процесса для использования в алгоритме breada. Конечно же, пока процесс не считал конец блока, ядро не запустит алгоритм чтения с продвижением для следующего блока.
Обратившись к Рисунку 4.9, вспомним, что номера некоторых блоков в индексе или в блоках косвенной адресации могут иметь нулевое значение, пусть даже номера последующих блоков и ненулевые. Если процесс попытается прочитать данные из такого блока, ядро выполнит запрос, выделяя произвольный буфер в цикле read, очищая его содержимое и копируя данные из него по адресу пользователя. Этот случай не имеет ничего общего с тем случаем, когда процесс обнаруживает конец файла, говорящий о том, что после этого места запись информации никогда не производилась. Обнаружив конец файла, ядро не возвращает процессу никакой информации (см. упражнение 5.1).
Когда процесс вызывает системную функцию read, ядро блокирует индекс на время выполнения вызова. Впоследствии, этот процесс может приостановиться во время чтения из буфера, ассоциированного с данными или с блоками косвенной адресации в индексе. Если еще одному процессу дать возможность вносить изменения в файл в то время, когда первый процесс приостановлен, функция read может возвратить несогласованные данные. Например, процесс может считать из файла несколько блоков; если он приостановился во время чтения первого блока, а второй процесс собирался вести запись в другие блоки, возвращаемые данные будут содержать старые данные вперемешку с новыми. Таким образом, индекс остается заблокированным на все время выполнения вызова функции read для того, чтобы процессы могли иметь целостное видение файла, то есть видение того образа, который был у файла перед вызовом функции.
Ядро может выгружать процесс, ведущий чтение, в режим задачи на время между двумя вызовами функций и планировать запуск других процессов. Так как по окончании выполнения системной функции с индекса снимается блокировка, ничто не мешает другим процессам обращаться к файлу и изменять его содержимое. Со стороны системы было бы несправедливо держать индекс заблокированным все время от момента, когда процесс открыл файл, и до того момента, когда файл будет закрыт этим процессом, поскольку тогда один процесс будет держать все время файл открытым, тем самым не давая другим процессам возможности обратиться к файлу. Если файл имеет имя «/etc/ passwd», то есть является файлом, используемым в процессе регистрации для проверки пользовательского пароля, один пользователь может умышленно (или, возможно, неумышленно) воспрепятствовать регистрации в системе всех остальных пользователей. Чтобы предотвратить возникновение подобных проблем, ядро снимает с индекса блокировку по окончании выполнения каждого вызова системной функции, использующей индекс. Если второй процесс внесет изменения в файл между двумя вызовами функции read, производимыми первым процессом, первый процесс может прочитать непредвиденные данные, однако структуры данных ядра сохранят свою согласованность.
Предположим, к примеру, что ядро выполняет два процесса, конкурирующие между собой (Рисунок 5.8). Если допустить, что оба процесса выполняют операцию open до того, как любой из них вызывает системную функцию read или write, ядро может выполнять функции чтения и записи в любой из шести последовательностей: чтение1, чтение2, запись1, запись2, или чтение1, запись1, чтение2, запись2, или чтение1, запись1, запись2, чтение2 и т. д. Состав информации, считываемой процессом A, зависит от последовательности, в которой система выполняет функции, вызываемые двумя процессами; система не гарантирует, что данные в файле останутся такими же, какими они были после открытия файла. Использование возможности захвата файла и записей (раздел 5.4) позволяет процессу гарантировать сохранение целостности файла после его открытия.

#include ‹fcntl.h›

/* процесс A */
main() {
int fd;
char buf[512];
fd = open("/etc/passwd", O_RDONLY);
read(fd, buf, sizeof(buf)); /* чтение1 */
read(fd, buf, sizeof(buf)); /* чтение2 */
}

/* процесс B */
main() {
int fd, i;
char buf[512];
for (i = 0; i ‹ sizeof(buf); i++) buf[i] = 'a';
fd = open("/etc/passwd", O_WRONLY);
write(fd, buf, sizeof(buf)); /* запись1 */
write(fd, buf, sizeof(buf)); /* запись2 */
}
Рисунок 5.8. Процессы, ведущие чтение и запись файла
2)алгоритм создания нового имени файла в UNIX файловой системы

Билет 23

1)

2)Алгоритм создания канала ввода-вывода





Дата публикования: 2015-01-24; Прочитано: 273 | Нарушение авторского права страницы | Мы поможем в написании вашей работы!



studopedia.org - Студопедия.Орг - 2014-2024 год. Студопедия не является автором материалов, которые размещены. Но предоставляет возможность бесплатного использования (0.008 с)...