Чтение онлайн

ЖАНРЫ

Разработка приложений в среде Linux. Второе издание

Троан Эрик В.

Шрифт:

Хотя управляющий терминал сеанса может быть изменен, обычно это делается только процессами, которые управляют начальным входом пользователя в систему. Информацию о том, как сменить управляющий терминал сеанса, можно найти в главе 16.

10.6.3. Группы процессов

Одной из главных целей Unix было создание набора простых инструментов, которые могут быть использованы вместе сложными способами (с помощью механизмов, подобных программным каналам). Большинство пользователей Linux делали нечто вроде следующего практического примера этой философии:

ls | grep "^[аА].*\.gz" | more

Другое популярное средство, появившееся в Unix достаточно давно — управление заданиями (job control). Управление заданиями дает возможность пользователям прерывать текущее задание (известное как задание переднего плана (foreground task))

в то время, пока они уходят и делают на терминале что-то другое. Когда приостановленное задание представляет собой последовательность процессов, работающих вместе, система должна отслеживать, какие именно процессы должны быть приостановлены, когда пользователь желает приостановить задание переднего плана. Группы процессов позволяют системе видеть, какие процессы работают вместе, а потому должны управляться совместно средствами управления заданиями.

Процессы добавляются в группы с помощью

setpgid
.

int setpgid(pid_t pid, pid_t pgid);

pid
— это процесс, который должен быть помещен в новую группу (
0
обозначает текущий процесс),
pgid
— это идентификатор группы процессов, к которой должен принадлежать процесс
pid
, или
0
, если процесс должен быть включен в новую группу процессов, чей
pgid
тот же, что и
pid
процесса. Подобно сеансам, лидер группы процессов — это процесс, чей
pid
совпадает в
pgid
группы.

Правила применения

setpgid
несколько сложны.

1. Процесс может устанавливать группу для себя или одного из своих потомков. Он не может изменять группу для любого другого процесса в системе, даже если процесс, вызвавший

setpgid
, имеет административные полномочия.

2. Лидер сеанса не может изменить свою группу.

3. Процесс не может быть перемещен в группу, чей лидер представляет другой сеанс, чем он сам. Другими словами, все процессы в группе должны относиться к одному и тому же сеансу.

Вызов

setpgid
помещает вызывающий процесс в свою собственную группу и собственный сеанс. Это необходимо для того, чтобы гарантировать, что два сеанса не содержат процессы, принадлежащие к одной и той же группе.

Полный пример групп процессов будет приведен при обсуждении системы управления заданиями в главе 15.

Когда соединение с терминалом теряется, ядро посылает сигнал (

SIGHUP
; подробнее о сигналах рассказывается в главе 12) лидеру сеанса, содержащему группу процессов переднего плана данного терминала. Обычно это командная оболочка. Это позволит оболочке безусловно прерывать пользовательские процессы, извещая их о том, что пользователь выходит из системы (обычно посредством
SIGHUP
), либо выполнить некоторые другие действия (или бездействие). Хотя это все может показаться усложненным, это дает возможность лидеру группы сеанса принимать решения о том, как управлять закрывающимися терминалами, вместо того, чтобы возлагать эту обязанность на ядро. Это также дает возможность администраторам гибко управлять политиками пользовательских учетных записей.

Определение группы процесса может быть выполнено просто, с помощью функций

getpgid
и
getpgrp
.

pid_t getpgid(pid_t pid)
Возвращает pgid процесса
pid
. Если
pid
равен
0
, возвращается pgid текущего процесса. Для вызова не требуется никаких специальных полномочий. Любой процесс может определять группу, к которой принадлежит любой другой процесс.
pid_t getpgrp(void)
Возвращает pgid текущего процесса
pid
(эквивалентно
getprgid(0)
)

10.6.4. Висячие группы процессов

