Загрузил Denis Bakhaev

[Doktorov A.E.] Operacionnaya sistema Linux Metod(BookFi)

Реклама
Операционная
система
Linux
Методические указания
ФЕДЕРАЛЬНОЕ АГЕНТСТВО ПО ОБРАЗОВАНИЮ
Государственное образовательное учреждение высшего профессионального образования
УЛЬЯНОВСКИЙ ГОСУДАРСТВЕННЫЙ ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ
Операционная система Linux
Методические указания к лабораторным работам № 1-3
по дисциплине «Операционные системы» для студентов специальности
23020165 «Информационные системы и технологии»
Составитель А. Е. Докторов
Ульяновск
2009
УДК 004.451 (076.5)
ББК 32.973-018.2 я7
О-60
Рецензент профессор кафедры «Вычислительная техника» факультета
информационных систем и технологий Ульяновского государственного
технического университета доктор технических наук
В. Н. Негода.
Одобрено секцией методических пособий научно-методического совета
университета
О-60
Операционная система Linux : методические указания к лабораторным
работам № 1-3 по дисциплине «Операционные системы» для студентов
специальности 23020165 «Информационные системы и технологии» /
сост.: А. Е. Докторов. - Ульяновск : УлГТУ, 2009. - 38 с.
Методические указания составлены в соответствии с учебным планом специаль­
ности 23020165 «Информационные системы и технологии». Преследуют цель ориен­
тировать студентов на содержание и порядок выполнения лабораторных работ по
операционной системе Linux. Даются начальные сведения по темам, примеры оформ­
ления и выполнения лабораторных заданий.
Методические указания подготовлены на кафедре ИВК.
УДК 004.451 (076.5)
ББК 32.973-018.2 я7
Учебное издание
Операционная система Linux
Методические указания
Составитель ДОКТОРОВ Александр Евгеньевич
Редактор М. В. Теленкова
Подписано в печать 25.12.2009 Формат60*84/16.
Усл. печ. л. 2,33. Тираж 50 экз. Заказ 38.
Ульяновский государственный технический университет
432027, Ульяновск, Сев. Венец, 32.
Типография УлГТУ, 432027, Ульяновск,Сев. Венец, 32.
© А. Е. Докторов, составление, 2009
© Оформление УлГТУ, 2009
СОДЕРЖАНИЕ
ВВЕДЕНИЕ
ОПД.Ф.11
ВВЕДЕНИЕ..................................................................................................................................1
ЛАБОРАТОРНАЯ
РАБОТА
№1...................................................................................................4
ЛАБОРАТОРНАЯ
РАБОТА
№2....................................................................................................7
ЛАБОРАТОРНАЯ
РАБОТА
№3............................................./.....................................................23
БИБЛИОГРАФИЧЕСКИЙ
СПИСОК.........................................................................................37
Операционные системы
102
Принципы построения операционных систем (ОС),
вычислительный процесс и его реализация с помощью
ОС; основные функции ОС; обзор современных ОС и
операционных оболочек; стандартные сервисные про­
граммы; машинно-зависимые свойства ОС; управление
вычислительными процессами, вводом-выводом, реаль­
ной памятью; управление виртуальной памятью; машин­
но-независимые свойства ОС; способы планирования за­
даний пользователей; динамические, последовательные и
параллельные структуры программ; способы построения
ОС; сохранность и защита программных систем; интер­
фейсы и основные стандарты в области системного про­
граммного обеспечения
Данные методические указания направлены на практическое изуче­
ние некоторых основных функций одной из наиболее распространенных
в настоящее время операционных систем. К этим функциям относятся:
организация интерфейса с пользователем, управление файловой подсис­
темой и управление процессами. На каждую функцию предусмотрено
одно лабораторное занятие.
Занятие №1 представляет: установку и настройку системы, ознаком­
ление с интерфейсом, утилитами и прикладными программами (файловы­
ми менеджерами, текстовым редактором и др.).
Занятие №2 предполагает изучение: структуры файловой системы,
типов файлов, процесса монтирования файловых систем, системных вызо­
вов для работы с файлами и директориями, системных вызовов для рабо­
ты с файлами, отображаемыми в память.
Занятие №3 рассматривает вопросы: идентификатор процесса, соз­
дание нового процесса, загрузка программы, межпроцессное взаимодейст­
вие через именованный и неименованный каналы. Вопросы синхрониза­
ции выполнения процессов предполагается изучать на других занятиях.
38
3
БИБЛИОГРАФИЧЕСКИЙ СПИСОК
Л А Б О Р А Т О Р Н А Я РАБОТА №1
Первый запуск системы и настройка. Интерфейс с пользователем
В качестве «учебной» системы был выбран Linux PuppyRus Jeans,
1. Гласc, Г. UNIX для программистов и пользователей / Г. Гласc; пер. с
англ. - 3-е изд. - СПб. : BHV-Санкт-Петербург, 2004. - 820 с.
который может быть установлен либо на компьютере, имеющем малые
2. Подбельский, В. В. Программирование на языке Си : учеб. пособие
аппаратные ресурсы, либо загружать систему в оперативную память,
для вузов / В. В. Подбельский. - 2-е изд., доп. - М. : Финансы и
не боясь «испортить» имеющуюся на компьютере операционную систему.
статистика, 2005. - 600 с.
3. Рогачевский, А. М. Операционная система UNIX : учеб. пособие для
Минимальные требования к оборудованию:
вузов / А. М. Рогачевский. - СПб. : БХВ-Петербург, 2002. - 528 с.
1) Процессор: Pentium II 233 МГц.
2) Оперативная память: 64 Мб, при наличии жесткого диска или сход­
ного по функциональности устройства для полной (full) инсталляции,
или 128 Мб для запуска с компакт-диска, USB-flash для экономной
(frufal) инсталляции. Обязательное наличие SWAP-раздела виртуаль­
ной памяти (при памяти менее 256 Мб).
3) Носитель информации размером от 128 Мб - любой из списка:
- CD-ROM,
- жесткий диск (встроенный или подключаемый через USB),
- USB-flash накопитель.
Порядок выполнения:
1.
Для выполнения задания получите у преподавателя образ диска опе­
рационной системы в формате ISO и программу для записи CDдисков, например, SCDWriter.exe (работает в ОС Windows). Следуя
инструкциям программы, запишите образ на CD-диск.
2.
Уточните параметры видеосистемы того компьютера, на котором бу­
дет установлена система, используя имеющуюся на этом компьютере
операционную систему.
3.
4.
Установите в BIOS первым устройством загрузки CD-диск.
После выполнения начальной загрузки будут предложены варианты
загрузки (PuppyRus по умолчанию, PuppyRus prix=ram).
Выберите
один из этих вариантов (при самой первой загрузке выбор вариантов
безразличен).
5.
Проведите настройку видеосервера.
4
37
6.
#include <sys/types.h>
В случае отсутствия приемлемого режима работы, попробуйте дру­
#include <sys/stat.h>
гие режимы, используя сообщения и рекомендации разработчиков.
#include <fcntl.h>
Так как загрузка системы проведена в оперативную память, то нет
#include <unistd.h>
ничего страшного в полной перезагрузке кнопкой «Reset».
7.
#include <stdio.h>
intfd, result;
Рабочий стол после загрузки будет иметь вид, похожий на рабочий
стол Windows. При работе учтите, что выбор элемента происходит
int main(){
size_t size;
char resstring[14];
при наведении указателя мыши на этот элемент, а для активизации
char name[]="aaa.fifo";
/* Права доступа файла FIFO должны соответствовать параметру mknod */
элемента достаточно одного нажатия левой кнопки мыши.
(void)umask(O);
Замечание: если будет выдано сообщение о том, что витрина не ис­
mknod(name, S_IFIFO \ 0666, 0); /* Создаем FIFO */
пользовалась, то необходимо закрыть это сообщение, а в меню выбрать:
result =fork(); /* Порождаем новый процесс */
Выключение>Перезагрузка Х-сервера.
if (result > 0) {/* Родительский процесс. FIFO открываем на запись.*/
8.
fd = ореn(name, O_WRONLY));
Если на вашем компьютере есть возможность загрузки с flash-диска,
size = write(fd, "Hello, world!", 14);/* Запись в FIFO 14 байт */
то создайте загрузочный flash-диск (диск не должен иметь файловую
/*Закрываем входной поток данных. Родитель прекращает работу */
систему NTFS, а также на нем должен быть только один раздел). Для
close(fd);
этого в меню выберите:
printf("Parent exit\n");}
Настройки>Универсальный инсталлятор PuppyRus.
else {/* Порожденный процесс. Открываем FIFO на чтение.*/
fd = ореn(name, O_RDONLY));
/*Чтение из FIFO 14 байт в массив */
size = read(fd, resstring, 14);
/* Печатаем прочитанную строку */
printf("%s\n ", resstring);
/* Закрываем входной поток и завершаем работу */
close(fd);
Далее следуйте инструкциям разработчиков.
9.
Ознакомьтесь по руководству пользователя с особенностями установ­
ки операционной системы на жесткий диск.
10. Ознакомьтесь с прикладными программами, иконки которых распо­
ложены на рабочем столе (Текст, Таблицы, Paint, Видео, Аудио, Ар­
хив).
11. Рассмотрите файловые менеджеры Midnight Commander и Rox-Filer
(вызов из меню). Менеджеры исходно отображают «домашний» ката­
}
return 0;
лог пользователя, которым будет каталог «root».
12. Установка компилятора с языка Си. Использование SFS - файлов.
}
Задание: напишите на базе предыдущего примера две программы,
одна из которых пишет информацию в FIFO, а вторая - читает из него, так
чтобы между ними не было ярко выраженных родственных связей (то
Компилятор с языка Си изначально отсутствует в дистрибутиве
PuppyRus Jeans. Он находится в SFS-модуле (devx_301.sfs). Инструкция по
подключению модуля подробно описана в руководстве пользователя.
есть, чтобы ни одна из них не была потомком другой).
36
5
Замечание: для подключения модуля «на один раз», то есть до пере­
При создании FIFO права доступа получаются из стандартной ком­
загрузки системы, можно в менеджере файлов ROX-Filer кликнуть правой
бинации параметра mode и маски создания файлов текущего процесса
кнопкой мыши на иконке этого файла, и во всплывающем меню выбрать
umask, а именно - они равны (0777 & mode) & ~umask.
При успешном создании FIFO системный вызов возвращает значе­
команду «Подключить модуль SFS».
13. Ознакомьтесь с возможностями интегрированной среды разработки
Системные вызовы read() и write() при работе с FIFO имеют те же
Geany.
Запуск
ние 0, при неуспешном - отрицательное значение.
Geany
можно
выполнить
из
меню
(Текстовый редак-
особенности поведения, что и при работе с каналом pipe.
top>Geany). Для работы с языком Си можно создать файл из шаблона.
Но системный вызов ореn() при открытии FIFO ведет себя несколько
Для успешной компиляции необходимо сохранить файл под другим име­
иначе, чем при открытии других типов файлов, что связано с возможно­
нем, отличным от «Без имени». Для компиляции, сборки и выполнения
стью блокирования выполняющих его процессов.
Если FIFO открывается только для чтения, и флаг O_NDELAY не за­
программы используйте меню «Сборка».
14. Проведите настройку сети, выбрав на рабочем столе иконку «Масте­
дан, то процесс, осуществивший системный вызов, блокируется до тех
ра» и, далее, в окне «Настройка Рuрру» - «Соединение с интернет че­
пор, пока какой-либо другой процесс не откроет FIFO на запись. Если
рез сетевой интерфейс...», а остальное в соответствии с подсказками,
флаг O_NDELAY задан, то возвращается значение файлового дескриптора,
предлагаемыми разработчиками.
ассоциированного с FIFO.
Если FIFO открывается только для записи, и флаг O_NDELAY не за­
Отчет должен содержать:
1. Перечень файлов загрузочного диска с указанием формата и назначе­
ния каждого файла.
2. Параметры системы личного компьютера и параметры видеосервера,
при которых была получена работоспособная система с графическим
интерфейсом. Для сравнения приведите параметры видеосистемы дан­
ного компьютера в системе Windows.
отличия
графического
интерфейса
от интерфейса
Windows?
3. Какие действия необходимо выполнить для установки системы на
жесткий диск?
4. Какое есть сходство и различия файловых менеджеров Linux с ана­
логичными программами Windows?
флаг O_NDELAY задан, то констатируется возникновение ошибки и воз­
вращается значение -1.
Задание флага 0_NDELAY в параметрах системного вызова ореn()
приводит и к тому, что процессу, открывшему FIFO, запрещается блоки­
данных и записи в него.
1. Каково назначение файлов загрузочного диска?
есть
пор, пока какой-либо другой процесс не откроет FIFO на чтение. Если
ровка при выполнении последующих операций чтения из этого потока
Контрольные вопросы:
2. Какие
дан, то процесс, осуществивший системный вызов, блокируется до тех
Задание: Для иллюстрации взаимодействия родственных процессов
через FIFO рассмотрите приведенную ниже программу (добавьте провер­
ку на успешность завершения операций). В этой программе информацией
между собой обмениваются процесс-родитель и процесс-ребенок. Обрати­
те внимание, что повторный запуск этой программы приведет к ошибке
при попытке создания FIFO, так как файл с заданным именем уже сущест­
вует. Перед каждым запуском программы удаляйте файл вручную или для
повторных запусков сделайте программу без вызова mknode().
6
35
открытии с помощью системного вызова ореn(). После открытия имено­
ванный pipe ведет себя точно так же, как и неименованный. Для дальней­
шей работы с ним применяются системные вызовы read(), write() и close().
Время существования FIFO в адресном пространстве ядра операционной
системы, как и в случае с именованным, не может превышать время жизни
последнего из использовавших его процессов. Когда все процессы, рабо­
тающие с FIFO, закрывают все файловые дескрипторы, ассоциированные
с ним, система освобождает ресурсы, выделенные под FIFO. Вся непрочи­
танная информация теряется. В то же время файл-метка остается на диске
и может использоваться для новой реальной организации FIFO в даль­
нейшем. Прототип системного вызова
ЛАБОРАТОРНАЯ РАБОТА №2
Файлы и файловая система
В UNIX [3] файлы организованы в виде древовидной структуры, на­
зываемой файловой системой. Каждый файл имеет имя, определяющее
его расположение в дереве файловой системы. Корнем этого дерева явля­
ется корневой каталог (root directory), имеющий имя «/». Имена всех ос­
тальных файлов содержат путь - список каталогов (ветвей), которые не­
обходимо пройти, чтобы достичь файла. В UNIX все доступное пользова­
телям файловое пространство объединено в единое дерево каталогов, кор­
нем которого является каталог «/».Таким образом, полное имя любого
файла начинается с «/» и не содержит идентификатора устройства, на ко­
#include <sys/stat.h>
тором он фактически хранится. Имя файла является атрибутом файловой
#include <unistd.h>
системы, а не набора некоторых данных на диске, который не имеет име­
int mknod(char *path, int mode, int dev);
ни как такового. Каждый файл имеет связанные с ним метаданные
Далее рассмотрены не все возможные варианты задания параметров
(хранящиеся в индексных дескрипторах - inode), содержащие все харак­
mknod, а только те из них, которые соответствуют применению для FIFO.
теристики файла и позволяющие операционной системе выполнять опера­
Параметр dev является несущественным в этой ситуации, и мы будем все­
ции, заказанные прикладной задачей: открыть файл, прочитать или за­
гда задавать его равным 0. Параметр path является указателем на строку,
писать данные, создать или удалить файл. В частности, метаданные со­
содержащую полное или относительное имя файла, который будет являть­
держат указатели на дисковые блоки хранения данных файла. Имя файла
ся меткой FIFO на диске. Для успешного создания FIFO файла с таким
в файловой системе является указателем на его метаданные, в то время
именем перед вызовом существовать не должно. Параметр mode уста­
как метаданные не содержат указателя на имя файла. Такая архитектура
навливает атрибуты прав доступа различных категорий пользователей
позволяет одному файлу иметь несколько имен в файловой системе. Име­
к FIFO. Этот параметр задается как результат побитовой операции «или»
на жестко связаны с метаданными и, соответственно, с данными файла,
значения S_IFIFO, указывающего, что системный вызов должен создать
в то время как сам файл существует независимо от того, как его называют
FIFO, и некоторой суммы следующих восьмеричных значений:
в файловой системе. Такая связь имени файла с его данными называется
0400 - разрешено чтение для пользователя, создавшего FIFO;
0200 - разрешена запись для пользователя, создавшего FIFO;
0040 - разрешено чтение для группы пользователя, создавшего FIFO;
0020 - разрешена запись для группы пользователя, создавшего FIFO;
0004 - разрешено чтение для всех остальных пользователей;
0002 - разрешена запись для всех остальных пользователей.
34
жесткой связью. По определению жесткие связи указывают на один и тот
же индексный дескриптор inode. Жесткая связь является естественной
формой связи имени файла с его метаданными и не принадлежит к особо­
му типу файла. Особым типом файла является символьная связь, позво­
ляющая косвенно адресовать файл. В отличие от жесткой связи, символи­
ческая связь адресует файл, который, в свою очередь, ссылается на другой
7
файл. В результате, последний файл адресуется символической связью
сы, у которых этот pipe открыт для записи, то системный вызов блокиру­
косвенно. Данные файла, являющегося символической связью, содержат
ется и ждет появления информации. Если таких процессов нет, он вернет
только имя целевого файла.
значение 0 без блокировки процесса. Эта особенность приводит к необхо­
Если к файловой системе UNIX монтируется файловая система,
димости закрытия файлового дескриптора, ассоциированного с выходным
в которой структуры файла и его метаданных существенно отличаются от
концом канала, в процессе, который будет использовать pipe для чтения
UNIX, то используется виртуальная файловая система, основанная на
(close(fd[l])
в процессе-ребенке, см. пример). Аналогичной особенностью
представлении метаданных файла в виде, сходном с традиционной семан­
поведения при отсутствии процессов, у которых pipe открыт для чтения,
тикой UNIX. Интерфейсом работы с файлами является vnode (от virtual
обладает и системный вызов write(), с чем связана необходимость закры­
inode - виртуальный индексный дескриптор). Метаданные всех активных
тия файлового дескриптора, ассоциированного с входным концом канала,
файлов (файлов, на которые ссылаются один или более процессов) пред­
в процессе, который будет использовать pipe для записи (close(fd[0])
ставлены в памяти в виде in-core inode, в качестве которых в виртуальной
в процессе-родителе в той же программе).
файловой системе выступают vnode. Структура данных vnode одинакова
для всех файлов, независимо от типа реальной файловой системы, где
фактически располагается файл. Данные vnode содержат информацию, не­
обходимую для работы виртуальной файловой системы, а также неизмен­
ные характеристики файла, например, такие как тип файла.
UNIX поддерживает три типа прав доступа для владельца, группы
Задание: напишите программу для определения в используемой
операционной системе размера канала. Не забудьте, что при попытке за­
писи в канал, в котором нет места, системный вызов write завершится с
ошибкой.
5. Межпроцессное взаимодействие через канал FIFO.
и прочих пользователей: на чтение (read, обозначается символом на r), за­
Для организации потокового взаимодействия любых процессов (а не
пись (write, обозначается символом w) и на выполнение (execute, обозна­
только родственных, как pipe) в операционной системе UNIX применяется
чается символом х). Права доступа могут быть изменены только владель­
средство связи, получившее название FIFO (First Input First Output) или
цем файла или администратором системы. Для этого используется коман­
именованный pipe. FIFO во всем подобен каналу pipe, за одним исключе­
да chmod (рассмотрите самостоятельно).
нием: данные о расположении FIFO в адресном пространстве ядра и его
Замечание: проверку результата работы команды chmod можно про­
вести только в режиме «обычного» пользователя, так как для администра­
тора атрибуты доступа не проверяются.
К дополнительным атрибутам относятся: г - позволяет пользователю
удалять только файлы, которыми он владеет или имеет права на запись
состоянии процессы могут получать не через родственные связи, а через
файловую систему. Для этого при создании именованного канала на диске
заводится файл специального типа, обращаясь к которому процессы могут
получить интересующую их информацию. Для создания FIFO использует­
ся системный вызов mknod() или существующая в некоторых версиях
UNIX функция mkfifo().
(используется для каталогов), s - установить права доступа запущенного
Следует отметить, что при их работе не происходит действительного
процесса. К сожалению, так как система PuppyRus Jeans исходно предна­
выделения области адресного пространства операционной системы под
значена для работы только в режиме администратора, наблюдать особен­
именованный pipe, а только заводится файл-метка, существование кото­
ности этих атрибутов невозможно.
рой позволяет осуществить реальную организацию FIFO в памяти при его
33
Задание: ознакомьтесь по рекомендуемым литературным источни­
if (result > 0) { /* Работает родительский процесс */
close(fd[0]);
/*
Входной поток данных не понадобится */
кам с организацией файловой системы операционной системы Unix. Рас­
size = write(fd[l], "Hello, world!", 14); /* Запись строки в поток */
смотрите следующие вопросы:
/* Закрываем выходной поток данных и завершаем работу родителя */
1) Общая структура файловой системы.
close(fd[l]);
2) Типы файлов.
printf("Parent exit\n ");}
3) Команды для работы с файлами и каталогами.
else { /* Работает порожденный процессе */
close(fd[l]);
/*
Выходной поток данных не понадобится */
size = read(fd[0], resstring, 14); /* Чтение строки из канала */
printf("%s\n",resstring);
/*
Печать прочитанной строки */
/* Закрыть входной поток и завершить работу */
close(fd[0]);
Необходимо рассмотреть следующие команды (у некоторых ко­
манд, чтобы не было ошибок, в скобках указано полное имя, от которо­
го получилось сокращенное): имя текущего каталога -pwd, список файлов
в каталоге - ls (list), изменить текущий каталог - cd, установить связи - ln
(link), копировать - ср, удалить - rm (remove), распечатать файл - cat.
Порядок выполнения работы:
}
return 0;
1.
Изучение структуры файловой системы и команд pwd, cd и ls.
Используя менеджеры файлов и эмулятор терминала, рассмотрите
}
Задание: модифицируйте этот пример для связи между собой двух
родственных процессов, исполняющих разные программы.
Канал pipe служит для организации однонаправленной или сим­
плексной связи. При попытке организовать через pipe двустороннюю
связь, когда процесс-родитель пишет информацию в pipe, предполагая,
что ее получит процесс-ребенок, а затем читает информацию из канала
pipe, предполагая, что ее записал порожденный процесс, то могла бы воз­
структуру файловой системы. Отметьте наличие или отсутствие «стан­
дартных» для Unix систем каталогов (например, bin, etc, usr и т.д.), а так­
же отметьте способы обозначения каталогов, файлов ссылок, как в менед­
жерах файлов, так и командной строке терминала. В эмуляторе терминала
для получения справки по команде просмотра содержимого каталога не­
обходимо использовать ключ — help (обратите внимание на использование
двух знаков «минус»), например,
ls--help
никнуть ситуация, в которой процесс-родитель прочитал бы собственную
информацию, а процесс-ребенок не получил бы ничего. Для использова­
ния одного канала pipe в двух направлениях необходимы специальные
средства синхронизации процессов.
2.
Изучение файлов типа связь и команд для работы с файлами.
Пример использования ссылочного типа файлов приведен в режиме
терминала, чтобы попутно рассмотреть команды создания нового каталога
Задание: измените предыдущий пример, причем для двухсторонней
mkdir и, особенно, команды cat, дающей много возможностей по обработ­
связи используйте два канала: один для передачи от родителя ребенку,
ке текстового файла. Все действия при работе с командами записаны
второй - от ребенка родителю.
очень подробно, чтобы обратить внимание на особенности работы в тер­
Одна из особенностей поведения блокирующегося системного вызо­
минальном режиме.
ва read() связана с попыткой чтения из пустого канала. Если есть процес32
9
Для удобства рассмотрения ссылочных файлов создайте в домашнем
/* Создание канала (добавьте проверку на успешность операции)*/
pipe(fd);
каталоге новый подкаталог, например, с именем new и перейдите в него.
/* Запись всей строки вместе с признаком конца строки в канал */
mkdir new
size = write(fd[l], string, 14);
cd new
Создайте два текстовых файла (например, с именами txtl, txt2), ис­
пользуя команду cat.
/* Чтение строки из канала */
size = read(fd[0], resstring, 14);
/* Печать прочитанной строки */
cat >txtl
printf("%s\n ",resstring);
первый файл
/* Закрыть входной и выходной потоки */
Ctrl+z
close(fd[0]);
close(fdfl]);
Здесь устройством ввода служит клавиатура, вывод перенаправлен
return 0;
в файл с именем txtl. Как и для большинства команд подобного рода,
стандартным устройством ввода будет служить клавиатура, а стандарт­
}
ным устройством вывода - монитор. Знак «»> указывает, что вывод пере­
Тот факт, что таблица открытых файлов наследуется процессом-
направлен в файл с именем txtl. При вводе с клавиатуры можно построчно
ребенком при порождении нового процесса системным вызовом fork()
вводить текст. Каждая строка завершается при нажатии клавиши «Enter».
и входит в состав неизменяемой части системного контекста процесса
Завершение ввода текста - «Ctrl+z». Таким образом, в файле txtl будет
при системном вызове exec(), позволяет организовать передачу информа­
содержаться текст «первый файл». Аналогично можно создать файл txt2.
Просмотрите содержимое каталога командой ls, используя два ключа:
i - для вывода inode и l - для использования широкого формата.
ции через pipe между родственными процессами, имеющими общего пра­
родителя, создавшего pipe. Примером служит программа для однона­
правленной связи между процессом-родителем и процессом-ребенком
ls-i-l
(как и в предыдущих примерах, все проверки на успешность завершения
2655 -rw-r--r--1 root root 22 2009-10-12 08:20 txtl
операций добавьте самостоятельно).
2656 -rw-r--r--1 root root 22 2009-10-12 08:21 txt2
#include <sys/types.h>
Сделайте жесткую ссылку newl на файл txtl, используя команду ln,
и опять просмотрите содержимое каталога.
#include <unistd.h>
#include <stdio.h>
int main(){
ln txt1 new1
intfd[2], result;
Is -i -l
2655 -rw-r--r-- 2 root root 22 2009-10-12 08:20 txt1
2656 -rw-r--r-- 1 root root 22 2009-10-12 08:21 txt2
2655 -rw-r--r-- 2 root root 22 2009-10-12 08:20 newl
10
size_t size;
char resstring[14];
pipe(fd); /* Создаем pipe */
result =fork(); /* Порождаем новый процесс */
31
Параметр fd является указателем на массив из двух целых перемен­
Обратите внимание на то, что у файла newl тот же inode (2655)
ных. При нормальном завершении вызова, в первый элемент массива
и совпадает время создания. В третьей колонке число 2 показывает коли­
(fd[0]) будет занесен файловый дескриптор, соответствующий входному
чество ссылок на файл.
потоку данных канала и позволяющий выполнять только операцию чте­
Измените содержимое файла newl и убедитесь, что файлы txtl
ния, а во второй элемент массива (fd[1]) будет занесен файловый дескрип­
и newl - это один и тот же файл на диске, только у него два имени. Также
тор, соответствующий выходному потоку данных и позволяющий выпол­
проверьте, что жесткая ссылка не нарушается при перемещении файлов по
нять только операцию записи. Системный вызов возвращает значение
каталогам, а также то, что нельзя делать жесткие ссылки на каталоги.
равное 0 при нормальном завершении и значение -1 при возникновении
Символьную ссылку можно делать как на файлы, так и на каталоги.
Например, можно сделать ссылку на файл txt2.
ошибок.
Системный вызов организует выделение области памяти под буфер
и указатели и заносит информацию, соответствующую входному и выход­
ному потокам данных, в два элемента таблицы открытых файлов, связы­
вая тем самым с каждым каналом два файловых дескриптора. Для выпол­
нения операций передачи данных можно использовать системные вызовы
read() и write(). По окончании использования входного или/и выходного
потока данных, нужно закрыть соответствующий поток с помощью сис­
темного вызова close(). Необходимо отметить, что, когда все процессы,
использующие pipe, закрывают все ассоциированные с ним файловые де­
скрипторы, операционная система ликвидирует pipe.
Достаточно яркой иллюстрацией действий по созданию канала, за­
писи в него данных, чтению из него и освобождению выделенных ресур­
сов может служить программа, организующая работу с каналом в рамках
одного процесса, приведенная ниже.
ln -s 2 new2
Результатом будет новый файл со своим inode и временем создания.
Количество ссылок на файл txt2 не изменится. Размер файла соответствует
длине имени файла, на который делается ссылка. Обращение к файлу
new2 будет переадресовано на файл txt2.
2887 Irwxrwxrwx 1 root root 1 2009-10-12 08:23 new2 -> 2
Можно даже сделать символьную связь из каталога на сам этот каталог.
Рассмотрите, что произойдет при многократном переходе в этот каталог.
ln -s ../new newdir
Проверьте глубину символьных связей в данной системе. Найдите
места расположения ссылок на компилятор с языка Си и расположение
остальных каталогов и файлов, относящихся к компилятору.
3. Монтирование файловых систем.
#include <sys/types.h>
Видимое пользователю дерево каталогов образуется по следующей
#include <unistd.h>
схеме. Одну из доступных файловых систем ядро считает корневой. Эта
#include <stdio.h>
int main(){
файловая система монтируется на корневой каталог «/», в результате чего
intfd[2J;
ее содержимое становится доступно в виде дерева каталогов, растущего
size_t size;
непосредственно из корневого. Любой из каталогов текущего дерева мо­
char string[] = "Hello, world!";
жет служить точкой монтирования другой файловой системы. После вы­
char resstring[14];
полнения команды вида mount файл-дырка каталог, например,
30
11
mount /dev/hda5 /usr
программы мы указываем ее полное имя с путем от корневого каталога
содержимое файловой системы, лежащей на разделе, которому соответст­
/bin/cat (аргумент с индексом 0). Первое слово в командной строке должно
вует файл-дырка, становится доступно в виде дерева, растущего из ката­
совпадать с именем запускаемой программы. Второе слово в командной
лога /usr. Если до монтирования, в /usr были какие-то файлы и подкатало­
строке - это имя файла, содержимое которого распечатывается. */
ги, принадлежащие корневой файловой системе, они становятся недос­
тупны до выполнения соответствующей команды umount. Все устройства,
(void) execle("/bin/cat", "/bin/cat", "l.c", 0, envp);
/* Это сообщение печатается только при возникновении ошибки */
файловые системы которых могут быть смонтированы, в виде файла-
printf("Error on program start\n ");
дырки можно увидеть в каталоге /dev, например, для устройства CD-ROM
exit(-l);
это будет /dev/cdrom. Точки монтирования, то есть каталоги, в которые
return 0;
будут монтироваться файловые системы, расположены в каталоге /mnt,
например, /mnt/cdrom.
}
Список всех файловых систем, которые монтиру­
Задание: модифицируйте программу, созданную при выполнении
ются по ходу начальной загрузки, обычно лежит в файле /etc/fstab. Обра­
задания, использующую вызов fork() с разным поведением процессов ре­
тите внимание в этом файле на тип каждой из файловых систем. Напри­
бенка и родителя, так, чтобы порожденный процесс запускал на исполне­
мер, содержимое файла fstab может выглядеть так.
ние новую (любую) программу.
4. Межпроцессное взаимодействие через канал pipe.
Наиболее простым способом для передачи информации с помощью
потоковой модели между различными процессами или даже внутри одно­
го процесса в операционной системе UNIX является pipe (канал, труба,
конвейер). Pipe имеет и другое название - именованный канал. Прочитан­
ная информация немедленно из него удаляется и не может быть прочитана
повторно. Pipe представляет собой область памяти, недоступную пользо­
Помимо дисковых файловых систем (hda - могут быть разделами од­
вательским процессам напрямую. Она зачастую организована в виде
ного и того же диска) здесь можно встретить файловые системы в памяти
кольцевого буфера (хотя существуют и другие виды организации). По бу­
(временные - sys или proc - представление структуры процессов в виде
феру при операциях чтения и записи перемещаются два указателя, соот­
дерева каталогов). Некоторые устройства (например, CD-ROM) помечены
ветствующие входному и выходному потокам. При этом выходной указа­
noauto в знак того, что при старте их монтировать не надо. Запись в fstab
тель никогда не может перегнать входной и наоборот. Для создания ново­
служит только напоминанием, какое именно устройство какой точке
го экземпляра такого кольцевого буфера внутри операционной системы
монтирования
используется системный вызов pipe(). Прототип системного вызова
соответствует.
В командной строке проведите монтирование устройств. Найдите,
куда монтируется devx_301.sfs.
#include <unistd.h>
int pipe(int *fd);
12
29
Аргумент file является указателем на имя файла, который должен
быть загружен. Аргумент path - это указатель на полный путь к файлу,
который должен быть загружен. Аргументы
4. Системные вызовы для работы с файлами.
Из курса программирования на языке Си известны функции работы
argN представляют
с файлами из стандартной библиотеки ввода-вывода, такие как fopen(),
собой указатели на аргументы командной строки. Заметим, что аргумент
fread(), fwrite() и т.д. Эти функции входят как неотъемлемая часть в стан­
arg0 должен указывать на имя загружаемого файла. Аргумент argv пред­
дарт ANSI на язык Си и позволяют программисту получать информацию
ставляет собой массив из указателей на аргументы командной строки. На­
из файла или записывать ее в файл. Но операции, определяемые функция­
arg0,
чальный элемент массива должен указывать на имя загружаемой про­
ми стандартной библиотеки ввода-вывода, не являются потоковыми опе­
граммы, а заканчиваться массив должен элементом, содержащим указа­
рациями, так как каждая из них требует наличия некоторой структуры пе­
тель NULL. Аргумент envp содержит переменные окружения, установлен-
редаваемых данных. В операционной системе UNIX эти функции пред­
ные в операционной системе для данного пользователя. Переменные ок­
ставляют собой надстройку (сервисный интерфейс) над системными вы­
ружения можно взять те же, что передаются в функцию main()
зовами, осуществляющими прямые потоковые операции обмена ин­
int main (int argc, char *argv[], char *envp[])
Задание: напишите программу, которая распечатывает на экране
понятие файлового дескриптора. Информация о файлах, используемых
значения переменных окружения.
Поскольку системный контекст процесса при вызове ехес() остает­
ся практически неизменным, большинство атрибутов процесса, доступ­
ных пользователю через системные вызовы (PID, UID, GID, PPID и дру­
гие), после запуска новой программы также не изменяется.
Важно понимать разницу между системными вызовами fork()
и ехес(). Системный вызов fork() создает новый процесс, у которого поль­
зовательский контекст совпадает с пользовательским контекстом процес­
са-родителя. Системный вызов ехес() изменяет пользовательский контекст
текущего процесса, не создавая новый процесс.
Задание: Рассмотрите
формацией между процессом и файлом и не требующими никаких зна­
ний о том, что она содержит. В системных вызовах open(), read(), write()и close(), которые
пример использования системного вызова
exec(). Проанализируйте результат.
процессом, входит в состав его системного контекста и хранится в его
блоке управления - РСВ. В операционной системе UNIX можно упрощен­
но полагать, что информация о файлах, с которыми процесс осуществляет
операции потокового обмена, наряду с информацией о потоковых линиях
связи, соединяющих процесс с другими процессами и устройствами вво­
да-вывода, хранится в некотором массиве, получившем название табли­
цы открытых файлов или таблицы файловых дескрипторов. Индекс
элемента этого массива, соответствующий определенному потоку вводавывода, получил название файлового дескриптора для этого потока. Та­
ким образом, файловый дескриптор представляет собой небольшое целое
неотрицательное число, которое для текущего процесса в данный момент
времени однозначно определяет некоторый действующий канал ввода-
#include <sys/types.h>
вывода. Некоторые файловые дескрипторы на этапе старта любой про­
#include <unistd.h>
граммы ассоциируются со стандартными потоками ввода-вывода. Так,
#include <stdio.h>
например, файловый дескриптор О соответствует стандартному потоку
int main(int argc, char *argv[], char *envp[])
ввода, файловый дескриптор 1 - стандартному потоку вывода, файловый
{/* Программа запускает команду "cat 1.c", которая должна вывести со­
держимое данного файла на экран. Для функции execle в качестве имени
28
13
дескриптор 2 — стандартному потоку для вывода ошибок. В нормальном
полнение либо до завершения процесса-родителя, либо до того момента,
интерактивном
поток ввода связывает
когда родитель получит эту информацию. Процессы, находящиеся в со­
процесс с клавиатурой, а стандартные потоки вывода и вывода оши­
стоянии закончил исполнение, в операционной системе UNIX принято
бок — с текущим терминалом.
называть процессами-зомби (zombie, defunct).
режиме
работы стандартный
Системный вызов open предназначен для выполнения операции от­
Задание: напишите программу, создающую процесс-зомби. Выведи­
крытия файла и, в случае ее удачного осуществления, возвращает файло­
те на экран его pid и посмотрите в другом окне эмулятора терминала, как
вый дескриптор открытого файла. Прототип системного вызова open
обозначается данный процесс при вызове команды просмотра состояния
#include <fcntl.h>
процессов (команда ps).
int open(char *path, int flags);
3. Системный вызов ехес()
int open (char *path, int flags, int mode);
Для
изменения
пользовательского контекста процесса
(загрузки
Параметр path является указателем на строку, содержащую полное
новой программы в системный контекст текущего процесса) применяется
или относительное имя файла. Параметр flags может принимать одно из
системный вызов ехес(). Вызов ехес() заменяет пользовательский кон­
следующих трех значений:
текст текущего процесса содержимым некоторого исполняемого файла
•
OR_DONLY - если над файлом в дальнейшем будут совершаться
только операции чтения;
•
O_WRONLY- если над файлом в дальнейшем будут осуществляться
только операции записи;
•
O_RDWR - если над файлом будут осуществляться и операции чте­
ния, и операции записи.
операции «побитовое или ( | ) » с одним или несколькими флагами:
если файла с указанным именем не существует, он дол­
жен быть создан;
•
устанавливает программный счетчик на начало загружаемой программы).
Этот вызов требует для своей работы задания имени исполняемого файла,
аргументов командной строки и параметров окружающей среды. Для
осуществления вызова программист может воспользоваться одной из шес­
ти функций: execlp(), execvp(), execl() и, execv(), execle(), execve(), отли­
чающихся друг от друга представлением параметров, необходимых для
Каждое из этих значений может быть скомбинировано посредством
• O_CREAT-
и устанавливает начальные значения регистров процессора (в том числе
работы системного вызова ехес(). Прототипы вызовов имеют вид
#include <unistd.h>
int execlp(const char *flle, const char *arg0,... const char *argN,
(char *)NULL);
O_EXCL - применяется совместно с флагом O_CREAT. При совме­
стном их использовании и существовании файла с указанным име­
нем, открытие файла не производится и констатируется ошибочная
ситуация;
int execvp(const char *file, char *argv[]);
int execl(const char *path, const char *arg0,... const char *argN,
(char *)NULL);
int execv(const char *path, char *argv[]);
• O_NDELAY - запрещает перевод процесса в состояние «ожидание»
при выполнении операции открытия и любых последующих опера­
циях над этим файлом;
int execle(const char *path, const char *arg0, ... const char *argN,
(char *)NULL, char * envp[]);
int execve(const char *path, char *argv[], char *envp[]).
14
27
•
else
O_APPEND - при открытии файла и перед выполнением каждой
if (pid == 0) { ... /*ребенок */ ... }
операции записи (если операция разрешена) указатель текущей пози­
else {... /*родитель */ ... }
ции в файле устанавливается на конец файла;
Задание: измените предыдущую программу с fork() так, чтобы роди­
тель и ребенок совершали разные действия (какие - не важно).
Существует два способа корректного завершения процесса в про­
•
O_TRUNC - если файл существует, уменьшить его размер до 0, с со­
хранением существующих атрибутов файла, кроме времени послед­
него доступа к файлу и времени его последней модификации.
граммах, написанных на языке Си. Первый способ мы использовали до
Параметр mode устанавливает атрибуты прав доступа различных ка­
сих пор: процесс корректно завершался по достижении конца функции
тегорий пользователей к новому файлу при его создании. Он обязателен,
main() или при выполнении оператора return в функции main(), второй
если среди заданных флагов присутствует флаг O_CREAT, и может быть
способ применяется при необходимости завершить процесс в каком-либо
опущен в противном случае. Этот параметр задается как сумма следую­
другом месте программы. Для этого используется функция exit() из стан­
щих восьмеричных чисел X00+0X0+00X. Первое число определяет права
дартной библиотеки функций для языка Си. При выполнении этой функ­
доступа владельца, второе - группы, третье - других пользователей. Каж­
ции происходит сброс всех частично заполненных буферов ввода-вывода
дая восьмеричная цифра, обозначенная как «X», представляет собой триа­
с закрытием соответствующих потоков, после чего инициируется систем­
ду двоичных цифр, соответствующих правам доступа rwx.
ный вызов прекращения работы процесса и перевода его в состояние за­
Системные вызовы read и write предназначены для осуществления
кончил исполнение. Возврата из функции в текущий процесс не проис­
потоковых операций ввода (чтения) и вывода (записи) информации над
ходит и функция exit() процессу-родителю ничего не возвращает. Значе­
каналами связи, описываемыми файловыми дескрипторами, т.е. для фай­
ние параметра функции exit(), то есть кода завершения процесса, переда­
лов pipe, FIFO и socket. Прототипы системных вызовов read и write.
ется ядру операционной системы и затем может быть получено процес­
сом, породившим завершившийся процесс. При этом используются только
младшие 8 бит параметра, так что для кода завершения допустимы значе­
ния от 0 до 255 (или от -128 до +127). По соглашению, код завершения О
означает безошибочное завершение процесса. На самом деле при дости­
жении конца функции main() также неявно вызывается эта функция со
значением параметра 0. Прототип функции exit() имеет вид
#include <sys/types.h>
#include <unistd.h>
size_t read(int fd, void *addr, size_t nbytes);
size_t write (int fd, void *addr, size_t nbytes);
Параметр fd является файловым дескриптором созданного ранее по­
токового канала связи. Параметр addr представляет собой адрес области
памяти, начиная с которого будет браться информация для передачи или
#include <stdlib.h>
размещаться принятая информация. Параметр nbytes, определяет количе­
void exit (int status);
ство передаваемых (для вызова write) или принимаемых байтов (для вызо­
Если процесс завершает свою работу раньше, чем его родитель,
и родитель явно не указал, что он не хочет получать информацию о ста­
ва read). Возвращаемое значение - количество реально принятых (read)
или переданных (write) байтов.
тусе завершения порожденного процесса, то завершившийся процесс не
исчезает из системы окончательно, а остается в состоянии закончил ис26
15
Системный вызов close(fd) производит действие, обратное по отно­
шению к вызову open. Возвращаемое значение - 0, если операция прошла
/* При успешном создании нового процесса с этого места псевдопараллельно начинают работать два процесса: старый и новый */
(void)fork();
успешно, и -1 в случае возникновения ошибки.
Системные вызовы stat, fstat и lstat служат для получения информа­
ции об атрибутах файла. Прототипы системных вызовов:
/* Узнаем идентификаторы текущего и родительского процесса (дальней­
шие действия будут выполняться в каждом из процессов) */
#include <sys/stat.h>
pid = getpid();
#include <unistd.h>
ppid = getppid();
int stat(char *filename, struct stat *buf);
/* Перед выполнением следующего выражения значение переменной а
в обоих процессах равно 0 */
int fstat(intfd, struct stat *buf);
а++;
int lstat(char *filename, struct stat *buf);
Системный вызов stat читает информацию об атрибутах файла,
на имя которого указывает параметр filename, и заполняет ими струк­
/* Печатаем значения PID, PPID и вычисленное значение переменной а
(в каждом из процессов) */
printf("My pid = %d, my ppid = %d, result = %d\n", (int)pid, (int)ppid, a);
туру, расположенную по адресу buf. Имя файла должно быть полным,
либо должно строиться относительно того каталога, который является
текущим для процесса, совершившего вызов. Если имя файла относит­
ся к файлу типа «связь», то читается информация об атрибутах файла,
на который указывает символическая связь.
Системный вызов lstat идентичен системному вызову stat за одним
исключением: если имя файла относится к файлу типа «связь», то читает­
ся информация о самом файле типа «связь».
return 0;
}
Задание: измените программу так, чтобы увеличение значения пе­
ременной а и вывод на экран монитора выполнялось в цикле. Количество
повторений выберите такое, чтобы за один квант времени, выделенный
процессу, программа выполнила только часть цикла.
Для того чтобы после возвращения из системного вызова fork() про­
Системный вызов fstat идентичен системному вызову stat, только
цессы могли определить, кто из них является ребенком, а кто родителем,
файл задается не именем, а своим файловым дескриптором (естественно,
и, соответственно, по-разному организовать свое поведение, системный
что файл к этому моменту должен быть открыт).
вызов возвращает в них разные значения. При успешном создании нового
Для системных вызовов stat и lstat процессу не нужны никакие права
процесса процессу-родителю возвращается положительное значение, рав­
доступа к указанному файлу, но могут понадобиться права для поиска во
ное идентификатору процесса-ребенка. А процессу-ребенку возвращается
всех каталогах, входящих в заданное имя файла.
значение 0. Если по какой-либо причине создать новый процесс не уда­
Структура stat в различных версиях UNIX может быть описана поразному. В Linux она содержит следующие поля:
лось, то системный вызов вернет в инициировавший его процесс значение
-1. Таким образом, общая схема организации различной работы процессаребенка и процесса-родителя выглядит так:
struct stat {
dev_t st_dev; /* устройство, на котором расположен файл */
pid =fork();
ino_t st_ino; /* номер индексного узла для файла */
if (pid ==-1) { ... /* ошибка */ ...}
16
25
зывать процессом-ребенком
•
(child process).
Процесс-ребенок является
почти полной копией родительского процесса. Но у порожденного про­
nlink_t st_nlink; /* счетчик числа жестких связей */
цесса изменяются значения следующих параметров:
uid_t st_uid; /* идентификатор пользователя владельца */
время,
• идентификатор процесса;
gid_t st_gid; /* идентификатор группы владельца */
• идентификатор родительского процесса;
dev_t st_rdev; /* тип устройства для специальных файлов устройств*/
оставшееся
до
получения
сигнала
off J st_size; /* размер файла в байтах */
SIGALRM;
• сигналы, ожидавшие доставки родительскому процессу, не будут
При однократном системном вызове fork возврат из него может про­
изойти дважды: один раз в родительском процессе, а второй раз в порож­
денном процессе. Если создание нового процесса произошло успешно,
то в порожденном процессе системный вызов вернет значение 0, а в роди­
тельском процессе - положительное значение, равное идентификатору
процесса-ребенка. Если создать новый процесс не удалось, то системный
time_t st_atime; /* время последнего доступа к файлу */
time_t st_mtime; /* время последней модификации файла */
time_t st_ctime; /* время создания файла */
}
Для определения типа файла можно использовать следующие логи­
ческие макросы, применяя их к значению поля st_mode:
вызов вернет в инициировавший его процесс отрицательное значение. По­
• S_ISLNK(m) - файл типа «связь»?
сле выхода из системного вызова оба процесса продолжают выполнение
• S_ISREG(m) - регулярный файл?
регулярного пользовательского кода, следующего за системным вызовом.
• S_ISDIR(m) - каталог?
Задание: Наберите следующую программу, откомпилируйте ее и за­
Пример
unsigbed long st_blksize; /* размер блока для файловой системы */
unsigned long st_blocks; /* число выделенных блоков */
доставляться порожденному процессу.
/*
mode_t st_mode; /* тип файла и права доступа к нему */
• S_ISCHR(m) - специальный файл символьного устройства?
пустите на исполнение (лучше всего это делать не из оболочки тс, так как
• S_ISBLK(m) — специальный файл блочного устройства?
она не очень корректно сбрасывает буферы ввода-вывода). Проанализи­
• S_ISFIFO(m) - файл типа FIFO?
руйте полученный результат.
• S_ISSOCK(m) - файл типа "socket"?
создания
нового
процесса с
одинаковой
работой
процессов
Младшие 9 бит поля st_mode определяют права доступа к файлу по­
добно тому, как это делается в маске создания файлов текущего процесса.
ребенка и родителя */
#include <sys/types.h>
Системные вызовы для создания связи: link, symlink, unlink.
#include <unistd.h>
#include <unistd.h>
#include <stdio.h>
int link(char *pathname, char *linkpathname);
int main()
int symlink(char *pathname, char *linkpathname);
{
int unlink(char *pathname);
pid_t pid, ppid;
Задание: рассмотренные ранее по пунктам 1-3 действия над файла­
int a = 0;
ми реализуйте в программе на языке Си с помощью системных вызовов.
24
17
5. Системные вызовы для работы с каталогами (директориями).
ЛАБОРАТОРНАЯ РАБОТА №3
Управление процессами
#include <dirent.h>
DIR *opendir (char *dirname);
1. Идентификатор процесса
struct dirent *readdir(DIR *dirp);
Данные ядра, находящиеся в контексте ядра процесса, не могут
struct dirent *rewindir(DIR *dirp);
быть прочитаны процессом непосредственно. Для получения информации
int closedir(DIR *dirp);
о них процесс должен совершить соответствующий системный вызов.
Функция opendir служит для открытия потока информации для ка­
Значение идентификатора текущего процесса может быть получено с по­
талога. Тип данных DIR представляет собой некоторую структуру дан­
мощью системного вызова getpid(), а значение идентификатора родитель­
ных, описывающую такой поток. Функция opendir позиционирует поток
ского процесса для текущего процесса - с помощью системного вызова
на первой записи каталога. С точки зрения программиста в этом интер­
getppid(). Прототипы этих системных вызовов и соответствующие типы
фейсе каталог представляется как файл последовательного доступа, над
данных описаны в системных файлах <sys/types.h> и <unistd.h>. Систем­
которым можно совершать операции чтения очередной записи и пози­
ные вызовы не имеют параметров и возвращают идентификатор текуще­
ционирования на начале файла. Чтение очередной записи из каталога
го процесса и идентификатор родительского процесса, соответственно.
осуществляет функция readdir(), одновременно позиционируя указатель
Прототипы системных вызовов
на начале следующей записи (если она, конечно, существует). Для опера­
#include <sys/types.h>
ции нового позиционирования на начале каталога (при необходимости)
#include <unistd.h>
применяется функция rewinddir(). После окончания работы с каталогом
pid_t getpid(void) ;
его необходимо закрыть с помощью функции closedir(). Тип данных struct
pid_t getppid(void);
dirent представляет собой некоторую структуру данных, описывающую
одну запись в каталоге. Поля этой записи сильно варьируются от одной
файловой системы к другой, но одно из полей всегда присутствует в ней.
Это поле char d_name[] неопределенной длины, не превышающей значе­
ния NAME_MAX+1, которое содержит символьное имя файла, завершаю­
щееся символом конца строки. Данные, возвращаемые функцией readdir,
переписываются при очередном вызове этой функции для того же самого
потока каталога.
Задание: используя системные вызовы для работы с файлами и кa-
Тип данных pid_t является синонимом для одного из целочисленных
типов языка Си.
Задание: В качестве примера использования системных вызо­
вов getpid() и getppid() самостоятельно напишите программу, печатаю­
щую значения PID и PPID для текущего процесса. Запустите ее несколько
раз подряд. Посмотрите, как меняется идентификатор текущего процесса.
Объясните наблюдаемые изменения.
2. Создание нового процесса
талогами, реализуйте программу на языке Си, позволяющую сделать рас­
В операционной системе UNIX новый процесс может быть порожден
печатку содержимого каталога, указав тип файла и права доступа (аналог
единственным способом - с помощью системного вызова fork(). Процесс,
команды ls с ключом -l). Задача повышенной сложности - рекурсивная
который инициировал системный вызов fork, принято называть родитель­
распечатка содержимого вложенных каталогов.
ским процессом (parent process). Вновь порожденный процесс принято на-
18
23
/* Открываем файл */
6. Системные вызовы для работы с файлами, отображаемыми в память.
fd = open("mapped.dat", 0_RDWR | O_CREAT, 0666);
/* Вычисляем будущую длину файла для записи в него 1000 структур */
length = 1000*sizeof(struct А);
/*Увеличиваем длину файла с помощью вызова ftruncate(). */
С точки зрения программиста работа с такими файлами выглядит
следующим образом:
•
процесса происходит в два этапа: сначала выполняется отображение
ftruncate(fd, length);
в дисковое пространство, а уже затем из дискового пространства
/* Файл отображаем с его начала (offset = 0) и до конца (length = длине
в адресное. Поэтому вначале файл необходимо открыть, используя
файла). */
обычный системный вызов ореn().
ptr = (struct А *) mmap (NULL, length,
PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
/* Файловый дескриптор нам более не нужен, и мы его закрываем */
.
Вторым этапом является отображение файла целиком или частично
из дискового пространства в адресное пространство процесса. Для
этого используется системный вызов mmap(). Файл после этого
close(fd);
/* Если отобразить файл не удалось - сообщаем об ошибке */
\n");
можно закрыть, выполнив системный вызов close(), так как необхо­
димая информация о расположении файла на диске сохраняется
if (ptr == MAP_FAILED )
{printf("Mappingfailed!
Отображение файла из пространства имен в адресное пространство
exit(2); }
/* В цикле заполняем образ файла числами */
в других структурах данных при вызове mmap().
#include <sys/types.h>
tmpptr = ptr;
#include <unistd.h>
for(i = 1; i <=100000; i++)
#include <sys/mman.h>
void *mmap (void *start, size_t length, int prot, int flags, int fd, off_t offset);
{tmpptr->f= i;
tmpptr->f2 = i*i;
Параметр fd является файловым дескриптором файла, отображаемо­
tmpptr++;}
го в адресное пространство (возвращает системный вызов open()). Значе­
/* Прекращаем отображать файл в память, записываем содержимое ото­
ние параметра start чаще всего выбирается равным NULL, позволяя опера­
бражения на диск и освобождаем память. */
ционной системе самой выбрать начало области адресного пространства,
munmap((void *)ptr, length);
в которую будет отображен файл.
return 0;
В память будет отображаться часть файла, начиная с позиции внутри
}
его, заданной значением параметра offset - смещение от начала файла
Задания: Модифицируйте приведенную программу так, чтобы она
в байтах, и длиной, равной значению параметра length (тоже в байтах).
отображала файл mapped.dat, записанный программой из примера. Опре­
Значение параметра length может и превышать реальную длину от пози­
делите размер файла, который можно отобразить в память. Проверьте,
ции offset до конца существующего файла. На поведении системного
можно ли отобразить в одну и ту же область памяти несколько файлов.
вызова это никак не отразится, но в дальнейшем при попытке досту­
Реализуйте указанные действия другими средствами языка Си.
па к ячейкам памяти, лежащим вне границ реального файла, возникнет
22
19
сигнал SIGBUS (реакция на него по умолчанию - прекращение процесса
во вторичной памяти. После его выполнения области памяти, использовав­
с образованием core файла).
шиеся для отображения файла, становятся недоступны текущему процессу.
Параметр flags определяет способ отображения файла в адресное
пространство.
Рассмотрим
только
два
его
возможных
значения:
#include <sys/types.h>
#include <unistd.h>
MAP_SHARED и MAP_PRIVATE. Если в качестве его значения выбрано
#include <sys/mman.h>
MAP SHARED, то полученное отображение файла впоследствии будет ис­
int munmap (void * start, size_t length);
пользоваться и другими процессами, вызвавшими mmap для этого файла
с аналогичными значениями параметров, а все изменения, сделанные
в отображенном файле, будут сохранены во вторичной памяти. Если в ка­
честве значения параметра flags указано MAP_PRIVATE, то процесс полу­
чает отображение файла в свое монопольное распоряжение, но все изме­
нения в нем не могут быть сохранены.
Параметр prot определяет разрешенные операции над областью па­
мяти, в которую будет отображен файл. В качестве его значения можно
использовать значения PROT_READ (разрешено чтение), PROT_WRITE
(разрешена запись) или их комбинацию через операцию «побитовое или».
Необходимо отметить две существенные особенности системного вызова,
связанные с этим параметром:
Параметр start является адресом начала области памяти, выделенной
для отображения файла, то есть значением, которое вернул системный вы­
зов mmap(). Параметр length определяет ее длину, и его значение должно
совпадать со значением соответствующего параметра в системном вызове
mmap().
Программа, приведенная ниже, создает файл, отображает его в ад­
ресное пространство процесса и заносит в него информацию с помощью
обычных операций языка Си. Обратите внимание на необходимость уве­
личения размера файла перед его отображением. Созданный файл имеет
нулевой размер, и если его с этим размером отобразить в память, то мы
сможем записать в него или прочитать из него не более 0 байт, то есть ни­
чего. Для увеличения размера файла использован системный вызов
1. Значение параметра prot не может быть шире, чем операции над
файлом, заявленные при его открытии в параметре flags системного
вызова ореn().
2. В результате ошибки в операционной системе Linux при работе на
ftruncate(), хотя это можно было бы сделать и любым другим способом.
int main(void)
{
486-х и 586-х процессорах попытка записать в отображение файла,
int fd; /* Файловый дескриптор */
открытое только для записи, более 32-х байт одновременно приводит
size_t length; /* Длина отображаемой части файла */
к ошибке (возникает сигнал о нарушении защиты памяти).
int i;
Системный вызов munmap служит для прекращения отображения
memory mapped файла в адресное пространство вычислительной системы.
Если при системном вызове mmap() было задано значение пapaмeтpa flags,
равное MAP_SHARED, и в отображении файла была разрешена операция
записи (в параметре prot использовалось значение PROT_WRITE), то
munmap синхронизирует содержимое отображения с содержимым файла
20
/* struct A - тип данных для заполнения файла,
ptr - начальный адрес выделенной области памяти,
tmpptr - указатель для перемещения внутри области памяти. */
struct А {
double f;
double f2;} *ptr, *tmpptr;
21
Скачать