summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorshyouhei <shyouhei@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-07-07 06:01:50 +0000
committershyouhei <shyouhei@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-07-07 06:01:50 +0000
commit8cfa1773652264837eab45cd907b1a99e9e20980 (patch)
treed1b723ee31102d3d209d1fe290f438db49e8a503
parent7d110cc79c20df49f24936db409192a281046479 (diff)
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_6@17928 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--eval.c84
-rw-r--r--gc.c20
-rw-r--r--node.h13
-rw-r--r--version.h2
4 files changed, 77 insertions, 42 deletions
diff --git a/eval.c b/eval.c
index 9770450873..d384a69f98 100644
--- a/eval.c
+++ b/eval.c
@@ -1442,9 +1442,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;
@@ -1463,8 +1460,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;
@@ -1517,7 +1516,7 @@ error_handle(ex)
rb_bug("Unknown longjmp status %d", ex);
break;
}
- thread_reset_raised();
+ rb_thread_reset_raised(th);
return status;
}
@@ -2710,6 +2709,7 @@ call_trace_func(event, node, self, id, klass)
NODE *node_save;
VALUE srcfile;
char *event_name;
+ rb_thread_t th = curr_thread;
if (!trace_func) return;
if (tracing) return;
@@ -2741,7 +2741,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);
@@ -2753,7 +2753,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();
@@ -4569,8 +4569,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);
}
@@ -4584,6 +4585,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);
}
}
@@ -4609,7 +4613,7 @@ rb_longjmp(tag, mesg)
ruby_errinfo = mesg;
}
else if (status) {
- thread_reset_raised();
+ rb_thread_reset_raised(th);
JUMP_TAG(status);
}
}
@@ -4624,11 +4628,20 @@ 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;
{
@@ -5544,18 +5557,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);
}
}
@@ -9710,11 +9716,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);
@@ -9886,10 +9895,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)
@@ -9941,19 +9949,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;
}
@@ -11091,7 +11105,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);
@@ -12020,7 +12034,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;
@@ -12238,7 +12252,7 @@ rb_thread_status_name(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 be883583bb..807d8eb2ec 100644
--- a/gc.c
+++ b/gc.c
@@ -74,16 +74,22 @@ static void run_final();
static VALUE nomem_error;
static void garbage_collect();
+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);
}
@@ -97,9 +103,8 @@ ruby_xmalloc(size)
rb_raise(rb_eNoMemError, "negative allocation size (or too big)");
}
if (size == 0) size = 1;
- malloc_increase += size;
- if (malloc_increase > malloc_limit) {
+ if ((malloc_increase+size) > malloc_limit) {
garbage_collect();
}
RUBY_CRITICAL(mem = malloc(size));
@@ -110,6 +115,7 @@ ruby_xmalloc(size)
rb_memerror();
}
}
+ malloc_increase += size;
return mem;
}
@@ -138,7 +144,6 @@ ruby_xrealloc(ptr, size)
}
if (!ptr) return xmalloc(size);
if (size == 0) size = 1;
- malloc_increase += size;
RUBY_CRITICAL(mem = realloc(ptr, size));
if (!mem) {
garbage_collect();
@@ -147,6 +152,7 @@ ruby_xrealloc(ptr, size)
rb_memerror();
}
}
+ malloc_increase += size;
return mem;
}
@@ -2064,6 +2070,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 b96af5696f..7d3f756e30 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 810cb34e1a..0f0c2336e7 100644
--- a/version.h
+++ b/version.h
@@ -2,7 +2,7 @@
#define RUBY_RELEASE_DATE "2008-07-07"
#define RUBY_VERSION_CODE 186
#define RUBY_RELEASE_CODE 20080707
-#define RUBY_PATCHLEVEL 267
+#define RUBY_PATCHLEVEL 268
#define RUBY_VERSION_MAJOR 1
#define RUBY_VERSION_MINOR 8