11use super :: lazy:: LazyKeyInner ;
2- use crate :: cell:: Cell ;
3- use crate :: sys :: thread_local_dtor :: register_dtor ;
4- use crate :: { fmt , mem , panic } ;
2+ use crate :: cell:: { Cell , RefCell } ;
3+ use crate :: fmt ;
4+ use crate :: mem :: { self , forget } ;
55
66#[ doc( hidden) ]
77#[ allow_internal_unstable( thread_local_internals, cfg_target_thread_local, thread_local) ]
@@ -37,13 +37,11 @@ pub macro thread_local_inner {
3737
3838 // Safety: Performs `drop_in_place(ptr as *mut $t)`, and requires
3939 // 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- } ) ;
40+ unsafe fn destroy ( ptr : * mut $crate:: primitive:: u8 ) {
41+ let old_state = STATE . replace ( 2 ) ;
42+ $crate:: debug_assert_eq!( old_state, 1 ) ;
43+ // Safety: safety requirement is passed on to caller.
44+ unsafe { $crate:: ptr:: drop_in_place ( ptr. cast :: < $t> ( ) ) ; }
4745 }
4846
4947 unsafe {
@@ -152,8 +150,8 @@ impl<T> Key<T> {
152150
153151 // note that this is just a publicly-callable function only for the
154152 // 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 ) ) {
153+ // free `register_dtor` function.
154+ pub unsafe fn register_dtor ( a : * mut u8 , dtor : unsafe fn ( * mut u8 ) ) {
157155 unsafe {
158156 register_dtor ( a, dtor) ;
159157 }
@@ -217,7 +215,7 @@ impl<T> Key<T> {
217215 }
218216}
219217
220- unsafe extern "C" fn destroy_value < T > ( ptr : * mut u8 ) {
218+ unsafe fn destroy_value < T > ( ptr : * mut u8 ) {
221219 let ptr = ptr as * mut Key < T > ;
222220
223221 // SAFETY:
@@ -230,14 +228,71 @@ unsafe extern "C" fn destroy_value<T>(ptr: *mut u8) {
230228 // `Option<T>` to `None`, and `dtor_state` to `RunningOrHasRun`. This
231229 // causes future calls to `get` to run `try_initialize_drop` again,
232230 // 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 {
231+ unsafe {
237232 let value = ( * ptr) . inner . take ( ) ;
238233 ( * ptr) . dtor_state . set ( DtorState :: RunningOrHasRun ) ;
239234 drop ( value) ;
240- } ) ) {
241- rtabort ! ( "thread local panicked on drop" ) ;
242235 }
243236}
237+
238+ #[ thread_local]
239+ static DTORS : RefCell < Vec < ( * mut u8 , unsafe fn ( * mut u8 ) ) > > = RefCell :: new ( Vec :: new ( ) ) ;
240+
241+ // Ensure this can never be inlined on Windows because otherwise this may break
242+ // in dylibs. See #44391.
243+ #[ cfg_attr( windows, inline( never) ) ]
244+ unsafe fn register_dtor ( t : * mut u8 , dtor : unsafe fn ( * mut u8 ) ) {
245+ // Ensure that destructors are run on thread exit.
246+ crate :: sys:: thread_local_guard:: activate ( ) ;
247+
248+ let mut dtors = match DTORS . try_borrow_mut ( ) {
249+ Ok ( dtors) => dtors,
250+ // The only place this function can be called reentrantly is inside the
251+ // heap allocator. This is currently forbidden.
252+ Err ( _) => rtabort ! ( "the global allocator may not register TLS destructors" ) ,
253+ } ;
254+ dtors. push ( ( t, dtor) ) ;
255+ }
256+
257+ /// Called by the platform on thread exit to run all registered destructors.
258+ /// The signature was chosen so that this function may be passed as a callback
259+ /// to platform functions. The argument is ignored.
260+ ///
261+ /// # Safety
262+ /// May only be called on thread exit. In particular, no thread locals may
263+ /// currently be referenced.
264+ pub unsafe extern "C" fn run_dtors ( _unused : * mut u8 ) {
265+ struct Guard ;
266+ impl Drop for Guard {
267+ fn drop ( & mut self ) {
268+ rtabort ! ( "thread local panicked on drop" ) ;
269+ }
270+ }
271+
272+ // This function must not unwind. This is ensured by the `extern "C"` ABI
273+ // regardless, but by using a guard that aborts on drop, we can give a
274+ // nicer abort reason.
275+ let guard = Guard ;
276+ let dtors = & DTORS ;
277+
278+ loop {
279+ // Ensure that the `RefMut` guard is not held while the destructor is
280+ // executed to allow initializing TLS variables in destructors.
281+ let ( t, dtor) = {
282+ let mut dtors = dtors. borrow_mut ( ) ;
283+ match dtors. pop ( ) {
284+ Some ( entry) => entry,
285+ None => break ,
286+ }
287+ } ;
288+
289+ unsafe {
290+ ( dtor) ( t) ;
291+ }
292+ }
293+
294+ // All destructors were run, deallocate the list.
295+ drop ( dtors. replace ( Vec :: new ( ) ) ) ;
296+ // Disarm the guard.
297+ forget ( guard) ;
298+ }
0 commit comments