Андрей Робачевский - Операционная система UNIX
- Название:Операционная система UNIX
- Автор:
- Жанр:
- Издательство:BHV - Санкт-Петербург
- Год:1997
- Город:Санкт-Петербург
- ISBN:5-7791-0057-8
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Андрей Робачевский - Операционная система UNIX краткое содержание
Книга посвящена семейству операционных систем UNIX и содержит информацию о принципах организации, идеологии и архитектуре, объединяющих различные версии этой операционной системы.
В книге рассматриваются: архитектура ядра UNIX (подсистемы ввода/вывода, управления памятью и процессами, а также файловая подсистема), программный интерфейс UNIX (системные вызовы и основные библиотечные функции), пользовательская среда (командный интерпретатор shell, основные команды и утилиты) и сетевая поддержка в UNIX (протоколов семейства TCP/IP, архитектура сетевой подсистемы, программные интерфейсы сокетов и TLI).
Для широкого круга пользователей
Операционная система UNIX - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Заметим, что в BSD UNIX вызов signal(3) является упрощенным интерфейсом к более общей функции sigaction(2) , в то время как в ветви System V signal(3) подразумевает использование старой семантики ненадежных сигналов.
В заключение для иллюстрации изложенных соображений, приведем версию функции signal() , позволяющую использовать надежные сигналы. Похожая реализация используется в BSD UNIX. С помощью этой "надежной" версии мы повторим пример, рассмотренный нами выше, в измененном виде.
#include
#include
#include
#include
#include
/* Вариант "надежной" функции signal() */
void (*mysignal(int signo, void (*hndlr)(int)))(int) {
struct sigaction act, oact;
/* Установим маску сигналов */
act.sa_handler = hndlr;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
if (signo != SIGALRM)
act.sa_flags = SA_RESTART;
/* Установим диспозицию */
if (sigaction(signo, &act, &oact) < 0)
return SIG_ERR;
return(oact.sa_handler);
}
/* Функция-обработчик сигнала */
static void sig_hndlr(int signo) {
/* Эта часть кода нам уже не нужна
mysignal(SIGINT, sig_hndlr);
*/
printf("Получен сигнал SIGINT\n");
}
main() {
/* Установим диспозицию */
mysignal(SIGINT, sig_hndlr);
mysignal(SIGUSR2, SIG_IGN);
/* Бесконечный цикл */
while (1)
pause();
}
Заметим, что при использовании надежных сигналов, не нужно восстанавливать диспозицию в функции-обработчике при получении сигнала.
Группы и сеансы
После создания процесса ему присваивается уникальный идентификатор, возвращаемый системным вызовом fork(2) родительскому процессу. Дополнительно ядро назначает процессу идентификатор группы процессов (process group ID). Группа процессов включает один или более процессов и существует, пока в системе присутствует хотя бы один процесс этой группы. Временной интервал, начинающийся с создания группы и заканчивающийся, когда последний процесс ее покинет, называется временем жизни группы . Последний процесс может либо завершить свое выполнение, либо перейти в другую группу.
Многие системные вызовы могут быть применены как к единичному процессу, так и ко всем процессам группы. Например, системный вызов kill(2) может отправить сигнал как одному процессу, так и всем процессам указанной группы. Точно так же функция waitpid(2) позволяет родительскому процессу ожидать завершения конкретного процесса или любого процесса группы.
Каждый процесс, помимо этого, является членом сеанса (session), являющегося набором одной нескольких групп процессов. Понятие сеанса было введено в UNIX для логического объединения процессов, а точнее, групп процессов, созданных в результате регистрации и последующей работы пользователя в системе. Таким образом, термин "сеанс работы" в системе тесно связан с понятием сеанса, описывающего набор процессов, которые порождены пользователем за время пребывания в системе.
Процесс имеет возможность определить идентификатор собственной группы процессов или группы процесса, который является членом того же сеанса. Для этого используются два системных вызова: getpgrp(2) и getpgid(2) :
#include
#include
pid_t getpgrp(void);
pid_t getpgid(pid_t pid);
Аргумент pid
, который передается функции getpgid(2) , адресует процесс, идентификатор группы которого требуется узнать. Если этот процесс не принадлежит к тому же сеансу, что и процесс, сделавший системный вызов, функция возвращает ошибку.
Системный вызов setpgid(2) позволяет процессу стать членом существующей группы или создать новую группу.
#include
#include
int setpgid(pid_t pid, pid_t pgid);
Функция устанавливает идентификатор группы процесса pid
равным pgid
. Процесс имеет возможность установить идентификатор группы для себя и для своих потомков (дочерних процессов). Однако процесс не может изменить идентификатор группы для дочернего процесса, который выполнил системный вызов exec(2) , запускающий на выполнение другую программу.
Если значения обоих аргументов равны, то создается новая группа с идентификатором pgid
, а процесс становится лидером (group leader) этой группы. Поскольку именно таким образом создаются новые группы, их идентификаторы гарантированно уникальны. Заметим, что группа не удаляется при завершении ее лидера, пока в нее входит хотя бы один процесс.
Идентификатор сеанса можно узнать с помощью функции getsid(2) :
#include
#include
pid_t getsid(pid_t pid);
Как и в случае с группой, идентификатор pid
должен адресовать процесс, являющийся членом того же сеанса, что и процесс, вызвавший getsid(2) . Заметим, что эти ограничения не распространяются на процессы, имеющие привилегии суперпользователя.
Вызов функции setsid(2) приводит к созданию нового сеанса:
#include
#include
pid_t setsid(void);
Новый сеанс создается лишь при условии, что процесс не является лидером какого-либо сеанса. В случае успеха процесс становится лидером сеанса и лидером новой группы.
Понятия группы и сеанса тесно связаны с терминалом или, точнее, с драйвером терминала. Каждый сеанс может иметь один ассоциированный терминал, который называется управляющим терминалом (controlling terminal), а группы, созданные в данном сеансе, наследуют этот управляющий терминал. Наличие управляющего терминала позволяет ядру контролировать стандартный ввод/вывод процессов, а также дает возможность отправить сигнал всем процессам ассоциированной с терминалом группы, например, при его отключении. Типичным примером является регистрация и работа пользователя в системе. При входе в систему терминал пользователя становится управляющим для лидера сеанса (в данном случае для командного интерпретатора shell) и всех процессов, порожденных лидером (в данном случае для всех процессов, которые запускает пользователь из командной строки интерпретатора). При выходе пользователя из системы shell завершает свою работу и таким образом отключается от управляющего терминала, что вызывает отправление сигнала SIGHUP
всем незавершенным процессам текущей группы. Это гарантирует, что после завершения работы пользователя в системе не останется запущенных им процессов. [26] Тем не менее в системе будут продолжать выполняться процессы, запущенные в фоновом режиме. Это утверждение также не справедливо для демонов — процессов, являющихся членами сеанса, не имеющего управляющего терминала. Система не имеет возможности автоматического отправления сигнала SIGHUP таким процессам при выходе пользователя, и они будут продолжать выполняться даже после завершения пользователем работы в UNIX. Для "превращения" процесса в демона, он должен воспользоваться функцией setsid(2) и создать новый сеанс, лидером которого он автоматически окажется и который не будет ассоциирован с управляющим терминалом. Эти вопросы будут более подробно обсуждены при иллюстрации программы-демона далее в этой главе.
Интервал:
Закладка: