summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--Makefile.in2
-rw-r--r--error.c4
-rw-r--r--gc.c47
-rw-r--r--numeric.c2
-rw-r--r--object.c5
-rw-r--r--random.c1
-rw-r--r--rubysig.h38
-rw-r--r--signal.c25
-rw-r--r--version.h4
-rw-r--r--win32/win32.c552
-rw-r--r--win32/win32.h26
12 files changed, 508 insertions, 202 deletions
diff --git a/ChangeLog b/ChangeLog
index 9b7ab98aa4..d97eef3dc1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+Mon Nov 13 22:44:52 2000 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * error.c (rb_bug): print version to stderr.
+
Mon Nov 13 19:02:08 2000 WATANABE Hirofumi <eban@ruby-lang.org>
* win32/win32.c, io.c, process.c: the exit status of program must be
diff --git a/Makefile.in b/Makefile.in
index 60cbd40eb1..94ebfb9a8c 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -245,7 +245,7 @@ dir.@OBJEXT@: dir.c ruby.h config.h defines.h intern.h
dln.@OBJEXT@: dln.c config.h defines.h dln.h
dmyext.@OBJEXT@: dmyext.c
enum.@OBJEXT@: enum.c ruby.h config.h defines.h intern.h
-error.@OBJEXT@: error.c ruby.h config.h defines.h intern.h env.h
+error.@OBJEXT@: error.c ruby.h config.h defines.h intern.h env.h version.h
eval.@OBJEXT@: eval.c ruby.h config.h defines.h intern.h node.h env.h rubysig.h st.h dln.h
file.@OBJEXT@: file.c ruby.h config.h defines.h intern.h rubyio.h rubysig.h
gc.@OBJEXT@: gc.c ruby.h config.h defines.h intern.h rubysig.h st.h node.h env.h re.h regex.h
diff --git a/error.c b/error.c
index 34eae0d6b0..4527128030 100644
--- a/error.c
+++ b/error.c
@@ -12,6 +12,8 @@
#include "ruby.h"
#include "env.h"
+#include "version.h"
+
#include <stdio.h>
#ifdef HAVE_STDARG_PROTOTYPES
#include <stdarg.h>
@@ -172,7 +174,7 @@ rb_bug(fmt, va_alist)
va_init_list(args, fmt);
warn_print(buf, args);
va_end(args);
- ruby_show_version();
+ fprintf(stderr, "ruby %s (%s) [%s]\n", RUBY_VERSION, RUBY_RELEASE_DATE, RUBY_PLATFORM);
abort();
}
diff --git a/gc.c b/gc.c
index 1444a960a2..ac05c11c22 100644
--- a/gc.c
+++ b/gc.c
@@ -74,10 +74,10 @@ ruby_xmalloc(size)
if (malloc_memories > GC_MALLOC_LIMIT) {
rb_gc();
}
- mem = malloc(size);
+ RUBY_CRITICAL(mem = malloc(size));
if (!mem) {
rb_gc();
- mem = malloc(size);
+ RUBY_CRITICAL(mem = malloc(size));
if (!mem) {
if (size >= 10 * 1024 * 1024) {
rb_raise(rb_eNoMemError, "tried to allocate too big memory");
@@ -114,10 +114,10 @@ ruby_xrealloc(ptr, size)
if (!ptr) return xmalloc(size);
if (size == 0) size = 1;
malloc_memories += size;
- mem = realloc(ptr, size);
+ RUBY_CRITICAL(mem = realloc(ptr, size));
if (!mem) {
rb_gc();
- mem = realloc(ptr, size);
+ RUBY_CRITICAL(mem = realloc(ptr, size));
if (!mem)
if (size >= 50 * 1024 * 1024) {
rb_raise(rb_eNoMemError, "tried to re-allocate too big memory");
@@ -132,7 +132,8 @@ void
ruby_xfree(x)
void *x;
{
- if (x) free(x);
+ if (x)
+ RUBY_CRITICAL(free(x));
}
extern int ruby_in_compile;
@@ -186,7 +187,7 @@ rb_gc_unregister_address(addr)
if (tmp->varptr == addr) {
Global_List = tmp->next;
- free(tmp);
+ RUBY_CRITICAL(free(tmp));
return;
}
while (tmp->next) {
@@ -194,7 +195,7 @@ rb_gc_unregister_address(addr)
struct gc_list *t = tmp->next;
tmp->next = tmp->next->next;
- free(t);
+ RUBY_CRITICAL(free(t));
break;
}
tmp = tmp->next;
@@ -253,13 +254,13 @@ add_heap()
if (heaps_used == heaps_length) {
/* Realloc heaps */
heaps_length += HEAPS_INCREMENT;
- heaps = (heaps_used>0)?
- (RVALUE**)realloc(heaps, heaps_length*sizeof(RVALUE*)):
- (RVALUE**)malloc(heaps_length*sizeof(RVALUE*));
+ RUBY_CRITICAL(heaps = (heaps_used>0)?
+ (RVALUE**)realloc(heaps, heaps_length*sizeof(RVALUE*)):
+ (RVALUE**)malloc(heaps_length*sizeof(RVALUE*)));
if (heaps == 0) mem_error("heaps: can't alloc memory");
}
- p = heaps[heaps_used++] = (RVALUE*)malloc(sizeof(RVALUE)*HEAP_SLOTS);
+ RUBY_CRITICAL(p = heaps[heaps_used++] = (RVALUE*)malloc(sizeof(RVALUE)*HEAP_SLOTS));
if (p == 0) mem_error("add_heap: can't alloc memory");
pend = p + HEAP_SLOTS;
if (lomem == 0 || lomem > p) lomem = p;
@@ -754,12 +755,12 @@ obj_free(obj)
case T_STRING:
#define STR_NO_ORIG FL_USER2 /* copied from string.c */
if (!RANY(obj)->as.string.orig || FL_TEST(obj, STR_NO_ORIG)) {
- free(RANY(obj)->as.string.ptr);
+ RUBY_CRITICAL(free(RANY(obj)->as.string.ptr));
}
break;
case T_ARRAY:
if (RANY(obj)->as.array.ptr) {
- free(RANY(obj)->as.array.ptr);
+ RUBY_CRITICAL(free(RANY(obj)->as.array.ptr));
}
break;
case T_HASH:
@@ -772,13 +773,13 @@ obj_free(obj)
re_free_pattern(RANY(obj)->as.regexp.ptr);
}
if (RANY(obj)->as.regexp.str) {
- free(RANY(obj)->as.regexp.str);
+ RUBY_CRITICAL(free(RANY(obj)->as.regexp.str));
}
break;
case T_DATA:
if (DATA_PTR(obj)) {
if ((long)RANY(obj)->as.data.dfree == -1) {
- free(DATA_PTR(obj));
+ RUBY_CRITICAL(free(DATA_PTR(obj)));
}
else if (RANY(obj)->as.data.dfree) {
(*RANY(obj)->as.data.dfree)(DATA_PTR(obj));
@@ -788,13 +789,13 @@ obj_free(obj)
case T_MATCH:
if (RANY(obj)->as.match.regs) {
re_free_registers(RANY(obj)->as.match.regs);
- free(RANY(obj)->as.match.regs);
+ RUBY_CRITICAL(free(RANY(obj)->as.match.regs));
}
break;
case T_FILE:
if (RANY(obj)->as.file.fptr) {
rb_io_fptr_finalize(RANY(obj)->as.file.fptr);
- free(RANY(obj)->as.file.fptr);
+ RUBY_CRITICAL(free(RANY(obj)->as.file.fptr));
}
break;
case T_ICLASS:
@@ -807,19 +808,19 @@ obj_free(obj)
case T_BIGNUM:
if (RANY(obj)->as.bignum.digits) {
- free(RANY(obj)->as.bignum.digits);
+ RUBY_CRITICAL(free(RANY(obj)->as.bignum.digits));
}
break;
case T_NODE:
switch (nd_type(obj)) {
case NODE_SCOPE:
if (RANY(obj)->as.node.u1.tbl) {
- free(RANY(obj)->as.node.u1.tbl);
+ RUBY_CRITICAL(free(RANY(obj)->as.node.u1.tbl));
}
break;
#ifdef C_ALLOCA
case NODE_ALLOCA:
- free(RANY(obj)->as.node.u1.value);
+ RUBY_CRITICAL(free(RANY(obj)->as.node.u1.value));
break;
#endif
}
@@ -830,15 +831,15 @@ obj_free(obj)
RANY(obj)->as.scope.flag != SCOPE_ALLOCA) {
VALUE *vars = RANY(obj)->as.scope.local_vars-1;
if (vars[0] == 0)
- free(RANY(obj)->as.scope.local_tbl);
+ RUBY_CRITICAL(free(RANY(obj)->as.scope.local_tbl));
if (RANY(obj)->as.scope.flag&SCOPE_MALLOC)
- free(vars);
+ RUBY_CRITICAL(free(vars));
}
break;
case T_STRUCT:
if (RANY(obj)->as.rstruct.ptr) {
- free(RANY(obj)->as.rstruct.ptr);
+ RUBY_CRITICAL(free(RANY(obj)->as.rstruct.ptr));
}
break;
diff --git a/numeric.c b/numeric.c
index cc53c3660a..0a172a3965 100644
--- a/numeric.c
+++ b/numeric.c
@@ -785,7 +785,7 @@ rb_num2long(val)
return Qnil; /* not reached */
default:
- val = rb_Integer(val);
+ val = rb_to_int(val);
return NUM2LONG(val);
}
}
diff --git a/object.c b/object.c
index 9b5d50a457..c4283cb069 100644
--- a/object.c
+++ b/object.c
@@ -885,8 +885,8 @@ rb_to_integer(val, method)
val = rb_rescue2(to_type, (VALUE)&arg1, fail_to_type, (VALUE)&arg2,
rb_eStandardError, rb_eNameError, 0);
if (!rb_obj_is_kind_of(val, rb_cInteger)) {
- rb_raise(rb_eTypeError, "%s#%s_i should return Integer",
- method, rb_class2name(CLASS_OF(arg1.val)));
+ rb_raise(rb_eTypeError, "%s#%s should return Integer",
+ rb_class2name(CLASS_OF(arg1.val)), method);
}
return val;
}
@@ -1166,6 +1166,7 @@ Init_Object()
rb_undef_method(CLASS_OF(rb_cSymbol), "new");
rb_define_method(rb_cSymbol, "type", sym_type, 0);
rb_define_method(rb_cSymbol, "to_i", sym_to_i, 0);
+ rb_define_method(rb_cSymbol, "to_int", sym_to_i, 0);
rb_define_method(rb_cSymbol, "inspect", sym_inspect, 0);
rb_define_method(rb_cSymbol, "to_s", sym_to_s, 0);
rb_define_method(rb_cSymbol, "id2name", sym_to_s, 0);
diff --git a/random.c b/random.c
index 028820d861..5ac7868bf1 100644
--- a/random.c
+++ b/random.c
@@ -114,6 +114,7 @@ rb_f_srand(argc, argv, obj)
VALUE a;
unsigned int seed, old;
+ rb_secure(4);
if (rb_scan_args(argc, argv, "01", &a) == 0) {
static int n = 0;
struct timeval tv;
diff --git a/rubysig.h b/rubysig.h
index a837c017b2..88b30830d9 100644
--- a/rubysig.h
+++ b/rubysig.h
@@ -13,14 +13,40 @@
#ifndef SIG_H
#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))
+typedef LONG rb_atomic_t;
+
+# define ATOMIC_TEST(var) InterlockedExchange(&(var), 0)
+# define ATOMIC_SET(var, val) InterlockedExchange(&(var), (val))
+# define ATOMIC_INC(var) InterlockedIncrement(&(var))
+# define ATOMIC_DEC(var) InterlockedDecrement(&(var))
+
+/* Windows doesn't allow interrupt while system calls */
+# define TRAP_BEG win32_enter_syscall()
+# define TRAP_END win32_leave_syscall()
+# define RUBY_CRITICAL(statements) do {\
+ win32_disable_interrupt();\
+ statements;\
+ win32_enable_interrupt();\
+} while (0)
#else
-#define TRAP_BEG (rb_trap_immediate=1)
-#define TRAP_END (rb_trap_immediate=0)
+typedef int rb_atomic_t;
+
+# define ATOMIC_TEST(var) ((var) ? ((var) = 0, 1) : 0)
+# define ATOMIC_SET(var, val) ((var) = (val))
+# define ATOMIC_INC(var) (++(var))
+# define ATOMIC_DEC(var) (--(var))
+
+# define TRAP_BEG (rb_trap_immediate=1)
+# define TRAP_END (rb_trap_immediate=0)
+# define RUBY_CRITICAL(statements) do {\
+ int trap_immediate = rb_trap_immediate;\
+ rb_trap_immediate = 0;\
+ statements;\
+ rb_trap_immediate = trap_immediate;\
+} while (0)
#endif
+EXTERN rb_atomic_t rb_trap_immediate;
EXTERN int rb_prohibit_interrupt;
#define DEFER_INTS {rb_prohibit_interrupt++;}
@@ -29,7 +55,7 @@ EXTERN int rb_prohibit_interrupt;
VALUE rb_with_disable_interrupt _((VALUE(*)(),VALUE));
-EXTERN int rb_trap_pending;
+EXTERN rb_atomic_t rb_trap_pending;
void rb_trap_restore_mask _((void));
EXTERN int rb_thread_critical;
diff --git a/signal.c b/signal.c
index b5ed58ec75..77233c1852 100644
--- a/signal.c
+++ b/signal.c
@@ -260,9 +260,9 @@ rb_f_kill(argc, argv)
}
static VALUE trap_list[NSIG];
-static int trap_pending_list[NSIG];
-int rb_trap_pending;
-int rb_trap_immediate;
+static rb_atomic_t trap_pending_list[NSIG];
+rb_atomic_t rb_trap_pending;
+rb_atomic_t rb_trap_immediate;
int rb_prohibit_interrupt;
void
@@ -303,6 +303,7 @@ posix_signal(signum, handler)
#define ruby_signal(sig,handle) signal((sig),(handle))
#endif
+static void signal_exec _((int sig));
static void
signal_exec(sig)
int sig;
@@ -342,11 +343,9 @@ sighandle(sig)
int sig;
{
#ifdef NT
-#define end_interrupt() win32_thread_resume_main()
- if (win32_main_context(sig, sighandle)) return;
-
+#define IN_MAIN_CONTEXT(f, a) (win32_main_context(a, f) ? (void)0 : f(a))
#else
-#define end_interrupt() (void)0
+#define IN_MAIN_CONTEXT(f, a) f(a)
#endif
if (sig >= NSIG) {
@@ -357,16 +356,14 @@ sighandle(sig)
ruby_signal(sig, sighandle);
#endif
- if (rb_trap_immediate) {
- rb_trap_immediate = 0;
- signal_exec(sig);
- rb_trap_immediate = 1;
+ if (ATOMIC_TEST(rb_trap_immediate)) {
+ IN_MAIN_CONTEXT(signal_exec, sig);
+ ATOMIC_SET(rb_trap_immediate, 1);
}
else {
- rb_trap_pending++;
- trap_pending_list[sig]++;
+ ATOMIC_INC(rb_trap_pending);
+ ATOMIC_INC(trap_pending_list[sig]);
}
- end_interrupt();
}
#ifdef SIGBUS
diff --git a/version.h b/version.h
index 9f8914673b..d731091ec4 100644
--- a/version.h
+++ b/version.h
@@ -1,4 +1,4 @@
#define RUBY_VERSION "1.6.2"
-#define RUBY_RELEASE_DATE "2000-11-13"
+#define RUBY_RELEASE_DATE "2000-11-14"
#define RUBY_VERSION_CODE 162
-#define RUBY_RELEASE_CODE 20001113
+#define RUBY_RELEASE_CODE 20001114
diff --git a/win32/win32.c b/win32/win32.c
index 7a2dea8848..74c18aa3ed 100644
--- a/win32/win32.c
+++ b/win32/win32.c
@@ -34,6 +34,32 @@
#define bool int
#endif
+#if USE_INTERRUPT_WINSOCK
+
+# if defined(_MSC_VER) && _MSC_VER <= 1000
+/* VC++4.0 doesn't have this. */
+extern DWORD WSAWaitForMultipleEvents(DWORD nevent, const HANDLE *events,
+ BOOL waitall, DWORD timeout,
+ BOOL alertable);
+# endif
+
+# define WaitForMultipleEvents WSAWaitForMultipleEvents
+# define CreateSignal() (HANDLE)WSACreateEvent()
+# define SetSignal(ev) WSASetEvent(ev)
+# define ResetSignal(ev) WSAResetEvent(ev)
+#else /* USE_INTERRUPT_WINSOCK */
+# define WaitForMultipleEvents WaitForMultipleObjectsEx
+# define CreateSignal() CreateEvent(NULL, FALSE, FALSE, NULL);
+# define SetSignal(ev) SetEvent(ev)
+# define ResetSignal(ev) (void)0
+#endif /* USE_INTERRUPT_WINSOCK */
+
+#ifdef WIN32_DEBUG
+#define Debug(something) something
+#else
+#define Debug(something) /* nothing */
+#endif
+
#define TO_SOCKET(x) _get_osfhandle(x)
bool NtSyncProcess = TRUE;
@@ -46,6 +72,7 @@ static bool NtHasRedirection (char *);
static int valid_filename(char *s);
static void StartSockets ();
static char *str_grow(struct RString *str, size_t new_size);
+static DWORD wait_events(HANDLE event, DWORD timeout);
char *NTLoginName;
@@ -76,17 +103,23 @@ IsWinNT(void) {
}
/* main thread constants */
-HANDLE rb_CurrentProcessHandle;
-HANDLE rb_MainThreadHandle;
-DWORD rb_MainThreadId;
-HANDLE rb_InterruptEvent;
+static struct {
+ HANDLE handle;
+ DWORD id;
+} main_thread;
+
+/* interrupt stuff */
+static HANDLE interrupted_event;
HANDLE GetCurrentThreadHandle(void)
{
+ static HANDLE current_process_handle = NULL;
HANDLE h;
- HANDLE proc = rb_CurrentProcessHandle;
- if (!DuplicateHandle(proc, GetCurrentThread(), proc, &h,
+ if (!current_process_handle)
+ current_process_handle = GetCurrentProcess();
+ if (!DuplicateHandle(current_process_handle, GetCurrentThread(),
+ current_process_handle, &h,
0, FALSE, DUPLICATE_SAME_ACCESS))
return NULL;
return h;
@@ -98,68 +131,78 @@ HANDLE GetCurrentThreadHandle(void)
#define LK_ERR(f,i) ((f) ? (i = 0) : (errno = GetLastError()))
#define LK_LEN 0xffff0000
-int
-flock(int fd, int oper)
+static VALUE
+flock_winnt(VALUE self, int argc, VALUE* argv)
{
OVERLAPPED o;
int i = -1;
- HANDLE fh;
+ const HANDLE fh = (HANDLE)self;
+ const int oper = argc;
- fh = (HANDLE)_get_osfhandle(fd);
memset(&o, 0, sizeof(o));
- if(IsWinNT()) {
- switch(oper) {
- case LOCK_SH: /* shared lock */
- LK_ERR(LockFileEx(fh, 0, 0, LK_LEN, 0, &o),i);
- break;
- case LOCK_EX: /* exclusive lock */
- LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, 0, &o),i);
- break;
- case LOCK_SH|LOCK_NB: /* non-blocking shared lock */
- LK_ERR(LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o),i);
- break;
- case LOCK_EX|LOCK_NB: /* non-blocking exclusive lock */
- LK_ERR(LockFileEx(fh,
- LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
- 0, LK_LEN, 0, &o),i);
- if(errno == EDOM) errno = EWOULDBLOCK;
- break;
- case LOCK_UN: /* unlock lock */
- if (UnlockFileEx(fh, 0, LK_LEN, 0, &o)) {
- i = 0;
- }
- else {
- /* GetLastError() must returns `ERROR_NOT_LOCKED' */
+ switch(oper) {
+ case LOCK_SH: /* shared lock */
+ LK_ERR(LockFileEx(fh, 0, 0, LK_LEN, 0, &o), i);
+ break;
+ case LOCK_EX: /* exclusive lock */
+ LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, 0, &o), i);
+ break;
+ case LOCK_SH|LOCK_NB: /* non-blocking shared lock */
+ LK_ERR(LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o), i);
+ break;
+ case LOCK_EX|LOCK_NB: /* non-blocking exclusive lock */
+ LK_ERR(LockFileEx(fh,
+ LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
+ 0, LK_LEN, 0, &o), i);
+ if (errno == EDOM)
+ errno = EWOULDBLOCK;
+ break;
+ case LOCK_UN: /* unlock lock */
+ if (UnlockFileEx(fh, 0, LK_LEN, 0, &o)) {
+ i = 0;
+ if (errno == EDOM)
errno = EWOULDBLOCK;
- }
- if(errno == EDOM) errno = EWOULDBLOCK;
- break;
- default: /* unknown */
- errno = EINVAL;
- break;
- }
+ }
+ else {
+ /* GetLastError() must returns `ERROR_NOT_LOCKED' */
+ errno = EWOULDBLOCK;
+ }
+ break;
+ default: /* unknown */
+ errno = EINVAL;
+ break;
}
- else if(IsWin95()) {
- switch(oper) {
- case LOCK_EX:
- while(i == -1) {
- LK_ERR(LockFile(fh, 0, 0, LK_LEN, 0), i);
- if(errno != EDOM && i == -1) break;
- }
- break;
- case LOCK_EX | LOCK_NB:
+ return i;
+}
+
+static VALUE
+flock_win95(VALUE self, int argc, VALUE* argv)
+{
+ int i = -1;
+ const HANDLE fh = (HANDLE)self;
+ const int oper = argc;
+
+ switch(oper) {
+ case LOCK_EX:
+ while(i == -1) {
LK_ERR(LockFile(fh, 0, 0, LK_LEN, 0), i);
- if(errno == EDOM) errno = EWOULDBLOCK;
- break;
- case LOCK_UN:
- LK_ERR(UnlockFile(fh, 0, 0, LK_LEN, 0), i);
- if(errno == EDOM) errno = EWOULDBLOCK;
- break;
- default:
- errno = EINVAL;
- break;
- }
+ if (errno != EDOM && i == -1) break;
+ }
+ break;
+ case LOCK_EX | LOCK_NB:
+ LK_ERR(LockFile(fh, 0, 0, LK_LEN, 0), i);
+ if (errno == EDOM)
+ errno = EWOULDBLOCK;
+ break;
+ case LOCK_UN:
+ LK_ERR(UnlockFile(fh, 0, 0, LK_LEN, 0), i);
+ if (errno == EDOM)
+ errno = EWOULDBLOCK;
+ break;
+ default:
+ errno = EINVAL;
+ break;
}
return i;
}
@@ -167,6 +210,22 @@ flock(int fd, int oper)
#undef LK_ERR
#undef LK_LEN
+int
+flock(int fd, int oper)
+{
+ static asynchronous_func_t locker = NULL;
+
+ if (!locker) {
+ if (IsWinNT())
+ locker = flock_winnt;
+ else
+ locker = flock_win95;
+ }
+
+ return win32_asynchronize(locker,
+ (VALUE)_get_osfhandle(fd), oper, NULL,
+ (DWORD)-1);
+}
//#undef const
//FILE *fdopen(int, const char *);
@@ -1908,8 +1967,10 @@ myselect (int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
long r;
fd_set file_rd;
fd_set file_wr;
+#ifdef USE_INTERRUPT_WINSOCK
+ fd_set trap;
+#endif /* USE_INTERRUPT_WINSOCK */
int file_nfds;
- int trap_immediate = rb_trap_immediate;
if (!NtSocketsInitialized++) {
StartSockets();
@@ -1928,18 +1989,26 @@ myselect (int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
if (wr) *wr = file_wr;
return file_nfds;
}
- if (trap_immediate)
- TRAP_END;
+
+#if USE_INTERRUPT_WINSOCK
+ if (ex)
+ trap = *ex;
+ else
+ trap.fd_count = 0;
+ if (trap.fd_count < FD_SETSIZE)
+ trap.fd_array[trap.fd_count++] = (SOCKET)interrupted_event;
+ // else unable to catch interrupt.
+ ex = &trap;
+#endif /* USE_INTERRUPT_WINSOCK */
+
if ((r = select (nfds, rd, wr, ex, timeout)) == SOCKET_ERROR) {
errno = WSAGetLastError();
switch (errno) {
- case WSAEINTR:
+ case WSAEINTR:
errno = EINTR;
break;
}
}
- if (trap_immediate)
- TRAP_BEG;
return r;
}
@@ -1957,31 +2026,33 @@ StartSockets ()
//
version = MAKEWORD(1, 1);
if (ret = WSAStartup(version, &retdata))
- rb_fatal ("Unable to locate winsock library!\n");
+ rb_fatal ("Unable to locate winsock library!\n");
if (LOBYTE(retdata.wVersion) != 1)
- rb_fatal("could not find version 1 of winsock dll\n");
+ rb_fatal("could not find version 1 of winsock dll\n");
if (HIBYTE(retdata.wVersion) != 1)
- rb_fatal("could not find version 1 of winsock dll\n");
+ rb_fatal("could not find version 1 of winsock dll\n");
atexit((void (*)(void)) WSACleanup);
- iSockOpt = SO_SYNCHRONOUS_NONALERT;
+ iSockOpt = SO_SYNCHRONOUS_NONALERT;
/*
* Enable the use of sockets as filehandles
*/
setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,
- (char *)&iSockOpt, sizeof(iSockOpt));
+ (char *)&iSockOpt, sizeof(iSockOpt));
- rb_CurrentProcessHandle = GetCurrentProcess();
- rb_MainThreadHandle = GetCurrentThreadHandle();
- rb_MainThreadId = GetCurrentThreadId();
- rb_InterruptEvent = CreateEvent(NULL, FALSE, TRUE, NULL);
+ main_thread.handle = GetCurrentThreadHandle();
+ main_thread.id = GetCurrentThreadId();
+
+ interrupted_event = CreateSignal();
+ if (!interrupted_event)
+ rb_fatal("Unable to create interrupt event!\n");
}
#undef accept
-SOCKET
+SOCKET
myaccept (SOCKET s, struct sockaddr *addr, int *addrlen)
{
SOCKET r;
@@ -1990,12 +2061,8 @@ myaccept (SOCKET s, struct sockaddr *addr, int *addrlen)
if (!NtSocketsInitialized++) {
StartSockets();
}
- if (trap_immediate)
- TRAP_END;
if ((r = accept (TO_SOCKET(s), addr, addrlen)) == INVALID_SOCKET)
errno = WSAGetLastError();
- if (trap_immediate)
- TRAP_BEG;
return r;
}
@@ -2342,7 +2409,7 @@ waitpid (pid_t pid, int *stat_loc, int options)
} else {
timeout = INFINITE;
}
- if (WaitForSingleObject((HANDLE) pid, timeout) == WAIT_OBJECT_0) {
+ if (wait_events((HANDLE)pid, timeout) == WAIT_OBJECT_0) {
pid = _cwait(stat_loc, pid, 0);
#if !defined __BORLANDC__
*stat_loc <<= 8;
@@ -2487,25 +2554,26 @@ myrename(const char *oldpath, const char *newpath)
if (!MoveFile(oldpath, newpath))
res = -1;
- if (res == 0 || (GetLastError() != ERROR_ALREADY_EXISTS
- && GetLastError() != ERROR_FILE_EXISTS))
- goto done;
-
- if (IsWinNT()) {
- if (MoveFileEx(oldpath, newpath, MOVEFILE_REPLACE_EXISTING))
- res = 0;
- } else {
- for (;;) {
- if (!DeleteFile(newpath) && GetLastError() != ERROR_FILE_NOT_FOUND)
- break;
- else if (MoveFile(oldpath, newpath)) {
- res = 0;
- break;
+ if (res) {
+ switch (GetLastError()) {
+ case ERROR_ALREADY_EXISTS:
+ case ERROR_FILE_EXISTS:
+ if (IsWinNT()) {
+ if (MoveFileEx(oldpath, newpath, MOVEFILE_REPLACE_EXISTING))
+ res = 0;
+ } else {
+ for (;;) {
+ if (!DeleteFile(newpath) && GetLastError() != ERROR_FILE_NOT_FOUND)
+ break;
+ else if (MoveFile(oldpath, newpath)) {
+ res = 0;
+ break;
+ }
+ }
}
}
}
-done:
if (res)
errno = GetLastError();
else
@@ -2545,88 +2613,288 @@ mytimes(struct tms *tmbuf)
}
-static int win32_thread_exclusive(void)
+#undef Sleep
+#define yield_once() Sleep(0)
+#define yield_until(condition) do yield_once(); while (!(condition))
+
+static DWORD wait_events(HANDLE event, DWORD timeout)
{
- if (GetCurrentThreadId() == rb_MainThreadId) return FALSE;
+ HANDLE events[2];
+ int count = 0;
+ DWORD ret;
- SuspendThread(rb_MainThreadHandle);
- return TRUE;
+ if (event) {
+ events[count++] = event;
+ }
+ events[count++] = interrupted_event;
+
+ ret = WaitForMultipleEvents(count, events, FALSE, timeout, TRUE);
+
+ if (ret == WAIT_OBJECT_0 + count - 1) {
+ ResetSignal(interrupted_event);
+ errno = EINTR;
+ }
+
+ return ret;
}
-void win32_thread_resume_main(void)
+static CRITICAL_SECTION* system_state(void)
{
- if (GetCurrentThreadId() != rb_MainThreadId)
- ResumeThread(rb_MainThreadHandle);
+ static int initialized = 0;
+ static CRITICAL_SECTION syssect;
+
+ if (!initialized) {
+ InitializeCriticalSection(&syssect);
+ initialized = 1;
+ }
+ return &syssect;
}
-static void win32_suspend_self(void)
+static LONG flag_interrupt = -1;
+static volatile DWORD tlsi_interrupt = TLS_OUT_OF_INDEXES;
+
+void win32_disable_interrupt(void)
{
- SuspendThread(GetCurrentThread());
+ if (IsWinNT()) {
+ EnterCriticalSection(system_state());
+ return;
+ }
+
+ if (tlsi_interrupt == TLS_OUT_OF_INDEXES) {
+ tlsi_interrupt = TlsAlloc();
+ }
+
+ {
+ DWORD ti = (DWORD)TlsGetValue(tlsi_interrupt);
+ while (InterlockedIncrement(&flag_interrupt) > 0 && !ti) {
+ InterlockedDecrement(&flag_interrupt);
+ Sleep(1);
+ }
+ TlsSetValue(tlsi_interrupt, (PVOID)++ti);
+ }
+}
+
+void win32_enable_interrupt(void)
+{
+ if (IsWinNT()) {
+ LeaveCriticalSection(system_state());
+ return;
+ }
+
+ InterlockedDecrement(&flag_interrupt);
+ TlsSetValue(tlsi_interrupt, (PVOID)((DWORD)TlsGetValue(tlsi_interrupt) - 1));
}
-static void win32_call_handler(int arg, void (*handler)(int), CONTEXT ctx)
+struct handler_arg_t {
+ void (*handler)(int);
+ int arg;
+ int status;
+ int userstate;
+ HANDLE handshake;
+};
+
+static void win32_call_handler(struct handler_arg_t* h)
{
- handler(arg);
- ctx.ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT;
- SetThreadContext(rb_MainThreadHandle, &ctx);
+ int status;
+ RUBY_CRITICAL(rb_protect((VALUE (*)())h->handler, (VALUE)h->arg, &h->status);
+ status = h->status;
+ SetEvent(h->handshake));
+ if (status) {
+ rb_jump_tag(status);
+ }
+ h->userstate = 1; /* never syscall after here */
+ for (;;); /* wait here in user state */
}
-static int catch_interrupt(unsigned long msec)
+static struct handler_arg_t* setup_handler(struct handler_arg_t *harg,
+ int arg,
+ void (*handler)(int),
+ HANDLE handshake)
{
- return !WaitForSingleObject(rb_InterruptEvent, msec);
+ harg->handler = handler;
+ harg->arg = arg;
+ harg->status = 0;
+ harg->userstate = 0;
+ harg->handshake = handshake;
+ return harg;
}
-int win32_interruptible(void)
+static void setup_call(CONTEXT* ctx, struct handler_arg_t *harg)
{
- if (catch_interrupt(0)) return TRUE;
- SetEvent(rb_InterruptEvent);
- return FALSE;
+#ifdef _M_IX86
+ DWORD *esp = (DWORD *)ctx->Esp;
+ *--esp = (DWORD)harg;
+ *--esp = ctx->Eip;
+ ctx->Esp = (DWORD)esp;
+ ctx->Eip = (DWORD)win32_call_handler;
+#else
+#error unsupported processor
+#endif
}
int win32_main_context(int arg, void (*handler)(int))
{
- if (!win32_thread_exclusive()) return FALSE;
+ static HANDLE interrupt_done = NULL;
+ struct handler_arg_t harg;
+ CONTEXT ctx_orig;
+ HANDLE current_thread = GetCurrentThread();
+ int old_priority = GetThreadPriority(current_thread);
- if (!catch_interrupt(0)) {
- SetEvent(rb_InterruptEvent);
- return FALSE;
- }
+ if (GetCurrentThreadId() == main_thread.id) return FALSE;
- {
+ SetSignal(interrupted_event);
+
+ RUBY_CRITICAL({ /* the main thread must be in user state */
CONTEXT ctx;
+ SuspendThread(main_thread.handle);
+ SetThreadPriority(current_thread, GetThreadPriority(main_thread.handle));
+
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;
+ GetThreadContext(main_thread.handle, &ctx);
+ ctx_orig = ctx;
+
+ /* handler context setup */
+ if (!interrupt_done) {
+ interrupt_done = CreateEvent(NULL, FALSE, FALSE, NULL);
+ /* anonymous one-shot event */
}
- ctx.Eip = (DWORD)win32_call_handler;
-#else
-#error
-#endif
+ else {
+ ResetEvent(interrupt_done);
+ }
+ setup_call(&ctx, setup_handler(&harg, arg, handler, interrupt_done));
ctx.ContextFlags = CONTEXT_CONTROL;
- SetThreadContext(rb_MainThreadHandle, &ctx);
+ SetThreadContext(main_thread.handle, &ctx);
+ ResumeThread(main_thread.handle);
+ });
+
+ /* give a chance to the main thread */
+ yield_once();
+ WaitForSingleObject(interrupt_done, INFINITE); /* handshaking */
+
+ if (!harg.status) {
+ /* no exceptions raised, restore old context. */
+ RUBY_CRITICAL({
+ /* ensure the main thread is in user state. */
+ yield_until(harg.userstate);
+
+ SuspendThread(main_thread.handle);
+ ctx_orig.ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT;
+ SetThreadContext(main_thread.handle, &ctx_orig);
+ ResumeThread(main_thread.handle);
+ });
}
- ResumeThread(rb_MainThreadHandle);
+ /* otherwise leave the main thread raised */
+
+ SetThreadPriority(current_thread, old_priority);
return TRUE;
}
-void win32_sleep(unsigned long msec)
+int win32_sleep(unsigned long msec)
{
- int trap_immediate = rb_trap_immediate;
+ return wait_events(NULL, msec) != WAIT_TIMEOUT;
+}
+
+static void catch_interrupt(void)
+{
+ yield_once();
+ win32_sleep(0);
+ CHECK_INTS;
+}
+
+void win32_enter_syscall(void)
+{
+ InterlockedExchange(&rb_trap_immediate, 1);
+ catch_interrupt();
+ win32_disable_interrupt();
+}
+
+void win32_leave_syscall(void)
+{
+ win32_enable_interrupt();
+ catch_interrupt();
+ InterlockedExchange(&rb_trap_immediate, 0);
+}
+
+struct asynchronous_arg_t {
+ /* output field */
+ void* stackaddr;
+
+ /* input field */
+ VALUE (*func)(VALUE self, int argc, VALUE* argv);
+ VALUE self;
+ int argc;
+ VALUE* argv;
+};
+
+static DWORD WINAPI
+call_asynchronous(PVOID argp)
+{
+ struct asynchronous_arg_t *arg = argp;
+ arg->stackaddr = &argp;
+ return (DWORD)arg->func(arg->self, arg->argc, arg->argv);
+}
+
+VALUE win32_asynchronize(asynchronous_func_t func,
+ VALUE self, int argc, VALUE* argv, VALUE intrval)
+{
+ DWORD val;
+ BOOL interrupted = FALSE;
+ HANDLE thr;
+
+ RUBY_CRITICAL({
+ struct asynchronous_arg_t arg;
+
+ arg.stackaddr = NULL;
+ arg.func = func;
+ arg.self = self;
+ arg.argc = argc;
+ arg.argv = argv;
+
+ thr = CreateThread(NULL, 0, call_asynchronous, &arg, 0, &val);
+
+ if (thr) {
+ yield_until(arg.stackaddr);
+
+ if (wait_events(thr, INFINITE) != WAIT_OBJECT_0) {
+ interrupted = TRUE;
+
+ if (TerminateThread(thr, intrval)) {
+ yield_once();
+ }
+ }
+
+ GetExitCodeThread(thr, &val);
+ CloseHandle(thr);
+
+ if (interrupted) {
+ /* must release stack of killed thread, why doesn't Windows? */
+ MEMORY_BASIC_INFORMATION m;
+
+ memset(&m, 0, sizeof(m));
+ if (!VirtualQuery(arg.stackaddr, &m, sizeof(m))) {
+ Debug(fprintf(stderr, "couldn't get stack base:%p:%d\n",
+ arg.stackaddr, GetLastError()));
+ }
+ else if (!VirtualFree(m.AllocationBase, 0, MEM_RELEASE)) {
+ Debug(fprintf(stderr, "couldn't release stack:%p:%d\n",
+ m.AllocationBase, GetLastError()));
+ }
+ }
+ }
+ });
+
+ if (!thr) {
+ rb_fatal("failed to launch waiter thread:%d", GetLastError());
+ }
+
+ if (interrupted) {
+ errno = EINTR;
+ CHECK_INTS;
+ }
- if (trap_immediate)
- TRAP_END;
- catch_interrupt(msec);
- if (trap_immediate)
- TRAP_BEG;
+ return val;
}
diff --git a/win32/win32.h b/win32/win32.h
index d0e18152e5..2976781401 100644
--- a/win32/win32.h
+++ b/win32/win32.h
@@ -427,17 +427,23 @@ struct tms {
#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)
+int win32_sleep(unsigned long msec);
+void win32_enter_syscall(void);
+void win32_leave_syscall(void);
+void win32_disable_interrupt(void);
+void win32_enable_interrupt(void);
+#define Sleep(msec) (void)win32_sleep(msec)
+
+/*
+== ***CAUTION***
+Since this function is very dangerous, ((*NEVER*))
+* lock any HANDLEs(i.e. Mutex, Semaphore, CriticalSection and so on) or,
+* use anything like TRAP_BEG...TRAP_END block structure,
+in asynchronous_func_t.
+*/
+typedef DWORD (*asynchronous_func_t)(DWORD self, int argc, DWORD* argv);
+DWORD win32_asynchronize(asynchronous_func_t func, DWORD self, int argc, DWORD* argv, DWORD intrval);
#endif