Управляющий терминал, сеанс, группы

Управляющий терминал, сеанс, группы

Для организации диалоговой работы пользователей в Unix вводится понятие терминальной сессии. С точки зрения пользователя - это процесс работы с текстовым терминалом с момента ввода имени и пароля и до выхода из системы командой logout (exit, нажатие ^D в пустой строке). Во время терминальной сессии может быть запущено несколько программ, которые будут параллельно выполнятся в фоновом режиме и между которыми можно переключаться в диалоговом режиме. После завершения терминальной сессии возможно принудительное завершение всех запущенных в ней фоновых процессов.

С точки зрения ядра - терминальная сессия - это группа процессов, имеющих один идентификатор сеанса sid. С идентификатором sid связан драйвер управляющего терминала, доступный всем членам сеанса как файл символьного устройства /dev/tty. Для каждого сеанса существует свой /dev/tty. Управляющий терминал взаимодействует с процессами сеанса с помощью отправки сигналов.

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

Группа процессов

Группа процессов - инструмент для доставки сигнала нескольким процессам, а также способ арбитража при доступе к терминалу. Идентификатор группы pgid равен pid создавшего её процесса - лидера группы. Процесс может переходить из группы в группу внутри одного сеанса.

#include <unistd.h>

int setpgid(pid_t pid, pid_t pgid); // включить процесс pid в группу pgid.
                                             // pid=0 означает текущий процесс,
                                             // pgid=0 означает pgid=pid текущего процесса
                                             // pid=pgid=0 - создание новой группы с pgid=pid текущего процесса
                                             //                      и переход в эту группу
pid_t getpgid(pid_t pid); // получить номер группы процесса pid.
                       // pid=0 - текущий процесс
int setpgrp(void); // создание группы, эквивалент setpgid(0.0);
pid_t getpgrp(void); // запрос текущей группы, эквивалент getpgid(0);

Сеанс

Сеанс - средство для контроля путем посылки сигналов над несколькими группами процессов со стороны терминального драйвера. Как правило соответствует диалоговой пользовательской сессии. Идентификатор сеанса sid равняется идентификатору pid, создавшего его процесса - лидера сеанса. Одновременно с сеансом создаётся новая группа с pgid равным pid лидера сеанса. Поскольку переход группы из сеанса в сеанс невозможен, то создающий сеанс процесс не может быть лидером группы.

#include <unistd.h>
pid_t setsid(void); //Создание  новой группы и нового сеанса. Текущий процесс не должен быть лидером группы.
pid_t getsid(pid_t pid); //Возвращает номер сеанса для указанного процесса

Создание собственного сеанса рекомендуется начать с fork, чтобы гарантировать, что процесс не является лидером группы.

if( fork() ) exit(0);
setsid();

Фоновая группа сеанса

Процессы в фоновой группе выполняются до тех пор, пока не попытаются осуществить чтение или запись через файловый дескриптор управляющего терминала. В этот момент они получают сигнал SIGTTIN или SIGTTOU соответственно. Действие по умолчанию для данного сигнала - приостановка выполнения процесса.

Назначение фоновой группы:

#include <unistd.h>

 pid_t tcgetpgrp(int fd); // получить pgid фоновой группы, связанной с управляющим терминалом, 
                     // на который ссылается файловый дескриптор fd
 int tcsetpgrp(int fd, pid_t pgrp); // назначить pgid фоновой группы терминалу,
                    // на который ссылается файловый дескриптор fd

Управляющий терминал

Некоторые сочетания клавиш позволяют посылать сигналы процессам сеанса:

  • ^C - SIGINT - завершение работы
  • ^Z - SIGTSTP - приостановка выполнения. bash отслеживает остановку дочерних процессов и вносит их в списки своих фоновых процессов. Остановленный процесс может быть продолжен командой fg n, где n - порядковый нрмер процесса в списке фоновых процессов

Открыть управляющий терминал сеанса

#include <stdio.h>

char name[L_ctermid];
int fd;
ctermid(name); // если name=NULL, то используется внутренний буфер
           // ctermid возвращает указатель на буфер
           // L_ctermid - библиотечная константа
fd = open(name, O_RDWR, 0);