web-dev-qa-db-ja.com

ログオフ時にバックグラウンドプロセスがSIGHUPを取得しますか?

この質問 のフォローアップです。

さらにいくつかのテストを実行しました。これが物理的なコンソールで行われるか、SSH経由で行われるかは問題ではないようです。また、これはSCPでのみ発生します。 cat /dev/zero > /dev/nullでもテストしました。動作はまったく同じです。

  • &を使用してバックグラウンドでプロセスを開始します(またはCTRL-Zbgを使用して開始した後にバックグラウンドで実行します);これはNohupを使用せずに行われます。
  • ログオフ。
  • 再度ログオンします。
  • プロセスはまだそこにあり、幸せに実行されており、initの直接の子になっています。

SIGHUPを送信すると、SCPとCATの両方がすぐに終了することを確認できます。私はkill -HUPを使用してこれをテストしました。

そのため、SIGHUPはログオフ時に not sent のように見えます。少なくともバックグラウンドプロセスに対して(明らかな理由でフォアグラウンドプロセスでテストすることはできません)。

これは当初、VMware ESX 3.5(RedHatベース)のサービスコンソールで起こりましたが、CentOS 5.4で正確に複製することができました。

ここでも問題です。ログオフ時に、バックグラウンドで実行されている場合でも、SIGHUPをプロセスに送信しないでください。なぜこれが起こらないのですか?


編集する

カイルの答えに従って、私はstraceで確認しました。
予想していたように、起動されたシェルからログオフしても、プロセスは any シグナルを取得しません。これは、サーバーのコンソールを使用する場合とSSH経由の場合の両方で発生します。

21
Massimo

回答が見つかりました。

BASHの場合、これはhuponexitシェルオプションに依存します。これは、組み込みshoptコマンドを使用して表示または設定できます。

このオプションは、少なくともRedHatベースのシステムでは、デフォルトでオフになっているようです。

BASH manページの詳細情報

シェルは、SIGHUPを受信するとデフォルトで終了します。終了する前に、対話型シェルは実行中または停止中のすべてのジョブにSIGHUPを再送信します。停止したジョブはSIGCONTに送信され、SIGHUPを確実に受信します。シェルが特定のジョブにシグナルを送信しないようにするには、disownビルトイン(下記のシェルの組み込みコマンドを参照)を使用してジョブテーブルから削除するか、disown -hを使用してSIGHUPを受信しないようにマークする必要があります。

Shoptでhuponexitシェルオプションが設定されている場合、bashは、対話型ログインシェルの終了時にすべてのジョブにSIGHUPを送信します。

27
Massimo

私のテストでは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 Again:

[kbrandt@kbrandt-opadmin: ~] exit
zsh: you have running jobs.
[kbrandt@kbrandt-opadmin: ~] exit
zsh: warning: 1 jobs SIGHUPed
Connection to localhost closed.

Shell2 Again

strace -e trace=signal -p1121
Process 1121 attached - interrupt to quit
pause()                                 = ? ERESTARTNOHAND (To be restarted)
--- SIGHUP (Hangup) @ 0 (0) ---
Process 1121 detached

なぜまだ動作するのですか?:
StevensによるUnix環境での高度なプログラミングは、セクション9.10:孤立したプロセスグループでこれをカバーしています。最も関連するセクションは次のとおりです。

親が終了するとプロセスグループは孤立するため、POSIX.1では、(子がそうであるように)停止した新しく孤立したプロセスグループ内のすべてのプロセスに、ハングアップ信号(SIGHUP)に続いて続行信号(SIGCONT)を送信する必要があります。 )。

これにより、ハングアップ信号を処理した後、子が続行されます。ハングアップシグナルのデフォルトのアクションはプロセスを終了することなので、シグナルをキャッチするシグナルハンドラーを提供する必要があります。したがって、sig_hup関数のprintfは、pr_ids関数のprintfの前に表示されると想定しています。

3
Kyle Brandt

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でトレースします。数回のループの後、ターミナル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の出力:

ターミナル

out 1
out 2
out 3
HUP
out 4
out 5
out 6

ただし、bashを終了すると、子にシグナルを送信せずに終了します。子がなくなったため端末は終了しますが、子シェルがすでになくなっているため、HUPを実行するユーザーがいません。以下に表示されるSIGINTSIG_BLOCKSIG_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

興味深いことに、私はhuponexitshopt -s huponexit; shoptでオンに設定し(後者のショップは確認する)、最後のテストを実行しましたbashはシグナルをバックグラウンドプロセスに送信しませんでした 。さらに興味深いことに、bashdidは、顔を閉じた端末からシグナルを受信した後で、シグナルをバックグラウンドプロセスに送信します。 huponexitにはどちらの方向にも関係がないようです。

これにより、HUP信号がいつどのように送信されるかについて、少なくともbashの幸福に関する謎や混乱が解消されることを願っています。少なくとも、私のテストは完全に再現可能でした。 bashの動作に影響を与える可能性のある他の設定があるかどうかを知りたいです。

そして、いつものように、YSMV(あなたのシェルは変わるかもしれません)。

補遺1

シェルをexec /bin/shとして実行してから、スクリプトを/bin/sh ./doit.sh &として実行し、シェルをきれいに終了すると、バックグラウンドジョブに信号が送信されず、実行が完了します。

補遺2

シェルをexec /bin/cshとして実行し、スクリプトを/bin/sh ./doit.sh &として実行し、シェルを正常に終了すると、バックグラウンドジョブに信号が送信されず、実行が完了します。

2
Mike S

私はキャッシュを使用しており、ログオフしてもバックグラウンドプロセスが実行され続けます。

0
Chris S