Фоновые процессы получают SIGHUP при выходе из системы?
Это продолжение этого вопроса.
Я провел еще несколько тестов; похоже, что на самом деле не имеет значения, выполняется ли это на физической консоли или через 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.
4 ответа
Ответ найден.
Для BASH это зависит от huponexit
опция оболочки, которую можно просматривать и / или устанавливать с помощью встроенного shopt
команда.
Похоже, эта опция отключена по умолчанию, по крайней мере, в системах на базе RedHat.
Больше информации на странице руководства BASH:
Оболочка выходит по умолчанию при получении SIGHUP. Перед выходом интерактивная оболочка отправляет SIGHUP всем работам, запущенным или остановленным. Остановленные задания отправляются SIGCONT, чтобы гарантировать получение SIGHUP. Чтобы предотвратить отправку оболочкой сигнала определенному заданию, его следует удалить из таблицы заданий с помощью встроенной команды disown (см. Ниже КОМАНДЫ СОСТАВЛЕНИЯ ОБОЛОЧКИ) или отметить, что она не получает SIGHUP с помощью команды disown -h.
Если параметр оболочки huponexit был установлен с помощью shopt, bash отправляет SIGHUP всем работам при выходе из интерактивной оболочки входа.
Он будет отправлен 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.
Я провел несколько тестов, используя 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
(последний просмотрел), затем выполнил последний тест и снова bash не отправил сигнал фоновому процессу. Даже более, как мы уже видели, bash отправил сигнал фоновому процессу после того, как получил его от терминала, который закрылся на его лице. Кажется как будто huponexit
не имел никакого отношения в ту или иную сторону.
Я надеюсь, что это устранит любую тайну или путаницу относительно, по крайней мере, счастья Баша, о том, когда и как отправляется сигнал HUP. По крайней мере, мои тесты были полностью воспроизводимы для меня. Мне было бы интересно узнать, есть ли другие параметры, которые могут влиять на поведение bash.
И, как всегда, YSMV (ваша оболочка может меняться).
Приложение 1
Когда я запускаю оболочку как exec /bin/sh
затем запустите скрипт как /bin/sh ./doit.sh &
, затем аккуратно выйдите из оболочки, никакие сигналы не отправляются в фоновое задание, и оно продолжает выполняться до завершения.
Приложение 2
Когда я запускаю оболочку как exec /bin/csh
затем запустите скрипт как /bin/sh ./doit.sh &
, затем аккуратно выйдите из оболочки, никакие сигналы не отправляются в фоновое задание, и оно продолжает выполняться до завершения.
Я использую csh, и фоновые процессы продолжают выполняться после выхода из системы.