Фоновые процессы получают SIGHUP при выходе из системы?

21

Это продолжение этого вопроса .

Я провел еще несколько тестов; похоже, что на самом деле не имеет значения, выполняется ли это на физической консоли или через SSH, и при этом это не происходит только с SCP; Я также проверил это с cat /dev/zero > /dev/null. Поведение точно такое же:

  • Запустите процесс в фоновом режиме, используя &(или поместите его в фоновом режиме после того, как он начал использовать CTRL-Zи bg); это делается без использованияnohup .
  • Выйти.
  • Войдите снова.
  • Процесс все еще там, счастливо протекает, и теперь является непосредственным ребенком init.

Я могу сразу подтвердить как SCP, так и CAT, если отправил SIGHUP; Я проверил это с помощью kill -HUP.

Таким образом, похоже, что SIGHUP не отправляется при выходе из системы, по крайней мере, в фоновые процессы (по понятным причинам не может тестироваться с передним планом).

Сначала это случилось со служебной консолью VMware ESX 3.5 (которая основана на RedHat), но я смог воспроизвести ее точно на CentOS 5.4.

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


редактировать

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

Massimo
источник
Используя Bash на CentOS 7.1, простой цикл сценария оболочки получит SIGHUP, если он оставлен на переднем плане, но терминал убит; Strace из другого терминала показывает: --- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=10676, si_uid=3000090} --- rt_sigreturn() = -1 EINTR (Interrupted system call) rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
Mike S
Так же будет фоновый скрипт. Обратите внимание, что терминал закрыт, пока цикл находится в режиме ожидания. Оболочка НЕ ​​выходила:--- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=13944, si_uid=3000090} --- +++ killed by SIGHUP +++
Майк С
Смотрите мой ответ для тестов. Интересно, что я не видел никаких изменений в поведении из-за huponexit.
Майк С

Ответы:

26

Ответ найден.

Для BASH это зависит от параметра huponexitоболочки, который можно просмотреть и / или установить с помощью встроенной shoptкоманды.

Похоже, эта опция отключена по умолчанию, по крайней мере, в системах на базе RedHat.

Больше информации на странице руководства BASH :

Оболочка выходит по умолчанию при получении SIGHUP. Перед выходом интерактивная оболочка отправляет SIGHUP всем работам, запущенным или остановленным. Остановленные задания отправляются SIGCONT, чтобы гарантировать получение SIGHUP. Чтобы предотвратить отправку оболочкой сигнала определенному заданию, его следует удалить из таблицы заданий с помощью встроенной команды disown (см. Ниже КОМАНДЫ СОСТАВЛЕНИЯ ОБОЛОЧКИ) или отметить, что она не получает SIGHUP с помощью команды disown -h.

Если параметр оболочки huponexit был установлен с помощью shopt, bash отправляет SIGHUP всем работам при выходе из интерактивной оболочки входа.

Massimo
источник
4
Проверенные. Когда я выполнял «выход», «выход из системы» или CTL-D, дочерний процесс (задание) не получал вздох (как для пользователя root, так и для пользователя reg). Однако, когда я сделал "kill -HUP $$", чтобы убить текущий экземпляр bash, дочерние процессы получили SID. Затем я установил huponexit, и дочерний процесс получил SIGHUP при выходе.
CarpeNoctem
3

Он будет отправлен SIGHUP в моих тестах:

оболочку1:

[kbrandt@kbrandt-opadmin: ~] ssh localhost
[kbrandt@kbrandt-opadmin: ~] perl -e sleep & 
[1] 1121
[kbrandt@kbrandt-opadmin: ~] ps
  PID TTY          TIME CMD
 1034 pts/46   00:00:00 zsh
 1121 pts/46   00:00:00 perl
 1123 pts/46   00:00:00 ps

Shell2:

strace -e trace=signal -p1121

Shell1 снова:

[kbrandt@kbrandt-opadmin: ~] exit
zsh: you have running jobs.
[kbrandt@kbrandt-opadmin: ~] exit
zsh: warning: 1 jobs SIGHUPed
Connection to localhost closed.

Shell2 снова :

