Skip to content

Commit a67cfb6

Browse files
etiennebarrieparacycle
authored andcommitted
Put the reference chain in RactorError#detailed_message
1 parent 10d0782 commit a67cfb6

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
@@ -33,6 +33,8 @@ static VALUE rb_eRactorMovedError;
3333
static VALUE rb_eRactorClosedError;
3434
static VALUE rb_cRactorMovedObject;
3535

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

3840

@@ -1038,13 +1040,37 @@ ractor_moved_missing(int argc, VALUE *argv, VALUE self)
10381040
*
10391041
*/
10401042

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

1069+
id_reference_chain = rb_intern_const("reference_chain");
1070+
10471071
rb_eRactorError = rb_define_class_under(rb_cRactor, "Error", rb_eRuntimeError);
1072+
rb_define_method(rb_eRactorError, "detailed_message", ractor_error_detailed_message, -1);
1073+
10481074
rb_eRactorIsolationError = rb_define_class_under(rb_cRactor, "IsolationError", rb_eRactorError);
10491075
rb_eRactorRemoteError = rb_define_class_under(rb_cRactor, "RemoteError", rb_eRactorError);
10501076
rb_eRactorMovedError = rb_define_class_under(rb_cRactor, "MovedError", rb_eRactorError);
@@ -1630,13 +1656,16 @@ rb_ractor_make_shareable(VALUE obj)
16301656
VALUE exception = Qfalse;
16311657
if (rb_obj_traverse(obj, make_shareable_check_shareable, null_leave, mark_shareable, &chain, &exception)) {
16321658
if (exception) {
1633-
VALUE id_mesg = rb_intern("mesg");
1634-
VALUE message = rb_attr_get(exception, id_mesg);
1635-
message = rb_sprintf("%"PRIsVALUE"%"PRIsVALUE, message, chain);
1636-
rb_ivar_set(exception, id_mesg, message);
1659+
if (!NIL_P(chain)) {
1660+
rb_ivar_set(exception, id_reference_chain, chain);
1661+
}
16371662
rb_exc_raise(exception);
16381663
}
1639-
rb_raise(rb_eRactorError, "can not make shareable object for %+"PRIsVALUE"%"PRIsVALUE, obj, chain);
1664+
exception = rb_exc_new3(rb_eRactorError, rb_sprintf("can not make shareable object for %+"PRIsVALUE, obj));
1665+
if (!NIL_P(chain)) {
1666+
rb_ivar_set(exception, id_reference_chain, chain);
1667+
}
1668+
rb_exc_raise(exception);
16401669
}
16411670
RB_GC_GUARD(chain);
16421671
RB_GC_GUARD(exception);
@@ -1669,6 +1698,23 @@ rb_ractor_ensure_main_ractor(const char *msg)
16691698
}
16701699
}
16711700

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

ractor_core.h

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

166166
bool rb_ractor_shareable_p_continue(VALUE obj, VALUE *chain);
167+
NORETURN(void rb_ractor_raise_isolation_error_with_chain(VALUE klass, VALUE chain, const char *fmt, ...));
167168

