[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]