Функция tcsetpgrp() меняет активную группу процессов терминала. Если вызывающий процесс имеет контролирующий терминал, на который указывает файловый дескриптор fd, то tcsetpgrp() назначает активной группе процессов значение pgid, которое должно совпадать с идентификатором PGID одного из процессов, входящих в текущую сессию.
Функции tcgetpgrp() и tcsetpgrp() являются частью стандарта SUSv3. В Linux, как и во многих других UNIX-системах, они реализованы с помощью двух нестандартных операций для вызова ioctl(): TIOCGPGRP и TIOCSPGRP.
Когда контролирующий процесс теряет соединение с терминалом, ядро информирует его об этом факте, отправляя ему сигнал SIGHUP (кроме того, чтобы обеспечить перезапуск процесса в случае, если тот был ранее остановлен по сигналу, отправляется сигнал SIGCONT). Обычно это происходит в одной из двух ситуаций.
• Когда «отключение» обнаруживается драйвером терминала и указывает на потерю сигнала в модеме или терминальном соединении.
• Когда окно терминала закрывается на клиентской стороне. Это случается в результате закрытия последнего открытого дескриптора на серверной стороне псевдотерминала, связанного с его окном.
По умолчанию сигнал SIGHUP завершает процесс терминала. Но если вместо этого контролирующий процесс обрабатывает или игнорирует данный сигнал, дальнейшие попытки прочитать информацию из терминала будут возвращать символ конца файла (EOF).
Стандарт SUSv3 гласит, что если теряется соединение с терминалом и вместе с этим выполняется одно из условий, приводящих к возникновению ошибки EIO во время работы функции read(), то невозможно сказать, какой результат вернет эта функция — символ конца файла или ошибку EIO. Переносимые программы должны учитывать обе возможности. Ситуация, когда read() завершается ошибкой EIO, будет рассмотрена в подразделах 34.7.2 и 34.7.4.
Доставка сигнала SIGHUP контролирующему процессу может запустить своеобразную цепную реакцию, в результате которой этот сигнал получают множество других процессов. Это может случиться двумя разными способами.
• В качестве контролирующего процесса обычно выступает командная оболочка. Она устанавливает обработчик сигнала SIGHUP, чтобы перед завершением ретранслировать этот сигнал всем заданиям, которые она создала. По умолчанию это приводит к завершению этих заданий, но, перехватив сигнал SIGHUP, они будут знать о том, что их оболочка завершила свою работу.
• Во время завершения контролирующего процесса ядро отсоединяет от связанного с ним терминала все процессы из его сессии, которая в итоге тоже отсоединяется от этого терминала (что позволяет использовать его уже в другой сессии). Кроме того, ядро информирует активную группу процессов о потере соединения с управляющим терминалом, отправляя ей сигнал SIGHUP.
Каждый из этих случаев будет подробно рассмотрен в следующих разделах.
Сигнал SIGHUP имеет и другие применения. В подразделе 34.7.4 вы увидите, что он генерируется, когда группа процессов остается без родителя. Кроме того, SIGHUP принято отправлять вручную для того, чтобы заставить процесс-демон заново себя инициализировать или еще раз прочитать свой конфигурационный файл (демон по определению не имеет контролирующего терминала, поэтому получить сигнал SIGHUP от ядра). Применение сигнала SIGHUP в контексте процессов-демонов будет описано в разделе 37.4.
34.6.1. Обработка сигнала SIGHUP командной оболочкой
В контексте сессии входа в систему командная оболочка обычно является управляющим процессом для терминала. Большинство оболочек написаны таким образом, что в интерактивном режиме они устанавливают обработчик сигнала SIGHUP. Этот обработчик завершает работу командной оболочки, но перед этим отправляет SIGHUP каждой группе процессов (активной и фоновой), созданной этой оболочкой (в зависимости от вида оболочки и от того, остановлено или нет ее задание, за SIGHUP может последовать сигнал SIGCONT). То, как процессы в этих группах отреагируют на сигнал SIGHUP, зависит от конкретного приложения; если не было предусмотрено никаких особых действий, они просто завершаются.
Некоторые командные оболочки, управляющие заданиями, при завершении (то есть при выходе из системы или при нажатии Ctrl+D в окне терминала) отправляют сигнал SIGHUP еще и фоновым процессам. Так поступают bash и Korn Shell (после того как выводят сообщение при первой попытке выхода).
Чтобы сделать процесс нечувствительным к SIGHUP, можно воспользоваться командой nohup(1); во время запуска процесса она устанавливает для SIGHUP действие SIG_IGN. Команда disown, встроенная в bash, имеет похожее назначение: она удаляет задание из списка заданий командной оболочки, чтобы, когда та завершит свою работу, сигнал SIGHUP доставлен не был.