From: KOSAKI Motohiro Date: 2012-11-07T04:37:07+09:00 Subject: [ruby-dev:46434] トラップハンドラで許されない操作はなにか 小崎です [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ブロックから外れてしまったようなケースにおいてスクリプトからそれを観測する方法はあるか、またそれは救うべきか というめんどくさい問題があるように思えます。正直もてあましているのでご意見お聞かせください