Московский физико-технический институт
Опубликован: 16.09.2004 | Доступ: свободный | Студентов: 7349 / 1504 | Оценка: 4.44 / 4.28 | Длительность: 15:33:00
Лекция 9:

Организация ввода-вывода в UNIX. Файлы устройств. Аппарат прерываний. Сигналы в UNIX

Понятия группы процессов, сеанса, лидера группы, лидера сеанса, управляющего терминала сеанса. Системные вызовы getpgrp(), setpgrp(), getpgid(), setpgid(), getsid(), setsid()

В лекции 2, раздел "Одноразовые операции", уже говорилось, что все процессы в системе связаны родственными отношениями и образуют генеалогическое дерево или лес из таких деревьев, где в качестве узлов деревьев выступают сами процессы, а связями служат отношения родитель-ребенок. Все эти деревья принято разделять на группы процессов, или семьи (см. рис. 13–14.1).

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

Иерархия процессов в UNIX

Рис. 13-14.1. Иерархия процессов в UNIX

В свою очередь, группы процессов объединяются в сеансы, образуя, с родственной точки зрения, некие кланы семей. Понятие сеанса изначально было введено в UNIX для логического объединения групп процессов, созданных в результате каждого входа и последующей работы пользователя в системе. С каждым сеансом, поэтому, может быть связан в системе терминал, называемый управляющим терминалом сеанса, через который обычно и общаются процессы сеанса с пользователем. Сеанс не может иметь более одного управляющего терминала, и один терминал не может быть управляющим для нескольких сеансов. В то же время могут существовать сеансы, вообще не имеющие управляющего терминала.

Каждая группа процессов в системе получает собственный уникальный номер. Узнать этот номер можно с помощью системного вызова getpgid() . Используя его, процесс может узнать номер группы для себя самого или для процесса из своего сеанса. К сожалению, не во всех версиях UNIX присутствует данный системный вызов. Здесь мы сталкиваемся с тяжелым наследием разделения линий UNIX'ов на линию BSD и линию System V, которое будет нас преследовать почти на всем протяжении данной темы. Вместо вызова getpgid() в таких системах существует системный вызов getpgrp() , который возвращает номер группы только для текущего процесса.

Системный вызов getpgid()

Прототип системного вызова

#include <sys/types.h>
#include <unistd.h>
pid_t getpgid(pid_t pid);

Описание системного вызова

Системный вызов возвращает идентификатор группы процессов для процесса с идентификатором pid.

Узнать номер группы процесс может только для себя самого или для процесса из своего сеанса. При других значениях pid системный вызов возвращает значение -1.

Тип данных pid_t является синонимом для одного из целочисленных типов языка C.

Системный вызов getpgrp()

Прототип системного вызова

#include <sys/types.h>
#include <unistd.h>
pid_t getpgrp(void);

Описание системного вызова

Системный вызов getpgrp возвращает идентификатор группы процессов для текущего процесса.

Тип данных pid_t является синонимом для одного из целочисленных типов языка C.

Для перевода процесса в другую группу процессов, возможно, с одновременным ее созданием, применяется системный вызов setpgid() . Перевести в другую группу процесс может либо самого себя (и то не во всякую и не всегда), либо свой процесс-ребенок, который не выполнял системный вызов exec(), т.е. не запускал на выполнение другую программу. При определенных значениях параметров системного вызова создается новая группа процессов с идентификатором, совпадающим с идентификатором переводимого процесса, состоящая первоначально только из одного этого процесса. Новая группа может быть создана только таким способом, поэтому идентификаторы групп в системе уникальны. Переход в другую группу без создания новой группы возможен лишь в пределах одного сеанса.

В некоторых разновидностях UNIX системный вызов setpgid() отсутствует, а вместо него используется системный вызов setpgrp() , способный только создавать новую группу процессов с идентификатором, совпадающим с идентификатором текущего процесса, и переводить в нее текущий процесс. (В ряде систем, где сосуществуют вызовы setpgrp() и setpgid() , например в Solaris, вызов setpgrp() ведет себя иначе – он аналогичен рассматриваемому ниже вызову setsid() .)

Системный вызов setpgid()

Прототип системного вызова

#include <sys/types.h>
#include <unistd.h>
int setpgid(pid_t pid, pid_t pgid);

Описание системного вызова

Системный вызов setpgid служит для перевода процесса из одной группы процессов в другую, а также для создания новой группы процессов .

Параметр pid является идентификатором процесса, который нужно перевести в другую группу, а параметр pgid – идентификатором группы процессов, в которую предстоит перевести этот процесс.

