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]
This commit is contained in:
lukeg 2023-01-25 07:45:19 -05:00 committed by John Hawthorn
parent 2183899fd1
commit d80f3a287c
Notes: git 2025-03-26 23:05:18 +00:00
3 changed files with 48 additions and 14 deletions

View File

@ -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

View File

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

2
vm.c
View File

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