Windowsがシャットダウンするとき、動作中のrubyプログラムはどうなるのか?

まあ強制終了されるのだけど。
普通、rubyプログラムは外部から強制終了させられるとき(INTシグナルが送られてきた時)はInterrupt例外を吐いて死ぬのだけど、OS自体がシャットダウンするときはどうなるのか?今回はWindows7で確かめてみた。ちなみにRubyruby 2.1.5p273 [i386-mingw32]というのを使った。
こんなプログラムを書いて実験してみた。

  • loop1.rb
while(true) do
  puts "working!"
  sleep 1
end

これを普通にCtrl+Cで強制終了するとまあ、以下のようになる。これは当たり前。

> ruby loop1.rb
working!
working!
working!
loop1.rb:3:in `sleep': Interrupt
  from loop2.rb:3:in `<main>'

今度は実行中にWindowsをシャットダウンしてみる。
シャットダウンした後にもう一度Windowsを立ち上げて実行結果を確かめられるように、標準出力と標準エラー出力をファイルに出すことにした。

> ruby loop1.rb > AAA.TXT 2> BBB.TXT

結果はAAA.TXTもBBB.TXTも空白。なんだそりゃ。
なぜ何も出力されないかを考えてみる。

  1. INTシグナル以外のシグナルが送られて来たことにより強制終了したため、Interrupt例外が発生しなかった。(INT以外のシグナルでも発生するかもしれないけど)
  2. シャットダウンの時は何のシグナルも送ってこず、ただ強制終了させられた。
  3. 何かしらのシグナルが送られてきたが、ruby側で捕捉する間もなく強制終了させられた。

とりあえずシャットダウンの時にシグナルが送られてきて、捕捉されるかどうかだけでも確かめたい。
以下の様なプログラムにしてみた。

  • loop2.rb
trap(:INT) { p "INT";exit }
#trap(:ILL) { p "ILL" }
#trap(:FPE) { p "FPE" }
#trap(:SEGV) { p "SEGV" }
trap(:TERM) { p "TERM";exit }
#trap(:BREAK){ p "BREAK" }
trap(:ABRT) { p "ABRT";exit }
trap(:EXIT) { p "EXIT";exit }

while(true) do
  puts "working!"
  sleep 1
end

リファレンスによれば、WindowsrubyではINT ILL FPE SEGV TERM BREAK ABRT EXITのシグナルが捕捉できる。
http://docs.ruby-lang.org/ja/2.1.0/class/Signal.html
ただし、ILL FPE SEGV BREAKはtrapメソッドの引数に指定すると実行時エラーになるのでコメントにした。
普通に実行してCtrl+Cで強制終了した場合*1は以下の様な出力になる。

> ruby loop2.rb
working!
working!
working!
"INT"
"EXIT"

*2
じゃあさっきと同じようにしてプログラムを起動し、Windowsをシャットダウンしてみる。

> ruby loop2.rb > AAA.TXT 2> BBB.TXT

そして、Windowsを立ち上げてAAA.TXTとBBB.TXTをテキストエディタで開いてみると。。
結果は空白。何にも出力されていなかった。

てなわけでrubyプログラムの実行中にWindowsをシャットダウンした時の動作は、

  • 何のシグナルも送ってこず、ただ強制終了させられる。
  • 何かしらのシグナルが送られるが、ruby側で捕捉する間もなく強制終了させられる。

の2つが濃厚なようです。あと、rubyで捕捉できないシグナルが送られてくる、っていうのも考えられるか。。

追記:2015/3/15
タスクマネージャーから強制終了したらどうなるのか?
気になったので試してみたらシャットダウンの時と同じ動きでした。



以下余談
こんなことを考えたのは、エラーログをなにも吐かずに異常終了したプログラム*3があって、なんとか終了した原因を知りたいというのがありました。やっぱり実行中にPC再起動しちゃったんじゃないかなあ。。WindowsUpdateとかだってあるかもしれんし。という疑いはあるのですが、証拠はありません。
それならOSのシャットダウンをRuby側で捕捉できるようにすれば、動かぬ証拠を記録できるのでは?と考えたのです。しかし結局ダメだった。

*1:本当は強制終了ではなくシグナルを捕捉した上で正常終了する。

*2:最後に”EXIT”が出ているのはINTを捕捉した後、exitメソッドを呼んだことによりEXITシグナルが送られてきたため。

*3:処理が終わるのにすっごく時間がかかる