(2012/06/25 20:32), Tanaka Akira wrote:
> まず、SIGINT (^C) で ruby を終了できることはとても重要ですから、
> これについては即座に例外になるべきでしょう。
> 
> SIGTERM など他のシグナルも同様だと思います。
> 
> それ以外については、100% コンパチブルという話を尊重するなら、
> やはりそれも現状どおり即座に例外なんじゃないでしょうか。
> 尊重しないなら、遅延させるという選択肢もあるかもしれません。


 少し考えて見ました.考えた過程のログを書いてみるので,ご意見頂けると幸
いです.



 状態としては,やはり先のメールの

  0. なるべく頻繁にチェックする(これまで通りの動作)
  1. ブロッキング処理のタイミングだけチェックする
    2. チェックしない

の3つになるような気がしていますので,ある例外がこれら 3 つのどの状態に
するか,という API を考えてみました.

  (a) Thread.interrupt_mask(exception, state) do; end
  (b) Thread.interrupt_mask(hash) do; end

state は

  :immediate_interruptible
  :blocking_interruptible
  :uninterruptible

の 3 つのシンボルが指定できるとします.それぞれ,モード 0, 1, 2 にあたる
と考えます.

 (a) の形式は,例えば

  Thread.interrupt_mask(TimeoutError, :immediate_interruptible) do
     # block
  end

と指定すると,blcok の中では,TimeoutError で割り込まれたとき,即座に例
外を発生する,という感じです.(b) の形式は,単に {e1 => state1, e2 =>
state2, ...} のように,複数指定出来るとします.

  Thread.interrupt_mask(param1) do
    Thread.interrupt_mask(param2) do
      # block (param1 and param2)
    end
  end

 このように,ネストした場合は,block の実行は param1,param2 の両方の設
定が効くとします.ただし,ある例外についての指定が衝突した場合は,内側
(この場合 param2)の設定が有効だとします.

 とりあえず,primitive な API(を考えるネタ)として,網羅していると思う
のですが,もし考え落としておりましたらご指摘下さい(ここが勘違いしていた
ら酷い).実際に使わせるための API については,名前など,よりよいものが
あるかと思いますが,まずは primitive を.


 このとき,デフォルトは互換性 100% の方針ということで,全ての例外が
immediate_interruptible だとします.

  begin
    # 何か処理
  ensure
    # リソース解放処理
  end

という,よくありそうな処理があったとき,リソース解放処理はなるべくなら解
放されたくない,ただし,^C,もしくは SIGTERM などのシグナルは blocking
処理しそうになった,もしくはしている時は割り込まれるのを許す,という処理
は次の様になるでしょうか.

  begin
    # 何か処理
  ensure
    Thread.mask_interrupt(Exception, :uninterruptible) do
      # 一度全部割り込み禁止にして
      Thread.mask_interrupt(SignalException, :blocking_interruptible) do
        # シグナルだけ割り込みを許して
        # リソース解放処理
      end
    end
  end

 2つ書かないといけないのは,ちょっと冗長かもしれませんね.Hash で渡す
方式では,

  begin
    # 何か処理
  ensure
    Thread.mask_interrupt(Exception => uninterruptible,
                          SignalException, :blocking_interruptible) do
      # シグナルだけ割り込みを許して
      # リソース解放処理
    end
  end

となって,ちょっとマシかな?


 書いていて,出てきた疑問点です.

(1) シグナルを許すと言っても,SIGUSR1 とかも許していいのかな.
(2) POSIX みたいに,このメソッドは blocking とか,すべてきちんと
    書き連ねる必要があるのかな.かなり,無理な気がする
 (そもそも,何がどのメソッドを呼び出すかわからない気が).
(3) ライブラリの至る所でこんなの書かれたらハッシュが大量発生して,
    オーバヘッドで大変になったりしないだろうか....
    そもそも,これって多用するんだろうか.
(4) ブロックを持たない Thread.mask_interrupt() は許すべきだろうか.
 (意味としては,「この呼び出し以降はこの設定で」,という感じ)
    なんとなく,許さない方がいいような気がするんだけど
(5) Thread.mask_interrupt() はネストしたら設定を混ぜていく,としたけど
    単に,置き換える,という選択肢もあるのか.こっちのほうが使いやすい?

-- 
// SASADA Koichi at atdot dot net
// interruptible って単語でいいのかな.スペルチェックにひっかかる.