1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@1039 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
matz 2000-11-14 07:10:31 +00:00
parent e9cf3b3bf5
commit 46620a8772
12 changed files with 510 additions and 204 deletions

View file

@ -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> 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 * win32/win32.c, io.c, process.c: the exit status of program must be

View file

@ -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 dln.@OBJEXT@: dln.c config.h defines.h dln.h
dmyext.@OBJEXT@: dmyext.c dmyext.@OBJEXT@: dmyext.c
enum.@OBJEXT@: enum.c ruby.h config.h defines.h intern.h 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 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 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 gc.@OBJEXT@: gc.c ruby.h config.h defines.h intern.h rubysig.h st.h node.h env.h re.h regex.h

View file

@ -12,6 +12,8 @@
#include "ruby.h" #include "ruby.h"
#include "env.h" #include "env.h"
#include "version.h"
#include <stdio.h> #include <stdio.h>
#ifdef HAVE_STDARG_PROTOTYPES #ifdef HAVE_STDARG_PROTOTYPES
#include <stdarg.h> #include <stdarg.h>
@ -172,7 +174,7 @@ rb_bug(fmt, va_alist)
va_init_list(args, fmt); va_init_list(args, fmt);
warn_print(buf, args); warn_print(buf, args);
va_end(args); va_end(args);
ruby_show_version(); fprintf(stderr, "ruby %s (%s) [%s]\n", RUBY_VERSION, RUBY_RELEASE_DATE, RUBY_PLATFORM);
abort(); abort();
} }

47
gc.c
View file

