Skip to content

Commit bd6d236

Browse files
committed
Put the reference chain in RactorError#detailed_message
1 parent 2fdc1fa commit bd6d236

File tree

6 files changed

+74
-26
lines changed

6 files changed

+74
-26
lines changed

bootstraptest/test_ractor.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1006,7 +1006,7 @@ def inspect = "#<Foo @ivar=#{@ivar.inspect}>"
10061006
begin
10071007
Ractor.make_shareable(Bar.new(Foo.new))
10081008
rescue Ractor::Error
1009-
$!.to_s.lines[1..].join
1009+
$!.detailed_message.lines[1..].join
10101010
end
10111011
}
10121012

ractor.c

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ static VALUE rb_eRactorMovedError;
3232
static VALUE rb_eRactorClosedError;
3333
static VALUE rb_cRactorMovedObject;
3434

35+
static ID id_reference_chain;
36+
3537
static void vm_ractor_blocking_cnt_inc(rb_vm_t *vm, rb_ractor_t *r, const char *file, int line);
3638

3739

@@ -1039,13 +1041,37 @@ ractor_moved_missing(int argc, VALUE *argv, VALUE self)
10391041
*
10401042
*/
10411043

1044+
/*
1045+
* call-seq:
1046+
* detailed_message(highlight: false, **kwargs) -> string
1047+
*
1048+
* Returns the message string with the reference chain appended.
1049+
*/
1050+
static VALUE
1051+
ractor_error_detailed_message(int argc, VALUE *argv, VALUE exc)
1052+
{
1053+
// Call super to get the base detailed_message
1054+
VALUE base_message = rb_call_super_kw(argc, argv, RB_PASS_CALLED_KEYWORDS);
1055+
1056+
VALUE chain = rb_attr_get(exc, id_reference_chain);
1057+
if (NIL_P(chain)) {
1058+
return base_message;
1059+
}
1060+
1061+
return rb_sprintf("%"PRIsVALUE"%"PRIsVALUE, base_message, chain);
1062+
}
1063+
10421064
void
10431065
Init_Ractor(void)
10441066
{
10451067
rb_cRactor = rb_define_class("Ractor", rb_cObject);
10461068
rb_undef_alloc_func(rb_cRactor);
10471069

1070+
id_reference_chain = rb_intern_const("reference_chain");
1071+
10481072
rb_eRactorError = rb_define_class_under(rb_cRactor, "Error", rb_eRuntimeError);
1073+
rb_define_method(rb_eRactorError, "detailed_message", ractor_error_detailed_message, -1);
1074+
10491075
rb_eRactorIsolationError = rb_define_class_under(rb_cRactor, "IsolationError", rb_eRactorError);
10501076
rb_eRactorRemoteError = rb_define_class_under(rb_cRactor, "RemoteError", rb_eRactorError);
10511077
rb_eRactorMovedError = rb_define_class_under(rb_cRactor, "MovedError", rb_eRactorError);
@@ -1631,13 +1657,16 @@ rb_ractor_make_shareable(VALUE obj)
16311657
VALUE exception = Qfalse;
16321658
if (rb_obj_traverse(obj, make_shareable_check_shareable, null_leave, mark_shareable, &chain, &exception)) {
16331659
if (exception) {
1634-
VALUE id_mesg = rb_intern("mesg");
1635-
VALUE message = rb_attr_get(exception, id_mesg);
1636-
message = rb_sprintf("%"PRIsVALUE"%"PRIsVALUE, message, chain);
1637-
rb_ivar_set(exception, id_mesg, message);
1660+
if (!NIL_P(chain)) {
1661+
rb_ivar_set(exception, id_reference_chain, chain);
1662+
}
16381663
rb_exc_raise(exception);
16391664
}
1640-
rb_raise(rb_eRactorError, "can not make shareable object for %+"PRIsVALUE"%"PRIsVALUE, obj, chain);
1665+
exception = rb_exc_new3(rb_eRactorError, rb_sprintf("can not make shareable object for %+"PRIsVALUE, obj));
1666+
if (!NIL_P(chain)) {
1667+
rb_ivar_set(exception, id_reference_chain, chain);
1668+
}
1669+
rb_exc_raise(exception);
16411670
}
16421671
RB_GC_GUARD(chain);
16431672
RB_GC_GUARD(exception);
@@ -1670,6 +1699,23 @@ rb_ractor_ensure_main_ractor(const char *msg)
16701699
}
16711700
}
16721701

