터미널 에뮬레이터가 종료되면 쉘도 종료되는 이유는 무엇입니까?

터미널 에뮬레이터가 종료되면 쉘도 종료되는 이유는 무엇입니까?

터미널 에뮬레이터(예: qterminal)를 시작하면 기본 셸(예: bash)이 시작됩니다. 터미널을 종료하면(예: x 버튼을 클릭하거나 터미널을 종료하여) 셸도 종료됩니다. 쉘은 프로세스를 남기지 않습니다. 이 메커니즘이 어떻게 구현되는지 알고 싶습니다.

처음에는 터미널이 쉘에 신호를 보내고 있다고 의심했습니다. 그래서 쉘에서 SIGQUIT, SIGINT, SIGTERM, SIGHUP을 잡았지만 어떤 신호도 발견하지 못했습니다. 신호 외에는 모르겠어요.

터미널과 셸에 따라 다를 수도 있고 운영 체제에 따라 달라질 수도 있습니다. 이 상황에 대한 정보를 알려주십시오.

답변1

일반적으로 터미널은 프로세스에 중단 신호(SIGHUP)를 보냅니다. 또한 터미널이 pty의 "기본" 측면을 닫으면 터미널에 연결된 일부 프로세스도 터미널이 SIGHUP을 보내든 안 보내든 커널에서 자동으로 SIGHUP을 받습니다.

커널의 신호가 pty를 제어 터미널로 하는 모든 프로세스에 전송되지는 않지만 - 구체적으로 확인하지는 않았지만 기본적으로 SIGINT/SIGQUIT와 동일한 "프론트엔드 pgroup"에 특별히 전달되는 것 같습니다. Ctrl+C/Ctrl+\ 에서.

쉘 자체(예: Bash)에는 이미 다른 모든 쉘에 추가 SIGHUP을 보내는 SIGHUP 핸들러가 있습니다.배경 작업셸에 의해 관리됩니다( ed 무시 disown). 예를 들어 sleep 1h &a는 SIGHUP 자체를 수신했기 때문에 종료하려고 할 때 Bash에 의해 SIGHUP됩니다.

예를 들어 터미널을 깨끗하게 닫는 경우:

$ sudo strace -p ${pid_of_bash}
strace: Process 102874 attached
pselect6(1, [0], NULL, NULL, NULL, {sigmask=[], sigsetsize=8}) = ? ERESTARTNOHAND
--- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=87390, si_uid=1000} ---
--- SIGCONT {si_signo=SIGCONT, si_code=SI_KERNEL} ---
rt_sigreturn({mask=[]})                 = -1 EINTR (Interrupted system call)
--- SIGHUP {si_signo=SIGHUP, si_code=SI_KERNEL} ---
rt_sigreturn({mask=[]})                 = -1 EINTR (Interrupted system call)
[...]

close(ptmx_fd)디버거를 사용하여 터미널 프로세스에서 실행하는 경우:

$ sudo strace -p ${pid_of_bash}
pselect6(1, [0], NULL, NULL, NULL, {sigmask=[], sigsetsize=8}) = 1 (in [0])
--- SIGHUP {si_signo=SIGHUP, si_code=SI_KERNEL} ---
--- SIGCONT {si_signo=SIGCONT, si_code=SI_KERNEL} ---
rt_sigreturn({mask=[]})                 = 1
read(0, "", 1)                          = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8)  = 0
ioctl(2, TCXONC, TCOON)                 = -1 EIO (Input/output error)
write(2, "\33[?2004l\r", 9)             = -1 EIO (Input/output error)

마지막으로, pty가 닫히면 쉘(또는 다른 포그라운드 프로그램)은 pty에서 읽으려고 할 때 EOF(즉, 0 반환)를 수신 read()하고 Ctrl+D를 누르는 것처럼 이를 처리합니다. 이는 일반적으로 프로그램 나가려면 당연히 그렇지할 수 있다EOF 무시(SIGHUP을 무시하기로 결정했을 때 특정 프로그램이 이 상황에서 무한 루프에 빠지는 것을 본 적이 있습니다.그리고EOF).

쉘은 EOF에서 종료될 가능성이 높습니다.앞으로사용자 정의 SIGHUP 핸들러에 도달합니다. 예를 들어, trap ... SIGHUP그놈 터미널 아래 Bash에서 (호출되지 않고) 결과를 재현할 수 있습니다 .하지만,Bash에게 EOF에서 종료하지 말라고 추가로 지시하면 IGNOREEOF=1사용자 정의 SIGHUP 트랩이 호출됩니다.

커스텀 트랩도 발생씌우다Bash의 기본 "SIGHUP 종료" 동작입니다. 그래서 Bash에게 EOF를 무시하라고 말할 때그리고트랩 SIGHUP, 실제로는 존재하지 않는 tty에 프롬프트를 인쇄하려고 계속 시도합니다. "strace" 출력은 일반적인 PROMPT_COMMAND 후크를 모두 호출하고 stdout에 프롬프트를 쓰려고 시도하고 EIO를 가져온 다음 쓰려고 시도한다는 것을 보여줍니다. EIO에서 얻은 오류 메시지 stderr저것,그런 다음에야 충분하다고 판단하고 종료합니다.

관련 정보