From d10fd325ddb32fc92f20a5ad75367dbbed6c26cf Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Fri, 19 Dec 2025 17:16:01 -0500 Subject: [PATCH] Call rb_bug when Ruby mutator thread panics This will allow the Ruby backtrace, memory mapping, etc. to be outputted when a Ruby mutator thread panics. --- gc/mmtk/mmtk.c | 7 +++++++ gc/mmtk/mmtk.h | 1 + gc/mmtk/src/abi.rs | 1 + gc/mmtk/src/api.rs | 4 ++++ gc/mmtk/src/lib.rs | 8 ++++++++ 5 files changed, 21 insertions(+) diff --git a/gc/mmtk/mmtk.c b/gc/mmtk/mmtk.c index 131aaf3..52f653a 100644 --- a/gc/mmtk/mmtk.c +++ b/gc/mmtk/mmtk.c @@ -355,6 +355,12 @@ rb_mmtk_special_const_p(MMTk_ObjectReference object) return RB_SPECIAL_CONST_P(obj); } +static void +rb_mmtk_mutator_thread_panic_handler(void) +{ + rb_bug("Ruby mutator thread panicked"); +} + // Bootup MMTk_RubyUpcalls ruby_upcalls = { rb_mmtk_init_gc_worker_thread, @@ -374,6 +380,7 @@ MMTk_RubyUpcalls ruby_upcalls = { rb_mmtk_global_tables_count, rb_mmtk_update_finalizer_table, rb_mmtk_special_const_p, + rb_mmtk_mutator_thread_panic_handler, }; // Use max 80% of the available memory by default for MMTk diff --git a/gc/mmtk/mmtk.h b/gc/mmtk/mmtk.h index b00133a..18466c6 100644 --- a/gc/mmtk/mmtk.h +++ b/gc/mmtk/mmtk.h @@ -69,6 +69,7 @@ typedef struct MMTk_RubyUpcalls { int (*global_tables_count)(void); void (*update_finalizer_table)(void); bool (*special_const_p)(MMTk_ObjectReference object); + void (*mutator_thread_panic_handler)(void); } MMTk_RubyUpcalls; typedef struct MMTk_RawVecOfObjRef { diff --git a/gc/mmtk/src/abi.rs b/gc/mmtk/src/abi.rs index 2214441..1bd19fb 100644 --- a/gc/mmtk/src/abi.rs +++ b/gc/mmtk/src/abi.rs @@ -314,6 +314,7 @@ pub struct RubyUpcalls { pub global_tables_count: extern "C" fn() -> c_int, pub update_finalizer_table: extern "C" fn(), pub special_const_p: extern "C" fn(object: ObjectReference) -> bool, + pub mutator_thread_panic_handler: extern "C" fn(), } unsafe impl Sync for RubyUpcalls {} diff --git a/gc/mmtk/src/api.rs b/gc/mmtk/src/api.rs index 5217eb4..006e987 100644 --- a/gc/mmtk/src/api.rs +++ b/gc/mmtk/src/api.rs @@ -138,6 +138,10 @@ pub unsafe extern "C" fn mmtk_init_binding( upcalls: *const RubyUpcalls, weak_reference_dead_value: ObjectReference, ) { + crate::MUTATOR_THREAD_PANIC_HANDLER + .set((unsafe { (*upcalls).clone() }).mutator_thread_panic_handler) + .unwrap_or_else(|_| panic!("MUTATOR_THREAD_PANIC_HANDLER is already initialized")); + crate::set_panic_hook(); let builder = unsafe { Box::from_raw(builder) }; diff --git a/gc/mmtk/src/lib.rs b/gc/mmtk/src/lib.rs index d16a5bf..4bcafb5 100644 --- a/gc/mmtk/src/lib.rs +++ b/gc/mmtk/src/lib.rs @@ -55,6 +55,11 @@ impl VMBinding for Ruby { type VMMemorySlice = RubyMemorySlice; } +/// The callback for mutator thread panic handler (which calls rb_bug to output +/// debugging information such as the Ruby backtrace and memory maps). +/// This is set before BINDING is set because mmtk_init could panic. +pub static MUTATOR_THREAD_PANIC_HANDLER: OnceCell = OnceCell::new(); + /// The singleton object for the Ruby binding itself. pub static BINDING: OnceCell = OnceCell::new(); @@ -132,6 +137,9 @@ pub(crate) fn set_panic_hook() { handle_gc_thread_panic(panic_info); } else { old_hook(panic_info); + (crate::MUTATOR_THREAD_PANIC_HANDLER + .get() + .expect("MUTATOR_THREAD_PANIC_HANDLER is not set"))(); } })); }