著作一覧 |
しょっちゅうぶちぶち切れる回線経由でSolarisをいじくっているわけだが、ぶちぶち切れてはたまらないようなことをするときは、nohupする。
というのは、回線が切れてシェルが落ちるときにSIGHUPというシグナルを掴まされて、そのままだとプロセス自体が終わってしまうからだ。
nohup java -cp foo/bar.jar LongLongTimeConsumedJob
とやっておくと、nohupがSIGHUPとSIGQUITを無視するように設定して、さらに既定ではnohup.outというファイルに標準出力とエラーをリダイレクトするようにしてからコマンドを実行するからだ。したがって、ネットワークが切断されてSIGHUPが上がっても問題なし。
しかし、ときたま妙なことに気づいた。例外を吐いているわけでもないのに途中で処理が中断しているのだ。nohup.outを見てもさっぱり理由がわからない。
あるとき、ターミナルを動かしているマシンから離れてしばらくして戻ってくると、TeraTermが終了させられていた。まあ共用ターミナルだしなぁと思いながらふと気づくとネットワークは繋がったままになっている。で、再度ログインして……とやるとやはりジョブが中断している。ということは、待てよと気づく。
include <stdio.h> include <signal.h> void sigh(int sig) { printf("signal %d", sig); fflush(stdout); } int main(int argc, char* argv[]) { char wait[128]; signal(SIGHUP, sigh); signal(SIGQUIT, sigh); ... gets(wait); return 0; }
というプログラムを作ってnohup ./a.out
して、おもむろに、TeraTermのXボタンをクリックすると、ああ、SIGHUPと一緒にSIGTERMも来ているのだった。えーそういうものなのかなぁ? なんか納得がいかない(回線ぶち切れのときはSIGHUPだけだし)けど。でも、SIGTERMというくらいだから(いや、terminateというtermはわかっているのだが)、ターミナル(ここではTeraTermの意味)には意図的なクローズ時に実行するプロトコルがあるのだろう(sshといってもアプリケーション層のプロトコルはTELNETだろうからメタコマンドは使えるはず)。で、サーバー側はその結果としてSIGTERMを上げる。
というわけで、nohupするときは、&を付けてシェルから切り離しておかないとだめだよ、ということだった。
追記:ブクマコメに反応してちょっと(手)を入れた。やっぱりTeraTermが気を利かせてると考えるよね
さらに追記:TeraTermのソースをつい読んでみたがOnCloseとOnDestroyで処理しているのか。これはわかりやすい。で、IAC(TELNETのコマンド開始文字)を使う処理は行ってなかった。ということはどうやってtty(だと思った)は違いを見てるんだろ。RASのサーバは別マシンだからTCP接続になってるわけだし、RST/FINでSIGTERM、キープアライブ(あるのか?)タイムアウトでSIGHUPのみとか。
追記(3/2) というか、気づいたが、シェルそのものが生きているんだろうな(いきなり断線した場合)。で、そのうち人知れずアクティビティタイムアウトで死ぬ=そのときはnohupしたプロセスもSIGTERMで死ぬ
ジェズイットを見習え |