解決策 1:
答えが見つかりました。
BASH の場合、これは huponexit
に依存します。 組み込みの shopt
を使用して表示および/または設定できる shell オプション コマンド。
少なくとも RedHat ベースのシステムでは、このオプションはデフォルトでオフになっているようです。
詳細については、BASH の man ページを参照してください:
<ブロック引用>デフォルトでは、シェルは SIGHUP を受け取ると終了します。終了する前に、対話型シェルは、実行中または停止中のすべてのジョブに SIGHUP を再送信します。停止したジョブには SIGCONT が送信され、SIGHUP を確実に受信できるようになります。シェルが特定のジョブにシグナルを送信しないようにするには、ジョブ テーブルから disown ビルトイン (以下のシェルの組み込みコマンドを参照) を使用して削除するか、disown -h を使用して SIGHUP を受信しないようにマークする必要があります。
huponexit シェル オプションが shopt で設定されている場合、対話型ログイン シェルが終了すると、bash はすべてのジョブに SIGHUP を送信します。
解決策 2:
テストでは SIGHUP で送信されます:
シェル1:
[[email protected]: ~] ssh localhost
[[email protected]: ~] perl -e sleep &
[1] 1121
[[email protected]: ~] 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 再び:
[[email protected]: ~] exit
zsh: you have running jobs.
[[email protected]: ~] exit
zsh: warning: 1 jobs SIGHUPed
Connection to localhost closed.
再びシェル 2 :
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:Orphaned Process Groups で説明しています。最も関連性の高いセクションは次のとおりです:
親プロセスが終了するとプロセス グループは孤立するため、POSIX.1 では、新たに孤立したプロセス グループ内の (子プロセスのように) 停止されたすべてのプロセスに、ハングアップ シグナル (SIGHUP) に続いて続行シグナル (SIGCONT) を送信する必要があります。
これにより、ハングアップ シグナルを処理した後、子プロセスが続行されます。ハングアップ シグナルのデフォルトのアクションは、プロセスを終了することです。したがって、sig_hup 関数の printf が pr_ids 関数の printf の前に現れることが期待されます。
解決策 3:
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
のようです どちらにしても関係がありませんでした.
これにより、HUP シグナルがいつ、どのように送信されるかについて、少なくとも bash の幸せに関する謎や混乱が解消されることを願っています。少なくとも、私のテストは完全に再現可能でした。 bash の動作に影響を与えている可能性のある設定が他にあるかどうか知りたいです。
そして、いつものように、YSMV (Your Shell May Vary)
補遺 1
exec /bin/sh
としてシェルを実行すると 、次にスクリプトを /bin/sh ./doit.sh &
として実行します 、その後、シェルを正常に終了します。バックグラウンド ジョブにシグナルは送信されず、完了まで実行され続けます。
補遺 2
exec /bin/csh
としてシェルを実行すると 、次にスクリプトを /bin/sh ./doit.sh &
として実行します 、その後、シェルを正常に終了します。バックグラウンド ジョブにシグナルは送信されず、完了まで実行され続けます。