로그 오프 할 때 백그라운드 프로세스가 SIGHUP을 얻습니까?


21

이것은 이 질문에 대한 후속 조치 입니다.

테스트를 더 진행했습니다. 실제 콘솔에서 또는 SSH를 통해 수행되는지 여부는 실제로 문제가되지 않으며 SCP에서만 발생하지 않습니다. 나는 또한 그것을 테스트했다 cat /dev/zero > /dev/null. 동작은 정확히 같습니다 :

  • 사용하여 백그라운드에서 프로세스를 시작합니다 &(또는 사용하기 시작이야 후 배경에 넣어 CTRL-Zbg); 이 사용하지 않고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.