ruby-dev (Japanese) list archive (unofficial mirror)
 help / color / mirror / Atom feed
* [ruby-dev:46434] トラップハンドラで許されない操作はなにか
@ 2012-11-06 19:37 KOSAKI Motohiro
  2012-11-09  1:08 ` [ruby-dev:46454] トラップハンドラで許されない操作はなにか Tomoyuki Chikanaga
  0 siblings, 1 reply; 9+ messages in thread
From: KOSAKI Motohiro @ 2012-11-06 19:37 UTC (permalink / raw
  To: ruby developers list

小崎です

[Bug #7134] を調べていて深淵な仕様問題にはまってしまったので、みなさんの意見を聞きたく devにも振ります。

1.9.2p0 以降 (r20144
によるIOのシリアライズが入った後)、ほぼすべてのIOは暗黙にmutexをロックするので、メインスレッドとトラップハンドラが同時にIOをするとデッドロックで死にます。つまりトラップハンドラでIOすることは許されていなくてグローバル変数への書き込みだけが許されている(ほかにできることがあるだろうか?)

で、この仕様に文句をつけてる人がいます。色々なドキュメントのコード例でトラップハンドラがputs使ってるのを見るともっともだと思います。

ですが、よくよく考えてみると mutexがトラップハンドラで使えないこと自体も仕様には書かれていなくて、これは実装の都合です。実際
トラップハンドラでmutex使ってデッドロックした、なおせというバグレポートも過去ありました。番号探せないけど

さて、あるべき仕様とはなんでしょうか。以下の三択かと思います

1.現状のインプリが正しい。トラップハンドラはグローバル変数に書き込んですぐ抜けるべし
2.mutexはトラップハンドラで使えないが、IOは使えるべき。
3.mutexもIOもトラップハンドラから使えるべき


2だと、わたしが[Bug #7134]
にはったようなIO中はトラップハンドラのinvocationを禁止するマスク処理をいれるパッチになりますし、3なら、(以前ささださんが話していたように)トラップハンドラをメインスレッドで走らせるのをやめて専用スレッドで走らせるという解になります。

ところで、C言語でシグナルを専用スレッドで走らせることができないのは端的に言えばlongjmpで戻ってこれることを期待してる輩がいて互換性問題が発生するからですが、Rubyにも似たような問題があります。


http://stackoverflow.com/questions/2089421/capturing-ctrl-c-in-ruby

をみるとトラップハンドラからcatch/throwで抜けることをおすすめしている人がいます(もちろんこれは間違ってます。catchする前にthrowできちゃうから)

これをまじめに考えると
・そもそもトラップからthrowして制御を戻すのは合法か?
・throwで投げたオブジェクトをトラップハンドラスレッドからメインスレッドにキューで渡して非同期的に実行することは許されるか
・throwした瞬間はcatchブロックの中にいたけど、キューイングしてる間に
catchブロックから外れてしまったようなケースにおいてスクリプトからそれを観測する方法はあるか、またそれは救うべきか


というめんどくさい問題があるように思えます。正直もてあましているのでご意見お聞かせください

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

* [ruby-dev:46454] Re: トラップハンドラで許されない操作はなにか
  2012-11-06 19:37 [ruby-dev:46434] トラップハンドラで許されない操作はなにか KOSAKI Motohiro
@ 2012-11-09  1:08 ` Tomoyuki Chikanaga
  2012-11-09 15:41   ` [ruby-dev:46466] " KOSAKI Motohiro
  2012-11-10 14:32   ` [ruby-dev:46475] " Tanaka Akira
  0 siblings, 2 replies; 9+ messages in thread