Не все комбинации этих параметров разрешены. Перевести в другую группу процесс может либо самого себя (и то не во всякую, и не всегда), либо свой процесс-ребенок, который не выполнял системный вызов exec(), т.е. не запускал на выполнение другую программу.

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

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

Тип данных pid_t является синонимом для одного из целочисленных типов языка C.

Возвращаемое значение

Системный вызов возвращает значение 0 при нормальном завершении и значение -1 при возникновении ошибки.

Системный вызов setpgrp()

Прототип системного вызова

#include <sys/types.h>
#include <unistd.h>
int setpgrp(void);

Описание системного вызова

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

Возвращаемое значение

Системный вызов возвращает значение 0 при нормальном завершении и значение -1 при возникновении ошибки.

Процесс, идентификатор которого совпадает с идентификатором его группы, называется лидером группы. Одно из ограничений на применение вызовов setpgid() и setpgrp() состоит в том, что лидер группы не может перебраться в другую группу.

Каждый сеанс в системе также имеет собственный номер. Для того чтобы узнать его, можно воспользоваться системным вызовом getsid() . В разных версиях UNIX на него накладываются различные ограничения. В Linux такие ограничения отсутствуют.

Системный вызов getsid()

Прототип системного вызова

#include <sys/types.h>
#include <unistd.h>
pid_t getsid(pid_t pid);

Описание системного вызова

Системный вызов возвращает идентификатор сеанса для процесса с идентификатором pid . Если параметр pid равен 0, то возвращается идентификатор сеанса для данного процесса

Тип данных pid_t является синонимом для одного из целочисленных типов языка C.

Использование системного вызова setsid() приводит к созданию новой группы, состоящей только из процесса, который его выполнил (он становится лидером новой группы ), и нового сеанса, идентификатор которого совпадает с идентификатором процесса, сделавшего вызов. Такой процесс называется лидером сеанса. Этот системный вызов может применять только процесс, не являющийся лидером группы.

Системный вызов setsid()

Прототип системного вызова

#include <sys/types.h>
#include <unistd.h>
int setsid(void);

Описание системных вызовов

Этот системный вызов может применять только процесс, не являющийся лидером группы, т.е. процесс, идентификатор которого не совпадает с идентификатором его группы. Использование системного вызова setsid приводит к созданию новой группы, состоящей только из процесса, который его выполнил (он становится лидером новой группы ), и нового сеанса, идентификатор которого совпадает с идентификатором процесса, сделавшего вызов.

Возвращаемое значение

Системный вызов возвращает значение 0 при нормальном завершении и значение -1 при возникновении ошибки.

Если сеанс имеет управляющий терминал, то этот терминал обязательно приписывается к некоторой группе процессов, входящей в сеанс. Такая группа процессов называется текущей группой процессов для данного сеанса . Все процессы, входящие в текущую группу процессов, могут совершать операции ввода-вывода, используя управляющий терминал. Все остальные группы процессов сеанса называются фоновыми группами , а процессы, входящие в них – фоновыми процессами. При попытке ввода-вывода фонового процесса через управляющий терминал этот процесс получит сигналы, которые стандартно приводят к прекращению работы процесса. Передавать управляющий терминал от одной группы процессов к другой может только лидер сеанса. Заметим, что для сеансов, не имеющих управляющего терминала, все процессы являются фоновыми.

При завершении работы процесса – лидера сеанса все процессы из текущей группы сеанса получают сигнал SIGHUP , который при стандартной обработке приведет к их завершению. Таким образом, после завершения лидера сеанса в нормальной ситуации работу продолжат только фоновые процессы.

Процессы, входящие в текущую группу сеанса, могут получать сигналы, инициируемые нажатием определенных клавиш на терминале – SIGINT при нажатии клавиш <ctrl> и <c>, и SIGQUIT при нажатии клавиш <ctrl> и <4>. Стандартная реакция на эти сигналызавершение процесса (с образованием core файла для сигнала SIGQUIT ).

Необходимо ввести еще одно понятие, связанное с процессом, – эффективный идентификатор пользователя. В материалах первого семинара говорилось о том, что каждый пользователь в системе имеет собственный идентификатор – UID. Каждый процесс, запущенный пользователем, задействует этот UID для определения своих полномочий. Однако иногда, если у исполняемого файла были выставлены соответствующие атрибуты, процесс может выдать себя за процесс, запущенный другим пользователем. Идентификатор пользователя, от имени которого процесс пользуется полномочиями, и является эффективным идентификатором пользователя для процесса – EUID. За исключением выше оговоренного случая, эффективный идентификатор пользователя совпадает с идентификатором пользователя, создавшего процесс.