로그 오프 할 때 백그라운드 프로세스가 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이 백그라운드에서 실행 중이더라도 로그 오프시 프로세스로 전송되어서는 안된다는 것입니다. 왜 이런 일이 일어나지 않습니까?


편집하다

straceKyle의 답변에 따라으로 확인했습니다 .
내가 기대 한대로, 프로세스는하지 않는 어떤 이 시작된 쉘에서 로그 오프 할 때 신호를. 서버 콘솔을 사용하거나 SSH를 통해이 문제가 발생합니다.


CentOS 7.1에서 Bash를 사용하면 간단한 쉘 스크립트 루프가 포 그라운드에 남아 있지만 터미널이 종료되면 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 +++
— Mike S

테스트에 대한 내 대답을 참조하십시오. 흥미롭게도로 인해 행동에 변화가 없었습니다 huponexit.
— Mike S

답변:


26

답변을 찾았습니다.

BASH의 경우 이는 huponexit내장 옵션을 사용하여 보거나 설정할 수있는 쉘 옵션 에 따라 다릅니다 shopt.

이 옵션은 최소한 RedHat 기반 시스템에서 기본적으로 해제되어 있습니다.

BASH 매뉴얼 페이지 에 대한 추가 정보 :

SIGHUP을 받으면 기본적으로 쉘이 종료됩니다. 종료하기 전에 대화식 쉘은 SIGHUP을 실행 또는 중지 된 모든 작업으로 다시 보냅니다. 중지 된 작업은 SIGHUP을 수신 할 수 있도록 SIGCONT로 전송됩니다. 쉘이 특정 작업으로 신호를 보내지 못하게하려면 disown 내장 (아래 쉘 구현 명령 참조)이있는 작업 테이블에서 제거하거나 disown -h를 사용하여 SIGHUP을 수신하지 않도록 표시해야합니다.

huponexit 쉘 옵션이 shopt로 설정된 경우, bash는 대화식 로그인 쉘이 종료 될 때 모든 작업에 SIGHUP을 보냅니다.


4
확인되었습니다. "종료", "로그 아웃"또는 CTL-D를 수행 할 때 하위 proc (작업)은 sighup (루트 및 reg 사용자 모두)을받지 못합니다. 그러나 현재 bash 인스턴스를 종료하기 위해 "kill -HUP $$"를 수행하면 자식 프로세스 DID에 한숨이 생깁니다. 그런 다음 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

쉘 2 :

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

왜 여전히 실행
됩니까 ? : Stevens의 유닉스 환경에서의 고급 프로그래밍은 섹션 9.10 : 고아 프로세스 그룹에서 다루고 있습니다. 가장 관련성이 높은 섹션은 다음과 같습니다.

부모가 종료 될 때 프로세스 그룹이 분리되므로 POSIX.1에서는 새로 분리 된 프로세스 그룹의 모든 프로세스 (중지 된 하위 프로세스)에 중단 신호 (SIGHUP)와 계속 신호 (SIGCONT)를 보내야합니다. ).

이로 인해 끊기 신호를 처리 한 후 자식이 계속됩니다. 끊기 신호의 기본 동작은 프로세스를 종료하는 것이므로 신호를 잡기 위해 신호 처리기를 제공해야합니다. 따라서 sig_hup 함수의 printf가 pr_ids 함수의 printf 앞에 나타날 것으로 예상합니다.


그러나 여기에 SIGHUP을 명시 적으로 보냈습니다. 프로세스를 시작한 셸에서 로그 오프하면 어떻게되는지에 대해 이야기했습니다.
— Massimo

작업에 대한 경고가 표시되지만 종료를 다시 입력해도 종료를 입력 할 때와 동일한 결과 나는 이것을 ZSH로 테스트했다.
— Kyle Brandt

BASH를 사용하고 있으며 아마도 셸에 따라 다릅니다. 그러나 BASH 는 로그 오프 할 때 SIGHUP을 자식 프로세스로 보내야합니다.
— Massimo

Bash는 작업이 중지되면 분명히 SIGCONT를 보내지 만 작업이 중지되지 않으면 아무것도 보내지 않는다는 것을 확인합니다.
— Kyle Brandt

CentOS 7.1에서 Bash를 사용하면 다른 창에서 프로세스로 전송 된 SIGTERM이 다른 창에서 중지됩니다. 다른 창, 4) 원래 터미널을 종료하십시오. 그것은 내가 작업을 실행 한 다음 내 strace 쇼를 종료 한 후 : $ 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 +++ Odd, Stevens에서 인용 한 섹션과 일치하지 않는다고 불평합니다 .
— Mike S

2

CentOS 7.1 및 bash를 사용하여 몇 가지 테스트를 실행했습니다. 이 방법을 참고 huponexit입니다 off기본적으로 내 테스트의 대부분을 벗어났다.

당신은 필요 nohup터미널에서 작업을 시작할 때 때문에, 당신은 가까운 깨끗하게 쉘을 종료하지 않고 터미널한다는 경우 는 터미널이 모든 아이들에게 보내는 쉘에 SIGHUP 신호를 bash는 보냅니다. 쉘을 깨끗하게 종료하면 작업이 이미 백그라운드에 있어야 exit명령 프롬프트에서 Control-D를 입력 하거나 칠 수 있습니다-bash 에서 백그라운드 작업으로 어떤 종류의 신호도 보내지 않습니다.

테스트:

터미널 1

$ echo $$
16779

터미널 2

$ strace -e signal -p16779
Process 16779 attached

(터미널 2에서 볼 수있는 터미널 1을 닫으십시오) :

--- 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에서 in니다. 몇 번의 루프 후 터미널 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

흥미롭게도, I 세트 huponexit로에있을 shopt -s huponexit; shopt다음 (검토 후자 shopt 내부) 최종 검사를 행하고, 다시 배시 백그라운드 프로세스에 어떠한 신호도 전송되지 . 훨씬 더 간결하게, 우리가 bash 가 신호를 닫은 터미널에서 신호를받은 후 백그라운드 프로세스로 신호를 보내는 것을 보았습니다 . 그것은 huponexit어떤 식 으로든 베어링을 가지고 있지 않은 것처럼 보입니다 .

이것이 HUP 신호가 언제 어떻게 전송되는지에 관한 적어도 bash의 행복에 관한 수수께끼 나 혼란을 제거하기를 바랍니다. 적어도 내 테스트는 완전히 재현 가능했습니다. bash의 동작에 영향을 줄 수있는 다른 설정이 있는지 알고 싶습니다.

그리고 항상 그렇듯이 YSMV (Shell May Vary).

부록 1

으로 셸 exec /bin/sh을 실행 한 다음으로 스크립트를 실행 /bin/sh ./doit.sh &한 다음 셸을 완전히 종료하면 백그라운드 작업으로 신호가 전송되지 않고 완료로 계속 실행됩니다.

부록 2

으로 셸 exec /bin/csh을 실행 한 다음으로 스크립트를 실행 /bin/sh ./doit.sh &한 다음 셸을 완전히 종료하면 백그라운드 작업으로 신호가 전송되지 않고 완료로 계속 실행됩니다.


0

csh를 사용하고 로그 오프 할 때 백그라운드 프로세스가 계속 실행됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.