From: "Nobuyoshi.Nakada" Date: 2000-09-14T20:11:44+09:00 Subject: [ruby-dev:10920] SIGINT on windows なかだです。 Windows 環境での SIGINT の件ですが、とりあえず試した限りでは落ちないよ うなので出してみます。どうも TRAP_BEG と TRAP_END がすっきりしないので、 もしこれでうまくいくようなら rb_trap_immediate を置き換えるような形にし たほうのがいいのかも。 # ついでに myselect() の中で rb_InterruptEvent も一緒に待つようにしてみ # たものの、これって正しいのかちと不安。 diff -pruPX ./.excludes current/rubysig.h devel/rubysig.h --- current/rubysig.h Mon May 1 18:41:29 2000 +++ devel/rubysig.h Tue Sep 12 20:53:06 2000 @@ -14,8 +14,13 @@ #define SIG_H EXTERN int rb_trap_immediate; +#ifdef NT +#define TRAP_BEG (rb_trap_immediate=1, SetEvent(rb_InterruptEvent)) +#define TRAP_END (rb_trap_immediate=0, ResetEvent(rb_InterruptEvent)) +#else #define TRAP_BEG (rb_trap_immediate=1) #define TRAP_END (rb_trap_immediate=0) +#endif EXTERN int rb_prohibit_interrupt; #define DEFER_INTS {rb_prohibit_interrupt++;} diff -pruPX ./.excludes current/signal.c devel/signal.c --- current/signal.c Mon Aug 7 14:01:57 2000 +++ devel/signal.c Wed Sep 13 09:36:45 2000 @@ -341,6 +341,14 @@ static RETSIGTYPE sighandle(sig) int sig; { +#ifdef NT +#define end_interrupt() win32_thread_resume_main() + if (win32_main_context(sig, sighandle)) return; + +#else +#define end_interrupt() (void)0 +#endif + if (sig >= NSIG) { rb_bug("trap_handler: Bad signal %d", sig); } @@ -358,6 +366,7 @@ sighandle(sig) rb_trap_pending++; trap_pending_list[sig]++; } + end_interrupt(); } #ifdef SIGBUS diff -pruPX ./.excludes current/win32/win32.h devel/win32/win32.h --- current/win32/win32.h Tue Aug 15 15:22:49 2000 +++ devel/win32/win32.h Tue Sep 12 20:53:03 2000 @@ -143,7 +143,7 @@ extern "C++" { #define execvp _execvp #define execvpe _execvpe #define getpid _getpid -#define sleep(x) Sleep((x)*1000) +#define sleep(x) win32_sleep((x)*1000) #define spawnl _spawnl #define spawnle _spawnle #define spawnlp _spawnlp @@ -425,5 +425,19 @@ struct tms { #undef times #endif #define times mytimes + +/* thread stuff */ +/* initialized by NtInitialize() */ +HANDLE rb_CurrentProcessHandle; +HANDLE rb_MainThreadHandle; +HANDLE rb_InterruptEvent; +DWORD rb_MainThreadId; + +HANDLE GetCurrentThreadHandle(void); +int win32_main_context(int arg, void (*handler)(int)); +int win32_interruptible(void); +void win32_thread_resume_main(void); +void win32_sleep(unsigned long msec); +#define Sleep(msec) win32_sleep(msec) #endif diff -pruPX ./.excludes current/win32/win32.c devel/win32/win32.c --- current/win32/win32.c Fri Sep 1 12:31:05 2000 +++ devel/win32/win32.c Thu Sep 14 18:30:30 2000 @@ -75,6 +75,22 @@ return (IdOS() == VER_PLATFORM_WIN32_NT); } +/* main thread constants */ +HANDLE rb_CurrentProcessHandle; +HANDLE rb_MainThreadHandle; +DWORD rb_MainThreadId; +HANDLE rb_InterruptEvent; + +HANDLE GetCurrentThreadHandle(void) +{ + HANDLE h; + HANDLE proc = rb_CurrentProcessHandle; + + if (!DuplicateHandle(proc, GetCurrentThread(), proc, &h, + 0, FALSE, DUPLICATE_SAME_ACCESS)) + return NULL; + return h; +} /* simulate flock by locking a range on the file */ @@ -160,7 +176,8 @@ // Initialization stuff // void -NtInitialize(int *argc, char ***argv) { +NtInitialize(int *argc, char ***argv) +{ WORD version; int ret; @@ -1211,7 +1228,7 @@ // DIR * -opendir(const char *filename) +opendir(char *filename) { DIR *p; long len; @@ -1879,6 +1896,7 @@ long r; fd_set file_rd; fd_set file_wr; + fd_set trap; int file_nfds; int trap_immediate = rb_trap_immediate; @@ -1899,9 +1917,16 @@ if (wr) *wr = file_wr; return file_nfds; } + if (ex) + trap = *ex; + 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; - if ((r = select (nfds, rd, wr, ex, timeout)) == SOCKET_ERROR) { + if ((r = select (nfds, rd, wr, &trap, timeout)) == SOCKET_ERROR) { errno = WSAGetLastError(); switch (errno) { case WSAEINTR: @@ -1915,7 +1940,8 @@ } static void -StartSockets () { +StartSockets () +{ WORD version; WSADATA retdata; int ret; @@ -1942,6 +1968,11 @@ */ setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&iSockOpt, sizeof(iSockOpt)); + + rb_CurrentProcessHandle = GetCurrentProcess(); + rb_MainThreadHandle = GetCurrentThreadHandle(); + rb_MainThreadId = GetCurrentThreadId(); + rb_InterruptEvent = CreateEvent(NULL, FALSE, TRUE, NULL); } #undef accept @@ -2504,4 +2535,91 @@ tmbuf->tms_cstime = 0; } return 0; +} + + +static int win32_thread_exclusive(void) +{ + if (GetCurrentThreadId() == rb_MainThreadId) return FALSE; + + SuspendThread(rb_MainThreadHandle); + return TRUE; +} + +void win32_thread_resume_main(void) +{ + if (GetCurrentThreadId() != rb_MainThreadId) + ResumeThread(rb_MainThreadHandle); +} + +static void win32_suspend_self(void) +{ + 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) +{ + return !WaitForSingleObject(rb_InterruptEvent, msec); +} + +int win32_interruptible(void) +{ + if (catch_interrupt(0)) return TRUE; + SetEvent(rb_InterruptEvent); + return FALSE; +} + +int win32_main_context(int arg, void (*handler)(int)) +{ + if (!win32_thread_exclusive()) return FALSE; + + if (!catch_interrupt(0)) { + SetEvent(rb_InterruptEvent); + return FALSE; + } + + { + CONTEXT ctx; + + ZeroMemory(&ctx, sizeof(CONTEXT)); + ctx.ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT; + GetThreadContext(rb_MainThreadHandle, &ctx); +#ifdef _M_IX86 + { + DWORD *esp = (DWORD *)(ctx.Esp - sizeof(CONTEXT)); + *(CONTEXT *)esp = ctx; + *--esp = (DWORD)handler; + *--esp = arg; + *--esp = ctx.Eip; + ctx.Esp = (DWORD)esp; + } + ctx.Eip = (DWORD)win32_call_handler; +#else +#error +#endif + + ctx.ContextFlags = CONTEXT_CONTROL; + SetThreadContext(rb_MainThreadHandle, &ctx); + } + ResumeThread(rb_MainThreadHandle); + + return TRUE; +} + +void win32_sleep(unsigned long msec) +{ + int trap_immediate = rb_trap_immediate; + + if (trap_immediate) + TRAP_END; + catch_interrupt(msec); + if (trap_immediate) + TRAP_BEG; } -- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