1702+
NORETURN(void rb_ractor_raise_isolation_error_with_chain(VALUE klass, VALUE chain, const char *fmt, ...));
1703+
1704+
void
1705+
rb_ractor_raise_isolation_error_with_chain(VALUE klass, VALUE chain, const char *fmt, ...)
1706+
{
1707+
va_list args;
1708+
va_start(args, fmt);
1709+
VALUE message = rb_vsprintf(fmt, args);
1710+
va_end(args);
1711+
1712+
VALUE exception = rb_exc_new_str(klass, message);
1713+
if (!NIL_P(chain)) {
1714+
rb_ivar_set(exception, id_reference_chain, chain);
1715+
}
1716+
rb_exc_raise(exception);
1717+
}
1718+
16731719
static enum obj_traverse_iterator_result
16741720
shareable_p_enter(VALUE obj, struct obj_traverse_data *data)
16751721
{

ractor_core.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ RUBY_SYMBOL_EXPORT_BEGIN
151151
void rb_ractor_finish_marking(void);
152152

153153
bool rb_ractor_shareable_p_continue(VALUE obj, VALUE *chain);
154+
NORETURN(void rb_ractor_raise_isolation_error_with_chain(VALUE klass, VALUE chain, const char *fmt, ...));
154155

155156
// THIS FUNCTION SHOULD NOT CALL WHILE INCREMENTAL MARKING!!
156157
// This function is for T_DATA::free_func

test/ruby/test_ractor.rb

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -219,40 +219,40 @@ def initialize
219219
@unshareable = -> {}
220220
end
221221
end.new
222-
assert_unshareable(obj, /from instance variable @unshareable of an instance of #<Class:/)
222+
assert_unshareable(obj, detailed_message: /from instance variable @unshareable of an instance of #<Class:/)
223223
end
224224

225225
def test_error_includes_array_index
226-
assert_unshareable([0, -> {}], /from Array element at index 1/)
226+
assert_unshareable([0, -> {}], detailed_message: /from Array element at index 1/)
227227
end
228228

229229
def test_error_includes_hash_key_and_value
230-
assert_unshareable({ unshareable: -> {} }, /from Hash value at key :unshareable/)
230+
assert_unshareable({ unshareable: -> {} }, detailed_message: /from Hash value at key :unshareable/)
231231
end
232232

233233
def test_error_includes_hash_unshareable_key
234-
assert_unshareable({ -> {} => true }, /from Hash key #<Proc:0x[[:xdigit:]]+ #{__FILE__}:#{__LINE__}/)
234+
assert_unshareable({ -> {} => true }, detailed_message: /from Hash key #<Proc:0x[[:xdigit:]]+ #{__FILE__}:#{__LINE__}/)
235235
end
236236

237237
def test_error_includes_hash_default_proc
238238
h = Hash.new {}
239-
assert_unshareable(h, /from Hash default proc/)
239+
assert_unshareable(h, detailed_message: /from Hash default proc/)
240240
end
241241

242242
def test_error_includes_hash_default_value
243243
h = Hash.new(Mutex.new)
244-
assert_unshareable(h, /from Hash default value/, exception: Ractor::Error)
244+
assert_unshareable(h, detailed_message: /from Hash default value/, exception: Ractor::Error)
245245
end
246246

247247
S = Struct.new(:member)
248248
def test_error_includes_struct_member
249249
s = S.new(-> {})
250-
assert_unshareable(s, /from member :member of an instance of TestRactor::S/)
250+
assert_unshareable(s, detailed_message: /from member :member of an instance of TestRactor::S/)
251251
end
252252

253253
def test_error_includes_block_self
254254
pr = -> {}
255-
assert_unshareable(pr, /from block's self \(an instance of #{self.class.name}\)/)
255+
assert_unshareable(pr, detailed_message: /from block's self \(an instance of #{self.class.name}\)/)
256256
end
257257

258258
def test_error_wraps_freeze_error
@@ -278,7 +278,7 @@ def test_error_for_module_instance_variable
278278
$!
279279
end.value
280280
assert_kind_of Ractor::IsolationError, e
281-
assert_match(/from Hash default proc/, e.message)
281+
assert_match(/from Hash default proc/, e.detailed_message)
282282
RUBY
283283
end
284284

@@ -294,7 +294,7 @@ module ModuleWithUnshareableConstant
294294
$!
295295
end.value
296296
assert_kind_of(Ractor::IsolationError, e)
297-
assert_match(/from Hash default proc/, e.message)
297+
assert_match(/from Hash default proc/, e.detailed_message)
298298
RUBY
299299
end
300300

@@ -304,11 +304,12 @@ def assert_make_shareable(obj)
304304
assert Ractor.shareable?(obj), "object didn't become shareable"
305305
end
306306

307-
def assert_unshareable(obj, msg=nil, exception: Ractor::IsolationError)
307+
def assert_unshareable(obj, msg=//, detailed_message: nil, exception: Ractor::IsolationError)
308308
refute Ractor.shareable?(obj), "object is already shareable"
309309
e = assert_raise_with_message(exception, msg) do
310310
Ractor.make_shareable(obj)
311311
end
312+
assert_match(detailed_message, e.detailed_message) if detailed_message
312313
refute Ractor.shareable?(obj), "despite raising, object became shareable"
313314
e
314315
end

variable.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1447,9 +1447,9 @@ rb_ivar_lookup(VALUE obj, ID id, VALUE undef)
14471447
UNLIKELY(!rb_ractor_main_p())) {
14481448
VALUE chain = Qnil;
14491449
if (!rb_ractor_shareable_p_continue(val, &chain)) {
1450-
rb_raise(rb_eRactorIsolationError,
1451-
"can not get unshareable values from instance variables of classes/modules from non-main Ractors (%"PRIsVALUE" from %"PRIsVALUE")%"PRIsVALUE,
1452-
rb_id2str(id), obj, chain);
1450+
rb_ractor_raise_isolation_error_with_chain(rb_eRactorIsolationError, chain,
1451+
"can not get unshareable values from instance variables of classes/modules from non-main Ractors (%"PRIsVALUE" from %"PRIsVALUE")",
1452+
rb_id2str(id), obj);
14531453
}
14541454
}
14551455
return val;
@@ -3367,9 +3367,9 @@ rb_const_get_0(VALUE klass, ID id, int exclude, int recurse, int visibility)
33673367
if (UNLIKELY(!rb_ractor_main_p())) {
33683368
VALUE chain = Qnil;
33693369
if (!rb_ractor_shareable_p_continue(c, &chain)) {
3370-
rb_raise(rb_eRactorIsolationError,
3371-
"can not access non-shareable objects in constant %"PRIsVALUE"::%"PRIsVALUE" by non-main Ractor.%"PRIsVALUE,
3372-
rb_class_path(found_in), rb_id2str(id), chain);
3370+
rb_ractor_raise_isolation_error_with_chain(rb_eRactorIsolationError, chain,
3371+
"can not access non-shareable objects in constant %"PRIsVALUE"::%"PRIsVALUE" by non-main Ractor.",
3372+
rb_class_path(found_in), rb_id2str(id));
33733373
}
33743374
}
33753375
return c;

vm_insnhelper.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,9 +1145,9 @@ vm_get_ev_const(rb_execution_context_t *ec, VALUE orig_klass, ID id, bool allow_
11451145
if (UNLIKELY(!rb_ractor_main_p())) {
11461146
VALUE chain = Qnil;
11471147
if (!rb_ractor_shareable_p_continue(val, &chain)) {
1148-
rb_raise(rb_eRactorIsolationError,
1149-
"can not access non-shareable objects in constant %"PRIsVALUE"::%"PRIsVALUE" by non-main Ractor.%"PRIsVALUE,
1150-
rb_class_path(klass), rb_id2str(id), chain);
1148+
rb_ractor_raise_isolation_error_with_chain(rb_eRactorIsolationError, chain,
1149+
"can not access non-shareable objects in constant %"PRIsVALUE"::%"PRIsVALUE" by non-main Ractor.",
1150+
rb_class_path(klass), rb_id2str(id));
11511151
}
11521152
}
11531153
return val;

0 commit comments

Comments
 (0)