11use super :: lazy:: LazyKeyInner ;
2- use crate :: cell:: Cell ;
3- use crate :: sys:: thread_local_dtor:: register_dtor;
2+ use crate :: cell:: { Cell , RefCell } ;
43use crate :: { fmt, mem, panic} ;
54
65#[ doc( hidden) ]
@@ -37,13 +36,11 @@ pub macro thread_local_inner {
3736
3837 // Safety: Performs `drop_in_place(ptr as *mut $t)`, and requires
3938 // all that comes with it.
40- unsafe extern "C" fn destroy ( ptr : * mut $crate:: primitive:: u8 ) {
41- $crate:: thread:: local_impl:: abort_on_dtor_unwind ( || {
42- let old_state = STATE . replace ( 2 ) ;
43- $crate:: debug_assert_eq!( old_state, 1 ) ;
44- // Safety: safety requirement is passed on to caller.
45- unsafe { $crate:: ptr:: drop_in_place ( ptr. cast :: < $t> ( ) ) ; }
46- } ) ;
39+ unsafe fn destroy ( ptr : * mut $crate:: primitive:: u8 ) {
40+ let old_state = STATE . replace ( 2 ) ;
41+ $crate:: debug_assert_eq!( old_state, 1 ) ;
42+ // Safety: safety requirement is passed on to caller.
43+ unsafe { $crate:: ptr:: drop_in_place ( ptr. cast :: < $t> ( ) ) ; }
4744 }
4845
4946 unsafe {
@@ -152,8 +149,8 @@ impl<T> Key<T> {
152149
153150 // note that this is just a publicly-callable function only for the
154151 // const-initialized form of thread locals, basically a way to call the
155- // free `register_dtor` function defined elsewhere in std .
156- pub unsafe fn register_dtor ( a : * mut u8 , dtor : unsafe extern "C" fn ( * mut u8 ) ) {
152+ // free `register_dtor` function.
153+ pub unsafe fn register_dtor ( a : * mut u8 , dtor : unsafe fn ( * mut u8 ) ) {
157154 unsafe {
158155 register_dtor ( a, dtor) ;
159156 }
@@ -217,7 +214,7 @@ impl<T> Key<T> {
217214 }
218215}
219216
220- unsafe extern "C" fn destroy_value < T > ( ptr : * mut u8 ) {
217+ unsafe fn destroy_value < T > ( ptr : * mut u8 ) {
221218 let ptr = ptr as * mut Key < T > ;
222219
223220 // SAFETY:
@@ -230,14 +227,66 @@ unsafe extern "C" fn destroy_value<T>(ptr: *mut u8) {
230227 // `Option<T>` to `None`, and `dtor_state` to `RunningOrHasRun`. This
231228 // causes future calls to `get` to run `try_initialize_drop` again,
232229 // which will now fail, and return `None`.
233- //
234- // Wrap the call in a catch to ensure unwinding is caught in the event
235- // a panic takes place in a destructor.
236- if let Err ( _) = panic:: catch_unwind ( panic:: AssertUnwindSafe ( || unsafe {
230+ unsafe {
237231 let value = ( * ptr) . inner . take ( ) ;
238232 ( * ptr) . dtor_state . set ( DtorState :: RunningOrHasRun ) ;
239233 drop ( value) ;
240- } ) ) {
241- rtabort ! ( "thread local panicked on drop" ) ;
234+ }
235+ }
236+
237+ #[ thread_local]
238+ static DTORS : RefCell < Vec < ( * mut u8 , unsafe fn ( * mut u8 ) ) > > = RefCell :: new ( Vec :: new ( ) ) ;
239+
240+ // Ensure this can never be inlined on Windows because otherwise this may break
241+ // in dylibs. See #44391.
242+ #[ cfg_attr( windows, inline( never) ) ]
243+ unsafe fn register_dtor ( t : * mut u8 , dtor : unsafe fn ( * mut u8 ) ) {
244+ // Ensure that destructors are run on thread exit.
245+ crate :: sys:: thread_local_guard:: activate ( ) ;
246+
247+ let mut dtors = match DTORS . try_borrow_mut ( ) {
248+ Ok ( dtors) => dtors,
249+ // The only place this function can be called reentrantly is inside the
250+ // heap allocator. This is currently forbidden.
251+ Err ( _) => rtabort ! ( "the global allocator may not register TLS destructors" ) ,
252+ } ;
253+ dtors. push ( ( t, dtor) ) ;
254+ }
255+
256+ /// Called by the platform on thread exit to run all registered destructors.
257+ /// The signature was chosen so that this function may be passed as a callback
258+ /// to platform functions. The argument is ignored.
259+ ///
260+ /// # Safety
261+ /// May only be called on thread exit. In particular, no thread locals may
262+ /// currently be referenced.
263+ pub unsafe extern "C" fn run_dtors ( _unused : * mut u8 ) {
264+ // This function must not unwind. This is ensured by the `extern "C"` ABI,
265+ // but by catching the unwind, we can print a more helpful message.
266+
267+ match panic:: catch_unwind ( || {
268+ let dtors = & DTORS ;
269+
270+ loop {
271+ // Ensure that the `RefMut` guard is not held while the destructor is
272+ // executed to allow initializing TLS variables in destructors.
273+ let ( t, dtor) = {
274+ let mut dtors = dtors. borrow_mut ( ) ;
275+ match dtors. pop ( ) {
276+ Some ( entry) => entry,
277+ None => break ,
278+ }
279+ } ;
280+
281+ unsafe {
282+ ( dtor) ( t) ;
283+ }
284+ }
285+
286+ // All destructors were run, deallocate the list.
287+ drop ( dtors. replace ( Vec :: new ( ) ) ) ;
288+ } ) {
289+ Ok ( ( ) ) => { }
290+ Err ( _) => rtabort ! ( "thread local panicked on drop" ) ,
242291 }
243292}
0 commit comments