168169
// THIS FUNCTION SHOULD NOT CALL WHILE INCREMENTAL MARKING!!
169170
// 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
@@ -247,40 +247,40 @@ def initialize
247247
@unshareable = -> {}
248248
end
249249
end.new
250-
assert_unshareable(obj, /from instance variable @unshareable of an instance of #<Class:/)
250+
assert_unshareable(obj, detailed_message: /from instance variable @unshareable of an instance of #<Class:/)
251251
end
252252

253253
def test_error_includes_array_index
254-
assert_unshareable([0, -> {}], /from Array element at index 1/)
254+
assert_unshareable([0, -> {}], detailed_message: /from Array element at index 1/)
255255
end
256256

257257
def test_error_includes_hash_key_and_value
258-
assert_unshareable({ unshareable: -> {} }, /from Hash value at key :unshareable/)
258+
assert_unshareable({ unshareable: -> {} }, detailed_message: /from Hash value at key :unshareable/)
259259
end
260260

261261
def test_error_includes_hash_unshareable_key
262-
assert_unshareable({ -> {} => true }, /from Hash key #<Proc:0x[[:xdigit:]]+ #{__FILE__}:#{__LINE__}/)
262+
assert_unshareable({ -> {} => true }, detailed_message: /from Hash key #<Proc:0x[[:xdigit:]]+ #{__FILE__}:#{__LINE__}/)
263263
end
264264

265265
def test_error_includes_hash_default_proc
266266
h = Hash.new {}
267-
assert_unshareable(h, /from Hash default proc/)
267+
assert_unshareable(h, detailed_message: /from Hash default proc/)
268268
end
269269

270270
def test_error_includes_hash_default_value
271271
h = Hash.new(Mutex.new)
272-
assert_unshareable(h, /from Hash default value/, exception: Ractor::Error)
272+
assert_unshareable(h, detailed_message: /from Hash default value/, exception: Ractor::Error)
273273
end
274274

275275
S = Struct.new(:member)
276276
def test_error_includes_struct_member
277277
s = S.new(-> {})
278-
assert_unshareable(s, /from member :member of an instance of TestRactor::S/)
278+
assert_unshareable(s, detailed_message: /from member :member of an instance of TestRactor::S/)
279279
end
280280

281281
def test_error_includes_block_self
282282
pr = -> {}
283-
assert_unshareable(pr, /from block's self \(an instance of #{self.class.name}\)/)
283+
assert_unshareable(pr, detailed_message: /from block's self \(an instance of #{self.class.name}\)/)
284284
end
285285

286286
def test_error_wraps_freeze_error
@@ -306,7 +306,7 @@ def test_error_for_module_instance_variable
306306
$!
307307
end.value
308308
assert_kind_of Ractor::IsolationError, e
309-
assert_match(/from Hash default proc/, e.message)
309+
assert_match(/from Hash default proc/, e.detailed_message)
310310
RUBY
311311
end
312312

@@ -322,7 +322,7 @@ module ModuleWithUnshareableConstant
322322
$!
323323
end.value
324324
assert_kind_of(Ractor::IsolationError, e)
325-
assert_match(/from Hash default proc/, e.message)
325+
assert_match(/from Hash default proc/, e.detailed_message)
326326
RUBY
327327
end
328328

@@ -332,11 +332,12 @@ def assert_make_shareable(obj)
332332
assert Ractor.shareable?(obj), "object didn't become shareable"
333333
end
334334

335-
def assert_unshareable(obj, msg=nil, exception: Ractor::IsolationError)
335+
def assert_unshareable(obj, msg=//, detailed_message: nil, exception: Ractor::IsolationError)
336336
refute Ractor.shareable?(obj), "object is already shareable"
337337
e = assert_raise_with_message(exception, msg) do
338338
Ractor.make_shareable(obj)
339339
end
340+
assert_match(detailed_message, e.detailed_message) if detailed_message
340341
refute Ractor.shareable?(obj), "despite raising, object became shareable"
341342
e
342343
end

variable.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1457,9 +1457,9 @@ rb_ivar_lookup(VALUE obj, ID id, VALUE undef)
14571457
UNLIKELY(!rb_ractor_main_p())) {
14581458
VALUE chain = Qnil;
14591459
if (!rb_ractor_shareable_p_continue(val, &chain)) {
1460-
rb_raise(rb_eRactorIsolationError,
1461-
"can not get unshareable values from instance variables of classes/modules from non-main Ractors (%"PRIsVALUE" from %"PRIsVALUE")%"PRIsVALUE,
1462-
rb_id2str(id), obj, chain);
1460+
rb_ractor_raise_isolation_error_with_chain(rb_eRactorIsolationError, chain,
1461+
"can not get unshareable values from instance variables of classes/modules from non-main Ractors (%"PRIsVALUE" from %"PRIsVALUE")",
1462+
rb_id2str(id), obj);
14631463
}
14641464
}
14651465
return val;
@@ -3377,9 +3377,9 @@ rb_const_get_0(VALUE klass, ID id, int exclude, int recurse, int visibility)
33773377
if (UNLIKELY(!rb_ractor_main_p())) {
33783378
VALUE chain = Qnil;
33793379
if (!rb_ractor_shareable_p_continue(c, &chain)) {
3380-
rb_raise(rb_eRactorIsolationError,
3381-
"can not access non-shareable objects in constant %"PRIsVALUE"::%"PRIsVALUE" by non-main Ractor.%"PRIsVALUE,
3382-
rb_class_path(found_in), rb_id2str(id), chain);
3380+
rb_ractor_raise_isolation_error_with_chain(rb_eRactorIsolationError, chain,
3381+
"can not access non-shareable objects in constant %"PRIsVALUE"::%"PRIsVALUE" by non-main Ractor.",
3382+
rb_class_path(found_in), rb_id2str(id));
33833383
}
33843384
}
33853385
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)