@ -74,10 +74,10 @@ ruby_xmalloc(size)
if (malloc_memories > GC_MALLOC_LIMIT) { if (malloc_memories > GC_MALLOC_LIMIT) {
rb_gc(); rb_gc();
} }
mem = malloc(size); RUBY_CRITICAL(mem = malloc(size));
if (!mem) { if (!mem) {
rb_gc(); rb_gc();
mem = malloc(size); RUBY_CRITICAL(mem = malloc(size));
if (!mem) { if (!mem) {
if (size >= 10 * 1024 * 1024) { if (size >= 10 * 1024 * 1024) {
rb_raise(rb_eNoMemError, "tried to allocate too big memory"); rb_raise(rb_eNoMemError, "tried to allocate too big memory");
@ -114,10 +114,10 @@ ruby_xrealloc(ptr, size)
if (!ptr) return xmalloc(size); if (!ptr) return xmalloc(size);
if (size == 0) size = 1; if (size == 0) size = 1;
malloc_memories += size; malloc_memories += size;
mem = realloc(ptr, size); RUBY_CRITICAL(mem = realloc(ptr, size));
if (!mem) { if (!mem) {
rb_gc(); rb_gc();
mem = realloc(ptr, size); RUBY_CRITICAL(mem = realloc(ptr, size));
if (!mem) if (!mem)
if (size >= 50 * 1024 * 1024) { if (size >= 50 * 1024 * 1024) {
rb_raise(rb_eNoMemError, "tried to re-allocate too big memory"); rb_raise(rb_eNoMemError, "tried to re-allocate too big memory");
@ -132,7 +132,8 @@ void
ruby_xfree(x) ruby_xfree(x)
void *x; void *x;
{ {
if (x) free(x); if (x)
RUBY_CRITICAL(free(x));
} }
extern int ruby_in_compile; extern int ruby_in_compile;
@ -186,7 +187,7 @@ rb_gc_unregister_address(addr)
if (tmp->varptr == addr) { if (tmp->varptr == addr) {
Global_List = tmp->next; Global_List = tmp->next;
free(tmp); RUBY_CRITICAL(free(tmp));
return; return;
} }
while (tmp->next) { while (tmp->next) {
@ -194,7 +195,7 @@ rb_gc_unregister_address(addr)
struct gc_list *t = tmp->next; struct gc_list *t = tmp->next;
tmp->next = tmp->next->next; tmp->next = tmp->next->next;
free(t); RUBY_CRITICAL(free(t));
break; break;
} }
tmp = tmp->next; tmp = tmp->next;
@ -253,13 +254,13 @@ add_heap()
if (heaps_used == heaps_length) { if (heaps_used == heaps_length) {
/* Realloc heaps */ /* Realloc heaps */
heaps_length += HEAPS_INCREMENT; heaps_length += HEAPS_INCREMENT;
heaps = (heaps_used>0)? RUBY_CRITICAL(heaps = (heaps_used>0)?
(RVALUE**)realloc(heaps, heaps_length*sizeof(RVALUE*)): (RVALUE**)realloc(heaps, heaps_length*sizeof(RVALUE*)):
(RVALUE**)malloc(heaps_length*sizeof(RVALUE*)); (RVALUE**)malloc(heaps_length*sizeof(RVALUE*)));
if (heaps == 0) mem_error("heaps: can't alloc memory"); 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"); if (p == 0) mem_error("add_heap: can't alloc memory");
pend = p + HEAP_SLOTS; pend = p + HEAP_SLOTS;
if (lomem == 0 || lomem > p) lomem = p; if (lomem == 0 || lomem > p) lomem = p;
@ -754,12 +755,12 @@ obj_free(obj)
case T_STRING: case T_STRING:
#define STR_NO_ORIG FL_USER2 /* copied from string.c */ #define STR_NO_ORIG FL_USER2 /* copied from string.c */
if (!RANY(obj)->as.string.orig || FL_TEST(obj, STR_NO_ORIG)) { 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; break;
case T_ARRAY: case T_ARRAY:
if (RANY(obj)->as.array.ptr) { if (RANY(obj)->as.array.ptr) {
free(RANY(obj)->as.array.ptr); RUBY_CRITICAL(free(RANY(obj)->as.array.ptr));
} }
break; break;
case T_HASH: case T_HASH:
@ -772,13 +773,13 @@ obj_free(obj)
re_free_pattern(RANY(obj)->as.regexp.ptr); re_free_pattern(RANY(obj)->as.regexp.ptr);
} }
if (RANY(obj)->as.regexp.str) { if (RANY(obj)->as.regexp.str) {
free(RANY(obj)->as.regexp.str); RUBY_CRITICAL(free(RANY(obj)->as.regexp.str));
} }
break; break;
case T_DATA: case T_DATA:
if (DATA_PTR(obj)) { if (DATA_PTR(obj)) {
if ((long)RANY(obj)->as.data.dfree == -1) { 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) { else if (RANY(obj)->as.data.dfree) {
(*RANY(obj)->as.data.dfree)(DATA_PTR(obj)); (*RANY(obj)->as.data.dfree)(DATA_PTR(obj));
@ -788,13 +789,13 @@ obj_free(obj)
case T_MATCH: case T_MATCH:
if (RANY(obj)->as.match.regs) { if (RANY(obj)->as.match.regs) {
re_free_registers(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; break;
case T_FILE: case T_FILE:
if (RANY(obj)->as.file.fptr) { if (RANY(obj)->as.file.fptr) {
rb_io_fptr_finalize(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; break;
case T_ICLASS: case T_ICLASS:
@ -807,19 +808,19 @@ obj_free(obj)
case T_BIGNUM: case T_BIGNUM:
if (RANY(obj)->as.bignum.digits) { if (RANY(obj)->as.bignum.digits) {
free(RANY(obj)->as.bignum.digits); RUBY_CRITICAL(free(RANY(obj)->as.bignum.digits));
} }
break; break;
case T_NODE: case T_NODE:
switch (nd_type(obj)) { switch (nd_type(obj)) {
case NODE_SCOPE: case NODE_SCOPE:
if (RANY(obj)->as.node.u1.tbl) { if (RANY(obj)->as.node.u1.tbl) {
free(RANY(obj)->as.node.u1.tbl); RUBY_CRITICAL(free(RANY(obj)->as.node.u1.tbl));
} }
break; break;
#ifdef C_ALLOCA #ifdef C_ALLOCA
case NODE_ALLOCA: case NODE_ALLOCA:
free(RANY(obj)->as.node.u1.value); RUBY_CRITICAL(free(RANY(obj)->as.node.u1.value));
break; break;
#endif #endif
} }
@ -830,15 +831,15 @@ obj_free(obj)
RANY(obj)->as.scope.flag != SCOPE_ALLOCA) { RANY(obj)->as.scope.flag != SCOPE_ALLOCA) {
VALUE *vars = RANY(obj)->as.scope.local_vars-1; VALUE *vars = RANY(obj)->as.scope.local_vars-1;
if (vars[0] == 0) 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) if (RANY(obj)->as.scope.flag&SCOPE_MALLOC)
free(vars); RUBY_CRITICAL(free(vars));
} }
break; break;
case T_STRUCT: case T_STRUCT:
if (RANY(obj)->as.rstruct.ptr) { if (RANY(obj)->as.rstruct.ptr) {
free(RANY(obj)->as.rstruct.ptr); RUBY_CRITICAL(free(RANY(obj)->as.rstruct.ptr));
} }
break; break;

View file

@ -785,7 +785,7 @@ rb_num2long(val)
return Qnil; /* not reached */ return Qnil; /* not reached */
default: default:
val = rb_Integer(val); val = rb_to_int(val);
return NUM2LONG(val); return NUM2LONG(val);
} }
} }

View file

@ -885,8 +885,8 @@ rb_to_integer(val, method)
val = rb_rescue2(to_type, (VALUE)&arg1, fail_to_type, (VALUE)&arg2, val = rb_rescue2(to_type, (VALUE)&arg1, fail_to_type, (VALUE)&arg2,
rb_eStandardError, rb_eNameError, 0); rb_eStandardError, rb_eNameError, 0);
if (!rb_obj_is_kind_of(val, rb_cInteger)) { if (!rb_obj_is_kind_of(val, rb_cInteger)) {
rb_raise(rb_eTypeError, "%s#%s_i should return Integer", rb_raise(rb_eTypeError, "%s#%s should return Integer",
method, rb_class2name(CLASS_OF(arg1.val))); rb_class2name(CLASS_OF(arg1.val)), method);
} }
return val; return val;
} }
@ -1166,6 +1166,7 @@ Init_Object()
rb_undef_method(CLASS_OF(rb_cSymbol), "new"); rb_undef_method(CLASS_OF(rb_cSymbol), "new");
rb_define_method(rb_cSymbol, "type", sym_type, 0); 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_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, "inspect", sym_inspect, 0);
rb_define_method(rb_cSymbol, "to_s", sym_to_s, 0); rb_define_method(rb_cSymbol, "to_s", sym_to_s, 0);
rb_define_method(rb_cSymbol, "id2name", sym_to_s, 0); rb_define_method(rb_cSymbol, "id2name", sym_to_s, 0);

View file

@ -114,6 +114,7 @@ rb_f_srand(argc, argv, obj)
VALUE a; VALUE a;
unsigned int seed, old; unsigned int seed, old;
rb_secure(4);
if (rb_scan_args(argc, argv, "01", &a) == 0) { if (rb_scan_args(argc, argv, "01", &a) == 0) {
static int n = 0; static int n = 0;
struct timeval tv; struct timeval tv;

View file

@ -13,14 +13,40 @@
#ifndef SIG_H #ifndef SIG_H
#define SIG_H #define SIG_H
EXTERN int rb_trap_immediate;
#ifdef NT #ifdef NT
#define TRAP_BEG (rb_trap_immediate=1, SetEvent(rb_InterruptEvent)) typedef LONG rb_atomic_t;
#define TRAP_END (rb_trap_immediate=0, ResetEvent(rb_InterruptEvent))
# 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 #else
#define TRAP_BEG (rb_trap_immediate=1) typedef int rb_atomic_t;
#define TRAP_END (rb_trap_immediate=0)
# 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 #endif
EXTERN rb_atomic_t rb_trap_immediate;
EXTERN int rb_prohibit_interrupt; EXTERN int rb_prohibit_interrupt;
#define DEFER_INTS {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)); 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)); void rb_trap_restore_mask _((void));
EXTERN int rb_thread_critical; EXTERN int rb_thread_critical;

View file

@ -260,9 +260,9 @@ rb_f_kill(argc, argv)
} }
static VALUE trap_list[NSIG]; static VALUE trap_list[NSIG];
static int trap_pending_list[NSIG]; static rb_atomic_t trap_pending_list[NSIG];
int rb_trap_pending; rb_atomic_t rb_trap_pending;
int rb_trap_immediate; rb_atomic_t rb_trap_immediate;
int rb_prohibit_interrupt; int rb_prohibit_interrupt;
void void
@ -303,6 +303,7 @@ posix_signal(signum, handler)
#define ruby_signal(sig,handle) signal((sig),(handle)) #define ruby_signal(sig,handle) signal((sig),(handle))
#endif #endif
static void signal_exec _((int sig));
static void static void
signal_exec(sig) signal_exec(sig)
int sig; int sig;
@ -342,11 +343,9 @@ sighandle(sig)
int sig; int sig;
{ {
#ifdef NT #ifdef NT
#define end_interrupt() win32_thread_resume_main() #define IN_MAIN_CONTEXT(f, a) (win32_main_context(a, f) ? (void)0 : f(a))
if (win32_main_context(sig, sighandle)) return;
#else #else
#define end_interrupt() (void)0 #define IN_MAIN_CONTEXT(f, a) f(a)
#endif #endif
if (sig >= NSIG) { if (sig >= NSIG) {
@ -357,16 +356,14 @@ sighandle(sig)
ruby_signal(sig, sighandle); ruby_signal(sig, sighandle);
#endif #endif
if (rb_trap_immediate) { if (ATOMIC_TEST(rb_trap_immediate)) {
rb_trap_immediate = 0; IN_MAIN_CONTEXT(signal_exec, sig);
signal_exec(sig); ATOMIC_SET(rb_trap_immediate, 1);
rb_trap_immediate = 1;
} }
else { else {
rb_trap_pending++; ATOMIC_INC(rb_trap_pending);
trap_pending_list[sig]++; ATOMIC_INC(trap_pending_list[sig]);
} }
end_interrupt();
} }
#ifdef SIGBUS #ifdef SIGBUS

View file

@ -1,4 +1,4 @@
#define RUBY_VERSION "1.6.2" #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_VERSION_CODE 162
#define RUBY_RELEASE_CODE 20001113 #define RUBY_RELEASE_CODE 20001114

View file

@ -34,6 +34,32 @@
#define bool int #define bool int
#endif #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) #define TO_SOCKET(x) _get_osfhandle(x)
bool NtSyncProcess = TRUE; bool NtSyncProcess = TRUE;
@ -46,6 +72,7 @@ static bool NtHasRedirection (char *);
static int valid_filename(char *s); static int valid_filename(char *s);
static void StartSockets (); static void StartSockets ();
static char *str_grow(struct RString *str, size_t new_size); static char *str_grow(struct RString *str, size_t new_size);
static DWORD wait_events(HANDLE event, DWORD timeout);
char *NTLoginName; char *NTLoginName;
@ -76,17 +103,23 @@ IsWinNT(void) {
} }
/* main thread constants */ /* main thread constants */
HANDLE rb_CurrentProcessHandle; static struct {
HANDLE rb_MainThreadHandle; HANDLE handle;
DWORD rb_MainThreadId; DWORD id;
HANDLE rb_InterruptEvent; } main_thread;
/* interrupt stuff */
static HANDLE interrupted_event;
HANDLE GetCurrentThreadHandle(void) HANDLE GetCurrentThreadHandle(void)
{ {
static HANDLE current_process_handle = NULL;
HANDLE h; 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)) 0, FALSE, DUPLICATE_SAME_ACCESS))
return NULL; return NULL;
return h; return h;
@ -98,68 +131,78 @@ HANDLE GetCurrentThreadHandle(void)
#define LK_ERR(f,i) ((f) ? (i = 0) : (errno = GetLastError())) #define LK_ERR(f,i) ((f) ? (i = 0) : (errno = GetLastError()))
#define LK_LEN 0xffff0000 #define LK_LEN 0xffff0000
int static VALUE
flock(int fd, int oper) flock_winnt(VALUE self, int argc, VALUE* argv)
{ {
OVERLAPPED o; OVERLAPPED o;
int i = -1; int i = -1;
HANDLE fh; const HANDLE fh = (HANDLE)self;
const int oper = argc;
fh = (HANDLE)_get_osfhandle(fd);
memset(&o, 0, sizeof(o)); memset(&o, 0, sizeof(o));
if(IsWinNT()) { switch(oper) {
switch(oper) { case LOCK_SH: /* shared lock */
case LOCK_SH: /* shared lock */ LK_ERR(LockFileEx(fh, 0, 0, LK_LEN, 0, &o), i);
LK_ERR(LockFileEx(fh, 0, 0, LK_LEN, 0, &o),i); break;
break; case LOCK_EX: /* exclusive lock */
case LOCK_EX: /* exclusive lock */ LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, 0, &o), i);
LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, 0, &o),i); break;
break; case LOCK_SH|LOCK_NB: /* non-blocking shared lock */
case LOCK_SH|LOCK_NB: /* non-blocking shared lock */ LK_ERR(LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o), i);
LK_ERR(LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o),i); break;
break; case LOCK_EX|LOCK_NB: /* non-blocking exclusive lock */
case LOCK_EX|LOCK_NB: /* non-blocking exclusive lock */ LK_ERR(LockFileEx(fh,
LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o), i);
0, LK_LEN, 0, &o),i); if (errno == EDOM)
if(errno == EDOM) errno = EWOULDBLOCK; errno = EWOULDBLOCK;
break; break;
case LOCK_UN: /* unlock lock */ case LOCK_UN: /* unlock lock */
if (UnlockFileEx(fh, 0, LK_LEN, 0, &o)) { if (UnlockFileEx(fh, 0, LK_LEN, 0, &o)) {
i = 0; i = 0;
} if (errno == EDOM)
else {
/* GetLastError() must returns `ERROR_NOT_LOCKED' */
errno = EWOULDBLOCK; errno = EWOULDBLOCK;
} }
if(errno == EDOM) errno = EWOULDBLOCK; else {
break; /* GetLastError() must returns `ERROR_NOT_LOCKED' */
default: /* unknown */ errno = EWOULDBLOCK;
errno = EINVAL; }
break; break;
} default: /* unknown */
errno = EINVAL;
break;
} }
else if(IsWin95()) { return i;
switch(oper) { }
case LOCK_EX:
while(i == -1) { static VALUE
LK_ERR(LockFile(fh, 0, 0, LK_LEN, 0), i); flock_win95(VALUE self, int argc, VALUE* argv)
if(errno != EDOM && i == -1) break; {
} int i = -1;
break; const HANDLE fh = (HANDLE)self;
case LOCK_EX | LOCK_NB: const int oper = argc;
switch(oper) {
case LOCK_EX:
while(i == -1) {
LK_ERR(LockFile(fh, 0, 0, LK_LEN, 0), i); LK_ERR(LockFile(fh, 0, 0, LK_LEN, 0), i);
if(errno == EDOM) errno = EWOULDBLOCK; if (errno != EDOM && i == -1) break;
break; }
case LOCK_UN: break;
LK_ERR(UnlockFile(fh, 0, 0, LK_LEN, 0), i); case LOCK_EX | LOCK_NB:
if(errno == EDOM) errno = EWOULDBLOCK; LK_ERR(LockFile(fh, 0, 0, LK_LEN, 0), i);
break; if (errno == EDOM)
default: errno = EWOULDBLOCK;
errno = EINVAL; break;
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; return i;
} }
@ -167,6 +210,22 @@ flock(int fd, int oper)
#undef LK_ERR #undef LK_ERR
#undef LK_LEN #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 //#undef const
//FILE *fdopen(int, const char *); //FILE *fdopen(int, const char *);
@ -1908,8 +1967,10 @@ myselect (int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
long r; long r;
fd_set file_rd; fd_set file_rd;
fd_set file_wr; fd_set file_wr;
#ifdef USE_INTERRUPT_WINSOCK
fd_set trap;
#endif /* USE_INTERRUPT_WINSOCK */
int file_nfds; int file_nfds;
int trap_immediate = rb_trap_immediate;
if (!NtSocketsInitialized++) { if (!NtSocketsInitialized++) {
StartSockets(); StartSockets();
@ -1928,18 +1989,26 @@ myselect (int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
if (wr) *wr = file_wr; if (wr) *wr = file_wr;
return file_nfds; 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) { if ((r = select (nfds, rd, wr, ex, timeout)) == SOCKET_ERROR) {
errno = WSAGetLastError(); errno = WSAGetLastError();
switch (errno) { switch (errno) {
case WSAEINTR: case WSAEINTR:
errno = EINTR; errno = EINTR;
break; break;
} }
} }
if (trap_immediate)
TRAP_BEG;
return r; return r;
} }
@ -1957,31 +2026,33 @@ StartSockets ()
// //
version = MAKEWORD(1, 1); version = MAKEWORD(1, 1);
if (ret = WSAStartup(version, &retdata)) 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) 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) 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); atexit((void (*)(void)) WSACleanup);
iSockOpt = SO_SYNCHRONOUS_NONALERT; iSockOpt = SO_SYNCHRONOUS_NONALERT;
/* /*
* Enable the use of sockets as filehandles * Enable the use of sockets as filehandles
*/ */
setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,
(char *)&iSockOpt, sizeof(iSockOpt)); (char *)&iSockOpt, sizeof(iSockOpt));
rb_CurrentProcessHandle = GetCurrentProcess(); main_thread.handle = GetCurrentThreadHandle();
rb_MainThreadHandle = GetCurrentThreadHandle(); main_thread.id = GetCurrentThreadId();
rb_MainThreadId = GetCurrentThreadId();
rb_InterruptEvent = CreateEvent(NULL, FALSE, TRUE, NULL); interrupted_event = CreateSignal();
if (!interrupted_event)
rb_fatal("Unable to create interrupt event!\n");
} }
#undef accept #undef accept
SOCKET SOCKET
myaccept (SOCKET s, struct sockaddr *addr, int *addrlen) myaccept (SOCKET s, struct sockaddr *addr, int *addrlen)
{ {
SOCKET r; SOCKET r;
@ -1990,12 +2061,8 @@ myaccept (SOCKET s, struct sockaddr *addr, int *addrlen)
if (!NtSocketsInitialized++) { if (!NtSocketsInitialized++) {
StartSockets(); StartSockets();
} }
if (trap_immediate)
TRAP_END;
if ((r = accept (TO_SOCKET(s), addr, addrlen)) == INVALID_SOCKET) if ((r = accept (TO_SOCKET(s), addr, addrlen)) == INVALID_SOCKET)
errno = WSAGetLastError(); errno = WSAGetLastError();
if (trap_immediate)
TRAP_BEG;
return r; return r;
} }
@ -2342,7 +2409,7 @@ waitpid (pid_t pid, int *stat_loc, int options)
} else { } else {
timeout = INFINITE; 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); pid = _cwait(stat_loc, pid, 0);
#if !defined __BORLANDC__ #if !defined __BORLANDC__
*stat_loc <<= 8; *stat_loc <<= 8;
@ -2487,25 +2554,26 @@ myrename(const char *oldpath, const char *newpath)
if (!MoveFile(oldpath, newpath)) if (!MoveFile(oldpath, newpath))
res = -1; res = -1;
if (res == 0 || (GetLastError() != ERROR_ALREADY_EXISTS if (res) {
&& GetLastError() != ERROR_FILE_EXISTS)) switch (GetLastError()) {
goto done; case ERROR_ALREADY_EXISTS:
case ERROR_FILE_EXISTS:
if (IsWinNT()) { if (IsWinNT()) {
if (MoveFileEx(oldpath, newpath, MOVEFILE_REPLACE_EXISTING)) if (MoveFileEx(oldpath, newpath, MOVEFILE_REPLACE_EXISTING))
res = 0; res = 0;
} else { } else {
for (;;) { for (;;) {
if (!DeleteFile(newpath) && GetLastError() != ERROR_FILE_NOT_FOUND) if (!DeleteFile(newpath) && GetLastError() != ERROR_FILE_NOT_FOUND)
break; break;
else if (MoveFile(oldpath, newpath)) { else if (MoveFile(oldpath, newpath)) {
res = 0; res = 0;
break; break;
}
}
} }
} }
} }
done:
if (res) if (res)
errno = GetLastError(); errno = GetLastError();
else else
@ -2545,88 +2613,288 @@ mytimes(struct tms *tmbuf)
} }
static int win32_thread_exclusive(void) #undef Sleep
{ #define yield_once() Sleep(0)
if (GetCurrentThreadId() == rb_MainThreadId) return FALSE; #define yield_until(condition) do yield_once(); while (!(condition))
SuspendThread(rb_MainThreadHandle); static DWORD wait_events(HANDLE event, DWORD timeout)
return TRUE; {
HANDLE events[2];
int count = 0;
DWORD ret;
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) static int initialized = 0;
ResumeThread(rb_MainThreadHandle); 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);
}
} }
static void win32_call_handler(int arg, void (*handler)(int), CONTEXT ctx) void win32_enable_interrupt(void)
{ {
handler(arg); if (IsWinNT()) {
ctx.ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT; LeaveCriticalSection(system_state());
SetThreadContext(rb_MainThreadHandle, &ctx); return;
}
InterlockedDecrement(&flag_interrupt);
TlsSetValue(tlsi_interrupt, (PVOID)((DWORD)TlsGetValue(tlsi_interrupt) - 1));
} }
static int catch_interrupt(unsigned long msec) 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)
{ {
return !WaitForSingleObject(rb_InterruptEvent, msec); 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 */
} }
int win32_interruptible(void) static struct handler_arg_t* setup_handler(struct handler_arg_t *harg,
int arg,
void (*handler)(int),
HANDLE handshake)
{ {
if (catch_interrupt(0)) return TRUE; harg->handler = handler;
SetEvent(rb_InterruptEvent); harg->arg = arg;
return FALSE; harg->status = 0;
harg->userstate = 0;
harg->handshake = handshake;
return harg;
}
static void setup_call(CONTEXT* ctx, struct handler_arg_t *harg)
{
#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)) 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)) { if (GetCurrentThreadId() == main_thread.id) return FALSE;
SetEvent(rb_InterruptEvent);
return FALSE;
}
{ SetSignal(interrupted_event);
RUBY_CRITICAL({ /* the main thread must be in user state */
CONTEXT ctx; CONTEXT ctx;
SuspendThread(main_thread.handle);
SetThreadPriority(current_thread, GetThreadPriority(main_thread.handle));
ZeroMemory(&ctx, sizeof(CONTEXT)); ZeroMemory(&ctx, sizeof(CONTEXT));
ctx.ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT; ctx.ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT;
GetThreadContext(rb_MainThreadHandle, &ctx); GetThreadContext(main_thread.handle, &ctx);
#ifdef _M_IX86 ctx_orig = ctx;
{
DWORD *esp = (DWORD *)(ctx.Esp - sizeof(CONTEXT)); /* handler context setup */
*(CONTEXT *)esp = ctx; if (!interrupt_done) {
*--esp = (DWORD)handler; interrupt_done = CreateEvent(NULL, FALSE, FALSE, NULL);
*--esp = arg; /* anonymous one-shot event */
*--esp = ctx.Eip;
ctx.Esp = (DWORD)esp;
} }
ctx.Eip = (DWORD)win32_call_handler; else {
#else ResetEvent(interrupt_done);
#error }
#endif setup_call(&ctx, setup_handler(&harg, arg, handler, interrupt_done));
ctx.ContextFlags = CONTEXT_CONTROL; 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; 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;
}
if (trap_immediate)
TRAP_END; static void catch_interrupt(void)
catch_interrupt(msec); {
if (trap_immediate) yield_once();
TRAP_BEG; 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;
}
return val;
} }

View file

@ -427,17 +427,23 @@ struct tms {
#define times mytimes #define times mytimes
/* thread stuff */ /* thread stuff */
/* initialized by NtInitialize() */
HANDLE rb_CurrentProcessHandle;
HANDLE rb_MainThreadHandle;
HANDLE rb_InterruptEvent;
DWORD rb_MainThreadId;
HANDLE GetCurrentThreadHandle(void); HANDLE GetCurrentThreadHandle(void);
int win32_main_context(int arg, void (*handler)(int)); int win32_main_context(int arg, void (*handler)(int));
int win32_interruptible(void); int win32_sleep(unsigned long msec);
void win32_thread_resume_main(void); void win32_enter_syscall(void);
void win32_sleep(unsigned long msec); void win32_leave_syscall(void);
#define Sleep(msec) win32_sleep(msec) 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 #endif