Операционная система UNIX
Шрифт:
текущий и корневой каталоги,
маска создания файлов,
управляющий терминал,
файловые дескрипторы, для которых не установлен флаг
Наследование характеристик процесса играет существенную роль в работе операционной системы. Так наследование идентификаторов владельцев процесса гарантирует преемственность привилегий и, таким образом, неизменность привилегий пользователя при работе в UNIX. Наследование файловых дескрипторов позволяет установить направления ввода/вывода для нового процесса или новой программы. Именно так действует командный интерпретатор. Мы вернемся к вопросу о наследовании в главе 3.
В главе 1 уже говорилось о частом объединении вызовов fork(2) и exec(2), получившем специальное название fork-and-exec. Таким образом загружается подавляющее
При порождении процесса, который впоследствии может загрузить новую программу, "родителю" может быть небезынтересно узнать о завершении выполнения "потомка". Например, после того как запущена утилита ls(1), командный интерпретатор приостанавливает свое выполнение до завершения работы утилиты и только после этого выдает свое приглашение на экран. Можно привести еще множество ситуаций, когда процессам необходимо синхронизировать свое выполнение с выполнением других процессов. Одним из способов такой синхронизации является обработка родителем сигнала
Операционная система предоставляет процессу ряд функций, позволяющих ему контролировать выполнение потомков. Это функции wait(2), waitid(2) и waitpid(2):
Первый из этих вызовов wait(2) обладает самой ограниченной функциональностью — он позволяет заблокировать выполнение процесса, пока кто-либо из его непосредственных потомков не прекратит существование. Вызов wait(2) немедленно возвратит состояние уже завершившегося дочернего процесса в переменной
WIFEXITED(status) | Возвращает истинное (ненулевое) значение, если процесс завершился нормально. |
WEXITSTATUS(status) | Если WIFEXITED(status) не равно нулю, определяет код возврата завершившегося процесса (аргумент функции exit(2)). |
WIFSIGNALLED(status) | Возвращает истину, если процесс завершился по сигналу. |
WTERMSIG(status) | Если WIFSIGNALLED(status) не равно нулю, определяет номер сигнала, вызвавшего завершение выполнения процесса. |
WCOREDUMP(status) | Если WIFSIGNALLED(status) не равно нулю, макрос возвращает истину в случае создания файла core. |
Системный вызов waitid(2) предоставляет больше возможностей для контроля дочернего процесса. Аргументы
Значение аргумента idtype | Описание |
---|---|
P_PID | waitid(2) блокирует выполнение процесса, следя за потомком, PID которого равен id . |
P_PGID | waitid(2) блокирует выполнение процесса, следя за потомками, идентификаторы группы которых равны id . |
P_ALL | waitid(2) блокирует выполнение процесса, следя за всеми непосредственными потомками. |
Аргумент
Флаги аргумента options | Описание |
---|---|
WEXITED | Предписывает ожидать завершения выполнения процесса. |
WTRAPPED | Предписывает ожидать ловушки (trap) или точки останова (breakpoint) для трассируемых процессов. |
WSTOPPED | Предписывает ожидать останова процесса из-за получения сигнала. |
WCONTINUED | Предписывает вернуть статус процесса, выполнение которого было продолжено после останова. |
WNOHANG | Предписывает завершить свое выполнение, если отсутствует статусная информация (т.е. отсутствует ожидаемое событие). |
WNOWAIT | Предписывает получить статусную информацию, но не уничтожать ее, оставив дочерний процесс в состоянии ожидания. |
Аргумент
Функция waitpid(2), как и функции wait(2) и waitid(2), позволяет контролировать определенное множество дочерних процессов.
В заключение для иллюстрации описанных в этом разделе системных вызовов приведем схему работы командного интерпретатора при запуске команды.
Сигналы
Сигнал является способом передачи уведомления о некотором произошедшем событии между процессами или между ядром системы и процессами. Сигналы можно рассматривать, как простейшую форму межпроцессного взаимодействия, хотя на самом деле они больше напоминают программные прерывания, при которых нарушается нормальное выполнение процесса.
Сигналы появились уже в ранних версиях UNIX, но их реализация не была достаточно надежной. Сигнал мог быть "потерян", возникали также определенные сложности с отключением (блокированием) сигналов на время выполнения критических участков кода. В последующие версии системы, как BSD, так и System V, были внесены изменения, позволившие реализовать надежные (reliable) сигналы. Однако модель сигналов, принятая в версиях BSD, была несовместима с моделью версий System V. В настоящее время стандарт POSIX.1 вносит определенность в интерфейс надежных сигналов.