summaryrefslogtreecommitdiff
path: root/gc.c
diff options
context:
space:
mode:
Diffstat (limited to 'gc.c')
-rw-r--r--gc.c39
1 files changed, 22 insertions, 17 deletions
diff --git a/gc.c b/gc.c
index fe2c225f23..bc55f78a50 100644
--- a/gc.c
+++ b/gc.c
@@ -2691,36 +2691,41 @@ rb_gc_copy_finalizer(VALUE dest, VALUE obj)
}
static VALUE
-run_single_final(VALUE arg)
+run_single_final(VALUE final, VALUE objid)
{
- VALUE *args = (VALUE *)arg;
+ const VALUE cmd = RARRAY_AREF(final, 1);
+ const int level = OBJ_TAINTED(cmd) ?
+ RUBY_SAFE_LEVEL_MAX : FIX2INT(RARRAY_AREF(final, 0));
- return rb_check_funcall(args[0], idCall, 1, args+1);
+ rb_set_safe_level_force(level);
+ return rb_check_funcall(cmd, idCall, 1, &objid);
}
static void
run_finalizer(rb_objspace_t *objspace, VALUE obj, VALUE table)
{
long i;
- VALUE args[2];
+ int status;
const int safe = rb_safe_level();
const VALUE errinfo = rb_errinfo();
-
- args[1] = nonspecial_obj_id(obj);
-
- for (i=0; i<RARRAY_LEN(table); i++) {
- const VALUE final = RARRAY_AREF(table, i);
- const VALUE cmd = RARRAY_AREF(final, 1);
- const int level = OBJ_TAINTED(cmd) ?
- RUBY_SAFE_LEVEL_MAX : FIX2INT(RARRAY_AREF(final, 0));
- int status = 0;
-
- args[0] = cmd;
- rb_set_safe_level_force(level);
- rb_protect(run_single_final, (VALUE)args, &status);
+ const VALUE objid = nonspecial_obj_id(obj);
+ rb_thread_t *const th = GET_THREAD();
+ volatile long finished = 0;
+
+ TH_PUSH_TAG(th);
+ status = TH_EXEC_TAG();
+ if (status) {
+ ++finished; /* skip failed finalizer */
+ rb_set_safe_level_force(safe);
+ rb_set_errinfo(errinfo);
+ }
+ for (i = finished; i<RARRAY_LEN(table); i++) {
+ finished = i;
+ run_single_final(RARRAY_AREF(table, i), objid);
rb_set_safe_level_force(safe);
rb_set_errinfo(errinfo);
}
+ TH_POP_TAG();
}
static void