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