Skip to content

Commit e780a0b

Browse files
authored
Abort for GC thread panic (#221)
The code is mainly from `mmrk-ruby`. We hijack the Rust panic hook to make sure that if the GC threads panic, the process will be aborted. The current behavior is that when a GC thread panics, the process hangs and wait for that GC thread to finish its work. This should be ported to `master`.
1 parent b8ecd82 commit e780a0b

File tree

3 files changed

+66
-0
lines changed

3 files changed

+66
-0
lines changed

mmtk/src/api.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ pub extern "C" fn mmtk_gc_init(
9595
// Make sure we initialize MMTk here
9696
lazy_static::initialize(&SINGLETON);
9797

98+
// Hijack the panic hook to make sure that if we crash in the GC threads, the process aborts.
99+
crate::set_panic_hook();
100+
98101
// Assert to make sure our fastpath allocation is correct.
99102
{
100103
// If the assertion failed, check the allocation fastpath in Julia

mmtk/src/collection.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,27 @@ use crate::{BLOCK_FOR_GC, STW_COND, WORLD_HAS_STOPPED};
1616
static GC_START: AtomicU64 = AtomicU64::new(0);
1717
static CURRENT_GC_MAY_MOVE: AtomicBool = AtomicBool::new(true);
1818

19+
use std::collections::HashSet;
20+
use std::sync::RwLock;
21+
use std::thread::ThreadId;
22+
23+
lazy_static! {
24+
static ref GC_THREADS: RwLock<HashSet<ThreadId>> = RwLock::new(HashSet::new());
25+
}
26+
27+
pub(crate) fn register_gc_thread() {
28+
let id = std::thread::current().id();
29+
GC_THREADS.write().unwrap().insert(id);
30+
}
31+
pub(crate) fn unregister_gc_thread() {
32+
let id = std::thread::current().id();
33+
GC_THREADS.write().unwrap().remove(&id);
34+
}
35+
pub(crate) fn is_gc_thread() -> bool {
36+
let id = std::thread::current().id();
37+
GC_THREADS.read().unwrap().contains(&id)
38+
}
39+
1940
pub struct VMCollection {}
2041

2142
impl Collection<JuliaVM> for VMCollection {
@@ -99,6 +120,11 @@ impl Collection<JuliaVM> for VMCollection {
99120
.spawn(move || {
100121
use mmtk::util::opaque_pointer::*;
101122
use mmtk::util::Address;
123+
124+
// Remember this GC thread
125+
register_gc_thread();
126+
127+
// Start the worker loop
102128
let worker_tls = VMWorkerThread(VMThread(OpaquePointer::from_address(unsafe {
103129
Address::from_usize(thread_id::get())
104130
})));
@@ -107,6 +133,9 @@ impl Collection<JuliaVM> for VMCollection {
107133
mmtk::memory_manager::start_worker(&SINGLETON, worker_tls, w)
108134
}
109135
}
136+
137+
// The GC thread quits somehow. Unresgister this GC thread
138+
unregister_gc_thread();
110139
});
111140
}
112141

mmtk/src/lib.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,3 +143,37 @@ macro_rules! early_return_for_current_gc {
143143
}
144144
};
145145
}
146+
147+
pub(crate) fn set_panic_hook() {
148+
let old_hook = std::panic::take_hook();
149+
150+
std::panic::set_hook(Box::new(move |panic_info| {
151+
if crate::collection::is_gc_thread() {
152+
eprintln!("ERROR: An MMTk GC thread panicked. This is a bug.");
153+
eprintln!("{panic_info}");
154+
155+
let bt = std::backtrace::Backtrace::capture();
156+
match bt.status() {
157+
std::backtrace::BacktraceStatus::Unsupported => {
158+
eprintln!("Backtrace is unsupported.")
159+
}
160+
std::backtrace::BacktraceStatus::Disabled => {
161+
eprintln!("Backtrace is disabled.");
162+
eprintln!(
163+
"run with `RUST_BACKTRACE=1` environment variable to display a backtrace"
164+
);
165+
}
166+
std::backtrace::BacktraceStatus::Captured => {
167+
eprintln!("{bt}");
168+
}
169+
s => {
170+
eprintln!("Unknown backtrace status: {s:?}");
171+
}
172+
}
173+
174+
std::process::abort();
175+
} else {
176+
old_hook(panic_info);
177+
}
178+
}));
179+
}

0 commit comments

Comments
 (0)