strace -e trace=signal -p1121
Process 1121 attached - interrupt to quit
pause()                                 = ? ERESTARTNOHAND (To be restarted)
--- SIGHUP (Hangup) @ 0 (0) ---
Process 1121 detached

Почему он все еще работает ?:
Расширенное программирование в среде Unix от Стивенса рассматривает это в разделе 9.10: «Потерянные группы процессов». Наиболее актуальный раздел:

Поскольку при завершении родительского процесса группа процессов становится осиротевшей, POSIX.1 требует, чтобы каждому процессу в вновь осиротевшей группе процессов, который остановлен (как и наш потомок), был послан сигнал зависания (SIGHUP), за которым следует сигнал продолжения (SIGCONT ).

Это заставляет ребенка продолжать работу после обработки сигнала зависания. Действие по умолчанию для сигнала зависания - завершить процесс, поэтому мы должны предоставить обработчик сигнала для перехвата сигнала. Поэтому мы ожидаем, что printf в функции sig_hup появится перед printf в функции pr_ids.

Кайл Брандт
источник
Но вы явно отправили SIGHUP здесь; Я говорил о том, что происходит, когда вы выходите из оболочки, где вы начали процесс.
Массимо
Те же результаты, когда я набираю exit, хотя я получаю предупреждение о заданиях, но затем снова набираю exit. Я проверил это с ZSH.
Кайл Брандт
Я использую BASH, и это, вероятно, зависит от оболочки. Но BASH должен отправлять SIGHUP дочерним процессам при выходе из системы ...
Massimo
Bash отправляет SIGCONT, очевидно, если работа остановлена, но я подтверждаю, что ничего не отправляет, если работа не была остановлена.
Кайл Брандт
Используя Bash на CentOS 7.1, я получаю SIGTERM, отправленный моему процессу, остановленному в другом окне: 1.) Запустить простой сценарий оболочки (цикл с эхом и сном), 2.) Control-Z it, 3) запустить процесс в другое окно, 4) выйти из исходного терминала. Он жалуется на то, что у меня есть рабочие места, а затем после выхода из моих прямых шоу: $ strace -e signal -p1705 Process 1705 attached --- stopped by SIGTSTP --- --- SIGTERM {si_signo=SIGTERM, si_code=SI_USER, si_pid=791, si_uid=3000090} --- +++ killed by SIGTERM +++ Странно, определенно не в соответствии с разделом, цитируемым Стивенсом.
Майк С
2

Я провел несколько тестов, используя CentOS 7.1 и bash. Обратите внимание, что это означает, huponexitчто offпо умолчанию оно отключено для большинства моих тестов.

Вам нужно, nohupкогда вы запускаете задание в терминале, потому что, если вы закрываете этот терминал, не выходя из оболочки чисто , терминал отправляет bash сигнал SIGHUP в оболочку, которая затем отправляет его всем дочерним элементам. Если вы аккуратно выходите из оболочки - значит, задание уже должно быть в фоновом режиме, чтобы вы могли вводить exitили нажимать Control-D в командной строке - никакие сигналы любого рода не отправляются в фоновое задание из bash.

Тест:

Терминал 1

$ echo $$
16779

Терминал 2

$ strace -e signal -p16779
Process 16779 attached

(закрыть терминал 1, видно в терминале 2):

--- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=16777, si_uid=3000090} ---
rt_sigprocmask(SIG_BLOCK, [CHLD TSTP TTIN TTOU], [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], 8) = 0
rt_sigprocmask(SIG_SETMASK, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], 8) = 0
rt_sigprocmask(SIG_SETMASK, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], NULL, 8) = 0
rt_sigaction(SIGHUP, {SIG_DFL, [], SA_RESTORER, 0x7f7ace3d9a00}, {0x456880, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], SA_RESTORER, 0x7f7ace3d9a00}, 8) = 0
kill(16779, SIGHUP)                     = 0
rt_sigreturn()                          = -1 EINTR (Interrupted system call)
--- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=16779, si_uid=3000090} ---
+++ killed by SIGHUP +++

Работа doit.sh:

#!/bin/bash

imhupped() {
        echo "HUP" >> /tmp/outfile
}

trap imhupped SIGHUP

