Андрей Робачевский - Операционная система UNIX
- Название:Операционная система UNIX
- Автор:
- Жанр:
- Издательство:BHV - Санкт-Петербург
- Год:1997
- Город:Санкт-Петербург
- ISBN:5-7791-0057-8
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Андрей Робачевский - Операционная система UNIX краткое содержание
Книга посвящена семейству операционных систем UNIX и содержит информацию о принципах организации, идеологии и архитектуре, объединяющих различные версии этой операционной системы.
В книге рассматриваются: архитектура ядра UNIX (подсистемы ввода/вывода, управления памятью и процессами, а также файловая подсистема), программный интерфейс UNIX (системные вызовы и основные библиотечные функции), пользовательская среда (командный интерпретатор shell, основные команды и утилиты) и сетевая поддержка в UNIX (протоколов семейства TCP/IP, архитектура сетевой подсистемы, программные интерфейсы сокетов и TLI).
Для широкого круга пользователей
Операционная система UNIX - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Терминальная линия (TTY)
Терминал или псевдотерминал, ассоциированный с процессом, если такой существует. Процессы-демоны не имеют ассоциированного терминала.
Реальный (RID) и эффективный (EUID) идентификаторы пользователя
Реальным идентификатором пользователя данного процесса является идентификатор пользователя, запустившего процесс. Эффективный идентификатор служит для определения прав доступа процесса к системным ресурсам (в первую очередь к ресурсам файловой системы). Обычно реальный и эффективный идентификаторы эквивалентны, т.е. процесс имеет в системе те же права, что и пользователь, запустивший его. Однако существует возможность задать процессу более широкие права, чем права пользователя путем установки флага SUID, когда эффективному идентификатору присваивается значение идентификатора владельца исполняемого файла (например, администратора).
Реальный (RGID) и эффективный (EGID) идентификаторы группы
Реальный идентификатор группы равен идентификатору первичной или текущей группы пользователя, запустившего процесс. Эффективный идентификатор служит для определения прав доступа к системным ресурсам по классу доступа группы. Так же как и для эффективного идентификатора пользователя, возможна его установка равным идентификатору группы владельца исполняемого файла (флаг SGID).
Команда ps(1) (process status) позволяет вывести список процессов, выполняющихся в системе, и их атрибуты:
$ ps -ef | head -20
UID PID PPID С STIME TTY TIME CMD
root 0 0 0 Dec 17 ? 0:00 sched
root 1 0 0 Dec 17 ? 0:01 /etc/init -
root 2 0 0 Dec 17 ? 0:00 pageout
root 3 0 0 Dec 17 ? 7:00 fsflush
root 164 1 0 Dec 17 ? 0:01 /usr/lib/sendmail -bd -q1h
fed 627 311 0 Dec 17 pts/3 0:27 emiclock
fed 314 304 0 Dec 17 pts/4 0:00 /usr/local/bin/bash
fed 3521 512 0 0:01
Более подробное описание полей вывода команды ps(1) приведено далее в разделе "Основные утилиты UNIX".
Жизненный путь процесса
Процесс в UNIX создается системным вызовом fork(2) . Процесс, сделавший вызов fork(2) называется родительским , а вновь созданный процесс — дочерним . Новый процесс является точной копией породившего его процесса. Как это ни удивительно, но новый процесс имеет те же инструкции и данные, что и его родитель. Более того, выполнение родительского и дочернего процесса начнется с одной и той же инструкции, следующей за вызовом fork(2) . Единственно, чем они различаются — это идентификатором процесса PID. Каждый процесс имеет одного родителя, но может иметь несколько дочерних процессов.
Для запуска задачи, т.е. для загрузки новой программы, процесс должен выполнить системный вызов exec(2) . При этом новый процесс не порождается, а исполняемый код процесса полностью замещается кодом запускаемой программы. Тем не менее окружение новой программы во многом сохраняется, в частности сохраняются значения переменных окружения, назначения стандартных потоков ввода/вывода, вывода сообщений об ошибках, а также приоритет процесса.
В UNIX запуск на выполнение новой программы часто связан с порождением нового процесса, таким образом сначала процесс выполняет вызов fork(2) , порождая дочерний процесс, который затем выполняет exec(2) , полностью замещаясь новой программой.
Рассмотрим эту схему на примере.
Допустим, пользователь, работая в командном режиме (в командном интерпретаторе shell) запускает команду ls(1) . Текущий процесс (shell) делает вызов fork(2) , порождая вторую копию shell. В свою очередь, порожденный shell вызывает exec(2) , указывая в качестве параметра имя исполняемого файла, образ которого необходимо загрузить в память вместо кода shell. Код ls(1) замещает код порожденного shell, и утилита ls(1) начинает выполняться. По завершении работы ls(1) созданный процесс "умирает". Пользователь вновь возвращается в командный режим. Описанный процесс представлен на рис. 1.5. Мы также проиллюстрируем работу командного интерпретатора в примере, приведенном в главе 2.

Рис. 1.5. Создание процесса и запуск программы
Если сделать "отпечаток" выполняемых процессов, например командой ps(1) , между указанными стадиями, результат был бы следующим:
Пользователь работает в командном режиме:
UID PID PPID С STIME TTY TIME CMD
user1 745 1 10 10:11:34 ttyp4 0:01 sh
Пользователь запустил команду ls(1) , и shell произвел вызов fork(2) :
UID PID PPID С STIME TTY TIME CMD
user1 745 1 10 10:11:34 ttyp4 0:01 sh
user1 802 745 14 11:00:00 ttyp4 0:00 sh
Порожденный shell произвел вызов exec(2) :
UID PID PPID С STIME TTY TIME CMD
user1 745 1 10 10:11:34 ttyp4 0:01 sh
user1 802 745 12 11:00:00 ttyp4 0:00 ls
Процесс ls(1) завершил работу:
UID PID PPID С STIME TTY TIME CMD
user1 745 1 10 10:11:34 ttyp4 0:01 sh
Описанная процедура запуска новой программы называется fork-and-exec.
Однако бывают ситуации, когда достаточно одного вызова fork(2) без последующего exec(2) . В этом случае исполняемый код родительского процесса должен содержать логическое ветвление для родительского и дочернего процессов [9] Такое ветвление можно организовать на основании значения, возвращаемого системным вызовом fork(2) . Для родительского процесса fork возвращает идентификатор созданного дочернего процесса, а дочерний процесс получает значение, равное 0. Подробнее эти вопросы будут рассмотрены в главе 2.
.
Все процессы в UNIX создаются посредством вызова fork(2) . Запуск на выполнение новых задач осуществляется либо по схеме fork-and-exec, либо с помощью exec(2) . "Прародителем" всех процессов является процесс init(1М) , называемый также распределителем процессов . Если построить граф "родственных отношений" между процессами, то получится дерево, корнем которого является init(1M) . Показанные на рис. 1.6 процессы sched и vhand являются системными и формально не входят в иерархию (они будут рассматриваться в следующих главах).

Рис. 1.6. Типичное "дерево" процессов в UNIX
Сигналы
Сигналы являются способом передачи от одного процесса другому или от ядра операционной системы какому-либо процессу уведомления о возникновении определенного события. Сигналы можно рассматривать как простейшую форму межпроцессного взаимодействия. В то же время сигналы больше напоминают программные прерывания, — средство, с помощью которого нормальное выполнение процесса может быть прервано. Например, если процесс производит деление на 0, ядро посылает ему сигнал SIGFPE
, а при нажатии клавиш прерывания, обычно < Del > или < Ctrl >+< C >, текущему процессу посылается сигнал SIGINT
.
Интервал:
Закладка: