@@ -33,6 +33,8 @@ static VALUE rb_eRactorMovedError;
3333static VALUE rb_eRactorClosedError ;
3434static VALUE rb_cRactorMovedObject ;
3535
36+ static ID id_reference_chain ;
37+
3638static 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+
10411063void
10421064Init_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 );
@@ -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 );
@@ -1671,6 +1700,23 @@ rb_ractor_ensure_main_ractor(const char *msg)
16711700 }
16721701}
16731702
1703+ NORETURN (void rb_ractor_raise_isolation_error_with_chain (VALUE klass , VALUE chain , const char * fmt , ...));
1704+
1705+ void
1706+ rb_ractor_raise_isolation_error_with_chain (VALUE klass , VALUE chain , const char * fmt , ...)
1707+ {
1708+ va_list args ;
1709+ va_start (args , fmt );
1710+ VALUE message = rb_vsprintf (fmt , args );
1711+ va_end (args );
1712+
1713+ VALUE exception = rb_exc_new_str (klass , message );
1714+ if (!NIL_P (chain )) {
1715+ rb_ivar_set (exception , id_reference_chain , chain );
1716+ }
1717+ rb_exc_raise (exception );
1718+ }
1719+
16741720static enum obj_traverse_iterator_result
16751721shareable_p_enter (VALUE obj , struct obj_traverse_data * data )
16761722{
@@ -2782,6 +2828,34 @@ rb_ractor_isolation_violation(const char *fmt, ...)
27822828 rb_ractor_isolation_violation_str (message );
27832829}
27842830
2831+ void
2832+ rb_ractor_isolation_violation_with_chain (VALUE chain , const char * fmt , ...)
2833+ {
2834+ va_list args ;
2835+ va_start (args , fmt );
2836+ VALUE message = rb_vsprintf (fmt , args );
2837+ va_end (args );
2838+
2839+ if (rb_thread_ractor_isolation_check_p ()) {
2840+ // Warning path: append the chain inline so it shows next to the
2841+ // warning. There's no exception object to attach @reference_chain to.
2842+ if (!NIL_P (chain )) {
2843+ rb_str_append (message , chain );
2844+ }
2845+ rb_category_warn (RB_WARN_CATEGORY_RACTOR_ISOLATION , "%s" , StringValueCStr (message ));
2846+ return ;
2847+ }
2848+
2849+ // Raise path: keep the chain on the exception's @reference_chain so it
2850+ // surfaces via Exception#detailed_message (matches the design of
2851+ // rb_ractor_raise_isolation_error_with_chain).
2852+ VALUE exception = rb_exc_new_str (rb_eRactorIsolationError , message );
2853+ if (!NIL_P (chain )) {
2854+ rb_ivar_set (exception , id_reference_chain , chain );
2855+ }
2856+ rb_exc_raise (exception );
2857+ }
2858+
27852859static VALUE
27862860ractor_check_isolation_ensure (VALUE prev_state )
27872861{
0 commit comments