バックグラウンドプロセスはログオフ時に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をプロセスに送信するべきではありませんか?なぜこれが起こらないのですか?


編集

straceカイルの答えに従って、私はで確認しました。
私は期待していたように、プロセスは取得していない任意のそれが開始されたシェルからログオフするときに信号を。これは、サーバーのコンソールを使用する場合と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
マイク・S

バックグラウンドスクリプトも同様です。ループがスリープを待機している間、ターミナルが閉じられることに注意してください。シェルは終了していません:--- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=13944, si_uid=3000090} --- +++ killed by SIGHUP +++
マイク・Sを

テストについては私の答えをご覧ください。興味深いことに、私はによる行動の変化を見ませんでしたhuponexit
マイクS

回答:


26

答えが見つかりました。

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

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

BASHのマニュアルページの詳細:

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

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


4
確認済み。「exit」、「logout」、またはCTL-Dを実行したときに、子プロセス(ジョブ)がシグアップ(rootおよびregユーザーの両方)を受信しません。ただし、bashの現在のインスタンスを強制終了するために「kill -HUP $$」を実行すると、子プロセスDIDが溜息を受け取ります。次にhuponexitを設定し、子プロセスは終了時にSIGHUPを受け取りました。
CarpeNoctem

3

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

[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

なぜそれがまだ実行されるのですか?:
スティーブンスによるUnix環境での高度なプログラミングは、セクション9.10:孤立プロセスグループでこれをカバーします。最も関連するセクションは次のとおりです。

親が終了するとプロセスグループは孤立するため、POSIX.1では、(子として)停止した新しく孤立したプロセスグループ内のすべてのプロセスに、ハングアップシグナル(SIGHUP)に続いて継続シグナル(SIGCONT )。

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


ただし、ここに明示的にSIGHUPを送信しました。プロセスを開始したシェルからログオフするとどうなるかについて話していました。
マッシモ

exitと入力しても同じ結果になりますが、ジョブに関する警告が表示されますが、exitと再度入力します。これをZSHでテストしました。
カイルブラント

私はBASHを使用していますが、これはおそらくシェルに依存しています。ただし、BASH ログオフ時にSIGHUPを子プロセスに送信する必要があります...-
Massimo

Bashは、ジョブが停止している場合は明らかにSIGCONTを送信しますが、ジョブが停止していない場合は何も送信しないことを確認しています。
カイルブラント

CentOS 7.1でBashを使用すると、プロセスに送信されたSIGTERMが別のウィンドウで停止します。1。)単純なシェルスクリプトを開始します(エコーとスリープのループ)、2。)Control-Z it、3)プロセスを追跡します別のウィンドウ、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 +++ 奇妙なことに、Stevensから引用されたセクションとは明らかに一致していません。
マイクS

2

CentOS 7.1とbashを使用していくつかのテストを実行しました。この手段huponexitoffデフォルトであり、私のテストの大部分ではオフであったことに注意してください。

nohupターミナルでジョブを開始するときに必要なのは、シェルをきれい終了せずにターミナルを閉じるとターミナルが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には誰もいません。SIGINTSIG_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

おもしろいことに、私huponexitshopt -s huponexit; shopt(レビューする後者のショップ)をオンにして、最後のテストを実行し、再びbashはバックグラウンドプロセスにシグナルを送信しませんでした。さらに興味深いことに、bash 、閉じられた端末から信号を受信した後、バックグラウンドプロセスに信号を送信しました。しかしとして思えるhuponexit何の関係一つの方法または他のを持っていました。

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

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

補遺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.