From: Daisuke Aoki Date: 2000-10-14T23:57:36+09:00 Subject: [ruby-dev:11217] Re: SIGINT on windows 青木です。 nobu.nakada@nifty.ne.jp wrote: > このへんは使う側のバグもありますよね、基本的には。それに現状 > の Ruby では main thread 以外は signal thread だけなはずなので > 何とかなりそうな気がしますが。 Ruby が Windows の Native の thread 使ってたら、わんさか 問題が起こっていて、先人の苦労たるやものすごいものになっていた かと思います。私は後人なので(^^) > これは Win95 のバグなのかなぁ、signal thread から SetEvent() > できないというわけではなさそうだし…。ていうか同期処理すらでき > なかったら signal あっても何の役にも立たないし。具体的にどこま > でいって落ちるとかは分からないでしょうか。 本質的には、SetThreadContext() を問答無用に使っていくと、 Windows 9x では NT より致命的になりやすいという認識でいいんだと 思います。 > 若干遅くなってる可能性はあります、たしかに。しかし基本的に > malloc() が HeapAlloc() を呼んでたりする以上、クリティカルなの > は間違いないようです。GC が起きていると思われるときに Ctrl+C す > ると落ちるというのがなくなりましたし、現に。 なるほど。GC で落ちていたんですね。 > 一応私が作業してる NT4.0 SP5 では落ち着いてますんで、心置きな > くどうぞ(^^)。 ということで、Windows 95 用の修正パッチを用意しました。 うちではこの修正で問題は特に出ていません。 CVS の Ruby ソースに中田さんの [ruby-dev:11133] のパッチを当てて から添付ファイルのパッチを当てる必要があります。排他処理を API にあまり 頼らず自前してみました。Sleep(0) して待機しますのでシグナル処理時に ちょっと重くなるかもしれません。 後、中田さんの [ruby-dev:11133] のパッチで CriticalSection から Mutex & WaitForSingleObject() に変えても同じ 状況なので、Windows 95 だと、win32_call_handler内で同期用の API を 使うとダメのようです(^^; 下に修正パッチ。 *** win32.c_ Fri Oct 13 15:00:00 2000 --- win32.c Fri Oct 13 15:00:00 2000 *************** *** 2565,2578 **** return &syssect; } void win32_disable_interrupt(void) { ! EnterCriticalSection(system_state()); } void win32_enable_interrupt(void) { ! LeaveCriticalSection(system_state()); } struct handler_arg_t { --- 2565,2599 ---- return &syssect; } + static LONG flag_interrupt = -1; + static volatile DWORD tlsi_interrupt = 0xFFFFFFFF; void win32_disable_interrupt(void) { ! if(IsWin95()){ ! if(tlsi_interrupt==0xFFFFFFFF){ ! tlsi_interrupt = TlsAlloc(); ! /* TlsSetValue(tlsi_interrupt,(LPVOID)0); /* Initial value is 0. */ ! } ! if(!TlsGetValue(tlsi_interrupt)){ ! while(InterlockedIncrement(&flag_interrupt)>0){ ! InterlockedDecrement(&flag_interrupt); ! Sleep(0); ! } ! } ! TlsSetValue(tlsi_interrupt,(LPVOID)((DWORD)TlsGetValue(tlsi_interrupt)+1)); ! } else { ! EnterCriticalSection(system_state()); ! } } void win32_enable_interrupt(void) { ! if(IsWin95()){ ! InterlockedDecrement(&flag_interrupt); ! TlsSetValue(tlsi_interrupt,(LPVOID)((DWORD)TlsGetValue(tlsi_interrupt)-1)); ! } else { ! LeaveCriticalSection(system_state()); ! } } struct handler_arg_t { -- 青木大輔