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/