diff --git a/gc/mmtk/mmtk.c b/gc/mmtk/mmtk.c index 2d2de68..3c9518a 100644 --- a/gc/mmtk/mmtk.c +++ b/gc/mmtk/mmtk.c @@ -38,6 +38,11 @@ struct objspace { pthread_cond_t cond_world_started; size_t start_the_world_count; + struct { + bool gc_thread_crashed; + char crash_msg[256]; + } crash_context; + struct rb_gc_vm_context vm_context; unsigned int fork_hook_vm_lock_lev; @@ -169,6 +174,10 @@ rb_mmtk_block_for_gc(MMTk_VMMutatorThread mutator) pthread_cond_wait(&objspace->cond_world_started, &objspace->mutex); } + if (RB_UNLIKELY(objspace->crash_context.gc_thread_crashed)) { + rb_bug("%s", objspace->crash_context.crash_msg); + } + if (objspace->measure_gc_time) { struct timespec gc_end_time; clock_gettime(CLOCK_MONOTONIC, &gc_end_time); @@ -424,6 +433,32 @@ rb_mmtk_special_const_p(MMTk_ObjectReference object) return RB_SPECIAL_CONST_P(obj); } +RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 1, 2) +static void +rb_mmtk_gc_thread_bug(const char *msg, ...) +{ + struct objspace *objspace = rb_gc_get_objspace(); + + objspace->crash_context.gc_thread_crashed = true; + + va_list args; + va_start(args, msg); + vsnprintf(objspace->crash_context.crash_msg, sizeof(objspace->crash_context.crash_msg), msg, args); + va_end(args); + + rb_mmtk_resume_mutators(); + + sleep(5); + + rb_bug("rb_mmtk_gc_thread_bug"); +} + +static void +rb_mmtk_gc_thread_panic_handler(void) +{ + rb_mmtk_gc_thread_bug("MMTk GC thread panicked"); +} + static void rb_mmtk_mutator_thread_panic_handler(void) { @@ -454,6 +489,7 @@ MMTk_RubyUpcalls ruby_upcalls = { rb_mmtk_update_finalizer_table, rb_mmtk_special_const_p, rb_mmtk_mutator_thread_panic_handler, + rb_mmtk_gc_thread_panic_handler, }; // Use max 80% of the available memory by default for MMTk @@ -836,7 +872,7 @@ rb_mmtk_call_object_closure(VALUE obj, bool pin) char parent_obj_info_buf[info_size]; rb_raw_obj_info(parent_obj_info_buf, info_size, marking_parent_object); - rb_bug("try to mark T_NONE object (obj: %s, parent: %s)", obj_info_buf, parent_obj_info_buf); + rb_mmtk_gc_thread_bug("try to mark T_NONE object (obj: %s, parent: %s)", obj_info_buf, parent_obj_info_buf); } return (VALUE)rb_mmtk_gc_thread_tls->object_closure.c_function( diff --git a/gc/mmtk/mmtk.h b/gc/mmtk/mmtk.h index 51798c4..21a5bf9 100644 --- a/gc/mmtk/mmtk.h +++ b/gc/mmtk/mmtk.h @@ -79,6 +79,7 @@ typedef struct MMTk_RubyUpcalls { void (*update_finalizer_table)(void); bool (*special_const_p)(MMTk_ObjectReference object); void (*mutator_thread_panic_handler)(void); + void (*gc_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 1e03dbf..255b2b1 100644 --- a/gc/mmtk/src/abi.rs +++ b/gc/mmtk/src/abi.rs @@ -323,6 +323,7 @@ pub struct RubyUpcalls { 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(), + pub gc_thread_panic_handler: extern "C" fn(), } unsafe impl Sync for RubyUpcalls {} diff --git a/gc/mmtk/src/lib.rs b/gc/mmtk/src/lib.rs index 0ee8f67..52dc782 100644 --- a/gc/mmtk/src/lib.rs +++ b/gc/mmtk/src/lib.rs @@ -126,8 +126,6 @@ fn handle_gc_thread_panic(panic_info: &PanicHookInfo) { eprintln!("Unknown backtrace status: {s:?}"); } } - - std::process::abort(); } pub(crate) fn set_panic_hook() { @@ -140,6 +138,8 @@ pub(crate) fn set_panic_hook() { std::panic::set_hook(Box::new(move |panic_info| { if is_gc_thread(std::thread::current().id()) { handle_gc_thread_panic(panic_info); + + (crate::binding().upcalls().gc_thread_panic_handler)(); } else { old_hook(panic_info); (crate::MUTATOR_THREAD_PANIC_HANDLER