Убивает ли linux фоновые процессы, если мы закрываем терминал, с которого он начался?

у меня есть встроенная система, на которой я делаю telnet и затем я запускаю приложение в фоновом режиме:

./app_name &

теперь, если я закрою терминал и сделать telnet С другого терминала, и если я проверю, то я вижу, что этот процесс все еще работает.

чтобы проверить это, я написал небольшую программу:

#include<stdio.h>
main()
{
    while(1);
}

Я запустил эту программу на своем локальном ПК linux в фоновом режиме, и я закрыл терминал.

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

мой вопрос:

  • почему неопределенное поведение для одного и того же типа процесса?
  • от чего он зависит?
  • зависит ли это от версии Linux?

4 ответов


кто должен убивать Джобса?

обычно передние и фоновые задания убиваются SIGHUP отправлено ядром или оболочкой в разных обстоятельствах.


когда ядро отправляет SIGHUP?

ядро передает SIGHUP to контролировать процесс:

  • для реального (аппаратного) терминала: при обнаружении отключения в драйвере терминала, например, при зависании на модеме линия;
  • for псевдотерминала (pty): когда последний дескриптор, ссылающийся на главную сторону pty, закрыт, например, при закрытии окна терминала.

ядро передает SIGHUP для других групп процессов:

  • to группа процессов переднего плана, когда контролировать процесс прекращается;
  • to процесс осиротевшая группа, когда он становится сиротой и это остановило членов.

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

как правило, процесс управления-это ваша оболочка. Итак, подводя итог:

  • ядро посылает SIGHUP к оболочке, когда реальный или псевдотерминальный отключен / закрыт;
  • ядро посылает SIGHUP к группе процесса переднего плана когда раковина завершает;
  • ядро посылает SIGHUP в потерянную группу процессов, если она содержит остановленные процессы.

обратите внимание, что ядра не отправить SIGHUP в фоновую группу процессов, если она не содержит остановленных процессов.


когда bash отправить SIGHUP?

Баш передает SIGHUP to все задания (передний план и фон):

  • при получении SIGHUP, и это интерактивная оболочка (и Контрольная работа поддержка включена во время компиляции);
  • когда она выходит, это интерактивная оболочка входа в систему, и huponexit опция установлена (и Контрольная работа поддержка включена во время компиляции).

Посмотреть подробнее здесь.

Примечания:

  • bash не отправить SIGHUP для заданий, удаленных из списка заданий с помощью disown;
  • процессы начали использовать nohup игнорировать SIGHUP.

более подробная информация здесь.


как насчет других снарядов?

обычно оболочки распространяются SIGHUP. Генерация SIGHUP при нормальном выходе встречается реже.


Telnet или SSH

под telnet или SSH, следующее должно произойти, когда соединение закрыто (например, когда вы закрываете telnet окно на ПК):

  1. клиент убил;
  2. сервер обнаруживает, что клиентское соединение закрыто;
  3. сервер закрывает главную сторону pty;
  4. ядро обнаруживает, что master pty закрыт и отправляет SIGHUP to bash;
  5. bash получает SIGHUP, передает SIGHUP для всех заданий и завершается;
  6. каждый получает задание SIGHUP и завершается.

я могу воспроизвести проблему с помощью bash и telnetd С busybox или dropbear SSH-сервер: иногда, фоновое задание не получает SIGHUP (и не завершается), когда клиентское соединение закрыто.

кажется гонки возникает, когда сервер (telnetd или dropbear) закрывает главную сторону pty:

  1. как правило, bash получает SIGHUP и сразу же убивает фоновые задания (как и ожидалось) и завершает;
  2. но иногда, bash обнаруживает EOF на рабской стороне pty до обращение SIGHUP.

, когда bash обнаруживает EOF, он по умолчанию завершается немедленно без отправки SIGHUP. И фоновая работа остается запущенной!


решение

можно настроить bash отправить SIGHUP при нормальном выходе (включая EOF) тоже:

  • обеспечить bash как войти shell. The huponexit работает только для оболочек входа, AFAIK.

    оболочка входа включена или ведущий дефис на argv[0]. Вы можете настроить telnetd для выполнения /bin/bash -l или лучше /bin/login вызывает /bin/sh в оболочку режим.

    например:

    telnetd -l /bin/login
    
  • включить .

    например:

    shopt -s huponexit
    

    типа этого bash сеанс каждый раз или добавить его в .bashrc или /etc/profile.


почему гонка происходит?

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

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

вы можете начать копать от quit.h в исходном коде.

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


ссылка

  • "Управление Заданиями" раздел в официальном руководстве Glibc.
  • Глава 34 "группы процессов, сеансы и управление заданиями" книги "интерфейс программирования Linux".

для того, чтобы полностью понять, что происходит, вам нужно попасть в unix ВКУ немного.

когда вы используете команду

./app_name &

на app_name отправляется в фоновую группу процессов. Вы можете проверить о unix обработка группы здесь

когда вы закрываете bash при нормальном выходе он срабатывает SIGHUP сигнал зависания для всех своих заданий. Некоторая информация о unix Контрольная работа здесь.

для того, чтобы сохранить ваше приложение работает при выходе bash вам нужно сделать ваше приложение иммунным к сигналу зависания с nohup утилиты.

nohup-запустите команду, невосприимчивую к зависаниям, с выходом в non-tty

и, наконец, это то, как вам нужно это сделать.

nohup app_name & 2> /dev/null;


когда вы закрываете терминал, shell отправляет SIGHUP для всех фоновых процессов – и это их убивает. Это можно подавить несколькими способами, в частности:

nohup

при запуске программы с nohup он ловит SIGHUP и перенаправление вывода программы.

$ nohup app &

открестился

disown говорит shell не отправлять SIGHUP

$ app &
$ disown

зависит ли это от версии linux?

это зависит от вашей оболочки. Выше применяется по крайней мере для Баш.


AFAIK в обоих случаях процесс должен быть убит. Чтобы избежать этого, вы должны выпустить nohup следующим образом:

> nohup ./my_app &

таким образом, ваш процесс будет продолжать выполняться. Вероятно, часть telnet связана с ошибкой, подобной этой:

https://bugzilla.redhat.com/show_bug.cgi?id=89653