From: Daisuke Aoki Date: 2000-11-15T23:31:53+09:00 Subject: [ruby-dev:11540] Re: SIGINT on windows 青木です。 "Nobuyoshi.Nakada" wrote: > -MT 付きだと winsig.c:ctrlevent_capture() で _mlock(_SIGNAL_LOCK) とし > てクリティカルセクションを使ってるわけです。となると、単純に Win9x では > signal のスレッドではクリティカルセクションを使えないとは思えない、って > ことです。やっぱり SetThreadContext() との組み合わせがまずいってことか、 > 他になにか間違えてるか。 止まってしまう時の状況をちゃんと調べてみました。 SIGNAL: win32_main_context() の1番目の RUBY_CRITICAL に入る。 MAIN: win32_enter_syscall() の win32_disable_interrupt() で止まる。 SuspendThread() で止まっていないケース。 SIGNAL: win32_main_context() で MAIN を SetThreadContext() で操作。MAIN が動く。 SIGNAL: win32_main_context() の1番目の RUBY_CRITICAL から出る。 MAIN: win32_call_hander() の RUBY_CRITICAL に入る。 MAIN: win32_call_hander() の RUBY_CRITICAL から出る。 SIGNAL: win32_main_context() の2番目の RUBY_CRITICAL に入ろうとするが止まる。 という感じで、EnterCriticalSection() で止まっているスレッドに、 SetThreadContext() で操作しているしたのが原因?で win32_enter_syscall() の win32_disable_interrupt() で CriticalSection を獲得してないはずなのになぜか 獲得したことになってて、win32_main_context() の2番目の RUBY_CRITICAL に入ることが できずデッドロックしてしまうみたいです。 で、2行目の MAIN: win32_enter_syscall() の win32_disable_interrupt() がないケースでは デッドロックしていません。これは、rb_io_gets() 内のような win32_leave_syscall() の 後に win32_enter_syscall() がすぐ呼ばれるようなケースで起きやすいです。 前、win32_main_context() で SetThreadContext() 使って操作する前に、 メインスレッドで win32_enable_interrupt() でトップレベルまで戻ったときに、 ループで止めるという仕組みをつくって試したことがあったのですが、最終的にはそういうことを しないと同期 API で止まっている状況を完全に防ぐことはできなさそうですね。 -- 青木大輔