for i in $(seq 1 6); do echo out $i >> /tmp/outfile; sleep 5; done

Запустите его в фоновом режиме в терминале 1:

Терминал 1

$ ./doit.sh &
[1] 22954

Разместите это в Терминале 2; закройте Терминал 1 после нескольких петель:

Терминал 2

$ strace -e signal -p22954
Process 22954 attached
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=22980, si_status=0, si_utime=0, si_stime=0} ---
rt_sigreturn()                          = 0
rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x7f7a5d547a00}, {0x43e4b0, [], SA_RESTORER, 0x7f7a5d547a00}, 8) = 0
...
--- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=21685, si_uid=3000090} ---
rt_sigreturn()                          = -1 EINTR (Interrupted system call)
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_KILLED, si_pid=23017, si_status=SIGHUP, si_utime=0, si_stime=0} ---
rt_sigreturn()                          = 0
...

Выход в Терминал 3:

Терминал 3

out 1
out 2
out 3
HUP
out 4
out 5
out 6

Однако, если вы выходите bash, он просто выходит, вообще не посылая никакого сигнала ребенку. Терминал выйдет, потому что у него больше нет дочернего, но, конечно, нет никого, кто мог бы подключиться к HUP, потому что дочерняя оболочка уже пропала. SIGINT, SIG_BLOCKИ SIG_SETMASKвы видите ниже, в связи с sleepв оболочке.

Терминал 1

$ ./doit.sh &
26275

Терминал 2

$ strace -e signal -p26275
Process 26275 attached
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=26280, si_status=0, si_utime=0, si_stime=0} ---
rt_sigreturn()                          = 0
rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x7f5edd3a5a00}, {0x43e4b0, [], SA_RESTORER, 0x7f5edd3a5a00}, 8) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, [INT CHLD], [], 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigaction(SIGINT, {0x43e4b0, [], SA_RESTORER, 0x7f5edd3a5a00}, {SIG_DFL, [], SA_RESTORER, 0x7f5edd3a5a00}, 8) = 0


(..."exit" is typed in bash, notice no new signals sent...)


rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=26303, si_status=0, si_utime=0, si_stime=0} ---
rt_sigreturn()                          = 0
rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x7f5edd3a5a00}, {0x43e4b0, [], SA_RESTORER, 0x7f5edd3a5a00}, 8) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, [INT CHLD], [], 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigaction(SIGINT, {0x43e4b0, [], SA_RESTORER, 0x7f5edd3a5a00}, {SIG_DFL, [], SA_RESTORER, 0x7f5edd3a5a00}, 8) = 0

Терминал 3, выход

out 1
out 2
out 3
out 4
out 5
out 6

Интересно, что я установил , huponexitчтобы быть с shopt -s huponexit; shopt(последняя shopt к обзору), затем выполняется последнее испытание, и снова удар не посылали сигнал фонового процесса . Даже MORE Interstingly, как мы уже видели Баш сделал послать сигнал на фоновый процесс после того, как он получил его от терминала , который был закрыт в его лице. Кажется, что huponexitне имеет никакого отношения ни к одному, ни к другому.

Я надеюсь, что это устранит любую тайну или путаницу относительно, по крайней мере, счастья Баша, о том, когда и как отправляется сигнал HUP. По крайней мере, мои тесты были полностью воспроизводимы для меня. Мне было бы интересно узнать, есть ли другие параметры, которые могут влиять на поведение bash.

И, как всегда, YSMV (ваша оболочка может меняться).

Приложение 1

Когда я запускаю оболочку как exec /bin/sh, затем запускаю сценарий как /bin/sh ./doit.sh &, а затем аккуратно выхожу из оболочки, никакие сигналы не отправляются в фоновое задание и он продолжает выполняться до завершения.

Приложение 2

Когда я запускаю оболочку как exec /bin/csh, затем запускаю сценарий как /bin/sh ./doit.sh &, а затем аккуратно выхожу из оболочки, никакие сигналы не отправляются в фоновое задание и он продолжает выполняться до завершения.

Майк С
источник
0

Я использую csh, и фоновые процессы продолжают выполняться после выхода из системы.

Крис С
источник