$ echo $$
400
$ find / 2> /dev/null | wc — l &
[1] 659
$ sort < longlist | uniq — c
На этом этапе, помимо командной оболочки (bash), запущены программы find, wc, sort и uniq.
Каждый процесс имеет числовой идентификатор PGID, который определяет его принадлежность к той или иной группе. Новый процесс наследует PGID своего родителя. Для получения текущего идентификатора группы используется вызов getpgrp().
#include
pid_t getpgrp(void);
Всегда успешно возвращает идентификатор группы вызывающего процесса
Значение, возвращенное getpgrp(), совпадает с идентификатором вызывающего процесса, этот процесс является лидером своей группы.
Рис. 34.1.
Системный вызов setpgid() позволяет сменить группу процесса с идентификатором pid на значение, указанное в аргументе pgid.
#include
int setpgid(pid_t
Возвращает 0 при успешном завершении или –1, если случилась ошибка
Если в качестве pid указать 0, изменится идентификатор PGID вызывающего процесса. Если присвоить 0 аргументу pgid, PGID процесса, указанного с помощью pid, станет таким же, как идентификатор этого процесса. Таким образом, следующие вызовы setpgid() являются эквивалентными.
setpgid(0, 0);
setpgid(getpid(), 0);
setpgid(getpid(), getpid());
Если аргументы pid и pgid указывают на один и тот же процесс (то есть если pgid равен 0 или идентификатору процесса, заданному с помощью pid), создается новая группа процессов и ее лидером становится заданный процесс (то есть PGID и идентификатор процесса совпадают). Если в этих аргументах указаны разные значения (то есть когда pgid не равен 0 и не совпадает с идентификатором процесса, заданного с помощью pid), вызов setpgid() используется для перемещения процессов между группами. Обычно вызовы setpgid() и setsid() (описан в разделе 34.3), выполняют такие программы, как командная оболочка или login(1). В разделе 37.2 вы увидите, что вызов setsid() используется на одном из этапов превращения процесса в процесс-демон.
Вызов setpgid() имеет несколько ограничений.
• Аргумент pid может указывать только на вызывающий процесс или его потомка. Нарушение этого правила приводит к ошибке ESRCH.
• При перемещении процесса между группами вызывающий процесс, процесс, указанный с помощью pid (которые могут совпадать), и текущая группа должны принадлежать к одной и той же сессии. Нарушение этого правила приводит к ошибке EPERM.
• Процесс, на который указывает аргумент pid, не должен быть лидером сессии. Нарушение этого правила приводит к ошибке EPERM.
• Процесс не должен менять идентификатор PGID своего потомка, если тот уже вызвал exec(). Нарушение этого правила приводит к ошибке EACCES. Данное ограничение связано с тем, что программа может быть введена в заблуждение, если изменить идентификатор группы процессов уже после ее запуска.
Тот факт, что процессу запрещено менять идентификатор PGID своего потомка, если тот успел выполнить вызов exec(), влияет на архитектуру командных оболочек, управляющих заданиями, которые, в свою очередь, имеют следующие требования.
• Все процессы в задании (то есть в команде или конвейере) должны быть помещены в одну и ту же группу (желаемый результат можно увидеть на примере двух групп процессов, созданных оболочкой bash на рис. 34.1). На этом этапе командная оболочка может использовать вызов killpg() (или, как вариант, kill() с отрицательным аргументом pid) для одновременной отправки всем членам группы сигналов, управляющих заданием. Естественно, этот этап необходимо выполнить до отправки сигналов подобного рода.
• Все дочерние процессы должны быть доставлены в группу до запуска программы, поскольку сама программа ничего не знает о манипуляциях с идентификатором группы процессов.