ruby-dev (Japanese) list archive (unofficial mirror)
 help / color / mirror / Atom feed
* [ruby-dev:45341] 非同期割り込みに対する対処案(日本語版)
@ 2012-03-11 11:35 SASADA Koichi
  2012-03-11 12:01 ` [ruby-dev:45342] 非同期割り込みに対する対処案(日本語版) Kazuo Ishii
                   ` (3 more replies)
  0 siblings, 4 replies; 28+ messages in thread
From: SASADA Koichi @ 2012-03-11 11:35 UTC (permalink / raw
  To: ruby developers list

 ささだです.

 開発会議で出た「非同期割り込みがこの先生き残るには」という議論を,とり
あえず日本語でまとめました.まだあまりまとまっていない(すみません)の
で,すみませんが日本語で出させて下さい&突っ込んで下さい.

 あとで英語化したいと思います(してくれると嬉しい).英語化できたら,今
後はそっちということで.



用語:
・trap ハンドラ:trapで登録するシグナルが来たときに行うブロック
  trap(SIGINT){ ... } の ... 部分

・非同期割り込み:Thread#raise や trap ハンドラなど,意図しない
  イベントを,ここでは非同期割り込みと呼ぶ
 (他にもあったら教えて下さい)

・割り込みチェック:非同期例外があるかどうかチェックし,もしあれば
  例外を発生刺せたり trap ハンドラを実行したりする

・ブロッキング処理:I/O などで,ブロックするかもしれない処理.


概要:
 非同期割り込みをチェックするタイミングを制御する primitive を提供す
る.制御の種類は次の通り,
  0. なるべく頻繁にチェックする(これまで通りの動作)
  1. ブロッキング処理のタイミングだけチェックする
    2. チェックしない
 ただし.チェックする例外クラス(の祖先)は指定できる.
 なので,SignalException (を継承した Interrupt)は頻繁にチェックする,
すなわち Ctrl+C はだいたい効く,しかし,TimeoutError のような例外は安全
なところまで遅延して処理するといった挙動が容易に記述できる.


背景:
 Thread#raise を使うと,スレッドに対していろんなちょっかいを出すことが
できる.また,trap(signal){...} とすると,任意のシグナルについて対応する
ことができる.

  # 例1
  th = Thread.new{
    begin
      ...
    rescue NantokaError
      ...
    end
  }
  th.raise(NantokaError) #=> th に NantokaError を強制的に引き起こす


  # 例2
  q = Queue.new
  th1 = Thread.new{
    q << calc_in_algorithm1
  }
  th2 = Thread.new{
    q << calc_in_algorithm2
  }
  result = q.pop
  th1.raise(TerminateCalcError)
  th2.raise(TerminateCalcError)
  # アルゴリズム1,2 で計算して,どちらか先に答えが出たら,
  # もう1つのほうを止める


  # 例3
  trap(SIGINT){
    # 何か後処理
  }
  trap(SIGHUP){
    # 何か reload 処理
  }
  server_exec # サーバの処理

 なお,現在の割り込みチェックは,RUBY_VM_CHECK_INTS() で行っており,メ
ソッドの起動時,リターン時,前方へのジャンプ時,ブロッキング処理の前後で
行っている.


問題点:

 Thread#raise だとかが上がってくるタイミングは制御できないので,例えば
ensure 中で後処理をしていた場合に困る.

 例えば,例4 は timeout の実装(の簡略版)ですが,yield で起動したブ
ロック中で,ensure を用いて何か資源の後始末をしていたとしても,その後始
末中に(ensure 節実行中に)TimeoutError が発生してしまう可能性がある.

  # 例4
  def timeout(sec)
    timer_thread = Thread.new(Thread.current){|parent|
      sleep(sec)
      parent.raise(TimeoutError)
    }
    begin
      yield
    ensure
      timer_thread.stop # close thread
    end
  end

  timeout(3){
    begin
      f = open(...)  # open(...){|f| ...} でいいんだけど,まぁ例として
    ensure
      f.close
    end
  }

  では,ensure だけでいいのか,というと,それ以外にも問題がある.例えば
次に示す例5について考える.

  # 例5
  begin
    f = open(...)
  ensure
    f.close if f
  end

 open(...) で開いたものを,"f =" でローカル変数に代入が完了する前に割り
込まれたとき,f は nil のままなので ensure で close されない.この例の
File の場合は GC で閉じることも可能だが,解放を必須とする資源一般を考え
ると問題である.

 この点について,例えば,行末まで割り込みを許さない(行末だけチェックす
る),といった解決案も提案されたが,"f =" や "open(...)" がもっと複雑
だった場合,その解決では無理である(例えば,"foo.bar =" は複数行のメソッ
ドの場合がある).


提案:
 非同期割り込みをチェックするタイミングを制御するための仕組みを新設す
る.原案は [1] にあるとおり.ただ,名前については今後検討する.

 制御の種類は次の通り,
  0. なるべく頻繁にチェックする(これまで通りの動作)
  1. ブロック I/O のタイミングだけチェックする
    2. チェックしない

 0 はこれまで通り.

 1 は,POSIX thread の cancellation point らしい.長時間ブロックする処
理は Thread#raise やシグナルでキャンセルすることが可能.

 2 は,一切チェックしない.完全に非同期割り込みセーフに処理することが可能.

 ただし.チェックする例外クラス(の祖先)は指定できるようにする.これに
より,例えば SignalException (を継承した Interrupt)は頻繁にチェックす
る,すなわち Ctrl+C はだいたい効く,しかし,TimeoutError のような例外は
安全なところまで遅延して処理するといった挙動が容易に記述できる.


議論:

・デフォルトをどのモード(前節 0〜2 のこと)にするか?
 ・モード 1 で困る人はどれくらいいるか?
 (いないならデフォルトこれでいいんでは?)
 ・計算スレッドは止めても困らないので,例2のような場合はこれまで
  通り止めたい,という,モード 0 を期待する例はある.
・ensure 実行時に自動的にモードを変更するか?

※ええと,すみません,いろんな議論があったと思いましたが,誰か補完して下
さい....


余談(というか TODO):
 rb_blocking_region() 時に強制的に終了時に CHECK_INTS() しているのはけ
しからんので,CHECK_INTS() を呼び出し側でさせるバージョンを作るべきである.

 例えば,

  blocking_region{
    data = read(...)
  }

  とあったとき,data が到達しているのならば,割り込んで欲しくないはずで
ある.ただし,data が到達する前に割り込みで中断していれば,CHECK_INTS()
により例外を発生させるべきである.この判断は rb_bocking_region() 利用者
しかできないので,その判断をさせるべきである.


参考文献:
[1] Akira Tanaka "Re: Thread#raise, Thread#kill, and timeout.rb are
unsafe" ruty-talk (2008.3)
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/294917


謝辞:
 この議論は,3/11 10:00から開催されたRuby開発者会議で行われました.参加
者は田中さん,nahi さん,たるいさん,mrkn さん,skype 越しに小崎さん,中
田さん,sora さん,遠藤さんでした.朝もはよからありがとうございました.

-- 
// SASADA Koichi at atdot dot net

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [ruby-dev:45342] Re: 非同期割り込みに対する対処案(日本語版)
  2012-03-11 11:35 [ruby-dev:45341] 非同期割り込みに対する対処案(日本語版) SASADA Koichi
@ 2012-03-11 12:01 ` Kazuo Ishii
  2012-03-11 12:27 ` [ruby-dev:45343] " NISHIYAMA Tomoaki
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 28+ messages in thread
From: Kazuo Ishii @ 2012-03-11 12:01 UTC (permalink / raw
  To: ruby developers list

石井と申します。

本日、途中、11時から2時間ほど、参加させていただきました。
午後から他の用事があったので失礼させていただきました。
本日は興味深い議論を拝見させていただき、ありがとうございます。

普段はデータ解析にRuby  を含めいろいろな言語を使用していますが、
言語の実装を含め開発にも興味を持っています。

今後ともよろしくお願いいたします。

12/03/11 SASADA Koichi <ko1@atdot•net>:
>  ささだです.
>
>  開発会議で出た「非同期割り込みがこの先生き残るには」という議論を,とり
> あえず日本語でまとめました.まだあまりまとまっていない(すみません)の
> で,すみませんが日本語で出させて下さい&突っ込んで下さい.
>


-- 
Kazuo Ishii, Ph.D., Professor of Genome Science,
Tokyo University of Agriculture and Technology
3-5-8 Saiwai-cho, Fuchu, Tokyo 183-8509, JAPAN

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [ruby-dev:45343] Re: 非同期割り込みに対する対処案(日本語版)
  2012-03-11 11:35 [ruby-dev:45341] 非同期割り込みに対する対処案(日本語版) SASADA Koichi
  2012-03-11 12:01 ` [ruby-dev:45342] 非同期割り込みに対する対処案(日本語版) Kazuo Ishii
@ 2012-03-11 12:27 ` NISHIYAMA Tomoaki
  2012-03-12  3:24 ` [ruby-dev:45345] " Masaya TARUI
  2012-06-25  9:26 ` [ruby-dev:45816] " SASADA Koichi
  3 siblings, 0 replies; 28+ messages in thread
From: NISHIYAMA Tomoaki @ 2012-03-11 12:27 UTC (permalink / raw
  To: ruby developers list; +Cc: NISHIYAMA Tomoaki

議論には参加していませんが、概要まで訳してみました。

How can asynchronous interrupt survive

Terms
trap handler: a block that should be executed when a signal registered to trap
	the content (...) of trap(SIGINT){...}

asynchronous interrupt: unintended event such as Thread#raise or trap handler

意図しないってなんか変じゃありません?

Interrupt check: Determine if there is any asynchronous exception (未定義),
	and raise an error or invoke trap handler if there is any exception.

Blocking procedure: a procedure that may be blocked including I/O

Summary
	Ruby will provide a primitive to regulate the timing to check
for the asynchronous interrupt. Three kinds of regulation should be
provided
	0. check as frequently as possible (this is the current behaviour)
	1. check at a blocking procedure.
	2. don't check
Note that the behaviour can be specified per exception class.
Therefore, SignalException and its descendants are checked frequently.
This enables to write a code that Ctrl-C cause interrupt but 
exceptions like TimeoutError are delayed to a safe point.


On 2012/03/11, at 20:35, SASADA Koichi wrote:

>  ささだです.
> 
>  開発会議で出た「非同期割り込みがこの先生き残るには」という議論を,とり
> あえず日本語でまとめました.まだあまりまとまっていない(すみません)の
> で,すみませんが日本語で出させて下さい&突っ込んで下さい.
> 
>  あとで英語化したいと思います(してくれると嬉しい).英語化できたら,今
> 後はそっちということで.
> 
> 
> 
> 用語:
> ・trap ハンドラ:trapで登録するシグナルが来たときに行うブロック
>   trap(SIGINT){ ... } の ... 部分
> 
> ・非同期割り込み:Thread#raise や trap ハンドラなど,意図しない
>   イベントを,ここでは非同期割り込みと呼ぶ
>  (他にもあったら教えて下さい)
> 
> ・割り込みチェック:非同期例外があるかどうかチェックし,もしあれば
>   例外を発生刺せたり trap ハンドラを実行したりする
> 
> ・ブロッキング処理:I/O などで,ブロックするかもしれない処理.
> 
> 
> 概要:
>  非同期割り込みをチェックするタイミングを制御する primitive を提供す
> る.制御の種類は次の通り,
>   0. なるべく頻繁にチェックする(これまで通りの動作)
>   1. ブロッキング処理のタイミングだけチェックする
>    2. チェックしない
>  ただし.チェックする例外クラス(の祖先)は指定できる.
>  なので,SignalException (を継承した Interrupt)は頻繁にチェックする,
> すなわち Ctrl+C はだいたい効く,しかし,TimeoutError のような例外は安全
> なところまで遅延して処理するといった挙動が容易に記述できる.
> 
> 
> 背景:
>  Thread#raise を使うと,スレッドに対していろんなちょっかいを出すことが
> できる.また,trap(signal){...} とすると,任意のシグナルについて対応する
> ことができる.
> 
>  # 例1
>  th = Thread.new{
>    begin
>      ...
>    rescue NantokaError
>      ...
>    end
>  }
>  th.raise(NantokaError) #=> th に NantokaError を強制的に引き起こす
> 
> 
>  # 例2
>  q = Queue.new
>  th1 = Thread.new{
>    q << calc_in_algorithm1
>  }
>  th2 = Thread.new{
>    q << calc_in_algorithm2
>  }
>  result = q.pop
>  th1.raise(TerminateCalcError)
>  th2.raise(TerminateCalcError)
>  # アルゴリズム1,2 で計算して,どちらか先に答えが出たら,
>  # もう1つのほうを止める
> 
> 
>  # 例3
>  trap(SIGINT){
>    # 何か後処理
>  }
>  trap(SIGHUP){
>    # 何か reload 処理
>  }
>  server_exec # サーバの処理
> 
>  なお,現在の割り込みチェックは,RUBY_VM_CHECK_INTS() で行っており,メ
> ソッドの起動時,リターン時,前方へのジャンプ時,ブロッキング処理の前後で
> 行っている.
> 
> 
> 問題点:
> 
>  Thread#raise だとかが上がってくるタイミングは制御できないので,例えば
> ensure 中で後処理をしていた場合に困る.
> 
>  例えば,例4 は timeout の実装(の簡略版)ですが,yield で起動したブ
> ロック中で,ensure を用いて何か資源の後始末をしていたとしても,その後始
> 末中に(ensure 節実行中に)TimeoutError が発生してしまう可能性がある.
> 
>  # 例4
>  def timeout(sec)
>    timer_thread = Thread.new(Thread.current){|parent|
>      sleep(sec)
>      parent.raise(TimeoutError)
>    }
>    begin
>      yield
>    ensure
>      timer_thread.stop # close thread
>    end
>  end
> 
>  timeout(3){
>    begin
>      f = open(...)  # open(...){|f| ...} でいいんだけど,まぁ例として
>    ensure
>      f.close
>    end
>  }
> 
>  では,ensure だけでいいのか,というと,それ以外にも問題がある.例えば
> 次に示す例5について考える.
> 
>  # 例5
>  begin
>    f = open(...)
>  ensure
>    f.close if f
>  end
> 
>  open(...) で開いたものを,"f =" でローカル変数に代入が完了する前に割り
> 込まれたとき,f は nil のままなので ensure で close されない.この例の
> File の場合は GC で閉じることも可能だが,解放を必須とする資源一般を考え
> ると問題である.
> 
>  この点について,例えば,行末まで割り込みを許さない(行末だけチェックす
> る),といった解決案も提案されたが,"f =" や "open(...)" がもっと複雑
> だった場合,その解決では無理である(例えば,"foo.bar =" は複数行のメソッ
> ドの場合がある).
> 
> 
> 提案:
>  非同期割り込みをチェックするタイミングを制御するための仕組みを新設す
> る.原案は [1] にあるとおり.ただ,名前については今後検討する.
> 
>  制御の種類は次の通り,
>   0. なるべく頻繁にチェックする(これまで通りの動作)
>   1. ブロック I/O のタイミングだけチェックする
>    2. チェックしない
> 
>  0 はこれまで通り.
> 
>  1 は,POSIX thread の cancellation point らしい.長時間ブロックする処
> 理は Thread#raise やシグナルでキャンセルすることが可能.
> 
>  2 は,一切チェックしない.完全に非同期割り込みセーフに処理することが可能.
> 
>  ただし.チェックする例外クラス(の祖先)は指定できるようにする.これに
> より,例えば SignalException (を継承した Interrupt)は頻繁にチェックす
> る,すなわち Ctrl+C はだいたい効く,しかし,TimeoutError のような例外は
> 安全なところまで遅延して処理するといった挙動が容易に記述できる.
> 
> 
> 議論:
> 
> ・デフォルトをどのモード(前節 0~2 のこと)にするか?
>  ・モード 1 で困る人はどれくらいいるか?
>  (いないならデフォルトこれでいいんでは?)
>  ・計算スレッドは止めても困らないので,例2のような場合はこれまで
>   通り止めたい,という,モード 0 を期待する例はある.
> ・ensure 実行時に自動的にモードを変更するか?
> 
> ※ええと,すみません,いろんな議論があったと思いましたが,誰か補完して下
> さい....
> 
> 
> 余談(というか TODO):
>  rb_blocking_region() 時に強制的に終了時に CHECK_INTS() しているのはけ
> しからんので,CHECK_INTS() を呼び出し側でさせるバージョンを作るべきである.
> 
>  例えば,
> 
>  blocking_region{
>    data = read(...)
>  }
> 
>  とあったとき,data が到達しているのならば,割り込んで欲しくないはずで
> ある.ただし,data が到達する前に割り込みで中断していれば,CHECK_INTS()
> により例外を発生させるべきである.この判断は rb_bocking_region() 利用者
> しかできないので,その判断をさせるべきである.
> 
> 
> 参考文献:
> [1] Akira Tanaka "Re: Thread#raise, Thread#kill, and timeout.rb are
> unsafe" ruty-talk (2008.3)
> http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/294917
> 
> 
> 謝辞:
>  この議論は,3/11 10:00から開催されたRuby開発者会議で行われました.参加
> 者は田中さん,nahi さん,たるいさん,mrkn さん,skype 越しに小崎さん,中
> 田さん,sora さん,遠藤さんでした.朝もはよからありがとうございました.
> 
> -- 
> // SASADA Koichi at atdot dot net
> 
> 


^ permalink raw reply	[flat|nested] 28+ messages in thread

* [ruby-dev:45345] Re: 非同期割り込みに対する対処案(日本語版)
  2012-03-11 11:35 [ruby-dev:45341] 非同期割り込みに対する対処案(日本語版) SASADA Koichi
  2012-03-11 12:01 ` [ruby-dev:45342] 非同期割り込みに対する対処案(日本語版) Kazuo Ishii
  2012-03-11 12:27 ` [ruby-dev:45343] " NISHIYAMA Tomoaki
@ 2012-03-12  3:24 ` Masaya TARUI
  2012-03-12 12:00   ` [ruby-dev:45347] " Yusuke Endoh
  2012-06-25  9:26 ` [ruby-dev:45816] " SASADA Koichi
  3 siblings, 1 reply; 28+ messages in thread
From: Masaya TARUI @ 2012-03-12  3:24 UTC (permalink / raw
  To: ruby developers list

たるいです。

一点だけ追加です。

>  非同期割り込みをチェックするタイミングを制御する primitive を提供す
> る.制御の種類は次の通り,
>   0. なるべく頻繁にチェックする(これまで通りの動作)
>   1. ブロッキング処理のタイミングだけチェックする
>    2. チェックしない

非同期割り込みをチェックするタイミングを減らすので代わりに明示的にチェックする
primitiveも導入しようという話なっていたと思います。
そのチェックするprimitiveで、非同期例外について例外が来ていた場合にチェックして
例外を出すのか、例外オブジェクトを返すのかは議論が分かれていました。



2012年3月11日20:35 SASADA Koichi <ko1@atdot•net>:
>  ささだです.
>
>  開発会議で出た「非同期割り込みがこの先生き残るには」という議論を,とり
> あえず日本語でまとめました.まだあまりまとまっていない(すみません)の
> で,すみませんが日本語で出させて下さい&突っ込んで下さい.
>
>  あとで英語化したいと思います(してくれると嬉しい).英語化できたら,今
> 後はそっちということで.
>
>
>
> 用語:
> ・trap ハンドラ:trapで登録するシグナルが来たときに行うブロック
>   trap(SIGINT){ ... } の ... 部分
>
> ・非同期割り込み:Thread#raise や trap ハンドラなど,意図しない
>   イベントを,ここでは非同期割り込みと呼ぶ
>  (他にもあったら教えて下さい)
>
> ・割り込みチェック:非同期例外があるかどうかチェックし,もしあれば
>   例外を発生刺せたり trap ハンドラを実行したりする
>
> ・ブロッキング処理:I/O などで,ブロックするかもしれない処理.
>
>
> 概要:
>  非同期割り込みをチェックするタイミングを制御する primitive を提供す
> る.制御の種類は次の通り,
>   0. なるべく頻繁にチェックする(これまで通りの動作)
>   1. ブロッキング処理のタイミングだけチェックする
>    2. チェックしない
>  ただし.チェックする例外クラス(の祖先)は指定できる.
>  なので,SignalException (を継承した Interrupt)は頻繁にチェックする,
> すなわち Ctrl+C はだいたい効く,しかし,TimeoutError のような例外は安全
> なところまで遅延して処理するといった挙動が容易に記述できる.
>
>
> 背景:
>  Thread#raise を使うと,スレッドに対していろんなちょっかいを出すことが
> できる.また,trap(signal){...} とすると,任意のシグナルについて対応する
> ことができる.
>
>  # 例1
>  th = Thread.new{
>    begin
>      ...
>    rescue NantokaError
>      ...
>    end
>  }
>  th.raise(NantokaError) #=> th に NantokaError を強制的に引き起こす
>
>
>  # 例2
>  q = Queue.new
>  th1 = Thread.new{
>    q << calc_in_algorithm1
>  }
>  th2 = Thread.new{
>    q << calc_in_algorithm2
>  }
>  result = q.pop
>  th1.raise(TerminateCalcError)
>  th2.raise(TerminateCalcError)
>  # アルゴリズム1,2 で計算して,どちらか先に答えが出たら,
>  # もう1つのほうを止める
>
>
>  # 例3
>  trap(SIGINT){
>    # 何か後処理
>  }
>  trap(SIGHUP){
>    # 何か reload 処理
>  }
>  server_exec # サーバの処理
>
>  なお,現在の割り込みチェックは,RUBY_VM_CHECK_INTS() で行っており,メ
> ソッドの起動時,リターン時,前方へのジャンプ時,ブロッキング処理の前後で
> 行っている.
>
>
> 問題点:
>
>  Thread#raise だとかが上がってくるタイミングは制御できないので,例えば
> ensure 中で後処理をしていた場合に困る.
>
>  例えば,例4 は timeout の実装(の簡略版)ですが,yield で起動したブ
> ロック中で,ensure を用いて何か資源の後始末をしていたとしても,その後始
> 末中に(ensure 節実行中に)TimeoutError が発生してしまう可能性がある.
>
>  # 例4
>  def timeout(sec)
>    timer_thread = Thread.new(Thread.current){|parent|
>      sleep(sec)
>      parent.raise(TimeoutError)
>    }
>    begin
>      yield
>    ensure
>      timer_thread.stop # close thread
>    end
>  end
>
>  timeout(3){
>    begin
>      f = open(...)  # open(...){|f| ...} でいいんだけど,まぁ例として
>    ensure
>      f.close
>    end
>  }
>
>  では,ensure だけでいいのか,というと,それ以外にも問題がある.例えば
> 次に示す例5について考える.
>
>  # 例5
>  begin
>    f = open(...)
>  ensure
>    f.close if f
>  end
>
>  open(...) で開いたものを,"f =" でローカル変数に代入が完了する前に割り
> 込まれたとき,f は nil のままなので ensure で close されない.この例の
> File の場合は GC で閉じることも可能だが,解放を必須とする資源一般を考え
> ると問題である.
>
>  この点について,例えば,行末まで割り込みを許さない(行末だけチェックす
> る),といった解決案も提案されたが,"f =" や "open(...)" がもっと複雑
> だった場合,その解決では無理である(例えば,"foo.bar =" は複数行のメソッ
> ドの場合がある).
>
>
> 提案:
>  非同期割り込みをチェックするタイミングを制御するための仕組みを新設す
> る.原案は [1] にあるとおり.ただ,名前については今後検討する.
>
>  制御の種類は次の通り,
>   0. なるべく頻繁にチェックする(これまで通りの動作)
>   1. ブロック I/O のタイミングだけチェックする
>    2. チェックしない
>
>  0 はこれまで通り.
>
>  1 は,POSIX thread の cancellation point らしい.長時間ブロックする処
> 理は Thread#raise やシグナルでキャンセルすることが可能.
>
>  2 は,一切チェックしない.完全に非同期割り込みセーフに処理することが可能.
>
>  ただし.チェックする例外クラス(の祖先)は指定できるようにする.これに
> より,例えば SignalException (を継承した Interrupt)は頻繁にチェックす
> る,すなわち Ctrl+C はだいたい効く,しかし,TimeoutError のような例外は
> 安全なところまで遅延して処理するといった挙動が容易に記述できる.
>
>
> 議論:
>
> ・デフォルトをどのモード(前節 0〜2 のこと)にするか?
>  ・モード 1 で困る人はどれくらいいるか?
>  (いないならデフォルトこれでいいんでは?)
>  ・計算スレッドは止めても困らないので,例2のような場合はこれまで
>   通り止めたい,という,モード 0 を期待する例はある.
> ・ensure 実行時に自動的にモードを変更するか?
>
> ※ええと,すみません,いろんな議論があったと思いましたが,誰か補完して下
> さい....
>
>
> 余談(というか TODO):
>  rb_blocking_region() 時に強制的に終了時に CHECK_INTS() しているのはけ
> しからんので,CHECK_INTS() を呼び出し側でさせるバージョンを作るべきである.
>
>  例えば,
>
>  blocking_region{
>    data = read(...)
>  }
>
>  とあったとき,data が到達しているのならば,割り込んで欲しくないはずで
> ある.ただし,data が到達する前に割り込みで中断していれば,CHECK_INTS()
> により例外を発生させるべきである.この判断は rb_bocking_region() 利用者
> しかできないので,その判断をさせるべきである.
>
>
> 参考文献:
> [1] Akira Tanaka "Re: Thread#raise, Thread#kill, and timeout.rb are
> unsafe" ruty-talk (2008.3)
> http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/294917
>
>
> 謝辞:
>  この議論は,3/11 10:00から開催されたRuby開発者会議で行われました.参加
> 者は田中さん,nahi さん,たるいさん,mrkn さん,skype 越しに小崎さん,中
> 田さん,sora さん,遠藤さんでした.朝もはよからありがとうございました.
>
> --
> // SASADA Koichi at atdot dot net
>



-- 
樽家昌也(Masaya TARUI)
No Tool,No Life.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [ruby-dev:45347] Re: 非同期割り込みに対する対処案(日本語版)
  2012-03-12  3:24 ` [ruby-dev:45345] " Masaya TARUI
@ 2012-03-12 12:00   ` Yusuke Endoh
  2012-03-13  2:56     ` [ruby-dev:45353] " Urabe Shyouhei
  0 siblings, 1 reply; 28+ messages in thread
From: Yusuke Endoh @ 2012-03-12 12:00 UTC (permalink / raw
  To: ruby developers list

遠藤です。

2012-03-11 SASADA Koichi <ko1@atdot•net>:
> 提案:
>  非同期割り込みをチェックするタイミングを制御するための仕組みを新設す
> る.原案は [1] にあるとおり.ただ,名前については今後検討する.
>
>  制御の種類は次の通り,
>   0. なるべく頻繁にチェックする(これまで通りの動作)
>   1. ブロック I/O のタイミングだけチェックする


一応補足しますと、ブロック I/O に限らずブロックを発生させうる API
は全部チェックすべきだと思います。例えば:

  - 明示的なウェイト (Kernel#sleep)
  - 条件変数待ち (ConditionVariable#wait)
  - スレッド終了待ち (Thread#join)
  - プロセス終了待ち (Kernel#system, Process#wait など)

要するに rb_thread_blocking_region を呼ぶあたり全部。少なくとも
POSIX thread の cancellation point はそう定義されています。


もっと細かいことを言うと、POSIX thread では mutex のロック待ちは
ブロックしうるけれど cancellation point になっていません。
その理由は、推測ですが

  - mutex のロックで割りこまれるようではプログラムを書くのが難しい
  - cancellation point に関係なく、mutex はロック内の処理を一瞬で
    終了することが求められていて、ロックで「ブロック」するほど待つ
    ケースは想定されていない

などかと思います。
ただし Haskell の非同期例外 [2] では mutex のロックも cancellation
point (相当) になっており、デファクトの設計ポリシーがあるわけでは
なさそうです。



> 参考文献:
> [1] Akira Tanaka "Re: Thread#raise, Thread#kill, and timeout.rb are
> unsafe" ruty-talk (2008.3)
> http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/294917

[2] Simon Marlow, Simon Peyton Jones, Andy Moran and John Reppy.
Asynchronous Exceptions in Haskell, in PLDI'01.

-- 
Yusuke Endoh <mame@tsg•ne.jp>

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [ruby-dev:45353] Re: 非同期割り込みに対する対処案(日本語版)
  2012-03-12 12:00   ` [ruby-dev:45347] " Yusuke Endoh
@ 2012-03-13  2:56     ` Urabe Shyouhei
  2012-03-13 11:48       ` [ruby-dev:45355] " Yusuke Endoh
  0 siblings, 1 reply; 28+ messages in thread
From: Urabe Shyouhei @ 2012-03-13  2:56 UTC (permalink / raw
  To: ruby developers list

On 2012年03月12日 21:00, Yusuke Endoh wrote:
> もっと細かいことを言うと、POSIX thread では mutex のロック待ちは
> ブロックしうるけれど cancellation point になっていません。
> その理由は、推測ですが
> 
>   - mutex のロックで割りこまれるようではプログラムを書くのが難しい
>   - cancellation point に関係なく、mutex はロック内の処理を一瞬で
>     終了することが求められていて、ロックで「ブロック」するほど待つ
>     ケースは想定されていない
> 
> などかと思います。

POSIXではキャンセルが起こるとただ処理が中断されるのではなくクリーンアップ
ハンドラが動くことがあります。ここで、条件変数を待っているスレッドがキャン
セルされた時にクリーンアップハンドラに突入すると、そのハンドラ内で条件変数
が待っていたmuetxはロックされた状態で突入してくることになっています。した
がってクリーンアップハンドラは常にmutexをロックしている前提で書いてよいこ
とになっています。ところがmutexのキャンセルがOKということにすると、クリー
ンアップハンドラはmutexがロックされているのか、ロックされていないのかよく
わからないような感じで動くということになります。これは正しく書くのがとても
面倒です。

といったことがpthread_cond_wait(3posix)のRATIONALEに書いてあります。

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [ruby-dev:45355] Re: 非同期割り込みに対する対処案(日本語版)
  2012-03-13  2:56     ` [ruby-dev:45353] " Urabe Shyouhei
@ 2012-03-13 11:48       ` Yusuke Endoh
  0 siblings, 0 replies; 28+ messages in thread
From: Yusuke Endoh @ 2012-03-13 11:48 UTC (permalink / raw
  To: ruby developers list

遠藤です。

2012-03-13 Urabe Shyouhei <shyouhei@ruby-lang.org>:
> On 2012年03月12日 21:00, Yusuke Endoh wrote:
>> もっと細かいことを言うと、POSIX thread では mutex のロック待ちは
>> ブロックしうるけれど cancellation point になっていません。
>> その理由は、推測ですが
>>
>>   - mutex のロックで割りこまれるようではプログラムを書くのが難しい
>>   - cancellation point に関係なく、mutex はロック内の処理を一瞬で
>>     終了することが求められていて、ロックで「ブロック」するほど待つ
>>     ケースは想定されていない
>>
>> などかと思います。
>
> POSIXではキャンセルが起こるとただ処理が中断されるのではなくクリーンアップ
> ハンドラが動くことがあります。ここで、条件変数を待っているスレッドがキャン
> セルされた時にクリーンアップハンドラに突入すると、そのハンドラ内で条件変数
> が待っていたmuetxはロックされた状態で突入してくることになっています。した
> がってクリーンアップハンドラは常にmutexをロックしている前提で書いてよいこ
> とになっています。ところがmutexのキャンセルがOKということにすると、クリー
> ンアップハンドラはmutexがロックされているのか、ロックされていないのかよく
> わからないような感じで動くということになります。これは正しく書くのがとても
> 面倒です。
>
> といったことがpthread_cond_wait(3posix)のRATIONALEに書いてあります。


へー。これは知りませんでした。
POSIX thread を真似するなら気をつけた方がいいですね。


ただ、私が言ったのは「pthread_mutex_lock はブロックしうるけど
cancellation point じゃない」という話で、上とは別の話です。

http://pubs.opengroup.org/onlinepubs/007904875/functions/pthread_mutex_lock.html

は見たんですが、特に rationale は書いてないようでした。検索してみたら

http://www.mkssoftware.com/docs/man3/pthread_cancel.3.asp

pthread_mutex_lock() is not a cancellation point, although it may
block indefinitely; making pthread_mutex_lock() a cancellation point
would make writing correct cancellation handlers difficult, if not
impossible.

http://sourceware.org/pthreads-win32/manual/pthread_mutex_init.html

None of the mutex functions is a cancellation point, not even
pthread_mutex_lock, in spite of the fact that it can suspend a thread
for arbitrary durations. This way, the status of mutexes at
cancellation points is predictable, allowing cancellation handlers to
unlock precisely those mutexes that need to be unlocked before the
thread stops executing. Consequently, threads using deferred
cancellation should never hold a mutex for extended periods of time.

など、やはり「プログラムを書くのが難しくなりすぎるから」ということの
ようです。


いずれにせよ、かなり余談に近い話です。すみません。

-- 
Yusuke Endoh <mame@tsg•ne.jp>

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [ruby-dev:45816] Re: 非同期割り込みに対する対処案(日本語版)
  2012-03-11 11:35 [ruby-dev:45341] 非同期割り込みに対する対処案(日本語版) SASADA Koichi
                   ` (2 preceding siblings ...)
  2012-03-12  3:24 ` [ruby-dev:45345] " Masaya TARUI
@ 2012-06-25  9:26 ` SASADA Koichi
  2012-06-25 10:05   ` [ruby-dev:45817] " Tanaka Akira
  3 siblings, 1 reply; 28+ messages in thread
From: SASADA Koichi @ 2012-06-25  9:26 UTC (permalink / raw
  To: ruby developers list

 ささだです.

(2012/03/11 20:35), SASADA Koichi wrote:
>  開発会議で出た「非同期割り込みがこの先生き残るには」という議論を,とり
> あえず日本語でまとめました.まだあまりまとまっていない(すみません)の
> で,すみませんが日本語で出させて下さい&突っ込んで下さい.
> 
>  あとで英語化したいと思います(してくれると嬉しい).英語化できたら,今
> 後はそっちということで.

 こちら,すっかり放置していたんですが,なんとかしないとと思って reboot
します.すみません.指摘されている点を取り込みました.

田中さん:[ruby-talk:294917] で提案されていた API について,下記に疑問を
書いています.すみませんが教えて貰えませんか.

小崎さん:なんか突っ込みありますか.


その他,突っ込み歓迎します.結局,デフォルトはどうするべきなんだ.


----

用語:
・trap ハンドラ:trapで登録するシグナルが来たときに行うブロック
  trap(SIGINT){ ... } の ... 部分

・非同期割り込み:Thread#raise や trap ハンドラなど,意図しない
  イベントを,ここでは非同期割り込みと呼ぶ
 (他にもあったら教えて下さい)

・割り込みチェック:非同期例外があるかどうかチェックし,もしあれば
  例外を発生刺せたり trap ハンドラを実行したりする

・ブロッキング処理:I/O などで,ブロックするかもしれない処理.


概要:
 非同期割り込みをチェックするタイミングを制御する primitive を提供す
る.制御の種類は次の通り,

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

 ただし.チェックする例外クラス(の祖先)は指定できる.なの
で,SignalException (を継承した Interrupt)は頻繁にチェックする,
すなわち Ctrl+C はだいたい効く,しかし,TimeoutError のような例外は安全
なところまで遅延して処理するといった挙動が容易に記述できる.

 また,1, 2 の場合に,ユーザによって強制的にどのような例外が来ているか
チェックできる仕組みを導入する.


背景:
 Thread#raise を使うと,スレッドに対していろんなちょっかいを出すことが
できる.また,trap(signal){...} とすると,任意のシグナルについて,非同期
に呼ばれるブロックを指定することができる.

  # 例1
  th = Thread.new{
    begin
      ...
    rescue NantokaError
      ...
    end
  }
  th.raise(NantokaError) #=> th に NantokaError を強制的に引き起こす


  # 例2
  q = Queue.new
  th1 = Thread.new{
    q << calc_in_algorithm1
  }
  th2 = Thread.new{
    q << calc_in_algorithm2
  }
  result = q.pop
  th1.raise(TerminateCalcError)
  th2.raise(TerminateCalcError)
  # アルゴリズム1,2 で計算して,どちらか先に答えが出たら,
  # もう1つのほうを止める


  # 例3
  trap(SIGINT){
    # 何か後処理
  }
  trap(SIGHUP){
    # 何か reload 処理
  }
  server_exec # サーバの処理

 なお,現在の割り込みチェックは,RUBY_VM_CHECK_INTS() で行っており,メ
ソッドの起動時,リターン時,前方へのジャンプ時,ブロッキング処理の前後で
行っている.


問題点:

 Thread#raise だとかが上がってくるタイミングは制御できないので,例えば
ensure 中で後処理をしていた場合に困る.

 例えば,例4 は timeout の実装(の簡略版)だが,yield で起動したブロッ
ク中で,ensure を用いて何か資源の後始末をしていたとしても,その後始末中
に(ensure 節実行中に)TimeoutError が発生してしまう可能性がある.

  # 例4
  def timeout(sec)
    timer_thread = Thread.new(Thread.current){|parent|
      sleep(sec)
      parent.raise(TimeoutError)
    }
    begin
      yield
    ensure
      timer_thread.stop # close thread
    end
  end

  timeout(3){
    begin
      f = open(...)  # open(...){|f| ...} でいいんだけど,まぁ例として
    ensure
      f.close
    end
  }

  では,ensure だけでいいのか,というと,それ以外にも問題がある.例えば
次に示す例5について考える.

  # 例5
  begin
    f = open(...)
  ensure
    f.close if f
  end

 open(...) で開いたものを,"f =" でローカル変数に代入が完了する前に割り
込まれたとき,f は nil のままなので ensure で close されない.この例の
File の場合は GC で閉じることも可能だが,解放を必須とする資源一般を考え
ると問題である.

 この点について,例えば,行末まで割り込みを許さない(行末だけチェックす
る),といった解決案も提案されたが,"f =" や "open(...)" がもっと複雑
だった場合,その解決では無理である(例えば,"foo.bar =" は複数行のメソッ
ドとして定義されている可能性がある).


提案:
 非同期割り込みをチェックするタイミングを制御するための仕組みを新設す
る.原案は [1] にあるとおり.ただ,名前については今後検討する.

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

 0 はこれまで通り.

 1 は,POSIX thread の cancellation point を参考にしている.長時間ブ
ロックする処理は Thread#raise やシグナルでキャンセルすることが可能.

 I/O 以外にも

  - 明示的なウェイト (Kernel#sleep)
  - 条件変数待ち (ConditionVariable#wait)
  - スレッド終了待ち (Thread#join)
  - プロセス終了待ち (Kernel#system, Process#wait など)

などが含まれる.

 2 は,一切チェックしない.完全に非同期割り込みセーフに処理することが可能.

 ただし.チェックする例外クラス(の祖先)は指定できるようにする.これに
より,例えば SignalException (を継承した Interrupt)は頻繁にチェックす
る,すなわち Ctrl+C はだいたい効く,しかし,TimeoutError のような例外は
安全なところまで遅延して処理するといった挙動が容易に記述できる.


議論:

・デフォルトをどのモード(前節 0〜2 のこと)にするか?
 ・モード 1 で困る人はどれくらいいるか?
 (いないならデフォルトこれでいいんでは?)
 ・計算スレッドは止めても困らないので,例2のような場合はこれまで
  通り止めたい,という,モード 0 を期待する例はある.

・ensure 実行時に自動的にモードを変更するか?

・ユーザによって例外を poll する処理は,例外を発生するか,
 それとも例外オブジェクトを取得できるようにするだけにするか?

・モードを変更する API をどのように設計するべきか?
 [1] では,次の様な API を提案している.
   * Thread.check_interrupt(klass)
   * Thread.blocking_interruptible(klass) { ... }
   * Thread.blocking_uninterruptible(klass) { ... }
   * Thread.delay_interrupt(klass) { ... }

が,この API は,非同期割り込みを常にチェックするモード 0 は気にしていな
い気がする.あと,delay_interrupt ってなんだっけ?


参考文献:
[1] Akira Tanaka "Re: Thread#raise, Thread#kill, and timeout.rb are
unsafe" ruty-talk (2008.3)
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/294917


謝辞:
 この議論は,3/11 10:00から開催されたRuby開発者会議で行われました.参加
者は田中さん,nahi さん,たるいさん,mrkn さん,skype 越しに小崎さん,中
田さん,sora さん,遠藤さんでした.朝もはよからありがとうございました.
 その後,突っ込みを受けた内容を入れました.

-- 
// SASADA Koichi at atdot dot net

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [ruby-dev:45817] Re: 非同期割り込みに対する対処案(日本語版)
  2012-06-25  9:26 ` [ruby-dev:45816] " SASADA Koichi
@ 2012-06-25 10:05   ` Tanaka Akira
  2012-06-25 10:39     ` [ruby-dev:45819] " SASADA Koichi
  0 siblings, 1 reply; 28+ messages in thread
From: Tanaka Akira @ 2012-06-25 10:05 UTC (permalink / raw
  To: ruby developers list

2012年6月25日 18:26 SASADA Koichi <ko1@atdot•net>:

> 田中さん:[ruby-talk:294917] で提案されていた API について,下記に疑問を
> 書いています.すみませんが教えて貰えませんか.

疑問というのはこれですかね。

> あと,delay_interrupt ってなんだっけ?

覚えたませんでしたが、読み直すと、ブロッキング操作以外の (任意の) 場所について
割り込みを例外として発生させてよいかを制御するメソッドですね。

ブロックの中は遅延させるという意図です。
-- 
[田中 哲][たなか あきら][Tanaka Akira]

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [ruby-dev:45819] Re: 非同期割り込みに対する対処案(日本語版)
  2012-06-25 10:05   ` [ruby-dev:45817] " Tanaka Akira
@ 2012-06-25 10:39     ` SASADA Koichi
  2012-06-25 11:32       ` [ruby-dev:45820] " Tanaka Akira
  0 siblings, 1 reply; 28+ messages in thread
From: SASADA Koichi @ 2012-06-25 10:39 UTC (permalink / raw
  To: ruby developers list

 ささだです.

 早速,ありがとうございます.ただ,質問の仕方が悪かったので,質問だけ並
べてみました.

(2012/06/25 19:05), Tanaka Akira wrote:
>> > あと,delay_interrupt ってなんだっけ?
> 覚えたませんでしたが、読み直すと、ブロッキング操作以外の (任意の) 場所について
> 割り込みを例外として発生させてよいかを制御するメソッドですね。
> 
> ブロックの中は遅延させるという意図です。

 というわけで,わかりづらかったので,田中さん宛の疑問を列挙します.

(1) 結局,デフォルトの挙動はどうするべきか?

(2) Thread.delay_interrupt を呼ぶ前と,呼んだ後のブロックの中ではどのよ
うに挙動は変化するか?

(3) Thread.blocking_interruptible() を呼ぶ前と,呼んだ後のブロックの中で
はどのように挙動は変化するか?

(4) Thread.blocking_uninterruptible() を呼ぶ前と,呼んだ後のブロックの中
ではどのように挙動は変化するか?


私の推測・意見です:
(1) については特に規定していない気がします.間違ってたらすみません.
(2) は,上記の説明とメソッド名からどっちがどっちだかわかりませんでした.
(3) は モード1, 2 -> モード2 への制御を行う?
(4) は モード0, 1 -> モード2 への制御を行う?
(3, 4) があれば, (2) は不要じゃないか?



 あと,よくよく考えると,Thread.blocking_uninterruptible などで,klass
の指定が n 個ネストすると,非同期割り込みが起こる度に n 回チェックする必
要がある気がします.包含関係があるので,単純にそうではないんですが.継承
関係を考えると,ハッシュで O(1),というわけにもいかない(飛んできた例外
オブジェクトの継承木の高さが m 個の場合,O(m) でいけるか).

 また,[ruby-talk:294917] ではキューで管理するべき,ということでした
が,種類によって割り込みが追い越す可能性があります(例えば,TimeoutError
がブロックされており,キューに貯まっているとき,InterruptError が来たら
どうなるか).

 この2点について,考えをお聞かせ下さい.


(5) チェックのコストをどう考えるか(O(m) は甘受すべきコストか)
(6) 追い越しが発生するとき,どうすると良いか


 もし,議論を見逃していたらすみません.追い越しの件は,なんか以前聞いた
ことがあるような気がしたのですが,忘れてしまいました.

 あと,[ruby-talk:294917] では "It is because Thread.check_interrupt
with blocking operations causes race conditions." と,race が起こるとか
いてあるんですが,これどういう話でしたっけ.


-- 
// SASADA Koichi at atdot dot net

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [ruby-dev:45820] Re: 非同期割り込みに対する対処案(日本語版)
  2012-06-25 10:39     ` [ruby-dev:45819] " SASADA Koichi
@ 2012-06-25 11:32       ` Tanaka Akira
  2012-06-25 12:01         ` [ruby-dev:45821] " SASADA Koichi
  2012-06-25 18:40         ` [ruby-dev:45827] " SASADA Koichi
  0 siblings, 2 replies; 28+ messages in thread
From: Tanaka Akira @ 2012-06-25 11:32 UTC (permalink / raw
  To: ruby developers list

2012年6月25日 19:39 SASADA Koichi <ko1@atdot•net>:
>
> (1) 結局,デフォルトの挙動はどうするべきか?

まず、SIGINT (^C) で ruby を終了できることはとても重要ですから、
これについては即座に例外になるべきでしょう。

SIGTERM など他のシグナルも同様だと思います。

それ以外については、100% コンパチブルという話を尊重するなら、
やはりそれも現状どおり即座に例外なんじゃないでしょうか。
尊重しないなら、遅延させるという選択肢もあるかもしれません。

> (2) Thread.delay_interrupt を呼ぶ前と,呼んだ後のブロックの中ではどのよ
> うに挙動は変化するか?

ブロックの内側では非同期イベントに対する例外は safe point まで遅延します。

外側については、さらに外側で Thread.delay_interrupt で括られているかどうかに
依存します。

> (3) Thread.blocking_interruptible() を呼ぶ前と,呼んだ後のブロックの中で
> はどのように挙動は変化するか?

ブロックの内側については、ブロッキング操作が safe point になります。

外側については、さらに外側で Thread.blocking_interruptible や
Thread.blocking_uninterruptible で括られているかどうかに依存します。

> (4) Thread.blocking_uninterruptible() を呼ぶ前と,呼んだ後のブロックの中
> ではどのように挙動は変化するか?

ブロックの内側については、ブロッキング操作が safe point でなくなります。

外側については、さらに外側で Thread.blocking_interruptible や
Thread.blocking_uninterruptible で括られているかどうかに依存します。

> 私の推測・意見です:
> (1) については特に規定していない気がします.間違ってたらすみません.
> (2) は,上記の説明とメソッド名からどっちがどっちだかわかりませんでした.
> (3) は モード1, 2 -> モード2 への制御を行う?
> (4) は モード0, 1 -> モード2 への制御を行う?
> (3, 4) があれば, (2) は不要じゃないか?

私が書いた時点ではモード 0, 1, 2 という考え方ではなかったのでしょう。

ブロックする操作やそれ以外の場所を safe point とするかどうかを制御する感じに
だったように思います。

>  あと,よくよく考えると,Thread.blocking_uninterruptible などで,klass
> の指定が n 個ネストすると,非同期割り込みが起こる度に n 回チェックする必
> 要がある気がします.包含関係があるので,単純にそうではないんですが.継承
> 関係を考えると,ハッシュで O(1),というわけにもいかない(飛んできた例外
> オブジェクトの継承木の高さが m 個の場合,O(m) でいけるか).

そうですね。

>  また,[ruby-talk:294917] ではキューで管理するべき,ということでした
> が,種類によって割り込みが追い越す可能性があります(例えば,TimeoutError
> がブロックされており,キューに貯まっているとき,InterruptError が来たら
> どうなるか).

追い越すのではないかと思います。

> (5) チェックのコストをどう考えるか(O(m) は甘受すべきコストか)

非同期イベントはそのコストが問題になるほど頻繁に使うべきものではないんじゃないでしょうか。

原則的には、プロセスの終了のためにのみ使うべきだと思っています、

> (6) 追い越しが発生するとき,どうすると良いか

追い越せばいいんじゃないでしょうか。
なにを問題と感じているのかわかりません。

>  あと,[ruby-talk:294917] では "It is because Thread.check_interrupt
> with blocking operations causes race conditions." と,race が起こるとか
> いてあるんですが,これどういう話でしたっけ.

あぁ、race もありますが、もっとあからさまにブロックしている最中に
中断できなければならないというほうがわかりやすい必要性かもしれません。

race は、ブロックする直前や直後にシグナルが来たときの話を想定していました。
もし Binary Hacks を持っているなら「sigsafeでシグナル処理を安全にする」という
のを読んでみてください。
-- 
[田中 哲][たなか あきら][Tanaka Akira]

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [ruby-dev:45821] Re: 非同期割り込みに対する対処案(日本語版)
  2012-06-25 11:32       ` [ruby-dev:45820] " Tanaka Akira
@ 2012-06-25 12:01         ` SASADA Koichi
  2012-06-25 12:11           ` [ruby-dev:45822] " Tanaka Akira
  2012-06-25 18:40         ` [ruby-dev:45827] " SASADA Koichi
  1 sibling, 1 reply; 28+ messages in thread
From: SASADA Koichi @ 2012-06-25 12:01 UTC (permalink / raw
  To: ruby developers list

 ささだです.

 早速の回答,ありがとうございます.

 (1) はコメントとして書いておこう.

(2012/06/25 20:32), Tanaka Akira wrote:
> ブロックする操作やそれ以外の場所を safe point とするかどうかを制御する感じに
> だったように思います。

 それ以外の場所を safe point にする API が不足しているでしょうか?(私
の見落とし?)

 具体的には,Thread.delay_interrupt の逆.


>>  あと,よくよく考えると,Thread.blocking_uninterruptible などで,klass
>> の指定が n 個ネストすると,非同期割り込みが起こる度に n 回チェックする必
>> 要がある気がします.包含関係があるので,単純にそうではないんですが.継承
>> 関係を考えると,ハッシュで O(1),というわけにもいかない(飛んできた例外
>> オブジェクトの継承木の高さが m 個の場合,O(m) でいけるか).
> 
> そうですね。
> 
>>  また,[ruby-talk:294917] ではキューで管理するべき,ということでした
>> が,種類によって割り込みが追い越す可能性があります(例えば,TimeoutError
>> がブロックされており,キューに貯まっているとき,InterruptError が来たら
>> どうなるか).
> 
> 追い越すのではないかと思います。
> 
>> (5) チェックのコストをどう考えるか(O(m) は甘受すべきコストか)
> 
> 非同期イベントはそのコストが問題になるほど頻繁に使うべきものではないんじゃないでしょうか。
> 
> 原則的には、プロセスの終了のためにのみ使うべきだと思っています、

 つまり,このキューは殆どの場合空であるため,もしくは空にするべきである
ため,コストに関してはあまり気にならないんじゃないの,ということですね.


>> (6) 追い越しが発生するとき,どうすると良いか
> 
> 追い越せばいいんじゃないでしょうか。
> なにを問題と感じているのかわかりません。

 何かの弾みでキューに例外が詰まってきたとき,ナイーブに作るとかなりオー
バヘッドがかかりそうだなぁ,と思ったんですが,気合い入れて結果をきちんと
キャッシュすればなんとかなるかな....


>>  あと,[ruby-talk:294917] では "It is because Thread.check_interrupt
>> with blocking operations causes race conditions." と,race が起こるとか
>> いてあるんですが,これどういう話でしたっけ.
> 
> あぁ、race もありますが、もっとあからさまにブロックしている最中に
> 中断できなければならないというほうがわかりやすい必要性かもしれません。
> 
> race は、ブロックする直前や直後にシグナルが来たときの話を想定していました。
> もし Binary Hacks を持っているなら「sigsafeでシグナル処理を安全にする」という
> のを読んでみてください。

 なるほど,その話でしたか.了解です.

-- 
// SASADA Koichi at atdot dot net

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [ruby-dev:45822] Re: 非同期割り込みに対する対処案(日本語版)
  2012-06-25 12:01         ` [ruby-dev:45821] " SASADA Koichi
@ 2012-06-25 12:11           ` Tanaka Akira
  0 siblings, 0 replies; 28+ messages in thread
From: Tanaka Akira @ 2012-06-25 12:11 UTC (permalink / raw
  To: ruby developers list

2012年6月25日 21:01 SASADA Koichi <ko1@atdot•net>:

>  それ以外の場所を safe point にする API が不足しているでしょうか?(私
> の見落とし?)
>
>  具体的には,Thread.delay_interrupt の逆.

あったほうが適切かもしれませんね。
-- 
[田中 哲][たなか あきら][Tanaka Akira]

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [ruby-dev:45827] Re: 非同期割り込みに対する対処案(日本語版)
  2012-06-25 11:32       ` [ruby-dev:45820] " Tanaka Akira
  2012-06-25 12:01         ` [ruby-dev:45821] " SASADA Koichi
@ 2012-06-25 18:40         ` SASADA Koichi
  2012-06-25 19:44           ` [ruby-dev:45835] " KOSAKI Motohiro
  2012-06-25 20:07           ` [ruby-dev:45841] " Tanaka Akira
  1 sibling, 2 replies; 28+ messages in thread
From: SASADA Koichi @ 2012-06-25 18:40 UTC (permalink / raw
  To: ruby developers list

(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 って単語でいいのかな.スペルチェックにひっかかる.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [ruby-dev:45835] Re: 非同期割り込みに対する対処案(日本語版)
  2012-06-25 18:40         ` [ruby-dev:45827] " SASADA Koichi
@ 2012-06-25 19:44           ` KOSAKI Motohiro
  2012-06-25 20:05             ` [ruby-dev:45840] " SASADA Koichi
  2012-06-25 20:07           ` [ruby-dev:45841] " Tanaka Akira
  1 sibling, 1 reply; 28+ messages in thread
From: KOSAKI Motohiro @ 2012-06-25 19:44 UTC (permalink / raw
  To: ruby developers list

> の3つになるような気がしていますので,ある例外がこれら 3 つのどの状態に
> するか,という API を考えてみました.
>
>  (a) Thread.interrupt_mask(exception, state) do; end
>  (b) Thread.interrupt_mask(hash) do; end

(b)のほうは指定した全ての変更がアトミックに切り替わらないと絶対文句が出るAPIだと思うのですが、はたしてそんなことが可能でしょうか

また、blocking_interruptibleのときが、pthread cancel モデルなのであれば、
自発的に例外を確認する pthread cancel() 関数相当のメソッドが必要だと思います

> :immediate_interruptible
> :blocking_interruptible
> :uninterruptible

メソッド名と引数の両方に interruptの単語が入っているのはやや冗長ではないでしょうか


> (1) シグナルを許すと言っても,SIGUSR1 とかも許していいのかな.

シグナル毎に違うExceptionを投げるべきだと思います。全部SignalExceptionの
サブクラスにすれば既存のコードで動くんじゃないでしょうか

>(2) POSIX みたいに,このメソッドは blocking とか,すべてきちんと
>   書き連ねる必要があるのかな.かなり,無理な気がする
> (そもそも,何がどのメソッドを呼び出すかわからない気が).

当面GVL離すところで、チェックするようにして、GVL離すタイミングを
徐々に増やしていくとかですかね。


>(3) ライブラリの至る所でこんなの書かれたらハッシュが大量発生して,
>   オーバヘッドで大変になったりしないだろうか....
>   そもそも,これって多用するんだろうか.

わたしの想定は、1行目で blocking_interruptible にして二度と変えない。
ensureの中でIOを呼ぶときだけ一時的に uninterruptibleに変更


> (4) ブロックを持たない Thread.mask_interrupt() は許すべきだろうか.
> (意味としては,「この呼び出し以降はこの設定で」,という感じ)
>   なんとなく,許さない方がいいような気がするんだけど

(3)とあわせてブロック必須だと全プログラムが一段ネストが深くなるので
うれしくないなあ

> (5) Thread.mask_interrupt() はネストしたら設定を混ぜていく,としたけど
>   単に,置き換える,という選択肢もあるのか.こっちのほうが使いやすい?

混ぜていく。というのがなにを指しているのか取れなかったので置き換えるモデルで動作例を書いていただけるとうれしいです

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [ruby-dev:45840] Re: 非同期割り込みに対する対処案(日本語版)
  2012-06-25 19:44           ` [ruby-dev:45835] " KOSAKI Motohiro
@ 2012-06-25 20:05             ` SASADA Koichi
  2012-06-29  6:56               ` [ruby-dev:45872] " SASADA Koichi
  0 siblings, 1 reply; 28+ messages in thread
From: SASADA Koichi @ 2012-06-25 20:05 UTC (permalink / raw
  To: ruby developers list

(2012/06/26 4:44), KOSAKI Motohiro wrote:
>> の3つになるような気がしていますので,ある例外がこれら 3 つのどの状態に
>> するか,という API を考えてみました.
>>
>>  (a) Thread.interrupt_mask(exception, state) do; end
>>  (b) Thread.interrupt_mask(hash) do; end
> 
> (b)のほうは指定した全ての変更がアトミックに切り替わらないと絶対文句が出るAPIだと思うのですが、はたしてそんなことが可能でしょうか

 C で書く API だから,atomic に変わります.

> また、blocking_interruptibleのときが、pthread cancel モデルなのであれば、
> 自発的に例外を確認する pthread cancel() 関数相当のメソッドが必要だと思います

 それを忘れていました.要するに例外が届いているかチェックするメソッドで
すよね.Thread.check_ints() としておこう(名前はとりあえず適当です).

>> :immediate_interruptible
>> :blocking_interruptible
>> :uninterruptible
> 
> メソッド名と引数の両方に interruptの単語が入っているのはやや冗長ではないでしょうか

 冗長だというのに同意します.が,とりあえず挙動を議論したいので,そのま
まで.名前はもうちょっと後で.

>> (1) シグナルを許すと言っても,SIGUSR1 とかも許していいのかな.
> 
> シグナル毎に違うExceptionを投げるべきだと思います。全部SignalExceptionの
> サブクラスにすれば既存のコードで動くんじゃないでしょうか

 これは,ちょっと off topic ですかね.


>> (2) POSIX みたいに,このメソッドは blocking とか,すべてきちんと
>>   書き連ねる必要があるのかな.かなり,無理な気がする
>>  (そもそも,何がどのメソッドを呼び出すかわからない気が).
> 
> 当面GVL離すところで、チェックするようにして、GVL離すタイミングを
> 徐々に増やしていくとかですかね。

 ここは,ドキュメントの話をしていたつもりです.

 増やしていくと嬉しいことがある?

>> (3) ライブラリの至る所でこんなの書かれたらハッシュが大量発生して,
>>   オーバヘッドで大変になったりしないだろうか....
>>   そもそも,これって多用するんだろうか.
> 
> わたしの想定は、1行目で blocking_interruptible にして二度と変えない。
> ensureの中でIOを呼ぶときだけ一時的に uninterruptibleに変更
> 
> 
>> (4) ブロックを持たない Thread.mask_interrupt() は許すべきだろうか.
>>  (意味としては,「この呼び出し以降はこの設定で」,という感じ)
>>   なんとなく,許さない方がいいような気がするんだけど
> 
> (3)とあわせてブロック必須だと全プログラムが一段ネストが深くなるので
> うれしくないなあ

 ここは,誰か偉い人にデザインを任せたいところなんですが....


>> (5) Thread.mask_interrupt() はネストしたら設定を混ぜていく,としたけど
>>   単に,置き換える,という選択肢もあるのか.こっちのほうが使いやすい?
> 
> 混ぜていく。というのがなにを指しているのか取れなかったので置き換えるモデルで動作例を書いていただけるとうれしいです

 置き換える例について,先のコード例ですと,

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

では,混ぜていく場合は block では param1 & param2 が効きますが,置き換え
る場合とは,これを param2 *しか* 効かなくするのはどうだろう,ということ
です.外側は一切見ない.

 これだと,ハッシュを使い回すというか,よくやる「akr が薦めるだいたい安
全セット」「kosaki 認定絶対安全セット」みたいなのを作ってそれを使う様に
すると,毎回 Hash を作らなくなって,よくなるかも.


# あと,実装はこっちのほうが楽なんすよね....

-- 
// SASADA Koichi at atdot dot net

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [ruby-dev:45841] Re: 非同期割り込みに対する対処案(日本語版)
  2012-06-25 18:40         ` [ruby-dev:45827] " SASADA Koichi
  2012-06-25 19:44           ` [ruby-dev:45835] " KOSAKI Motohiro
@ 2012-06-25 20:07           ` Tanaka Akira
  2012-06-25 20:15             ` [ruby-dev:45844] " SASADA Koichi
  1 sibling, 1 reply; 28+ messages in thread
From: Tanaka Akira @ 2012-06-25 20:07 UTC (permalink / raw
  To: ruby developers list

2012年6月26日 3:40 SASADA Koichi <ko1@atdot•net>:

>  (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 にあたる
> と考えます.

名前ですが、Thread.interruptable_at(:blocking) とかはどうかなぁ。

>  このとき,デフォルトは互換性 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

外側が :immediate_interruptible であるとすると、これは race がありますよね。

「何か処理」で例外が起きて、ensure 節に入った後、
Thread.mask_interrupt(Exception, :uninterruptible) を呼び出す前に
非同期イベントによる例外が起きると、リソース開放処理がスキップされます。

実装上はそこでは例外は起きないのかもしれませんが...
-- 
[田中 哲][たなか あきら][Tanaka Akira]

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [ruby-dev:45844] Re: 非同期割り込みに対する対処案(日本語版)
  2012-06-25 20:07           ` [ruby-dev:45841] " Tanaka Akira
@ 2012-06-25 20:15             ` SASADA Koichi
  2012-06-29  6:55               ` [ruby-dev:45871] " Tanaka Akira
  2012-07-02 11:14               ` [ruby-dev:45893] " Yusuke Endoh
  0 siblings, 2 replies; 28+ messages in thread
From: SASADA Koichi @ 2012-06-25 20:15 UTC (permalink / raw
  To: ruby developers list

(2012/06/26 5:07), Tanaka Akira wrote:
> 
> 名前ですが、Thread.interruptable_at(:blocking) とかはどうかなぁ。

 これだと,例外クラスを指定する場合,

    Thread.interruptable_at(:blocking, TimeoutError)

みたいに書くの?


>>  begin
>> >    # 何か処理
>> >  ensure
>> >    Thread.mask_interrupt(Exception, :uninterruptible) do
>> >      # 一度全部割り込み禁止にして
>> >      Thread.mask_interrupt(SignalException, :blocking_interruptible) do
>> >        # シグナルだけ割り込みを許して
>> >        # リソース解放処理
>> >      end
>> >    end
>> >  end
> 外側が :immediate_interruptible であるとすると、これは race がありますよね。
> 
> 「何か処理」で例外が起きて、ensure 節に入った後、
> Thread.mask_interrupt(Exception, :uninterruptible) を呼び出す前に
> 非同期イベントによる例外が起きると、リソース開放処理がスキップされます。
> 
> 実装上はそこでは例外は起きないのかもしれませんが...

 確かに,仰るとおりです.寝ぼけた頭では,とりあえず

(1) 「実装上はそこでは例外は起きない」ことを仕様にする
(2) ensure に細工する(あまりやりたくない)
(3) 利用者が immediate にしない

が考えられると思います.どれがいいでしょう.または,他の選択肢はあるで
しょうか.

-- 
// SASADA Koichi at atdot dot net

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [ruby-dev:45871] Re: 非同期割り込みに対する対処案(日本語版)
  2012-06-25 20:15             ` [ruby-dev:45844] " SASADA Koichi
@ 2012-06-29  6:55               ` Tanaka Akira
  2012-06-29 10:41                 ` [ruby-dev:45873] " KOSAKI Motohiro
  2012-07-02 11:14               ` [ruby-dev:45893] " Yusuke Endoh
  1 sibling, 1 reply; 28+ messages in thread
From: Tanaka Akira @ 2012-06-29  6:55 UTC (permalink / raw
  To: ruby developers list

2012年6月26日 5:15 SASADA Koichi <ko1@atdot•net>:
> (2012/06/26 5:07), Tanaka Akira wrote:
>>
>> 名前ですが、Thread.interruptable_at(:blocking) とかはどうかなぁ。
>
>  これだと,例外クラスを指定する場合,
>
>    Thread.interruptable_at(:blocking, TimeoutError)
>
> みたいに書くの?

そうなりますね。

>  確かに,仰るとおりです.寝ぼけた頭では,とりあえず
>
> (1) 「実装上はそこでは例外は起きない」ことを仕様にする
> (2) ensure に細工する(あまりやりたくない)
> (3) 利用者が immediate にしない
>
> が考えられると思います.どれがいいでしょう.または,他の選択肢はあるで
> しょうか.

kosaki さんの「1行目で blocking_interruptible にして二度と変えない。」とか、
私の「(100% コンパチブルという話を) 尊重しないなら、
遅延させるという選択肢もあるかもしれません。」
とかが、そのへんに対する表明なんじゃないですかねぇ。

また、昔ので Thread.delay_interrupt の逆がないというのも、
そうだったのかもしれません。

kosaki さんは (3) で、
私はどちらかというとデフォルトを変えてしまうほうに向いているかな。
-- 
[田中 哲][たなか あきら][Tanaka Akira]

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [ruby-dev:45872] Re: 非同期割り込みに対する対処案(日本語版)
  2012-06-25 20:05             ` [ruby-dev:45840] " SASADA Koichi
@ 2012-06-29  6:56               ` SASADA Koichi
  2012-06-29 10:46                 ` [ruby-dev:45874] " KOSAKI Motohiro
  0 siblings, 1 reply; 28+ messages in thread
From: SASADA Koichi @ 2012-06-29  6:56 UTC (permalink / raw
  To: ruby developers list

(2012/06/26 5:05), SASADA Koichi wrote:
>>> (3) ライブラリの至る所でこんなの書かれたらハッシュが大量発生して,
>>>   オーバヘッドで大変になったりしないだろうか....
>>>   そもそも,これって多用するんだろうか.
>>
>> わたしの想定は、1行目で blocking_interruptible にして二度と変えない。
>> ensureの中でIOを呼ぶときだけ一時的に uninterruptibleに変更
>>
>>
>>> (4) ブロックを持たない Thread.mask_interrupt() は許すべきだろうか.
>>>  (意味としては,「この呼び出し以降はこの設定で」,という感じ)
>>>   なんとなく,許さない方がいいような気がするんだけど
>>
>> (3)とあわせてブロック必須だと全プログラムが一段ネストが深くなるので
>> うれしくないなあ
> 
>  ここは,誰か偉い人にデザインを任せたいところなんですが....

 ブロック必須じゃないと,不届きなライブラリが設定を変えてしまい,意図し
ない変更が起きるので,まずいんじゃないかと思いはじめました.

  def foo
    Thread.interrupt_mask(割り込み許可)
  end

  Thread.interrupt_mask(割り込み禁止) do
    foo()
    ... # 割り込み許可になってしまう
  end

 初期状態は,別の方法(例えば,コマンドライオプションや環境変数)で渡す
のがいいような気がしています.どうでしょうか.


>>> >> (5) Thread.mask_interrupt() はネストしたら設定を混ぜていく,としたけど
>>> >>   単に,置き換える,という選択肢もあるのか.こっちのほうが使いやすい?
>> > 
>> > 混ぜていく。というのがなにを指しているのか取れなかったので置き換えるモデルで動作例を書いていただけるとうれしいです
>  置き換える例について,先のコード例ですと,
> 
>   Thread.interrupt_mask(param1) do
>     Thread.interrupt_mask(param2) do
>       # block
>     end
>   end
> 
> では,混ぜていく場合は block では param1 & param2 が効きますが,置き換え
> る場合とは,これを param2 *しか* 効かなくするのはどうだろう,ということ
> です.外側は一切見ない.
> 
>  これだと,ハッシュを使い回すというか,よくやる「akr が薦めるだいたい安
> 全セット」「kosaki 認定絶対安全セット」みたいなのを作ってそれを使う様に
> すると,毎回 Hash を作らなくなって,よくなるかも.

 これ,置き換えるほうがいいように思えてきました.シチュエーション的に
は,元のケースはどうであれ,ここではこれを守って欲しい! という指定のほ
うがありそうな,という予想です.


 もう,一度作って試さないとダメかな,これは.

-- 
// SASADA Koichi at atdot dot net

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [ruby-dev:45873] Re: 非同期割り込みに対する対処案(日本語版)
  2012-06-29  6:55               ` [ruby-dev:45871] " Tanaka Akira
@ 2012-06-29 10:41                 ` KOSAKI Motohiro
  2012-07-02 13:23                   ` [ruby-dev:45897] " Tanaka Akira
  0 siblings, 1 reply; 28+ messages in thread
From: KOSAKI Motohiro @ 2012-06-29 10:41 UTC (permalink / raw
  To: ruby developers list

> kosaki さんの「1行目で blocking_interruptible にして二度と変えない。」とか、
> 私の「(100% コンパチブルという話を) 尊重しないなら、
> 遅延させるという選択肢もあるかもしれません。」
> とかが、そのへんに対する表明なんじゃないですかねぇ。
>
> また、昔ので Thread.delay_interrupt の逆がないというのも、
> そうだったのかもしれません。
>
> kosaki さんは (3) で、
> 私はどちらかというとデフォルトを変えてしまうほうに向いているかな。

私自身は現在の仕様は壊れていると思っており、デフォルトを変えるのには
反対じゃないんですがどう変えるという意図でしょうか。
デフォルトが :blocking という意味でしょうか?

別件ですが、sigprocmask(2)とかと違って :blocking中でも配送されてくることがある
セマンティクスなので :blocking という名前には反対です。

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [ruby-dev:45874] Re: 非同期割り込みに対する対処案(日本語版)
  2012-06-29  6:56               ` [ruby-dev:45872] " SASADA Koichi
@ 2012-06-29 10:46                 ` KOSAKI Motohiro
  0 siblings, 0 replies; 28+ messages in thread
From: KOSAKI Motohiro @ 2012-06-29 10:46 UTC (permalink / raw
  To: ruby developers list

>> では,混ぜていく場合は block では param1 & param2 が効きますが,置き換え
>> る場合とは,これを param2 *しか* 効かなくするのはどうだろう,ということ
>> です.外側は一切見ない.
>>
>>  これだと,ハッシュを使い回すというか,よくやる「akr が薦めるだいたい安
>> 全セット」「kosaki 認定絶対安全セット」みたいなのを作ってそれを使う様に
>> すると,毎回 Hash を作らなくなって,よくなるかも.
>
>  これ,置き換えるほうがいいように思えてきました.シチュエーション的に
> は,元のケースはどうであれ,ここではこれを守って欲しい! という指定のほ
> うがありそうな,という予想です.

ええと、思想的には「混ぜていく」がアプリケーションの指定優先で、「置き換える」が
ライブラリ優先になると思うのですが、「混ぜていく」方式でもライブラリは例外全部を
明示的に上書きすることによって望む動作を実現できますが、「置き換える」方式は
アプリケーションの意思を表明する方法がなくて表現力が弱いと思っています。

さらにいうと、スレッドのKILLと割り込みとtimeoutを気にする人がそれぞれ違う気がするので
置き換える方式はあんまり気が乗りません

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [ruby-dev:45893] Re: 非同期割り込みに対する対処案(日本語版)
  2012-06-25 20:15             ` [ruby-dev:45844] " SASADA Koichi
  2012-06-29  6:55               ` [ruby-dev:45871] " Tanaka Akira
@ 2012-07-02 11:14               ` Yusuke Endoh
  2012-07-02 11:29                 ` [ruby-dev:45894] " SASADA Koichi
  1 sibling, 1 reply; 28+ messages in thread
From: Yusuke Endoh @ 2012-07-02 11:14 UTC (permalink / raw
  To: ruby developers list

遠藤です。

2012/06/26 SASADA Koichi <ko1@atdot•net>:
>>>  begin
>>> >    # 何か処理
>>> >  ensure
>>> >    Thread.mask_interrupt(Exception, :uninterruptible) do
>>> >      # 一度全部割り込み禁止にして
>>> >      Thread.mask_interrupt(SignalException, :blocking_interruptible)
>>> > do
>>> >        # シグナルだけ割り込みを許して
>>> >        # リソース解放処理
>>> >      end
>>> >    end
>>> >  end
>> 外側が :immediate_interruptible であるとすると、これは race がありますよね。
>>
>> 「何か処理」で例外が起きて、ensure 節に入った後、
>> Thread.mask_interrupt(Exception, :uninterruptible) を呼び出す前に
>> 非同期イベントによる例外が起きると、リソース開放処理がスキップされます。
>>
>> 実装上はそこでは例外は起きないのかもしれませんが...
>
>  確かに,仰るとおりです.寝ぼけた頭では,とりあえず
>
> (1) 「実装上はそこでは例外は起きない」ことを仕様にする
> (2) ensure に細工する(あまりやりたくない)
> (3) 利用者が immediate にしない
>
> が考えられると思います.どれがいいでしょう.または,他の選択肢はあるで
> しょうか.


以下のようにすれば現状の API で問題ないと思うのですが、
何か見落としているでしょうか。

  # (1) と (2) の間の割り込みを防ぐために
  Thread.mask_interrupt(Exception, :blocking_interruptible) do # (0)
    begin
      # begin 〜 ensure 内での割り込みはいつでも許す
      Thread.mask_interrupt(Exception, :immediate_interruptible) do
        # 何か処理
      end
    ensure # (1)
      # (0) のおかげでこの間に割り込まれることはない
      Thread.mask_interrupt(Exception, :uninterruptible) do (2)
        # 一度全部割り込み禁止にして
        Thread.mask_interrupt(SignalException, :blocking_interruptible) do
          # シグナルだけ割り込みを許して
          # リソース解放処理
        end
      end
    end
  end

-- 
Yusuke Endoh <mame@tsg•ne.jp>

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [ruby-dev:45894] Re: 非同期割り込みに対する対処案(日本語版)
  2012-07-02 11:14               ` [ruby-dev:45893] " Yusuke Endoh
@ 2012-07-02 11:29                 ` SASADA Koichi
  2012-07-02 11:35                   ` [ruby-dev:45895] " Yusuke Endoh
  0 siblings, 1 reply; 28+ messages in thread
From: SASADA Koichi @ 2012-07-02 11:29 UTC (permalink / raw
  To: ruby developers list

(2012/07/02 20:14), Yusuke Endoh wrote:
> 以下のようにすれば現状の API で問題ないと思うのですが、
> 何か見落としているでしょうか。
> 
>   # (1) と (2) の間の割り込みを防ぐために
>   Thread.mask_interrupt(Exception, :blocking_interruptible) do # (0)
>     begin
>       # begin 〜 ensure 内での割り込みはいつでも許す
>       Thread.mask_interrupt(Exception, :immediate_interruptible) do
>         # 何か処理
>       end
>     ensure # (1)
>       # (0) のおかげでこの間に割り込まれることはない
>       Thread.mask_interrupt(Exception, :uninterruptible) do (2)
>         # 一度全部割り込み禁止にして
>         Thread.mask_interrupt(SignalException, :blocking_interruptible) do
>           # シグナルだけ割り込みを許して
>           # リソース解放処理
>         end
>       end
>     end
>   end
> 

 (0) 書きたくねーよ! てな話なのかなぁ,とも思ったのですが,どうでしょ
う.個人的には,これで良ければこれで行きたい気がします.

-- 
// SASADA Koichi at atdot dot net

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [ruby-dev:45895] Re: 非同期割り込みに対する対処案(日本語版)
  2012-07-02 11:29                 ` [ruby-dev:45894] " SASADA Koichi
@ 2012-07-02 11:35                   ` Yusuke Endoh
  2012-07-02 11:39                     ` [ruby-dev:45896] " SASADA Koichi
  0 siblings, 1 reply; 28+ messages in thread
From: Yusuke Endoh @ 2012-07-02 11:35 UTC (permalink / raw
  To: ruby developers list

2012年7月2日 20:29 SASADA Koichi <ko1@atdot•net>:
>  (0) 書きたくねーよ! てな話なのかなぁ,とも思ったのですが,どうでしょ
> う.個人的には,これで良ければこれで行きたい気がします.

あくまで primitive の話なんですよね?
実際に書きたいかどうかでいうと、ensure の中の二重の mask_interrupt も
個人的には書きたくないです。

-- 
Yusuke Endoh <mame@tsg•ne.jp>

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [ruby-dev:45896] Re: 非同期割り込みに対する対処案(日本語版)
  2012-07-02 11:35                   ` [ruby-dev:45895] " Yusuke Endoh
@ 2012-07-02 11:39                     ` SASADA Koichi
  0 siblings, 0 replies; 28+ messages in thread
From: SASADA Koichi @ 2012-07-02 11:39 UTC (permalink / raw
  To: ruby developers list

(2012/07/02 20:35), Yusuke Endoh wrote:
> 実際に書きたいかどうかでいうと、ensure の中の二重の mask_interrupt も
> 個人的には書きたくないです。

 書きたくなる様なインターフェースの話に脱線しますが,

  ensure
    Thread.mask_interrupt(
      Exception => :uninterruptible,
      SignalException => :blocking_interruptible) do
       # 解放
    end
  end

なら良いという話?
それとも上記パターンを行う短い名前を用意?
それとも ensure になんか細工する仕組みを別途用意?

-- 
// SASADA Koichi at atdot dot net

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [ruby-dev:45897] Re: 非同期割り込みに対する対処案(日本語版)
  2012-06-29 10:41                 ` [ruby-dev:45873] " KOSAKI Motohiro
@ 2012-07-02 13:23                   ` Tanaka Akira
  2012-07-03  2:22                     ` [ruby-dev:45899] " KOSAKI Motohiro
  0 siblings, 1 reply; 28+ messages in thread
From: Tanaka Akira @ 2012-07-02 13:23 UTC (permalink / raw
  To: ruby developers list

2012年6月29日 19:41 KOSAKI Motohiro <kosaki.motohiro@gmail•com>:

> 私自身は現在の仕様は壊れていると思っており、デフォルトを変えるのには
> 反対じゃないんですがどう変えるという意図でしょうか。
> デフォルトが :blocking という意味でしょうか?

シグナル以外についてはブロックしうるところで例外発生、
シグナルについてはどこでも例外発生、
というのがデフォルトだといいんじゃないかなぁ、と思っています。

シグナルについてはもうすこし細かく分類して挙動を変えてもいいかもしれませんが。
-- 
[田中 哲][たなか あきら][Tanaka Akira]

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [ruby-dev:45899] Re: 非同期割り込みに対する対処案(日本語版)
  2012-07-02 13:23                   ` [ruby-dev:45897] " Tanaka Akira
@ 2012-07-03  2:22                     ` KOSAKI Motohiro
  0 siblings, 0 replies; 28+ messages in thread
From: KOSAKI Motohiro @ 2012-07-03  2:22 UTC (permalink / raw
  To: ruby developers list

2012/7/2 Tanaka Akira <akr@fsij•org>:
> 2012年6月29日 19:41 KOSAKI Motohiro <kosaki.motohiro@gmail•com>:
>
>> 私自身は現在の仕様は壊れていると思っており、デフォルトを変えるのには
>> 反対じゃないんですがどう変えるという意図でしょうか。
>> デフォルトが :blocking という意味でしょうか?
>
> シグナル以外についてはブロックしうるところで例外発生、
> シグナルについてはどこでも例外発生、
> というのがデフォルトだといいんじゃないかなぁ、と思っています。

なるほど。
サーバーアプリケーションだと Ctrl+C は使わないことが多いので、どのユースケースにも
いいデフォルトな気がします。ちゃんと考えていませんが。


> シグナルについてはもうすこし細かく分類して挙動を変えてもいいかもしれませんが。

SIGUSRは blockingとかそういう意味ですかね。

1) ruby repository のtestではSIGINTばかり使われている(主にWindows対策だけど)
2) SIGHUPみたいに、普通は即死してほしいけど、daemonのときだけblockingになって
     欲しいとかある

とかを考えると、シグナルに特化したシンタックスシュガーつくって簡単にblocking に変えられるように
した方が幸せになれるような気がしました。これもあんまりアイデア寝れてません

^ permalink raw reply	[flat|nested] 28+ messages in thread

end of thread, other threads:[~2012-07-03  2:25 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-03-11 11:35 [ruby-dev:45341] 非同期割り込みに対する対処案(日本語版) SASADA Koichi
2012-03-11 12:01 ` [ruby-dev:45342] 非同期割り込みに対する対処案(日本語版) Kazuo Ishii
2012-03-11 12:27 ` [ruby-dev:45343] " NISHIYAMA Tomoaki
2012-03-12  3:24 ` [ruby-dev:45345] " Masaya TARUI
2012-03-12 12:00   ` [ruby-dev:45347] " Yusuke Endoh
2012-03-13  2:56     ` [ruby-dev:45353] " Urabe Shyouhei
2012-03-13 11:48       ` [ruby-dev:45355] " Yusuke Endoh
2012-06-25  9:26 ` [ruby-dev:45816] " SASADA Koichi
2012-06-25 10:05   ` [ruby-dev:45817] " Tanaka Akira
2012-06-25 10:39     ` [ruby-dev:45819] " SASADA Koichi
2012-06-25 11:32       ` [ruby-dev:45820] " Tanaka Akira
2012-06-25 12:01         ` [ruby-dev:45821] " SASADA Koichi
2012-06-25 12:11           ` [ruby-dev:45822] " Tanaka Akira
2012-06-25 18:40         ` [ruby-dev:45827] " SASADA Koichi
2012-06-25 19:44           ` [ruby-dev:45835] " KOSAKI Motohiro
2012-06-25 20:05             ` [ruby-dev:45840] " SASADA Koichi
2012-06-29  6:56               ` [ruby-dev:45872] " SASADA Koichi
2012-06-29 10:46                 ` [ruby-dev:45874] " KOSAKI Motohiro
2012-06-25 20:07           ` [ruby-dev:45841] " Tanaka Akira
2012-06-25 20:15             ` [ruby-dev:45844] " SASADA Koichi
2012-06-29  6:55               ` [ruby-dev:45871] " Tanaka Akira
2012-06-29 10:41                 ` [ruby-dev:45873] " KOSAKI Motohiro
2012-07-02 13:23                   ` [ruby-dev:45897] " Tanaka Akira
2012-07-03  2:22                     ` [ruby-dev:45899] " KOSAKI Motohiro
2012-07-02 11:14               ` [ruby-dev:45893] " Yusuke Endoh
2012-07-02 11:29                 ` [ruby-dev:45894] " SASADA Koichi
2012-07-02 11:35                   ` [ruby-dev:45895] " Yusuke Endoh
2012-07-02 11:39                     ` [ruby-dev:45896] " SASADA Koichi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).