From c14831d7f19ffd6c2d35b9ed0fe1a4d6c4db3c2d Mon Sep 17 00:00:00 2001 From: shyouhei Date: Mon, 7 Jul 2008 06:17:24 +0000 Subject: merge revision(s) 17832: * 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. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8_7@17930 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 21 ++++++++++++++++ eval.c | 84 +++++++++++++++++++++++++++++++++++++-------------------------- gc.c | 20 ++++++++++----- node.h | 13 ++++++++++ version.h | 2 +- 5 files changed, 98 insertions(+), 42 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4c3272e3a5..71bf04e75b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +Mon Jul 7 15:02:13 2008 Nobuyoshi Nakada + + * 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. + Mon Jul 7 12:23:05 2008 Masaki Suketa * ext/win32ole/win32ole.c: avoid creating Ruby object during diff --git a/eval.c b/eval.c index aac4be2449..698e04971c 100644 --- a/eval.c +++ b/eval.c @@ -1441,9 +1441,6 @@ int ruby_in_eval; 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 @@ error_handle(ex) 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 @@ error_handle(ex) rb_bug("Unknown longjmp status %d", ex); break; } - thread_reset_raised(); + rb_thread_reset_raised(th); return status; } @@ -2709,6 +2708,7 @@ call_trace_func(event, node, self, id, klass) 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 @@ call_trace_func(event, node, self, id, klass) } } 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 @@ call_trace_func(event, node, self, id, klass) klass), Qundef, 0); } - if (raised) thread_set_raised(); + if (raised) rb_thread_set_raised(th); POP_TAG(); POP_FRAME(); @@ -4571,8 +4571,9 @@ rb_longjmp(tag, mesg) 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 @@ rb_longjmp(tag, mesg) 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 @@ rb_longjmp(tag, mesg) ruby_errinfo = mesg; } else if (status) { - thread_reset_raised(); + rb_thread_reset_raised(th); JUMP_TAG(status); } } @@ -4626,10 +4630,19 @@ rb_longjmp(tag, mesg) 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 @@ rb_with_disable_interrupt(proc, data) 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 @@ Init_Proc() 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 @@ extern VALUE rb_last_status; # 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 @@ struct thread_status_t { (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 @@ rb_thread_join(th, limit) 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 @@ rb_thread_start_0(fn, arg, th) } 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_status(thread) 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; } diff --git a/gc.c b/gc.c index f11695ffc9..f75a11a937 100644 --- a/gc.c +++ b/gc.c @@ -78,16 +78,22 @@ static void garbage_collect(); 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(1); } - 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); } @@ -136,9 +142,8 @@ ruby_xmalloc(size) 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)); @@ -149,6 +154,7 @@ ruby_xmalloc(size) rb_memerror(); } } + malloc_increase += size; return mem; } @@ -177,7 +183,6 @@ ruby_xrealloc(ptr, size) } 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) { @@ -187,6 +192,7 @@ ruby_xrealloc(ptr, size) rb_memerror(); } } + malloc_increase += size; return mem; } @@ -2110,6 +2116,8 @@ Init_GC() 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); diff --git a/node.h b/node.h index 0c7227eb28..10ab4855c7 100644 --- a/node.h +++ b/node.h @@ -468,6 +468,19 @@ extern VALUE (*ruby_sandbox_restore)_((rb_thread_t)); 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 diff --git a/version.h b/version.h index 4b5d938a12..fe6b6f2576 100644 --- a/version.h +++ b/version.h @@ -2,7 +2,7 @@ #define RUBY_RELEASE_DATE "2008-07-07" #define RUBY_VERSION_CODE 187 #define RUBY_RELEASE_CODE 20080707 -#define RUBY_PATCHLEVEL 48 +#define RUBY_PATCHLEVEL 49 #define RUBY_VERSION_MAJOR 1 #define RUBY_VERSION_MINOR 8 -- cgit v1.2.3