ruby-changes:6030
From: nobu <ko1@a...>
Date: Sun, 22 Jun 2008 11:13:18 +0900 (JST)
Subject: [ruby-changes:6030] Ruby:r17539 (mvm): * gc.c (ruby_stack_check), vm_eval.c (stack_check): disable check if
nobu 2008-06-22 11:12:59 +0900 (Sun, 22 Jun 2008)
New Revision: 17539
Modified files:
branches/mvm/ChangeLog
branches/mvm/gc.c
branches/mvm/signal.c
branches/mvm/thread_pthread.c
branches/mvm/thread_win32.c
branches/mvm/vm.c
branches/mvm/vm_eval.c
Log:
* gc.c (ruby_stack_check), vm_eval.c (stack_check): disable check if
hard stack check is available.
* signal.c (Init_signal): use alternative stack for SEGV.
* thread_{pthread,win32}.c (native_thread_init_stack): get stack
boundary.
* thread_pthread.c (ruby_stack_overflow_p): check fault address is
stack overflow.
* vm.c (vm_eval_body): if thrown exception is frozen, reraise it to
create a new instance.
http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/mvm/vm.c?r1=17539&r2=17538&diff_format=u
http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/mvm/ChangeLog?r1=17539&r2=17538&diff_format=u
http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/mvm/thread_pthread.c?r1=17539&r2=17538&diff_format=u
http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/mvm/thread_win32.c?r1=17539&r2=17538&diff_format=u
http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/mvm/gc.c?r1=17539&r2=17538&diff_format=u
http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/mvm/signal.c?r1=17539&r2=17538&diff_format=u
http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/mvm/vm_eval.c?r1=17539&r2=17538&diff_format=u
Index: mvm/thread_win32.c
===================================================================
--- mvm/thread_win32.c (revision 17538)
+++ mvm/thread_win32.c (revision 17539)
@@ -436,18 +436,27 @@
#define CHECK_ERR(expr) \
{if (!(expr)) {rb_bug("err: %lu - %s", GetLastError(), #expr);}}
-static void
-native_thread_init_stack(rb_thread_t *th)
+static int
+native_get_stack(void **addr, size_t *size)
{
MEMORY_BASIC_INFORMATION mi;
char *base, *end;
DWORD size, space;
-
- CHECK_ERR(VirtualQuery(&mi, &mi, sizeof(mi)));
+ if (!VirtualQuery(&mi, &mi, sizeof(mi))) return -1;
base = mi.AllocationBase;
end = mi.BaseAddress;
end += mi.RegionSize;
- size = end - base;
+ *addr = base;
+ *size = end - base;
+}
+
+static void
+native_thread_init_stack(rb_thread_t *th)
+{
+ DWORD size, space;
+ void *end;
+
+ if (native_get_stack(&end, &size)) return;
space = size / 5;
if (space > 1024*1024) space = 1024*1024;
th->machine_stack_start = (VALUE *)end - 1;
Index: mvm/ChangeLog
===================================================================
--- mvm/ChangeLog (revision 17538)
+++ mvm/ChangeLog (revision 17539)
@@ -1,3 +1,19 @@
+Sun Jun 22 11:12:57 2008 Nobuyoshi Nakada <nobu@r...>
+
+ * gc.c (ruby_stack_check), vm_eval.c (stack_check): disable check if
+ hard stack check is available.
+
+ * signal.c (Init_signal): use alternative stack for SEGV.
+
+ * thread_{pthread,win32}.c (native_thread_init_stack): get stack
+ boundary.
+
+ * thread_pthread.c (ruby_stack_overflow_p): check fault address is
+ stack overflow.
+
+ * vm.c (vm_eval_body): if thrown exception is frozen, reraise it to
+ create a new instance.
+
Sat Jun 21 17:33:50 2008 NAKAMURA Usaku <usa@r...>
* win32/win32.c (rb_w32_spawn): no longer support P_WAIT.
Index: mvm/thread_pthread.c
===================================================================
--- mvm/thread_pthread.c (revision 17538)
+++ mvm/thread_pthread.c (revision 17539)
@@ -13,6 +13,15 @@
#include "gc.h"
+#if defined HAVE_PTHREAD_NP_H
+#include <pthread_np.h>
+#elif defined HAVE_THR_STKSEGMENT
+#include <thread.h>
+#endif
+#ifdef HAVE_SYS_SIGNAL_H
+#include <sys/signal.h>
+#endif
+
#ifdef HAVE_SYS_RESOURCE_H
#include <sys/resource.h>
#endif
@@ -170,6 +179,59 @@
#define USE_THREAD_CACHE 0
+static int
+get_stack(void **addr, size_t *size)
+{
+#define STACKADDR_AVAILABLE 1
+#define CHECK_ERR(expr) \
+ {int err = (expr); if (err) return err;}
+#if defined HAVE_PTHREAD_GETATTR_NP || defined HAVE_PTHREAD_ATTR_GET_NP
+ pthread_attr_t attr;
+ size_t guard = 0;
+
+# ifdef HAVE_PTHREAD_GETATTR_NP
+ CHECK_ERR(pthread_getattr_np(pthread_self(), &attr));
+# ifdef HAVE_PTHREAD_ATTR_GETSTACK
+ CHECK_ERR(pthread_attr_getstack(&attr, addr, size));
+# else
+ CHECK_ERR(pthread_attr_getstackaddr(&attr, addr));
+ CHECK_ERR(pthread_attr_getstacksize(&attr, size));
+# endif
+# else
+ CHECK_ERR(pthread_attr_init(&attr));
+ CHECK_ERR(pthread_attr_get_np(pthread_self(), &attr));
+ CHECK_ERR(pthread_attr_getstackaddr(&attr, addr));
+ CHECK_ERR(pthread_attr_getstacksize(&attr, size));
+# endif
+ CHECK_ERR(pthread_attr_getguardsize(&attr, &guard));
+# ifndef HAVE_PTHREAD_GETATTR_NP
+ pthread_attr_destroy(&attr);
+# endif
+ size -= guard;
+#elif defined HAVE_PTHREAD_GET_STACKADDR_NP && defined HAVE_PTHREAD_GET_STACKSIZE_NP
+ pthread_t th = pthread_self();
+ *addr = pthread_get_stackaddr_np(th);
+ *size = pthread_get_stacksize_np(th);
+#elif defined HAVE_THR_STKSEGMENT || defined HAVE_PTHREAD_STACKSEG_NP
+ stack_t stk;
+# if defined HAVE_THR_STKSEGMENT
+ CHECK_ERR(thr_stksegment(&stk));
+# else
+ CHECK_ERR(pthread_stackseg_np(pthread_self(), &stk));
+# endif
+ *addr = stk.ss_sp;
+ *size = stk.ss_size;
+#else
+#undef STACKADDR_AVAILABLE
+ return -1;
+#endif
+#ifdef STACKADDR_AVAILABLE
+ return 0;
+#endif
+#undef CHECK_ERR
+}
+
+#ifndef STACKADDR_AVAILABLE
static struct {
rb_thread_id_t id;
size_t stack_maxsize;
@@ -178,6 +240,7 @@
VALUE *register_stack_start;
#endif
} native_main_thread;
+#endif
#undef ruby_init_stack
void
@@ -187,6 +250,7 @@
#endif
)
{
+#ifndef STACKADDR_AVAILABLE
native_main_thread.id = pthread_self();
if (!native_main_thread.stack_start ||
STACK_UPPER(&addr,
@@ -212,44 +276,50 @@
}
}
#endif
+#endif
}
-#define CHECK_ERR(expr) \
- {int err = (expr); if (err) {rb_bug("err: %d - %s", err, #expr);}}
+#if STACK_GROW_DIRECTION
+#define STACK_GROW_DIR_DETECTION
+#define STACK_DIR_UPPER(a,b) STACK_UPPER(0, a, b)
+#else
+#define STACK_GROW_DIR_DETECTION VALUE stack_grow_dir_detection
+#define STACK_DIR_UPPER(a,b) STACK_UPPER(&stack_grow_dir_detection, a, b)
+#endif
static int
native_thread_init_stack(rb_thread_t *th)
{
- rb_thread_id_t curr = pthread_self();
-
- if (pthread_equal(curr, native_main_thread.id)) {
- th->machine_stack_start = native_main_thread.stack_start;
- th->machine_stack_maxsize = native_main_thread.stack_maxsize;
- }
- else {
-#ifdef HAVE_PTHREAD_GETATTR_NP
- pthread_attr_t attr;
- void *start;
- CHECK_ERR(pthread_getattr_np(curr, &attr));
-# if defined HAVE_PTHREAD_ATTR_GETSTACK
- CHECK_ERR(pthread_attr_getstack(&attr, &start, &th->machine_stack_maxsize));
-# elif defined HAVE_PTHREAD_ATTR_GETSTACKSIZE && defined HAVE_PTHREAD_ATTR_GETSTACKADDR
- CHECK_ERR(pthread_attr_getstackaddr(&attr, &start));
- CHECK_ERR(pthread_attr_getstacksize(&attr, &th->machine_stack_maxsize));
-# endif
- th->machine_stack_start = start;
+#ifdef STACKADDR_AVAILABLE
+ void *addr;
+ size_t size;
+ int err = get_stack(&addr, &size);
+ STACK_GROW_DIR_DETECTION;
+ if (err) return err;
+ size -= sizeof(VALUE);
+ th->machine_stack_start = (VALUE *)((char *)addr + STACK_DIR_UPPER(0, size));
+ th->machine_stack_maxsize = size;
#else
- rb_raise(rb_eNotImpError, "ruby engine can initialize only in the main thread");
+ th->machine_stack_start = native_main_thread.stack_start;
+ th->machine_stack_maxsize = native_main_thread.stack_maxsize;
#endif
- }
#ifdef __ia64
+ th->machine_stack_maxsize += sizeof(VALUE);
+#ifdef STACKADDR_AVAILABLE
th->machine_register_stack_start = native_main_thread.register_stack_start;
+#else
+ th->machine_register_stack_start =
+ (VALUE *)((char *)th->machine_stack_start - th->machine_stack_maxsize / 2);
+#endif
th->machine_stack_maxsize /= 2;
+ th->machine_stack_maxsize -= sizeof(VALUE);
th->machine_register_stack_maxsize = th->machine_stack_maxsize;
#endif
return 0;
}
+void ruby_install_altstack(rb_thread_t *);
+
static void *
thread_start_func_1(void *th_ptr)
{
@@ -260,6 +330,17 @@
rb_thread_t *th = th_ptr;
VALUE stack_start;
+#ifdef STACKADDR_AVAILABLE
+ void *addr;
+ size_t size;
+ if (get_stack(&addr, &size)) return 0;
+ size -= STACK_UPPER(&stack_start,
+ (char *)&stack_start - (char *)addr,
+ (char *)addr - (char *)&stack_start);
+ th->machine_stack_start = &stack_start;
+ th->machine_stack_maxsize = size;
+#endif
+ ruby_install_altstack(th);
/* run */
thread_start_func_2(th, &stack_start, rb_ia64_bsp());
}
@@ -368,6 +449,21 @@
return result;
}
+enum {
+ RUBY_STACK_MIN_LIMIT = 512 * 1024, /* 512KB */
+ RUBY_STACK_MIN = (
+#ifdef PTHREAD_STACK_MIN
+ (RUBY_STACK_MIN_LIMIT < PTHREAD_STACK_MIN) ? PTHREAD_STACK_MIN * 2 :
+#endif
+ RUBY_STACK_MIN_LIMIT),
+ RUBY_STACK_SPACE_LIMIT = 1024 * 1024,
+ RUBY_STACK_SPACE = (RUBY_STACK_MIN/5 > RUBY_STACK_SPACE_LIMIT ?
+ RUBY_STACK_SPACE_LIMIT : RUBY_STACK_MIN/5),
+};
+
+#define CHECK_ERR(expr) \
+ {int err = (expr); if (err) {rb_bug("err: %d - %s", err, #expr);}}
+
static int
native_thread_create(rb_thread_t *th)
{
@@ -378,20 +474,17 @@
}
else {
pthread_attr_t attr;
- size_t stack_size = 512 * 1024; /* 512KB */
- size_t space;
+ const size_t stack_size = RUBY_STACK_MIN;
+#if HAVE_SIGALTSTACK
+ const size_t space = 0;
+#else
+ const size_t space = RUBY_STACK_SPACE;
+#endif
-#ifdef PTHREAD_STACK_MIN
- if (stack_size < PTHREAD_STACK_MIN) {
- stack_size = PTHREAD_STACK_MIN * 2;
- }
-#endif
- space = stack_size/5;
- if (space > 1024*1024) space = 1024*1024;
- th->machine_stack_maxsize = stack_size - space;
+ th->machine_stack_maxsize = stack_size - space;
#ifdef __ia64
- th->machine_stack_maxsize /= 2;
- th->machine_register_stack_maxsize = th->machine_stack_maxsize;
+ th->machine_stack_maxsize /= 2;
+ th->machine_register_stack_maxsize = th->machine_stack_maxsize;
#endif
CHECK_ERR(pthread_attr_init(&attr));
@@ -696,4 +789,40 @@
rb_disable_interrupt(); /* only timer thread recieve signal */
}
+#ifdef HAVE_SIGALTSTACK
+int
+ruby_stack_overflow_p(siginfo_t *info, ucontext_t *ctx)
+{
+ void *base, *addr = info->si_addr;
+ size_t size;
+ const size_t water_mark = 64 * 1024;
+ rb_thread_t *th = ruby_thread_from_native();
+ STACK_GROW_DIR_DETECTION;
+
+ if (th) {
+ size = th->machine_stack_maxsize;
+ base = (char *)th->machine_stack_start - STACK_DIR_UPPER(0, size);
+ }
+#ifdef STACKADDR_AVAILABLE
+ else if (get_stack(&base, &size) == 0) {
+ STACK_DIR_UPPER(base = (char *)base + size, (void)0);
+ }
+#endif
+ else {
+ return 0;
+ }
+ size /= 5;
+ if (size > water_mark) size = water_mark;
+ if (STACK_DIR_UPPER(1, 0)) {
+ if (size > ~(size_t)base+1) size = ~(size_t)base+1;
+ if (addr > base && addr <= (void *)((char *)base + size)) return 1;
+ }
+ else {
+ if (size > (size_t)base) size = (size_t)base;
+ if (addr > (void *)((char *)base - size) && addr <= base) return 1;
+ }
+ return 0;
+}
+#endif
+
#endif /* THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION */
Index: mvm/vm_eval.c
===================================================================
--- mvm/vm_eval.c (revision 17538)
+++ mvm/vm_eval.c (revision 17539)
@@ -167,12 +167,14 @@
static inline void
stack_check(void)
{
+#ifndef HAVE_SIGALTSTACK
rb_thread_t *th = GET_THREAD();
if (!rb_thread_raised_p(th, RAISED_STACKOVERFLOW) && ruby_stack_check()) {
rb_thread_raised_set(th, RAISED_STACKOVERFLOW);
rb_exc_raise(sysstack_error);
}
+#endif
}
static inline VALUE
Index: mvm/gc.c
===================================================================
--- mvm/gc.c (revision 17538)
+++ mvm/gc.c (revision 17539)
@@ -809,10 +809,14 @@
int
ruby_stack_check(void)
{
- int ret;
+ int ret = 0;
+#if !defined HAVE_SIGALTSTACK || defined __ia64
rb_thread_t *th = GET_THREAD();
+#endif
+#ifndef HAVE_SIGALTSTACK
SET_STACK_END;
ret = STACK_LENGTH > STACK_LEVEL_MAX - GC_WATER_MARK;
+#endif
#ifdef __ia64
if (!ret) {
ret = (VALUE*)rb_ia64_bsp() - th->machine_register_stack_start >
Index: mvm/vm.c
===================================================================
--- mvm/vm.c (revision 17538)
+++ mvm/vm.c (revision 17539)
@@ -1072,6 +1072,7 @@
err = th->errinfo;
if (state == TAG_RAISE) {
+ if (OBJ_FROZEN(err)) rb_exc_raise(err);
rb_ivar_set(err, idThrowState, INT2FIX(state));
}
Index: mvm/signal.c
===================================================================
--- mvm/signal.c (revision 17538)
+++ mvm/signal.c (revision 17539)
@@ -15,6 +15,7 @@
#include "ruby/signal.h"
#include "ruby/node.h"
#include "vm_core.h"
+#include "eval_intern.h"
#include <signal.h>
#include <stdio.h>
@@ -424,12 +425,19 @@
#endif
typedef RETSIGTYPE (*sighandler_t)(int);
+#ifdef SA_SIGINFO
+typedef void ruby_sigaction_t(int, siginfo_t*, void*);
+#define SIGINFO_ARG , siginfo_t *info, void *ctx
+#else
+typedef RETSIGTYPE ruby_sigaction_t(int);
+#define SIGINFO_ARG
+#endif
#ifdef POSIX_SIGNAL
-static sighandler_t
-ruby_signal(int signum, sighandler_t handler)
+static int
+ruby_sigaction(int signum, ruby_sigaction_t *handler, int altstack, struct sigaction *old)
{
- struct sigaction sigact, old;
+ struct sigaction sigact;
#if 0
rb_trap_accept_nativethreads[signum] = 0;
@@ -437,18 +445,29 @@
sigemptyset(&sigact.sa_mask);
#ifdef SA_SIGINFO
- sigact.sa_sigaction = (void (*)(int, siginfo_t*, void*))handler;
+ sigact.sa_sigaction = handler;
sigact.sa_flags = SA_SIGINFO;
+#ifdef HAVE_SIGALTSTACK
+ if (altstack)
+ sigact.sa_flags |= SA_ONSTACK;
+#endif
#else
- sigact.sa_handler = handler;
+ sigact.sa_handler = (sighandler_t)handler;
sigact.sa_flags = 0;
#endif
#ifdef SA_NOCLDWAIT
- if (signum == SIGCHLD && handler == SIG_IGN)
+ if (signum == SIGCHLD && (sighandler_t)handler == SIG_IGN)
sigact.sa_flags |= SA_NOCLDWAIT;
#endif
- sigaction(signum, &sigact, &old);
+ return sigaction(signum, &sigact, old);
+}
+
+static sighandler_t
+ruby_signal(int signum, sighandler_t handler)
+{
+ struct sigaction old;
+ ruby_sigaction(signum, (ruby_sigaction_t *)handler, Qfalse, &old);
return old.sa_handler;
}
@@ -458,6 +477,21 @@
return ruby_signal(signum, handler);
}
+void
+ruby_install_altstack(rb_thread_t *th)
+{
+#ifdef HAVE_SIGALTSTACK
+ stack_t sigstk;
+ static void *segv_stack;
+
+ if (!segv_stack) segv_stack = malloc(SIGSTKSZ * 2);
+ sigstk.ss_sp = segv_stack;
+ sigstk.ss_size = SIGSTKSZ;
+ sigstk.ss_flags = 0;
+ sigaltstack(&sigstk, 0);
+#endif
+}
+
#else /* !POSIX_SIGNAL */
#define ruby_signal(sig,handler) (/* rb_trap_accept_nativethreads[sig] = 0,*/ signal((sig),(handler)))
#if 0 /* def HAVE_NATIVETHREAD */
@@ -548,14 +582,31 @@
#endif
#ifdef SIGSEGV
+# ifdef HAVE_SIGALTSTACK
+int ruby_stack_overflow_p(siginfo_t*, ucontext_t*);
+# endif
+
static int segv_received = 0;
static RETSIGTYPE
-sigsegv(int sig)
+sigsegv(int sig SIGINFO_ARG)
{
+#ifdef HAVE_SIGALTSTACK
+ if (ruby_stack_overflow_p(info, ctx)) {
+ rb_thread_t *th = GET_THREAD();
+ th->errinfo = sysstack_error;
+ rb_thread_raised_clear(th);
+ TH_JUMP_TAG(th, TAG_RAISE);
+ }
+#endif
if (segv_received) {
fprintf(stderr, "SEGV recieved in SEGV handler\n");
exit(EXIT_FAILURE);
}
+#ifdef RUBY_DEBUG_ENV
+ if (ruby_enable_coredump) {
+ signal(sig, SIG_DFL);
+ }
+#endif
else {
extern int ruby_disable_gc_stress;
segv_received = 1;
@@ -697,7 +748,7 @@
#endif
#ifdef SIGSEGV
case SIGSEGV:
- func = sigsegv;
+ func = (sighandler_t)sigsegv;
break;
#endif
#ifdef SIGPIPE
@@ -1112,10 +1163,11 @@
#ifdef SIGBUS
install_sighandler(SIGBUS, sigbus);
#endif
+ }
#ifdef SIGSEGV
- install_sighandler(SIGSEGV, sigsegv);
+ ruby_sigaction(SIGSEGV, sigsegv, Qtrue, NULL);
+ ruby_install_altstack(GET_THREAD());
#endif
- }
#ifdef SIGPIPE
install_sighandler(SIGPIPE, sigpipe);
#endif
--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/