summaryrefslogtreecommitdiff
path: root/gc.c
diff options
context:
space:
mode:
authorNobuyoshi Nakada <nobu@ruby-lang.org>2019-07-04 00:58:52 +0900
committerNobuyoshi Nakada <nobu@ruby-lang.org>2019-07-04 00:58:52 +0900
commitd0cd0866d82a58933e5dccd073c753c0c2ad4eb5 (patch)
treeffb8d9eac66dbe6e296d05555ae56a0dc5e90e0c /gc.c
parent9f1d67a68f55fe7a16840960e0817d362b16d5b2 (diff)
Disable GC during rb_objspace_reachable_object_p
Try to fix CI breakage by [Feature #15974].
Diffstat (limited to 'gc.c')
-rw-r--r--gc.c87
1 files changed, 54 insertions, 33 deletions
diff --git a/gc.c b/gc.c
index db830b93c2..94aa6ce0e5 100644
--- a/gc.c
+++ b/gc.c
@@ -2954,39 +2954,7 @@ should_be_finalizable(VALUE obj)
rb_check_frozen(obj);
}
-struct reachable_object_data {
- VALUE obj;
- VALUE set;
- bool found;
-};
-
-static void
-reachable_object_callback(VALUE child, void *dp)
-{
- struct reachable_object_data *data = dp;
- if (child == data->obj)
- data->found = true;
-
- if (data->found)
- return;
-
- // Maintain a set of objects already searched, so that we don't follow a cycle
- if (rb_hash_lookup2(data->set, child, Qfalse))
- return;
- rb_hash_aset(data->set, child, Qtrue);
-
- rb_objspace_reachable_objects_from(child, reachable_object_callback, data);
-}
-
-static int
-rb_objspace_reachable_object_p(VALUE obj, VALUE root)
-{
- struct reachable_object_data data = {obj, rb_ident_hash_new()};
- rb_obj_hide(data.set);
- rb_objspace_reachable_objects_from(root, reachable_object_callback, &data);
- rb_hash_clear(data.set);
- return data.found;
-}
+static int rb_objspace_reachable_object_p(VALUE obj, VALUE root);
/*
* call-seq:
@@ -9369,6 +9337,59 @@ rb_objspace_reachable_objects_from_root(void (func)(const char *category, VALUE,
POP_MARK_FUNC_DATA();
}
+struct reachable_object_data {
+ VALUE obj;
+ VALUE set;
+};
+
+static void
+reachable_object_callback(VALUE child, void *dp)
+{
+ struct reachable_object_data *data = dp;
+ if (child == data->obj) {
+ rb_throw_obj(data->set, Qtrue);
+ }
+
+ // Maintain a set of objects already searched, so that we don't follow a cycle
+ if (rb_hash_lookup2(data->set, child, Qfalse))
+ return;
+ rb_hash_aset(data->set, child, Qtrue);
+
+ rb_objspace_reachable_objects_from(child, reachable_object_callback, data);
+}
+
+static VALUE
+call_reachable_object(RB_BLOCK_CALL_FUNC_ARGLIST(set, arg))
+{
+ struct reachable_object_data *data = (void *)arg;
+ VALUE obj = data->set;
+ data->set = rb_obj_hide(set);
+ gc_mark_children(&rb_objspace, obj);
+ rb_hash_clear(set);
+ return Qfalse;
+}
+
+static int
+rb_objspace_reachable_object_p(VALUE obj, VALUE root)
+{
+ rb_objspace_t *objspace = &rb_objspace;
+ int reachable = FALSE;
+ if (is_markable_object(objspace, obj)) {
+ struct reachable_object_data data = {obj, root};
+ struct mark_func_data_struct mfd = {&data, reachable_object_callback};
+ int prev_dont_gc = dont_gc;
+ enum ruby_tag_type state;
+
+ dont_gc = TRUE;
+ PUSH_MARK_FUNC_DATA(&mfd);
+ reachable = RTEST(rb_catch_protect(rb_ident_hash_new(), call_reachable_object, (VALUE)&data, &state));
+ POP_MARK_FUNC_DATA();
+ dont_gc = prev_dont_gc;
+ if (state) EC_JUMP_TAG(GET_EC(), state);
+ }
+ return reachable;
+}
+
/*
------------------------ Extended allocator ------------------------
*/