Skip to content

Commit 08b6a47

Browse files
committed
std: begin unifying TLS destructor lists
1 parent 5bd5d21 commit 08b6a47

File tree

3 files changed

+69
-41
lines changed

3 files changed

+69
-41
lines changed

library/std/src/sys/pal/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)]
@@ -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 {
@@ -154,8 +151,8 @@ impl<T> Key<T> {
154151

155152
// note that this is just a publicly-callable function only for the
156153
// const-initialized form of thread locals, basically a way to call the
157-
// free `register_dtor` function defined elsewhere in std.
158-
pub unsafe fn register_dtor(a: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
154+
// free `register_dtor` function.
155+
pub unsafe fn register_dtor(a: *mut u8, dtor: unsafe fn(*mut u8)) {
159156
unsafe {
160157
register_dtor(a, dtor);
161158
}
@@ -219,7 +216,7 @@ impl<T> Key<T> {
219216
}
220217
}
221218

222-
unsafe extern "C" fn destroy_value<T>(ptr: *mut u8) {
219+
unsafe fn destroy_value<T>(ptr: *mut u8) {
223220
let ptr = ptr as *mut Key<T>;
224221

225222
// SAFETY:
@@ -232,14 +229,66 @@ unsafe extern "C" fn destroy_value<T>(ptr: *mut u8) {
232229
// `Option<T>` to `None`, and `dtor_state` to `RunningOrHasRun`. This
233230
// causes future calls to `get` to run `try_initialize_drop` again,
234231
// which will now fail, and return `None`.
235-
//
236-
// Wrap the call in a catch to ensure unwinding is caught in the event
237-
// a panic takes place in a destructor.
238-
if let Err(_) = panic::catch_unwind(panic::AssertUnwindSafe(|| unsafe {
232+
unsafe {
239233
let value = (*ptr).inner.take();
240234
(*ptr).dtor_state.set(DtorState::RunningOrHasRun);
241235
drop(value);
242-
})) {
243-
rtabort!("thread local panicked on drop");
236+
}
237+
}
238+
239+
#[thread_local]
240+
static DTORS: RefCell<Vec<(*mut u8, unsafe fn(*mut u8))>> = RefCell::new(Vec::new());
241+
242+
// Ensure this can never be inlined on Windows because otherwise this may break
243+
// in dylibs. See #44391.
244+
#[cfg_attr(windows, inline(never))]
245+
unsafe fn register_dtor(t: *mut u8, dtor: unsafe fn(*mut u8)) {
246+
// Ensure that destructors are run on thread exit.
247+
crate::sys::thread_local_guard::activate();
248+
249+
let mut dtors = match DTORS.try_borrow_mut() {
250+
Ok(dtors) => dtors,
251+
// The only place this function can be called reentrantly is inside the
252+
// heap allocator. This is currently forbidden.
253+
Err(_) => rtabort!("the global allocator may not register TLS destructors"),
254+
};
255+
dtors.push((t, dtor));
256+
}
257+
258+
/// Called by the platform on thread exit to run all registered destructors.
259+
/// The signature was chosen so that this function may be passed as a callback
260+
/// to platform functions. The argument is ignored.
261+
///
262+
/// # Safety
263+
/// May only be called on thread exit. In particular, no thread locals may
264+
/// currently be referenced.
265+
pub unsafe extern "C" fn run_dtors(_unused: *mut u8) {
266+
// This function must not unwind. This is ensured by the `extern "C"` ABI,
267+
// but by catching the unwind, we can print a more helpful message.
268+
269+
match panic::catch_unwind(|| {
270+
let dtors = &DTORS;
271+
272+
loop {
273+
// Ensure that the `RefMut` guard is not held while the destructor is
274+
// executed to allow initializing TLS variables in destructors.
275+
let (t, dtor) = {
276+
let mut dtors = dtors.borrow_mut();
277+
match dtors.pop() {
278+
Some(entry) => entry,
279+
None => break,
280+
}
281+
};
282+
283+
unsafe {
284+
(dtor)(t);
285+
}
286+
}
287+
288+
// All destructors were run, deallocate the list.
289+
drop(dtors.replace(Vec::new()));
290+
}) {
291+
Ok(()) => {}
292+
Err(_) => rtabort!("thread local panicked on drop"),
244293
}
245294
}

library/std/src/sys/pal/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)