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