summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rubysig.h5
-rw-r--r--sample/philos.rb4
-rw-r--r--signal.c9
-rw-r--r--win32/win32.c126
-rw-r--r--win32/win32.h16
5 files changed, 153 insertions, 7 deletions
diff --git a/rubysig.h b/rubysig.h
index dec1fa1..a837c01 100644
--- a/rubysig.h
+++ b/rubysig.h
@@ -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 --git a/sample/philos.rb b/sample/philos.rb
index 3ccb052..119e7c3 100644
--- a/sample/philos.rb
+++ b/sample/philos.rb
@@ -46,8 +46,8 @@ def philosopher(n)
end
end
-for i in 0..N-1
- Thread.start{philosopher(i)}
+for n in 0..N-1
+ Thread.start(n){|i| philosopher(i)}
sleep 0.1
end
diff --git a/signal.c b/signal.c
index f98a0b3..b5ed58e 100644
--- a/signal.c
+++ b/signal.c
@@ -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 --git a/win32/win32.c b/win32/win32.c
index 1311b7e..49b781f 100644
--- a/win32/win32.c
+++ b/win32/win32.c
@@ -75,6 +75,22 @@ IsWinNT(void) {
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 @@ flock(int fd, int oper)
// Initialization stuff
//
void
-NtInitialize(int *argc, char ***argv) {
+NtInitialize(int *argc, char ***argv)
+{
WORD version;
int ret;
@@ -1215,7 +1232,7 @@ NtMakeCmdVector (char *cmdline, char ***vec, int InputCmd)
//
DIR *
-opendir(const char *filename)
+opendir(char *filename)
{
DIR *p;
long len;
@@ -1887,6 +1904,7 @@ myselect (int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
long r;
fd_set file_rd;
fd_set file_wr;
+ fd_set trap;
int file_nfds;
int trap_immediate = rb_trap_immediate;
@@ -1907,9 +1925,16 @@ myselect (int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
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:
@@ -1923,7 +1948,8 @@ myselect (int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
}
static void
-StartSockets () {
+StartSockets ()
+{
WORD version;
WSADATA retdata;
int ret;
@@ -1950,6 +1976,11 @@ StartSockets () {
*/
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
@@ -2513,3 +2544,90 @@ mytimes(struct tms *tmbuf)
}
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;
+}
diff --git a/win32/win32.h b/win32/win32.h
index 0435e0c..d0e1815 100644
--- a/win32/win32.h
+++ b/win32/win32.h
@@ -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
@@ -426,4 +426,18 @@ struct tms {
#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