From: Daisuke Aoki Date: 2000-10-04T23:36:04+09:00 Subject: [ruby-dev:11131] Re: SIGINT on windows 青木です。 nobu.nakada@nifty.ne.jp wrote: > main の方も suspend されるまで待ってないといけないじゃないで > すか。システムコールに割り込めないとすると busy wait しかないの > かと思ったんですが。SuspendThread() じゃなきゃいいんでしょうか。 メインはそのままサスペンドするか、ビジーウェイトするだけだと思います。 現状で、Windows 95 だと SuspendThread() が効かないので、 ビジーループする必要があり、その時は、 while((volatile)busy_wait_flag) Sleep(0); とかして調べれば。 > [ruby-dev:11111]のようにして試したところ、printf() すると > trap してました。なんか Sleep() するまで signal thread の方が動 > いてないような感じでした。しかし優先度最高じゃないのか? Windows 95 だと、メインスレッドのスレッドプライオリティを 変えても、signal() で設定した Ctrl-C で呼び出される handler の スレッドプライオリティは 0 のままです。メインスレッドのスレッド プライオリティを思いっきり高くすると handler は呼ばれません。 シグナルを処理するスレッドは同一みたく、はじめ一回プライオリティを 変化させることで対処はできますが。 > NT とはこのへんで違いますね。SetThreadContext() しても > suspend 状態のままです。やはりシステムコール中に割り込むのは無 > 理があるような。ていうか、なんで一回目は SuspendThread() とか > SetThreadContext() できるんでしょう。 Windows 95 では、1回目の SetThreadContext() は安全に?できている ようです。ただ、SetThreadContext() した時点で、システムコール中 であるフラグがそのままで、サスペンドを識別機能が無効になったり するのではないでしょうか。あくまで推測ですが。そのへんの知識は ぜんぜんないのでして。 > これは[ruby-dev:10794]と似てますが、 私がメーリングリストに入る前なのでチェックしていませんでした(^^) よくはわかりませんが、古いコンテキストをそのまま使ってやれば 成功はしていたのでは(9x系では)。 > > handler(arg); > > ! ResetEvent(hEvent_win32_call_hander2); > > ! SetEvent(hEvent_win32_call_hander1); > > ! WaitForSingleObject(hEvent_win32_call_hander2,INFINITE); > ここが気になったんですが、WaitForSingleObject()は割り込んでも > 大丈夫なんでしょうか。 なるほど。for(;;) に変えたら問題が消えました。最後に載せますが、 下記のパッチだとWindows 95 でほぼ大丈夫かなと思えるぐらいの動作に なりました。けど、危険性は残っているかもしれません(^^;; > > Sleep(0) は他のスレッドに動作を譲る働きをしますが、Sleep() 自体が > これって明文化された仕様なんですか。 優先度が同じ別のスレッドに譲るみたいです。MSDN Library とかに NT の Win32 のHelp とかに書いてありますよね。多分、自分が優先度一番だと 無視されそうですが。 > > # 私としてはかなりうんざりしてて、SIGINT 関連にもう手を出すのは > > # 止めようと思ってます(^^;; > うーん、できれば…。 うーん(^^;; 以下、Windows 95 用に修正したパッチ(1.6.1からの差分)。けど、 Ctrl-C を押しっぱなしとか連射すると例外が出ます。 このパッチでは sleep 中の trap は無効です(^^;; *** WIN32.C0 Wed Sep 27 07:36:34 2000 --- WIN32.C Tue Oct 03 15:00:00 2000 *************** *** 1930,1936 **** else trap.fd_count = 0; if (trap.fd_count < FD_SETSIZE) ! trap.fd_array[trap.fd_count++] = rb_InterruptEvent; // else unable to catch interrupt. if (trap_immediate) TRAP_END; --- 1930,1936 ---- else trap.fd_count = 0; if (trap.fd_count < FD_SETSIZE) ! trap.fd_array[trap.fd_count++] = (SOCKET)rb_InterruptEvent; // else unable to catch interrupt. if (trap_immediate) TRAP_END; *************** *** 2565,2575 **** SuspendThread(GetCurrentThread()); } static void win32_call_handler(int arg, void (*handler)(int), CONTEXT ctx) { handler(arg); ! ctx.ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT; ! SetThreadContext(rb_MainThreadHandle, &ctx); } static int catch_interrupt(unsigned long msec) --- 2565,2590 ---- SuspendThread(GetCurrentThread()); } + static volatile HANDLE hEvent_win32_call_hander = NULL; + static volatile int win32_call_handler_end = 0; + #if 1 static void win32_call_handler(int arg, void (*handler)(int), CONTEXT ctx) + #else + static void win32_call_handler(int arg, void (*handler)(int)) + #endif { handler(arg); ! SetEvent(hEvent_win32_call_hander); ! for(win32_call_handler_end=1;;){ ! #ifdef _MSC_VER ! // nop や wait の方がいいのかな。 ! __asm { ! hlt ! } ! #endif ! } ! // ctx.ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT; ! // SetThreadContext(rb_MainThreadHandle, &ctx); } static int catch_interrupt(unsigned long msec) *************** *** 2586,2597 **** --- 2601,2619 ---- int win32_main_context(int arg, void (*handler)(int)) { + CONTEXT ctx_orig; + if (!win32_thread_exclusive()) return FALSE; + #if 0 if (!catch_interrupt(0)) { SetEvent(rb_InterruptEvent); return FALSE; } + #endif + + if(hEvent_win32_call_hander==NULL) + hEvent_win32_call_hander = CreateEvent(NULL,FALSE,FALSE,NULL); { CONTEXT ctx; *************** *** 2599,2608 **** --- 2621,2635 ---- ZeroMemory(&ctx, sizeof(CONTEXT)); ctx.ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT; GetThreadContext(rb_MainThreadHandle, &ctx); + ctx_orig = ctx; #ifdef _M_IX86 { + #if 1 DWORD *esp = (DWORD *)(ctx.Esp - sizeof(CONTEXT)); *(CONTEXT *)esp = ctx; + #else + DWORD *esp = (DWORD *)ctx.Esp; + #endif *--esp = (DWORD)handler; *--esp = arg; *--esp = ctx.Eip; *************** *** 2616,2622 **** --- 2643,2667 ---- ctx.ContextFlags = CONTEXT_CONTROL; SetThreadContext(rb_MainThreadHandle, &ctx); } + ResetEvent(hEvent_win32_call_hander); + win32_call_handler_end = 0; ResumeThread(rb_MainThreadHandle); + WaitForSingleObject(hEvent_win32_call_hander,INFINITE); + #undef Sleep + #if 0 + Sleep(100); + #else + { + HANDLE hThread = GetCurrentThread(); + int old = GetThreadPriority(hThread); + SetThreadPriority(hThread,THREAD_PRIORITY_NORMAL); + while(!(volatile int)win32_call_handler_end) + Sleep(0); + SetThreadPriority(hThread,old); + } + #endif + ctx_orig.ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT; + SetThreadContext(rb_MainThreadHandle, &ctx_orig); return TRUE; } -- 青木大輔