Skip to content

Commit 111c5dd

Browse files
committed
std: move UNIX to new destructor list implementation
1 parent 4c53d7f commit 111c5dd

File tree

4 files changed

+45
-111
lines changed

4 files changed

+45
-111
lines changed

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

Lines changed: 1 addition & 1 deletion
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;
Lines changed: 44 additions & 53 deletions
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
@@ -43,64 +46,47 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
4346
>;
4447
}
4548

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

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

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

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

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

library/std/src/sys_common/mod.rs

Lines changed: 0 additions & 1 deletion
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

Lines changed: 0 additions & 56 deletions
This file was deleted.

0 commit comments

Comments
 (0)