summaryrefslogtreecommitdiff
path: root/eval.c
diff options
context:
space:
mode:
authorshyouhei <shyouhei@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-02-22 13:01:37 +0000
committershyouhei <shyouhei@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-02-22 13:01:37 +0000
commit935b0347e2845a6cf6ea4a7863c2208a2c21c672 (patch)
treed28772f7ffe1012b7334d9053a42d8761cab8455 /eval.c
parent2af8e54e3bd182b6611d8bb3603d76d7a5d2146b (diff)
merge revision(s) 21353:
* eval.c (cc_mark): frees the continuation's stack if its thread is dead to avoid recursive gc that segfaults. [ruby-core:13889] a patch by Brent Roman <brent AT mbari.org>. * eval.c (rb_cont_check): checks for valid continuation instance. * eval.c (rb_callcc): assigns th->thread before scope_dup() to avoid segfaults if this scope_dup() triggers a gc pass. a patch by Brent Roman <brent AT mbari.org>. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8_6@22538 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'eval.c')
-rw-r--r--eval.c60
1 files changed, 48 insertions, 12 deletions
diff --git a/eval.c b/eval.c
index 3f8c32b593..8b79a210c6 100644
--- a/eval.c
+++ b/eval.c
@@ -10230,8 +10230,8 @@ rb_gc_abort_threads()
} END_FOREACH_FROM(main_thread, th);
}
-static void
-thread_free(th)
+static inline void
+stack_free(th)
rb_thread_t th;
{
if (th->stk_ptr) free(th->stk_ptr);
@@ -10240,6 +10240,13 @@ thread_free(th)
if (th->bstr_ptr) free(th->bstr_ptr);
th->bstr_ptr = 0;
#endif
+}
+
+static void
+thread_free(th)
+ rb_thread_t th;
+{
+ stack_free(th);
if (th->locals) st_free_table(th->locals);
if (th->status != THREAD_KILLED) {
if (th->prev) th->prev->next = th->next;
@@ -10532,8 +10539,7 @@ rb_thread_die(th)
{
th->thgroup = 0;
th->status = THREAD_KILLED;
- if (th->stk_ptr) free(th->stk_ptr);
- th->stk_ptr = 0;
+ stack_free(th);
}
static void
@@ -12776,6 +12782,38 @@ rb_thread_atfork()
}
+static void
+cc_purge(cc)
+ rb_thread_t cc;
+{
+ /* free continuation's stack if it has just died */
+ if (NIL_P(cc->thread)) return;
+ if (rb_thread_check(cc->thread)->status == THREAD_KILLED) {
+ cc->thread = Qnil;
+ rb_thread_die(cc); /* can't possibly activate this stack */
+ }
+}
+
+static void
+cc_mark(cc)
+ rb_thread_t cc;
+{
+ /* mark this continuation's stack only if its parent thread is still alive */
+ cc_purge(cc);
+ thread_mark(cc);
+}
+
+static rb_thread_t
+rb_cont_check(data)
+ VALUE data;
+{
+ if (TYPE(data) != T_DATA || RDATA(data)->dmark != (RUBY_DATA_FUNC)cc_mark) {
+ rb_raise(rb_eTypeError, "wrong argument type %s (expected Continuation)",
+ rb_obj_classname(data));
+ }
+ return (rb_thread_t)RDATA(data)->data;
+}
+
/*
* Document-class: Continuation
*
@@ -12850,14 +12888,16 @@ rb_callcc(self)
struct RVarmap *vars;
THREAD_ALLOC(th);
- cont = Data_Wrap_Struct(rb_cCont, thread_mark, thread_free, th);
+ /* must finish th initialization before any possible gc.
+ * brent@mbari.org */
+ th->thread = curr_thread->thread;
+ th->thgroup = cont_protect;
+ cont = Data_Wrap_Struct(rb_cCont, cc_mark, thread_free, th);
scope_dup(ruby_scope);
for (tag=prot_tag; tag; tag=tag->prev) {
scope_dup(tag->scope);
}
- th->thread = curr_thread->thread;
- th->thgroup = cont_protect;
for (vars = ruby_dyna_vars; vars; vars = vars->next) {
if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break;
@@ -12894,7 +12934,7 @@ rb_cont_call(argc, argv, cont)
VALUE *argv;
VALUE cont;
{
- rb_thread_t th = rb_thread_check(cont);
+ rb_thread_t th = rb_cont_check(cont);
if (th->thread != curr_thread->thread) {
rb_raise(rb_eRuntimeError, "continuation called across threads");
@@ -13070,10 +13110,6 @@ thgroup_add(group, thread)
rb_secure(4);
th = rb_thread_check(thread);
- if (!th->next || !th->prev) {
- rb_raise(rb_eTypeError, "wrong argument type %s (expected Thread)",
- rb_obj_classname(thread));
- }
if (OBJ_FROZEN(group)) {
rb_raise(rb_eThreadError, "can't move to the frozen thread group");