summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlukeg <luke.gru@gmail.com>2023-01-25 07:45:19 -0500
committerJohn Hawthorn <john@hawthorn.email>2025-03-26 16:05:02 -0700
commitd80f3a287c5c8d0404b6cb837db360cab320cde1 (patch)
tree1d28140a404021294365ceb00d9a1e84562424ee
parent2183899fd184ab1cfee80d57c0dd6f4dcd370375 (diff)
Ractor.make_shareable(proc_obj) makes inner structure shareable
Proc objects are now traversed like other objects when making them shareable. Fixes [Bug #19372] Fixes [Bug #19374]
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/12977
-rw-r--r--bootstraptest/test_ractor.rb37
-rw-r--r--ractor.c23
-rw-r--r--vm.c2
3 files changed, 48 insertions, 14 deletions
diff --git a/bootstraptest/test_ractor.rb b/bootstraptest/test_ractor.rb
index b296ad0331..fcdd31ac2e 100644
--- a/bootstraptest/test_ractor.rb
+++ b/bootstraptest/test_ractor.rb
@@ -1361,6 +1361,28 @@ assert_equal 'true', %q{
Ractor.shareable?(pr)
}
+# Ractor.make_shareable(a_proc) makes inner structure shareable and freezes it
+assert_equal 'true,true,true,true', %q{
+ class Proc
+ attr_reader :obj
+ def initialize
+ @obj = Object.new
+ end
+ end
+
+ pr = Ractor.current.instance_eval do
+ Proc.new {}
+ end
+
+ results = []
+ Ractor.make_shareable(pr)
+ results << Ractor.shareable?(pr)
+ results << pr.frozen?
+ results << Ractor.shareable?(pr.obj)
+ results << pr.obj.frozen?
+ results.map(&:to_s).join(',')
+}
+
# Ractor.shareable?(recursive_objects)
assert_equal '[false, false]', %q{
y = []
@@ -1389,6 +1411,21 @@ assert_equal '[C, M]', %q{
Ractor.make_shareable(ary = [C, M])
}
+# Ractor.make_shareable with curried proc checks isolation of original proc
+assert_equal 'isolation error', %q{
+ a = Object.new
+ orig = proc { a }
+ curried = orig.curry
+
+ begin
+ Ractor.make_shareable(curried)
+ rescue Ractor::IsolationError
+ 'isolation error'
+ else
+ 'no error'
+ end
+}
+
# define_method() can invoke different Ractor's proc if the proc is shareable.
assert_equal '1', %q{
class C
diff --git a/ractor.c b/ractor.c
index e0ee977a42..fc4d9fb02e 100644
--- a/ractor.c
+++ b/ractor.c
@@ -3045,7 +3045,7 @@ rb_obj_traverse(VALUE obj,
}
static int
-frozen_shareable_p(VALUE obj, bool *made_shareable)
+allow_frozen_shareable_p(VALUE obj)
{
if (!RB_TYPE_P(obj, T_DATA)) {
return true;
@@ -3055,13 +3055,6 @@ frozen_shareable_p(VALUE obj, bool *made_shareable)
if (type->flags & RUBY_TYPED_FROZEN_SHAREABLE) {
return true;
}
- else if (made_shareable && rb_obj_is_proc(obj)) {
- // special path to make shareable Proc.
- rb_proc_ractor_make_shareable(obj);
- *made_shareable = true;
- VM_ASSERT(RB_OBJ_SHAREABLE_P(obj));
- return false;
- }
}
return false;
@@ -3071,20 +3064,24 @@ static enum obj_traverse_iterator_result
make_shareable_check_shareable(VALUE obj)
{
VM_ASSERT(!SPECIAL_CONST_P(obj));
- bool made_shareable = false;
if (rb_ractor_shareable_p(obj)) {
return traverse_skip;
}
- if (!frozen_shareable_p(obj, &made_shareable)) {
- if (made_shareable) {
- return traverse_skip;
+ else if (!allow_frozen_shareable_p(obj)) {
+ if (rb_obj_is_proc(obj)) {
+ rb_proc_ractor_make_shareable(obj);
+ return traverse_cont;
}
else {
rb_raise(rb_eRactorError, "can not make shareable object for %"PRIsVALUE, obj);
}
}
+ if (RB_TYPE_P(obj, T_IMEMO)) {
+ return traverse_skip;
+ }
+
if (!RB_OBJ_FROZEN_RAW(obj)) {
rb_funcall(obj, idFreeze, 0);
@@ -3156,7 +3153,7 @@ shareable_p_enter(VALUE obj)
return traverse_skip;
}
else if (RB_OBJ_FROZEN_RAW(obj) &&
- frozen_shareable_p(obj, NULL)) {
+ allow_frozen_shareable_p(obj)) {
return traverse_cont;
}
diff --git a/vm.c b/vm.c
index f5bb777b75..d31759724e 100644
--- a/vm.c
+++ b/vm.c
@@ -1415,7 +1415,7 @@ rb_proc_ractor_make_shareable(VALUE self)
proc->is_isolated = TRUE;
}
- FL_SET_RAW(self, RUBY_FL_SHAREABLE);
+ rb_obj_freeze(self);
return self;
}