1
1
use 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 } ;
5
5
6
6
#[ doc( hidden) ]
7
7
#[ allow_internal_unstable( thread_local_internals, cfg_target_thread_local, thread_local) ]
@@ -37,13 +37,11 @@ pub macro thread_local_inner {
37
37
38
38
// Safety: Performs `drop_in_place(ptr as *mut $t)`, and requires
39
39
// 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> ( ) ) ; }
47
45
}
48
46
49
47
unsafe {
@@ -152,8 +150,8 @@ impl<T> Key<T> {
152
150
153
151
// note that this is just a publicly-callable function only for the
154
152
// 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 ) ) {
157
155
unsafe {
158
156
register_dtor ( a, dtor) ;
159
157
}
@@ -217,7 +215,7 @@ impl<T> Key<T> {
217
215
}
218
216
}
219
217
220
- unsafe extern "C" fn destroy_value < T > ( ptr : * mut u8 ) {
218
+ unsafe fn destroy_value < T > ( ptr : * mut u8 ) {
221
219
let ptr = ptr as * mut Key < T > ;
222
220
223
221
// SAFETY:
@@ -230,14 +228,71 @@ unsafe extern "C" fn destroy_value<T>(ptr: *mut u8) {
230
228
// `Option<T>` to `None`, and `dtor_state` to `RunningOrHasRun`. This
231
229
// causes future calls to `get` to run `try_initialize_drop` again,
232
230
// 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 {
237
232
let value = ( * ptr) . inner . take ( ) ;
238
233
( * ptr) . dtor_state . set ( DtorState :: RunningOrHasRun ) ;
239
234
drop ( value) ;
240
- } ) ) {
241
- rtabort ! ( "thread local panicked on drop" ) ;
242
235
}
243
236
}
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