From: Tomoyuki Chikanaga Date: 2011-12-14T21:45:18+09:00 Subject: [ruby-dev:44999] [ruby-trunk - Bug #5757] main threadがreadやselectで待っていると、^C でなかなか死なない Issue #5757 has been updated by Tomoyuki Chikanaga. File bug5757.patch added Motohiro KOSAKI wrote: > いや、スレッドがGVL競合してなくて、ubf_selectを登録したけどまだselectを読んでないとき > ubf_selectのkill(VTALRM) はスカるので、もう一回ubf_select_eachが呼ばれるようにする > トリックが必要だという認識です。 少しゆっくり考えてみましたところ、ubf_select() を呼ぶのがタイマースレッドでなければこれまで通り rb_thread_wakeup_timer_thread() を呼ぶので、 signal_thread_list に入れたものをタイマースレッドが確実に blocking region を抜けるまで面倒をみてくれる(定期的にSIGVTALRM送信)ので安泰です。 しかしタイマースレッドがシグナルを処理させるために rb_threadptr_check_signal() からメインスレッドに割り込みする時の ubf_select() で rb_thread_wakeup_timer_thread() を呼ばなくなるため、シグナル受信処理時に SIGVTALRM の喪失してメインスレッドが止まったままになる可能性があるのではないかと思います。 thread_timer() の ping_signal_thread_list() で signal_thread_list をチェックした(そして空だった)後に timer_thread_function() で新たに signal_thread_list にメインスレッドが追加された場合が問題なわけなので、この後に signal_thread_list のチェックを入れればいいのではないかと思います。というわけで追加のパッチを添付します。 ---------------------------------------- Bug #5757: main threadがreadやselectで待っていると、^C でなかなか死なない http://redmine.ruby-lang.org/issues/5757 Author: Yui NARUSE Status: Open Priority: Normal Assignee: Category: Target version: ruby -v: - FreeBSD 9 にて、 ./ruby と起動して ^C を投げてもなかなか死にません。 ./miniruby でも -e'$stdin.read' でも同じです。 仕組みとしては、main thread が read や select で待つ場合、最近は blocking region で unblock.func に ubf_select を設定するわけですが、この時にシグナルが来ると、 1. どこかのスレッドの sighandler が呼ばれて、rb_thread_wakeup_timer_thread() が呼ばれる 2. タイマースレッドが起きて、thread_timer() -> timer_thread_function() -> rb_threadptr_check_signal() -> rb_threadptr_interrupt() -> (th->unblock.func)(th->unblock.arg) -> ubf_select() -> rb_thread_wakeup_timer_thread() が呼ばれる 3. タイマースレッドが起きて、thread_timer() -> timer_thread_function() -> rb_threadptr_check_signal() -> rb_threadptr_interrupt() -> (th->unblock.func)(th->unblock.arg) -> ubf_select() -> rb_thread_wakeup_timer_thread() が呼ばれる 4. タイマースレッドが起きて、thread_timer() -> timer_thread_function() -> rb_threadptr_check_signal() -> rb_threadptr_interrupt() -> (th->unblock.func)(th->unblock.arg) -> ubf_select() -> rb_thread_wakeup_timer_thread() が呼ばれる ... 対策はいくつかあり得ると思うのですが、例えば、ubf_select() から rb_thread_wakeup_timer_thread() を呼ばないようにするとか -- http://redmine.ruby-lang.org