@@ -3,6 +3,11 @@ extern crate mmtk;
3
3
#[ macro_use]
4
4
extern crate log;
5
5
6
+ use std:: collections:: HashSet ;
7
+ use std:: panic:: PanicInfo ;
8
+ use std:: sync:: Mutex ;
9
+ use std:: thread:: ThreadId ;
10
+
6
11
use abi:: RubyUpcalls ;
7
12
use binding:: { RubyBinding , RubyBindingFast } ;
8
13
use mmtk:: vm:: edge_shape:: { SimpleEdge , UnimplementedMemorySlice } ;
@@ -65,3 +70,60 @@ pub fn mmtk() -> &'static MMTK<Ruby> {
65
70
pub fn upcalls ( ) -> & ' static RubyUpcalls {
66
71
binding ( ) . upcalls ( )
67
72
}
73
+
74
+ pub static GC_THREADS : OnceCell < Mutex < HashSet < ThreadId > > > = OnceCell :: new ( ) ;
75
+
76
+ pub ( crate ) fn register_gc_thread ( thread_id : ThreadId ) {
77
+ let mut gc_threads = GC_THREADS . get ( ) . unwrap ( ) . lock ( ) . unwrap ( ) ;
78
+ gc_threads. insert ( thread_id) ;
79
+ }
80
+
81
+ pub ( crate ) fn unregister_gc_thread ( thread_id : ThreadId ) {
82
+ let mut gc_threads = GC_THREADS . get ( ) . unwrap ( ) . lock ( ) . unwrap ( ) ;
83
+ gc_threads. remove ( & thread_id) ;
84
+ }
85
+
86
+ pub ( crate ) fn is_gc_thread ( thread_id : ThreadId ) -> bool {
87
+ let gc_threads = GC_THREADS . get ( ) . unwrap ( ) . lock ( ) . unwrap ( ) ;
88
+ gc_threads. contains ( & thread_id)
89
+ }
90
+
91
+ fn handle_gc_thread_panic ( panic_info : & PanicInfo ) {
92
+ eprintln ! ( "ERROR: An MMTk GC thread panicked. This is a bug." ) ;
93
+ eprintln ! ( "{panic_info}" ) ;
94
+
95
+ let bt = std:: backtrace:: Backtrace :: capture ( ) ;
96
+ match bt. status ( ) {
97
+ std:: backtrace:: BacktraceStatus :: Unsupported => {
98
+ eprintln ! ( "Backtrace is unsupported." )
99
+ }
100
+ std:: backtrace:: BacktraceStatus :: Disabled => {
101
+ eprintln ! ( "Backtrace is disabled." ) ;
102
+ eprintln ! ( "run with `RUST_BACKTRACE=1` environment variable to display a backtrace" ) ;
103
+ }
104
+ std:: backtrace:: BacktraceStatus :: Captured => {
105
+ eprintln ! ( "{bt}" ) ;
106
+ }
107
+ s => {
108
+ eprintln ! ( "Unknown backtrace status: {s:?}" ) ;
109
+ }
110
+ }
111
+
112
+ std:: process:: abort ( ) ;
113
+ }
114
+
115
+ pub ( crate ) fn set_panic_hook ( ) {
116
+ if GC_THREADS . set ( Default :: default ( ) ) . is_err ( ) {
117
+ return ;
118
+ }
119
+
120
+ let old_hook = std:: panic:: take_hook ( ) ;
121
+
122
+ std:: panic:: set_hook ( Box :: new ( move |panic_info| {
123
+ if is_gc_thread ( std:: thread:: current ( ) . id ( ) ) {
124
+ handle_gc_thread_panic ( panic_info) ;
125
+ } else {
126
+ old_hook ( panic_info) ;
127
+ }
128
+ } ) ) ;
129
+ }
0 commit comments