ruby-changes:6316
From: nobu <ko1@a...>
Date: Thu, 3 Jul 2008 06:17:46 +0900 (JST)
Subject: [ruby-changes:6316] Ruby:r17832 (ruby_1_8): * eval.c (rb_longjmp): duplicate the thrown exception to set backtrace
nobu 2008-07-03 06:17:31 +0900 (Thu, 03 Jul 2008) New Revision: 17832 Modified files: branches/ruby_1_8/ChangeLog branches/ruby_1_8/eval.c branches/ruby_1_8/gc.c branches/ruby_1_8/node.h Log: * eval.c (rb_longjmp): duplicate the thrown exception to set backtrace if it was frozen. clear all raised flags. * eval.c (stack_check): leave clearing flag to rb_longjmp. * eval.c (rb_thread_set_raised, rb_thread_reset_raised): use generic flags. * eval.c (Init_Proc), gc.c (Init_GC): freeze preallocated special exceptions. * gc.c (rb_memerror): use thread raised flag instead of static flag, and raise nomem_error without backtrace if failed to make backtrace. [ruby-dev:34724] * gc.c (ruby_xmalloc): increase malloc_increase only if malloc succeeds. failed malloc size can be huge. it may increase malloc_limit too big which cause less GC and memory full. (ruby_xrealloc): ditto. http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=17832 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/ChangeLog?r1=17832&r2=17831&diff_format=u http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/node.h?r1=17832&r2=17831&diff_format=u http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/gc.c?r1=17832&r2=17831&diff_format=u http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/eval.c?r1=17832&r2=17831&diff_format=u Index: ruby_1_8/ChangeLog =================================================================== --- ruby_1_8/ChangeLog (revision 17831) +++ ruby_1_8/ChangeLog (revision 17832) @@ -1,3 +1,24 @@ +Thu Jul 3 06:17:23 2008 Nobuyoshi Nakada <nobu@r...> + + * eval.c (rb_longjmp): duplicate the thrown exception to set backtrace + if it was frozen. clear all raised flags. + + * eval.c (stack_check): leave clearing flag to rb_longjmp. + + * eval.c (rb_thread_set_raised, rb_thread_reset_raised): use generic + flags. + + * eval.c (Init_Proc), gc.c (Init_GC): freeze preallocated special exceptions. + + * gc.c (rb_memerror): use thread raised flag instead of static flag, + and raise nomem_error without backtrace if failed to make backtrace. + [ruby-dev:34724] + + * gc.c (ruby_xmalloc): increase malloc_increase only if malloc + succeeds. failed malloc size can be huge. it may increase + malloc_limit too big which cause less GC and memory full. + (ruby_xrealloc): ditto. + Thu Jul 3 05:11:50 2008 Nobuyoshi Nakada <nobu@r...> * eval.c (PUSH_FRAME): suppress warnings. Index: ruby_1_8/eval.c =================================================================== --- ruby_1_8/eval.c (revision 17831) +++ ruby_1_8/eval.c (revision 17832) @@ -1441,9 +1441,6 @@ static void rb_thread_cleanup _((void)); static void rb_thread_wait_other_threads _((void)); -static int thread_set_raised(); -static int thread_reset_raised(); - static int thread_no_ensure _((void)); static VALUE exception_error; @@ -1462,8 +1459,10 @@ int ex; { int status = EXIT_FAILURE; + rb_thread_t th = curr_thread; - if (thread_set_raised()) return EXIT_FAILURE; + if (rb_thread_set_raised(th)) + return EXIT_FAILURE; switch (ex & TAG_MASK) { case 0: status = EXIT_SUCCESS; @@ -1516,7 +1515,7 @@ rb_bug("Unknown longjmp status %d", ex); break; } - thread_reset_raised(); + rb_thread_reset_raised(th); return status; } @@ -2709,6 +2708,7 @@ NODE *node_save; VALUE srcfile; const char *event_name; + rb_thread_t th = curr_thread; if (!trace_func) return; if (tracing) return; @@ -2740,7 +2740,7 @@ } } PUSH_TAG(PROT_NONE); - raised = thread_reset_raised(); + raised = rb_thread_reset_raised(th); if ((state = EXEC_TAG()) == 0) { srcfile = rb_str_new2(ruby_sourcefile?ruby_sourcefile:"(ruby)"); event_name = get_event_name(event); @@ -2752,7 +2752,7 @@ klass), Qundef, 0); } - if (raised) thread_set_raised(); + if (raised) rb_thread_set_raised(th); POP_TAG(); POP_FRAME(); @@ -4571,8 +4571,9 @@ VALUE mesg; { VALUE at; + rb_thread_t th = curr_thread; - if (thread_set_raised()) { + if (rb_thread_set_raised(th)) { ruby_errinfo = exception_error; JUMP_TAG(TAG_FATAL); } @@ -4586,6 +4587,9 @@ at = get_backtrace(mesg); if (NIL_P(at)) { at = make_backtrace(); + if (OBJ_FROZEN(mesg)) { + mesg = rb_obj_dup(mesg); + } set_backtrace(mesg, at); } } @@ -4611,7 +4615,7 @@ ruby_errinfo = mesg; } else if (status) { - thread_reset_raised(); + rb_thread_reset_raised(th); JUMP_TAG(status); } } @@ -4626,11 +4630,20 @@ if (!prot_tag) { error_print(); } - thread_reset_raised(); + rb_thread_raised_clear(th); JUMP_TAG(tag); } void +rb_exc_jump(mesg) + VALUE mesg; +{ + rb_thread_raised_clear(rb_curr_thread); + ruby_errinfo = mesg; + JUMP_TAG(TAG_RAISE); +} + +void rb_exc_raise(mesg) VALUE mesg; { @@ -5578,18 +5591,11 @@ static void stack_check() { - static int overflowing = 0; + rb_thread_t th = rb_curr_thread; - if (!overflowing && ruby_stack_check()) { - int state; - overflowing = 1; - PUSH_TAG(PROT_NONE); - if ((state = EXEC_TAG()) == 0) { - rb_exc_raise(sysstack_error); - } - POP_TAG(); - overflowing = 0; - JUMP_TAG(state); + if (!rb_thread_raised_p(th, RAISED_STACKOVERFLOW) && ruby_stack_check()) { + rb_thread_raised_set(th, RAISED_STACKOVERFLOW); + rb_exc_raise(sysstack_error); } } @@ -9987,11 +9993,14 @@ rb_global_variable(&exception_error); exception_error = rb_exc_new2(rb_eFatal, "exception reentered"); + OBJ_TAINT(exception_error); + OBJ_FREEZE(exception_error); rb_eSysStackError = rb_define_class("SystemStackError", rb_eStandardError); rb_global_variable(&sysstack_error); sysstack_error = rb_exc_new2(rb_eSysStackError, "stack level too deep"); OBJ_TAINT(sysstack_error); + OBJ_FREEZE(sysstack_error); rb_cProc = rb_define_class("Proc", rb_cObject); rb_undef_alloc_func(rb_cProc); @@ -10169,10 +10178,9 @@ # endif #endif -#define THREAD_RAISED 0x200 /* temporary flag */ #define THREAD_TERMINATING 0x400 /* persistent flag */ -#define THREAD_NO_ENSURE 0x800 /* persistent flag */ -#define THREAD_FLAGS_MASK 0xc00 /* mask for persistent flags */ +#define THREAD_NO_ENSURE 0x800 /* persistent flag */ +#define THREAD_FLAGS_MASK 0xfc00 /* mask for persistent flags */ #define FOREACH_THREAD_FROM(f,x) x = f; do { x = x->next; #define END_FOREACH_FROM(f,x) } while (x != f) @@ -10224,19 +10232,25 @@ (dst)->join = (src)->join, \ 0) -static int -thread_set_raised() +int +rb_thread_set_raised(th) + rb_thread_t th; { - if (curr_thread->flags & THREAD_RAISED) return 1; - curr_thread->flags |= THREAD_RAISED; + if (th->flags & RAISED_EXCEPTION) { + return 1; + } + th->flags |= RAISED_EXCEPTION; return 0; } -static int -thread_reset_raised() +int +rb_thread_reset_raised(th) + rb_thread_t th; { - if (!(curr_thread->flags & THREAD_RAISED)) return 0; - curr_thread->flags &= ~THREAD_RAISED; + if (!(th->flags & RAISED_EXCEPTION)) { + return 0; + } + th->flags &= ~RAISED_EXCEPTION; return 1; } @@ -11374,7 +11388,7 @@ if (!rb_thread_dead(th)) return Qfalse; } - if (!NIL_P(th->errinfo) && (th->flags & THREAD_RAISED)) { + if (!NIL_P(th->errinfo) && (th->flags & RAISED_EXCEPTION)) { VALUE oldbt = get_backtrace(th->errinfo); VALUE errat = make_backtrace(); VALUE errinfo = rb_obj_dup(th->errinfo); @@ -12250,7 +12264,7 @@ } if (state && status != THREAD_TO_KILL && !NIL_P(ruby_errinfo)) { - th->flags |= THREAD_RAISED; + th->flags |= RAISED_EXCEPTION; if (state == TAG_FATAL) { /* fatal error within this thread, need to stop whole script */ main_thread->errinfo = ruby_errinfo; @@ -12468,7 +12482,7 @@ rb_thread_t th = rb_thread_check(thread); if (rb_thread_dead(th)) { - if (!NIL_P(th->errinfo) && (th->flags & THREAD_RAISED)) + if (!NIL_P(th->errinfo) && (th->flags & RAISED_EXCEPTION)) return Qnil; return Qfalse; } Index: ruby_1_8/gc.c =================================================================== --- ruby_1_8/gc.c (revision 17831) +++ ruby_1_8/gc.c (revision 17832) @@ -88,16 +88,22 @@ int ruby_gc_stress = 0; +NORETURN(void rb_exc_jump _((VALUE))); + void rb_memerror() { - static int recurse = 0; + rb_thread_t th = rb_curr_thread; - if (!nomem_error || (recurse > 0 && rb_safe_level() < 4)) { + if (!nomem_error || + (rb_thread_raised_p(th, RAISED_NOMEMORY) && rb_safe_level() < 4)) { fprintf(stderr, "[FATAL] failed to allocate memory\n"); exit(EXIT_FAILURE); } - recurse++; + if (rb_thread_raised_p(th, RAISED_NOMEMORY)) { + rb_exc_jump(nomem_error); + } + rb_thread_raised_set(th, RAISED_NOMEMORY); rb_exc_raise(nomem_error); } @@ -146,9 +152,8 @@ rb_raise(rb_eNoMemError, "negative allocation size (or too big)"); } if (size == 0) size = 1; - malloc_increase += size; - if (ruby_gc_stress || malloc_increase > malloc_limit) { + if (ruby_gc_stress || (malloc_increase+size) > malloc_limit) { garbage_collect(); } RUBY_CRITICAL(mem = malloc(size)); @@ -159,6 +164,7 @@ rb_memerror(); } } + malloc_increase += size; return mem; } @@ -187,7 +193,6 @@ } if (!ptr) return xmalloc(size); if (size == 0) size = 1; - malloc_increase += size; if (ruby_gc_stress) garbage_collect(); RUBY_CRITICAL(mem = realloc(ptr, size)); if (!mem) { @@ -197,6 +202,7 @@ rb_memerror(); } } + malloc_increase += size; return mem; } @@ -2120,6 +2126,8 @@ rb_global_variable(&nomem_error); nomem_error = rb_exc_new2(rb_eNoMemError, "failed to allocate memory"); + OBJ_TAINT(nomem_error); + OBJ_FREEZE(nomem_error); rb_define_method(rb_mKernel, "hash", rb_obj_id, 0); rb_define_method(rb_mKernel, "__id__", rb_obj_id, 0); Index: ruby_1_8/node.h =================================================================== --- ruby_1_8/node.h (revision 17831) +++ ruby_1_8/node.h (revision 17832) @@ -468,6 +468,19 @@ extern rb_thread_t rb_curr_thread; extern rb_thread_t rb_main_thread; +enum { + RAISED_EXCEPTION = 0x1000, + RAISED_STACKOVERFLOW = 0x2000, + RAISED_NOMEMORY = 0x4000, + RAISED_MASK = 0xf000 +}; +int rb_thread_set_raised(rb_thread_t th); +int rb_thread_reset_raised(rb_thread_t th); +#define rb_thread_raised_set(th, f) ((th)->flags |= (f)) +#define rb_thread_raised_reset(th, f) ((th)->flags &= ~(f)) +#define rb_thread_raised_p(th, f) (((th)->flags & (f)) != 0) +#define rb_thread_raised_clear(th) ((th)->flags = 0) + #if defined(__cplusplus) } /* extern "C" { */ #endif -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/