From: Tomoyuki Chikanaga @ 2012-11-09  1:08 UTC (permalink / raw
  To: ruby developers list

近永と申します。

> 1.現状のインプリが正しい。トラップハンドラはグローバル変数に書き込んですぐ抜けるべし
> 2.mutexはトラップハンドラで使えないが、IOは使えるべき。
> 3.mutexもIOもトラップハンドラから使えるべき
なんでも使いたいユーザー目線としては 3 がいいのでしょうが、わたしの感覚では 2 だと思います。シグナルハンドラ内で mutex
使えないというのは納得感がありますが IO できないというのはあまり自明でないというのと、次に書くように実際の用途があると思います。

 子プロセスの終了を SIGCHLD で検出するために、トラップハンドラ内でロックが使えないので pipe
を使ってトラップハンドラで書込み、監視するスレッドで IO.select
で待って読むというのをやったことがあります。ロックも使えないしIOもできないとなると、変数に代入して監視するほうは polling
で検出するしかなくなり、その場合シグナルの喪失がありえると思います。

> ・そもそもトラップからthrowして制御を戻すのは合法か?
感覚的なことしか言えなくて申し訳ないのですが、これはさすがに無しじゃないでしょうか。

以上です。

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

* [ruby-dev:46466] Re: トラップハンドラで許されない操作はなにか
  2012-11-09  1:08 ` [ruby-dev:46454] トラップハンドラで許されない操作はなにか Tomoyuki Chikanaga
@ 2012-11-09 15:41   ` KOSAKI Motohiro
  2012-11-09 18:09     ` [ruby-dev:46469] " SASADA Koichi
  2012-11-10 14:32   ` [ruby-dev:46475] " Tanaka Akira
  1 sibling, 1 reply; 9+ messages in thread
From: KOSAKI Motohiro @ 2012-11-09 15:41 UTC (permalink / raw
  To: ruby developers list

2012/11/9 Tomoyuki Chikanaga <nagachika00@gmail•com>:
> 近永と申します。
>
>> 1.現状のインプリが正しい。トラップハンドラはグローバル変数に書き込んですぐ抜けるべし
>> 2.mutexはトラップハンドラで使えないが、IOは使えるべき。
>> 3.mutexもIOもトラップハンドラから使えるべき
> なんでも使いたいユーザー目線としては 3 がいいのでしょうが、わたしの感覚では 2 だと思います。シグナルハンドラ内で mutex
> 使えないというのは納得感がありますが IO できないというのはあまり自明でないというのと、次に書くように実際の用途があると思います。
>
>  子プロセスの終了を SIGCHLD で検出するために、トラップハンドラ内でロックが使えないので pipe
> を使ってトラップハンドラで書込み、監視するスレッドで IO.select
> で待って読むというのをやったことがあります。ロックも使えないしIOもできないとなると、変数に代入して監視するほうは polling
> で検出するしかなくなり、その場合シグナルの喪失がありえると思います。

この意見はなっとくできますし、他に意見もでてないようなので2で進めます。ただ制限が緩くなる方に変更するのはいつでもできるので蒸し返しは歓迎します。


>> ・そもそもトラップからthrowして制御を戻すのは合法か?
> 感覚的なことしか言えなくて申し訳ないのですが、これはさすがに無しじゃないでしょうか。

だれか stackoverflowに書き込みできる人はあれにレースがあるよ、動かないよとコメントしてあげてください。
急遽アカウント作ったものの作りたてのアカウントではコメント書き込みできないみたい

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

* [ruby-dev:46469] Re: トラップハンドラで許されない操作はなにか
  2012-11-09 15:41   ` [ruby-dev:46466] " KOSAKI Motohiro
@ 2012-11-09 18:09     ` SASADA Koichi
  2012-11-10 13:33       ` [ruby-dev:46474] " Tomoyuki Chikanaga
  2012-11-10 23:13       ` [ruby-dev:46476] " KOSAKI Motohiro
  0 siblings, 2 replies; 9+ messages in thread
From: SASADA Koichi @ 2012-11-09 18:09 UTC (permalink / raw
  To: ruby developers list

あまりまとまっていないのですが,思ったことを表明しておきます.

(2012/11/10 0:41), KOSAKI Motohiro wrote:
> 2012/11/9 Tomoyuki Chikanaga <nagachika00@gmail•com>:
>> 近永と申します。
>>
>>> 1.現状のインプリが正しい。トラップハンドラはグローバル変数に書き込んですぐ抜けるべし
>>> 2.mutexはトラップハンドラで使えないが、IOは使えるべき。
>>> 3.mutexもIOもトラップハンドラから使えるべき
>> なんでも使いたいユーザー目線としては 3 がいいのでしょうが、わたしの感覚では 2 だと思います。シグナルハンドラ内で mutex
>> 使えないというのは納得感がありますが IO できないというのはあまり自明でないというのと、次に書くように実際の用途があると思います。
>>
>>  子プロセスの終了を SIGCHLD で検出するために、トラップハンドラ内でロックが使えないので pipe
>> を使ってトラップハンドラで書込み、監視するスレッドで IO.select
>> で待って読むというのをやったことがあります。ロックも使えないしIOもできないとなると、変数に代入して監視するほうは polling
>> で検出するしかなくなり、その場合シグナルの喪失がありえると思います。
> 
> この意見はなっとくできますし、他に意見もでてないようなので2で進めます。ただ制限が緩くなる方に変更するのはいつでもできるので蒸し返しは歓迎します。

 ええと,「Mutex が使えない」というのは「trap handler は main thread と
同じ context なので,main thread が Mutex を lock している場合,trap
handler 内で Mutex を掴もうとすると例外が出てしまうから使えない」という
意味であってますよね.

 以前 ruby-core で,Queue に true を突っ込むように書いたら Mutex が
main thread と競合してしまって使えない,という話があって,そのときは
trap では複雑なことが出来ないことが多いから flag を突っ込むだけにしよ
う,という返事をしました.要するに近永さんがされた pipe trick みたいなこ
とを Queue を使ってやる,って話なのですが,そりゃ自然な話だよなぁ,とい
う気がしていました.

  require 'thread'
  q = Queue.new
  trap(:SIGINT){
    q << true
  }

  q.pop # block until sigint

... と思ったら,上記コードはデッドロック検出が働いて動かないんですなぁ.

/home/ko1/build/ruby/trunk/lib/thread.rb:192:in `sleep': No live threads
left. Deadlock?        from
/home/ko1/build/ruby/trunk/lib/thread.rb:192:in `block in pop'
        from <internal:prelude>:10:in `synchronize'
        from /home/ko1/build/ruby/trunk/lib/thread.rb:184:in `pop'
        from ../trunk/test.rb:7:in `<main>'

 signal 用 thread を用意しておくと,deadlock 検出が殆どうまく行かなくな
るような気がするので,やっぱなしでいいかなぁ.いや,trap handler が定義
された瞬間に signal 用 thread を用意してやるのは悪くない気もする.
が,2.0.0 向けじゃないですな.

 小崎さんが「この方針で修正」というのは,具体的にはどういう話でしょう
か.IO のロック時に semaphore や monitor のようにして,「同じスレッドで
ロックしても無視」にする感じでしょうか.semaphore だと単にデッドロックし
て死亡なので,monitor かな.そうすると,

  1. [main thread] IO を lock
  2. [main thread] signal により trap を起動
  3. [trap handler] monitor#lock
  4. [trap handler] IO する
  5. [trap handler] monitor#unlock
  6. [main thread] IO する
  7. [main thread] monitor#unlock

こんな感じで,lock で守りたかった IO はロック出来ているんでしょうか,と
いう疑問があります.

 やはり根本的な解決策は,下記のような感じでしょうか.

(1) trap ハンドラを設定すると,signal が配送されるのをまつ待機 thread を
生成する (signal thread と呼称する)
(2) trap ハンドラがすべて削除されると,その thread は削除される
(3) trap ハンドラ内での全ての例外は main thread へ Thread#raise される

でしょうか.

てきとーに用語を定義しないでフィーリングで読んでもらうと,こんな感じ.
スレッドセーフじゃないのはご愛敬.

  def trap(sig, &block) # 面倒なので cmd は略
    if block
      @@trap_handlers[sig] = block
      @@signal_thread = Thread.new{
        until @@trap_handlers.empty?
          sig = sigwait()
          begin
            @@trap_handlers[sig].call(sig)
          rescue CheckTrapHandler
            # ignore
          rescue Exception => e
            main_thread.kill(e)
          end
        end
      }
      end unless @@signal_thread
    else
      @@trap_handlers.delete(sig)
      @@signal_thread.raise(CheckTrapHandler) if @@signal_thread
    end
  end


 半年くらい早くからこの議論をしていれば,こんなふうに変えるとすっきりし
たんじゃないかと思います.2.0.0 ではどうしますかねぇ.


>>> ・そもそもトラップからthrowして制御を戻すのは合法か?
>> 感覚的なことしか言えなくて申し訳ないのですが、これはさすがに無しじゃないでしょうか。
> 
> だれか stackoverflowに書き込みできる人はあれにレースがあるよ、動かないよとコメントしてあげてください。
> 急遽アカウント作ったものの作りたてのアカウントではコメント書き込みできないみたい

 現在,たまたま出来ちゃうのがねえ.

-- 
// SASADA Koichi at atdot dot net

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

* [ruby-dev:46474] Re: トラップハンドラで許されない操作はなにか
  2012-11-09 18:09     ` [ruby-dev:46469] " SASADA Koichi
@ 2012-11-10 13:33       ` Tomoyuki Chikanaga
  2012-11-10 23:13       ` [ruby-dev:46476] " KOSAKI Motohiro
  1 sibling, 0 replies; 9+ messages in thread
From: Tomoyuki Chikanaga @ 2012-11-10 13:33 UTC (permalink / raw
  To: ruby developers list

[-- Attachment #1: Type: text/plain, Size: 797 bytes --]

近永と申します。

 ええと,「Mutex が使えない」というのは「trap handler は main thread と
> 同じ context なので,main thread が Mutex を lock している場合,trap
> handler 内で Mutex を掴もうとすると例外が出てしまうから使えない」という
> 意味であってますよね.

はい。そういう意味でした。
補足しておくと、現状ではシグナルハンドラは再入し得る(シグナルハンドラ実行中に再度シグナルハンドラが起動される)ので、メインスレッドでは同じ
Mutex とか Queue とか Monitor に触らないようにしても完全には回避されません。
なのでシグナルハンドラ用のスレッドを導入するのに加えて、シグナルハンドラの実行中には同じシグナルハンドラの呼び出しはマスクされるというのも必要かなぁと思っております。

[-- Attachment #2: Type: text/html, Size: 1057 bytes --]

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

* [ruby-dev:46475] Re: トラップハンドラで許されない操作はなにか
  2012-11-09  1:08 ` [ruby-dev:46454] トラップハンドラで許されない操作はなにか Tomoyuki Chikanaga
  2012-11-09 15:41   ` [ruby-dev:46466] " KOSAKI Motohiro
@ 2012-11-10 14:32   ` Tanaka Akira
  1 sibling, 0 replies; 9+ messages in thread
From: Tanaka Akira @ 2012-11-10 14:32 UTC (permalink / raw
  To: ruby developers list

2012年11月9日 10:08 Tomoyuki Chikanaga <nagachika00@gmail•com>:

>  子プロセスの終了を SIGCHLD で検出するために、トラップハンドラ内でロックが使えないので pipe
> を使ってトラップハンドラで書込み、監視するスレッドで IO.select
> で待って読むというのをやったことがあります。ロックも使えないしIOもできないとなると、変数に代入して監視するほうは polling
> で検出するしかなくなり、その場合シグナルの喪失がありえると思います。

この the pipe trick のためにトラップハンドラで IO を許すというのは、
IO をすべて使えるようにしなければならないという話ではないように思います。

pipe の大きさは有限であり、いっぱいになると書けない
(でも書けないときはなんらかのデータが pipe に入っているため、
select は readable になるので書けなくても問題ない) ので、
write_nonblock だけでいいんじゃないでしょうか。
-- 
[田中 哲][たなか あきら][Tanaka Akira]

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

* [ruby-dev:46476] Re: トラップハンドラで許されない操作はなにか
  2012-11-09 18:09     ` [ruby-dev:46469] " SASADA Koichi
  2012-11-10 13:33       ` [ruby-dev:46474] " Tomoyuki Chikanaga
@ 2012-11-10 23:13       ` KOSAKI Motohiro
  2012-11-12 10:48         ` [ruby-dev:46499] " SASADA Koichi
  1 sibling, 1 reply; 9+ messages in thread
From: KOSAKI Motohiro @ 2012-11-10 23:13 UTC (permalink / raw
  To: ruby developers list

>>>> 1.現状のインプリが正しい。トラップハンドラはグローバル変数に書き込んですぐ抜けるべし
>>>> 2.mutexはトラップハンドラで使えないが、IOは使えるべき。
>>>> 3.mutexもIOもトラップハンドラから使えるべき
>>> なんでも使いたいユーザー目線としては 3 がいいのでしょうが、わたしの感覚では 2 だと思います。シグナルハンドラ内で mutex
>>> 使えないというのは納得感がありますが IO できないというのはあまり自明でないというのと、次に書くように実際の用途があると思います。
>>>
>>>  子プロセスの終了を SIGCHLD で検出するために、トラップハンドラ内でロックが使えないので pipe
>>> を使ってトラップハンドラで書込み、監視するスレッドで IO.select
>>> で待って読むというのをやったことがあります。ロックも使えないしIOもできないとなると、変数に代入して監視するほうは polling
>>> で検出するしかなくなり、その場合シグナルの喪失がありえると思います。
>>
>> この意見はなっとくできますし、他に意見もでてないようなので2で進めます。ただ制限が緩くなる方に変更するのはいつでもできるので蒸し返しは歓迎します。
>
>  ええと,「Mutex が使えない」というのは「trap handler は main thread と
> 同じ context なので,main thread が Mutex を lock している場合,trap
> handler 内で Mutex を掴もうとすると例外が出てしまうから使えない」という
> 意味であってますよね.

あってます。


>  以前 ruby-core で,Queue に true を突っ込むように書いたら Mutex が
> main thread と競合してしまって使えない,という話があって,そのときは
> trap では複雑なことが出来ないことが多いから flag を突っ込むだけにしよ
> う,という返事をしました.要するに近永さんがされた pipe trick みたいなこ
> とを Queue を使ってやる,って話なのですが,そりゃ自然な話だよなぁ,とい
> う気がしていました.
>
>   require 'thread'
>   q = Queue.new
>   trap(:SIGINT){
>     q << true
>   }
>
>   q.pop # block until sigint
>
> ... と思ったら,上記コードはデッドロック検出が働いて動かないんですなぁ.
>
> /home/ko1/build/ruby/trunk/lib/thread.rb:192:in `sleep': No live threads
> left. Deadlock?        from
> /home/ko1/build/ruby/trunk/lib/thread.rb:192:in `block in pop'
>         from <internal:prelude>:10:in `synchronize'
>         from /home/ko1/build/ruby/trunk/lib/thread.rb:184:in `pop'
>         from ../trunk/test.rb:7:in `<main>'

そうです。いまパッチがある方針2だとこれは救えません。


>  signal 用 thread を用意しておくと,deadlock 検出が殆どうまく行かなくな
> るような気がするので,やっぱなしでいいかなぁ.いや,trap handler が定義
> された瞬間に signal 用 thread を用意してやるのは悪くない気もする.
> が,2.0.0 向けじゃないですな.

trap handlerを使うケースはもともとdeadlock検出はちゃんと動いていないのでこれ以上悪化するかなあというのが疑問だったり。
あと、わたしはsignal用threadはtrap
handler処理専用スレッド的なものをイメージしていたので、スレッド作成タイミングで挙動が変わるとは思っていなかった


>  小崎さんが「この方針で修正」というのは,具体的にはどういう話でしょう
> か.IO のロック時に semaphore や monitor のようにして,「同じスレッドで
> ロックしても無視」にする感じでしょうか.semaphore だと単にデッドロックし
> て死亡なので,monitor かな.そうすると,
>
>   1. [main thread] IO を lock
>   2. [main thread] signal により trap を起動
>   3. [trap handler] monitor#lock
>   4. [trap handler] IO する
>   5. [trap handler] monitor#unlock
>   6. [main thread] IO する
>   7. [main thread] monitor#unlock
>
> こんな感じで,lock で守りたかった IO はロック出来ているんでしょうか,と
> いう疑問があります.

いいえ、それは[Bug #7134] でバグ報告者が主張していた方針だと思うのですが(recursive
mutexを使う)、メモリ破壊が起きるのでやりたくないと返事をしています。

現在の実装は thread->trap_enabled というフラグを追加し、fptr->write_lockをとるときにこれを disableに変えてしまう。
そして、RUBY_VM_CHECK_INTS()で trap_enabledが0のあいだは、たとえ
thread->interrupt_flag が非0でもtrap handlerを呼び出さない
(今気づいたけど、添付したパッチは thread->interrupt_flagの 0x2以外も無視してるのでよくないですね。なおさないと)

この方針だと

・fptr->write_lockだけが特別扱い。もともとrubyには見えてないこっそりロックだから挙動を変えても非互換ではない
・stdoutへのIOはすべて許される
・pipeへのwriteはwrite_nonblockを使うか、読み出し側をサブスレッドにしないとIOでブロッキングして刺さることはありえる(現状どおり)
・trap handler とmain threadの両方で mutex classを使った場合は、deadlock検出で死ぬことはありうる(現状どおり)

という感じ
focusが trap { puts "hoge" } を救うことに集中してるバンドエイドパッチ。


>  やはり根本的な解決策は,下記のような感じでしょうか.
>
> (1) trap ハンドラを設定すると,signal が配送されるのをまつ待機 thread を
> 生成する (signal thread と呼称する)
> (2) trap ハンドラがすべて削除されると,その thread は削除される
> (3) trap ハンドラ内での全ての例外は main thread へ Thread#raise される
>
> でしょうか.

わたしのイメージはそんな感じ


> てきとーに用語を定義しないでフィーリングで読んでもらうと,こんな感じ.
> スレッドセーフじゃないのはご愛敬.
>
>   def trap(sig, &block) # 面倒なので cmd は略
>     if block
>       @@trap_handlers[sig] = block
>       @@signal_thread = Thread.new{
>         until @@trap_handlers.empty?
>           sig = sigwait()
>           begin
>             @@trap_handlers[sig].call(sig)
>           rescue CheckTrapHandler
>             # ignore
>           rescue Exception => e
>             main_thread.kill(e)
>           end
>         end
>       }
>       end unless @@signal_thread
>     else
>       @@trap_handlers.delete(sig)
>       @@signal_thread.raise(CheckTrapHandler) if @@signal_thread
>     end
>   end
>
>
>  半年くらい早くからこの議論をしていれば,こんなふうに変えるとすっきりし
> たんじゃないかと思います.2.0.0 ではどうしますかねぇ.
>
>
>>>> ・そもそもトラップからthrowして制御を戻すのは合法か?
>>> 感覚的なことしか言えなくて申し訳ないのですが、これはさすがに無しじゃないでしょうか。
>>
>> だれか stackoverflowに書き込みできる人はあれにレースがあるよ、動かないよとコメントしてあげてください。
>> 急遽アカウント作ったものの作りたてのアカウントではコメント書き込みできないみたい
>
>  現在,たまたま出来ちゃうのがねえ.

現状すでに何回かに一回はぎゃっとなるというコードしか書けない状態なので、throwも非同期になげるようにしても自体はあんまり悪化しないのでは。というあまり根拠のない予感があったり。だって、いま動いてないんだもん。

またはtrap handlerからthrowしたときに常にエラーになるようにエラーチェックを強化するというのも、何回かに一回失敗するよりかは親切なので、許される方針という認識

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

* [ruby-dev:46499] Re: トラップハンドラで許されない操作はなにか
  2012-11-10 23:13       ` [ruby-dev:46476] " KOSAKI Motohiro
@ 2012-11-12 10:48         ` SASADA Koichi
  2012-11-13  8:43           ` [ruby-dev:46508] " KOSAKI Motohiro
  0 siblings, 1 reply; 9+ messages in thread
From: SASADA Koichi @ 2012-11-12 10:48 UTC (permalink / raw
  To: ruby developers list

(2012/11/11 8:13), KOSAKI Motohiro wrote:
>>  signal 用 thread を用意しておくと,deadlock 検出が殆どうまく行かなくな
>> るような気がするので,やっぱなしでいいかなぁ.いや,trap handler が定義
>> された瞬間に signal 用 thread を用意してやるのは悪くない気もする.
>> が,2.0.0 向けじゃないですな.
> 
> trap handlerを使うケースはもともとdeadlock検出はちゃんと動いていないのでこれ以上悪化するかなあというのが疑問だったり。
> あと、わたしはsignal用threadはtrap
> handler処理専用スレッド的なものをイメージしていたので、スレッド作成タイミングで挙動が変わるとは思っていなかった

 私もそういうイメージですが,「スレッド作成タイミングで挙動が変わるとは
思っていなかった」というのはどういう話でしょうか.下記の擬似コード参照.

> 現在の実装は thread->trap_enabled というフラグを追加し、fptr->write_lockをとるときにこれを disableに変えてしまう。
> そして、RUBY_VM_CHECK_INTS()で trap_enabledが0のあいだは、たとえ
> thread->interrupt_flag が非0でもtrap handlerを呼び出さない
> (今気づいたけど、添付したパッチは thread->interrupt_flagの 0x2以外も無視してるのでよくないですね。なおさないと)
> 
> この方針だと
> 
> ・fptr->write_lockだけが特別扱い。もともとrubyには見えてないこっそりロックだから挙動を変えても非互換ではない
> ・stdoutへのIOはすべて許される
> ・pipeへのwriteはwrite_nonblockを使うか、読み出し側をサブスレッドにしないとIOでブロッキングして刺さることはありえる(現状どおり)
> ・trap handler とmain threadの両方で mutex classを使った場合は、deadlock検出で死ぬことはありうる(現状どおり)
> 
> という感じ
> focusが trap { puts "hoge" } を救うことに集中してるバンドエイドパッチ。

 ちょっと大げさな気がするけど,まぁいいのかなぁ.

>>  やはり根本的な解決策は,下記のような感じでしょうか.
>>
>> (1) trap ハンドラを設定すると,signal が配送されるのをまつ待機 thread を
>> 生成する (signal thread と呼称する)
>> (2) trap ハンドラがすべて削除されると,その thread は削除される
>> (3) trap ハンドラ内での全ての例外は main thread へ Thread#raise される
>>
>> でしょうか.
> 
> わたしのイメージはそんな感じ
> 
> 
>> てきとーに用語を定義しないでフィーリングで読んでもらうと,こんな感じ.
>> スレッドセーフじゃないのはご愛敬.
>>
>>   def trap(sig, &block) # 面倒なので cmd は略
>>     if block
>>       @@trap_handlers[sig] = block
>>       @@signal_thread = Thread.new{
>>         until @@trap_handlers.empty?
>>           sig = sigwait()
>>           begin
>>             @@trap_handlers[sig].call(sig)
>>           rescue CheckTrapHandler
>>             # ignore
>>           rescue Exception => e
>>             main_thread.kill(e)
>>           end
>>         end
>>       }
>>       end unless @@signal_thread
>>     else
>>       @@trap_handlers.delete(sig)
>>       @@signal_thread.raise(CheckTrapHandler) if @@signal_thread
>>     end
>>   end
>>
>>
>>  半年くらい早くからこの議論をしていれば,こんなふうに変えるとすっきりし
>> たんじゃないかと思います.2.0.0 ではどうしますかねぇ.

 実装もこんな感じで同意でしょうか.

 もう,いっそいろいろ面倒なんで,変えちゃう? 遠藤さんが ok っていった
ら変えてもよさそうだが,ちょっと大きすぎるかなぁ.


>>>>> ・そもそもトラップからthrowして制御を戻すのは合法か?
>>>> 感覚的なことしか言えなくて申し訳ないのですが、これはさすがに無しじゃないでしょうか。
>>>
>>> だれか stackoverflowに書き込みできる人はあれにレースがあるよ、動かないよとコメントしてあげてください。
>>> 急遽アカウント作ったものの作りたてのアカウントではコメント書き込みできないみたい
>>
>>  現在,たまたま出来ちゃうのがねえ.
> 
> 現状すでに何回かに一回はぎゃっとなるというコードしか書けない状態なので、throwも非同期になげるようにしても自体はあんまり悪化しないのでは。というあまり根拠のない予感があったり。だって、いま動いてないんだもん。

 今動いていない,というのは「タイミングによっては動かない場合がある」と
いう意味でいいでしょうか.私の主張は,「タイミングによっては動く場合があ
る」,しかも「動くタイミングが殆どである」という現状認識です.

> またはtrap handlerからthrowしたときに常にエラーになるようにエラーチェックを強化するというのも、何回かに一回失敗するよりかは親切なので、許される方針という認識

 それは同意.

-- 
// SASADA Koichi at atdot dot net

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

* [ruby-dev:46508] Re: トラップハンドラで許されない操作はなにか
  2012-11-12 10:48         ` [ruby-dev:46499] " SASADA Koichi
@ 2012-11-13  8:43           ` KOSAKI Motohiro
  0 siblings, 0 replies; 9+ messages in thread
From: KOSAKI Motohiro @ 2012-11-13  8:43 UTC (permalink / raw
  To: ruby developers list

>>>   def trap(sig, &block) # 面倒なので cmd は略
>>>     if block
>>>       @@trap_handlers[sig] = block
>>>       @@signal_thread = Thread.new{
>>>         until @@trap_handlers.empty?
>>>           sig = sigwait()
>>>           begin
>>>             @@trap_handlers[sig].call(sig)
>>>           rescue CheckTrapHandler
>>>             # ignore
>>>           rescue Exception => e
>>>             main_thread.kill(e)
>>>           end
>>>         end
>>>       }
>>>       end unless @@signal_thread
>>>     else
>>>       @@trap_handlers.delete(sig)
>>>       @@signal_thread.raise(CheckTrapHandler) if @@signal_thread
>>>     end
>>>   end
>>>
>>>
>>>  半年くらい早くからこの議論をしていれば,こんなふうに変えるとすっきりし
>>> たんじゃないかと思います.2.0.0 ではどうしますかねぇ.
>
>  実装もこんな感じで同意でしょうか.
>
>  もう,いっそいろいろ面倒なんで,変えちゃう? 遠藤さんが ok っていった
> ら変えてもよさそうだが,ちょっと大きすぎるかなぁ.

トラップハンドラスレッドもタイマースレッドと同じく特別扱いを用意してfork safeにするという改造が許されるなら、この案でも僕は異論ありません

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

end of thread, other threads:[~2012-11-13  8:42 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-11-06 19:37 [ruby-dev:46434] トラップハンドラで許されない操作はなにか KOSAKI Motohiro
2012-11-09  1:08 ` [ruby-dev:46454] トラップハンドラで許されない操作はなにか Tomoyuki Chikanaga
2012-11-09 15:41   ` [ruby-dev:46466] " KOSAKI Motohiro
2012-11-09 18:09     ` [ruby-dev:46469] " SASADA Koichi
2012-11-10 13:33       ` [ruby-dev:46474] " Tomoyuki Chikanaga
2012-11-10 23:13       ` [ruby-dev:46476] " KOSAKI Motohiro
2012-11-12 10:48         ` [ruby-dev:46499] " SASADA Koichi
2012-11-13  8:43           ` [ruby-dev:46508] " KOSAKI Motohiro
2012-11-10 14:32   ` [ruby-dev:46475] " Tanaka Akira

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).