Механизм прерывания процессов (либо возобновления их работы после приостановки) при исчезновении их сеанса довольно сложен. Представьте себе сеанс со многими группами процессов в нем (см. рис. 10.1). Сеанс запущен на терминале, и обычная системная оболочка является его лидером.

Когда лидер сеанса (оболочка) завершается, ее группы процессов оказываются в сложной ситуации. Если они

активно работают, то лишаются возможности использовать стандартные потоки
stdin
и
stdout
, поскольку терминал закрыт. Если они приостановлены, то вероятно, никогда не будут запущены снова, поскольку пользователь терминала не имеет возможности перезапустить их, к тому же то, что они не могут быть запущены, означает также, что они не могут быть и прерваны.

В этой ситуации каждая такая группа процессов получает название висячей (orphaned). Стандарт POSIX определяет ее как группу процессов, чей родитель является также членом этой группы либо не является членом сеанса этой группы. Другими словами, группа процессов не является висячей до тех пор, пока у нее есть родительский процесс, принадлежащий тому же сеансу, но другой группе.

Хотя оба определения выглядят сложными, концепция достаточно проста. Если группа процессов приостановлена, и не существует процесса, который бы принудил ее возобновиться, то эта группа становится висячей [33] .

33

В главе 15 все это проясняется, поэтому, возможно, будет полезно сначала прочитать ее.

Когда завершает работу командная оболочка, все ее дочерние процессы становятся дочерними по отношению к процессу init, оставаясь при этом в своих исходных сеансах. Предполагая, что все программы в сеансе являются потомками оболочки, все группы процессов этого сеанса становятся висячими [34] . Когда группа процессов превращается в висячую, каждый процесс этой группы получает сигнал

SIGHUP
, что обычно прерывает программу.

Программы, которые не прерываются по сигналу

SIGHUP
, получают сигнал
SIGCONT
, который продолжает выполнение приостановленных процессов. Такая последовательность прерывает большинство процессов и обеспечивает оставшимся возможность работать (то есть гарантирует, что они не будет в приостановленном состоянии) [35] .

34

Но, может быть, не сразу. Может существовать группа процессов, содержащая процессы, чьи родители относятся к другой группе в том же сеансе. Поскольку отношения "родительский-дочерний" между процессами образуют дерево, иногда может оказаться, что существует группа процессов, которая содержит только те процессы, чьим родителем является оболочка, и когда такая группа процессов завершается, другая становится висячей.

35

Обсуждение станет более понятным после того, как вы прочитаете главы, посвященные сигналам (глава 12) и управлению заданиями (глава 15).

Как только процесс становится висячим, он принудительно отключается от своего управляющего терминала (позволяя новому пользователю при необходимости применять этот терминал). Если продолжающие работать программы пытаются получить доступ к терминалу, эти попытки вызывают ошибки, устанавливающие

errno
в значение
EIO
. Процессы остаются в том же сеансе, и идентификатор сеанса не используется для новых идентификаторов процессов до тех пор, пока не завершатся все процессы данного сеанса.

10.7. Введение в

ladsh

Чтобы помочь проиллюстрировать идеи, обсуждаемые в нашей книге, на протяжении последующих разделов книги мы разработаем подмножество командной оболочки Unix. В конечном итоге наша оболочка будет поддерживать следующее.

• Простые встроенные команды.

• Запуск внешних команд.

• Перенаправление ввода-вывода (

>
,
|
и так далее).

• Управление заданиями.

Полный исходный текст окончательной версии этой оболочки,

ladsh4.с
, представлен в приложении Б. По мере добавления в
ladsh
новых средств, изменения исходного текста описываются в тексте книги. Чтобы уменьшить количество изменений, которые мы вносим между версиями, некоторые ранние версии несколько более сложны, чем было бы нужно. Эти небольшие усложнения, однако, далее в книге упрощают разработку оболочки, поэтому будьте терпеливы. Просто пока поверьте, что эти фрагменты кода необходимы; все они будут объяснены позднее.

Поделиться с друзьями: