Skip to content

Commit 06fa9f4

Browse files
committed
std: begin unifying TLS destructor lists
1 parent 928b3da commit 06fa9f4

File tree

3 files changed

+69
-41
lines changed

3 files changed

+69
-41
lines changed

library/std/src/sys/common/thread_local/fast_local.rs

+67-18
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use super::lazy::LazyKeyInner;
2-
use crate::cell::Cell;
3-
use crate::sys::thread_local_dtor::register_dtor;
2+
use crate::cell::{Cell, RefCell};
43
use 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
}

library/std/src/sys/common/thread_local/mod.rs

+1-22
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ cfg_if::cfg_if! {
1515
#[doc(hidden)]
1616
mod fast_local;
1717
#[doc(hidden)]
18-
pub use fast_local::{Key, thread_local_inner};
18+
pub use fast_local::{Key, thread_local_inner, run_dtors};
1919
} else {
2020
#[doc(hidden)]
2121
mod os_local;
@@ -101,24 +101,3 @@ mod lazy {
101101
}
102102
}
103103
}
104-
105-
/// Run a callback in a scenario which must not unwind (such as a `extern "C"
106-
/// fn` declared in a user crate). If the callback unwinds anyway, then
107-
/// `rtabort` with a message about thread local panicking on drop.
108-
#[inline]
109-
pub fn abort_on_dtor_unwind(f: impl FnOnce()) {
110-
// Using a guard like this is lower cost.
111-
let guard = DtorUnwindGuard;
112-
f();
113-
core::mem::forget(guard);
114-
115-
struct DtorUnwindGuard;
116-
impl Drop for DtorUnwindGuard {
117-
#[inline]
118-
fn drop(&mut self) {
119-
// This is not terribly descriptive, but it doesn't need to be as we'll
120-
// already have printed a panic message at this point.
121-
rtabort!("thread local panicked on drop");
122-
}
123-
}
124-
}

library/std/src/thread/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ cfg_if::cfg_if! {
206206
#[doc(hidden)]
207207
#[unstable(feature = "thread_local_internals", issue = "none")]
208208
pub mod local_impl {
209-
pub use crate::sys::common::thread_local::{thread_local_inner, Key, abort_on_dtor_unwind};
209+
pub use crate::sys::common::thread_local::{thread_local_inner, Key};
210210
}
211211
}
212212
}

0 commit comments

Comments
 (0)