Skip to content

Commit 654a0f0

Browse files
committed
std: move UNIX to new destructor list implementation
1 parent 7dcf025 commit 654a0f0

File tree

4 files changed

+45
-111
lines changed

4 files changed

+45
-111
lines changed

library/std/src/sys/unix/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ pub mod rand;
3838
pub mod stack_overflow;
3939
pub mod stdio;
4040
pub mod thread;
41-
pub mod thread_local_dtor;
41+
pub mod thread_local_guard;
4242
pub mod thread_local_key;
4343
pub mod thread_parking;
4444
pub mod time;
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
//! Ensures that thread-local destructors are run on thread exit.
2+
13
#![cfg(target_thread_local)]
24
#![unstable(feature = "thread_local_internals", issue = "none")]
35

4-
//! Provides thread-local destructors without an associated "key", which
5-
//! can be more efficient.
6+
use crate::ptr;
7+
use crate::sys::common::thread_local::run_dtors;
68

79
// Since what appears to be glibc 2.18 this symbol has been shipped which
810
// GCC and clang both use to invoke destructors in thread_local globals, so
@@ -16,9 +18,10 @@
1618
// FIXME: The Rust compiler currently omits weakly function definitions (i.e.,
1719
// __cxa_thread_atexit_impl) and its metadata from LLVM IR.
1820
#[no_sanitize(cfi, kcfi)]
19-
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
21+
pub fn activate() {
22+
use crate::cell::Cell;
2023
use crate::mem;
21-
use crate::sys_common::thread_local_dtor::register_dtor_fallback;
24+
use crate::sys_common::thread_local_key::StaticKey;
2225

2326
/// This is necessary because the __cxa_thread_atexit_impl implementation
2427
/// std links to by default may be a C or C++ implementation that was not
@@ -41,64 +44,47 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
4144
>;
4245
}
4346

44-
if let Some(f) = __cxa_thread_atexit_impl {
45-
unsafe {
46-
f(
47-
mem::transmute::<
48-
unsafe extern "C" fn(*mut u8),
49-
unsafe extern "C" fn(*mut libc::c_void),
50-
>(dtor),
51-
t.cast(),
52-
&__dso_handle as *const _ as *mut _,
53-
);
47+
unsafe {
48+
if let Some(atexit) = __cxa_thread_atexit_impl {
49+
#[thread_local]
50+
static REGISTERED: Cell<bool> = Cell::new(false);
51+
if !REGISTERED.get() {
52+
atexit(
53+
mem::transmute::<
54+
unsafe extern "C" fn(*mut u8),
55+
unsafe extern "C" fn(*mut libc::c_void),
56+
>(run_dtors),
57+
ptr::null_mut(),
58+
&__dso_handle as *const _ as *mut _,
59+
);
60+
REGISTERED.set(true);
61+
}
62+
} else {
63+
static KEY: StaticKey = StaticKey::new(Some(run_dtors));
64+
65+
KEY.set(ptr::invalid_mut(1));
5466
}
55-
return;
5667
}
57-
register_dtor_fallback(t, dtor);
5868
}
5969

60-
// This implementation is very similar to register_dtor_fallback in
61-
// sys_common/thread_local.rs. The main difference is that we want to hook into
62-
// macOS's analog of the above linux function, _tlv_atexit. OSX will run the
63-
// registered dtors before any TLS slots get freed, and when the main thread
70+
// We hook into macOS's analog of the above linux function, _tlv_atexit. OSX
71+
// will run `run_dtors` before any TLS slots get freed, and when the main thread
6472
// exits.
65-
//
66-
// Unfortunately, calling _tlv_atexit while tls dtors are running is UB. The
67-
// workaround below is to register, via _tlv_atexit, a custom DTOR list once per
68-
// thread. thread_local dtors are pushed to the DTOR list without calling
69-
// _tlv_atexit.
7073
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos", target_os = "tvos"))]
71-
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
72-
use crate::cell::{Cell, RefCell};
73-
use crate::ptr;
74-
75-
#[thread_local]
76-
static REGISTERED: Cell<bool> = Cell::new(false);
77-
78-
#[thread_local]
79-
static DTORS: RefCell<Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>> = RefCell::new(Vec::new());
80-
81-
if !REGISTERED.get() {
82-
_tlv_atexit(run_dtors, ptr::null_mut());
83-
REGISTERED.set(true);
84-
}
74+
pub fn activate() {
75+
use crate::cell::Cell;
8576

8677
extern "C" {
8778
fn _tlv_atexit(dtor: unsafe extern "C" fn(*mut u8), arg: *mut u8);
8879
}
8980

90-
match DTORS.try_borrow_mut() {
91-
Ok(mut dtors) => dtors.push((t, dtor)),
92-
Err(_) => rtabort!("global allocator may not use TLS"),
93-
}
81+
#[thread_local]
82+
static REGISTERED: Cell<bool> = Cell::new(false);
9483

95-
unsafe extern "C" fn run_dtors(_: *mut u8) {
96-
let mut list = DTORS.take();
97-
while !list.is_empty() {
98-
for (ptr, dtor) in list {
99-
dtor(ptr);
100-
}
101-
list = DTORS.take();
84+
if !REGISTERED.get() {
85+
unsafe {
86+
_tlv_atexit(run_dtors, ptr::null_mut());
87+
REGISTERED.set(true);
10288
}
10389
}
10490
}
@@ -110,7 +96,12 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
11096
target_os = "aix"
11197
))]
11298
#[cfg_attr(target_family = "wasm", allow(unused))] // might remain unused depending on target details (e.g. wasm32-unknown-emscripten)
113-
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
114-
use crate::sys_common::thread_local_dtor::register_dtor_fallback;
115-
register_dtor_fallback(t, dtor);
99+
pub fn activate() {
100+
use crate::sys_common::thread_local_key::StaticKey;
101+
102+
static KEY: StaticKey = StaticKey::new(Some(run_dtors));
103+
104+
unsafe {
105+
KEY.set(ptr::invalid_mut(1));
106+
}
116107
}

library/std/src/sys_common/mod.rs

-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ pub mod once;
2929
pub mod process;
3030
pub mod thread;
3131
pub mod thread_info;
32-
pub mod thread_local_dtor;
3332
pub mod thread_parking;
3433
pub mod wstr;
3534
pub mod wtf8;

library/std/src/sys_common/thread_local_dtor.rs

-56
This file was deleted.

0 commit comments

Comments
 (0)