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; }