Skip to content

Commit a2e506d

Browse files
committed
std: move UNIX to new destructor list implementation
1 parent 06fa9f4 commit a2e506d

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
@@ -37,7 +37,7 @@ pub mod rand;
3737
pub mod stack_overflow;
3838
pub mod stdio;
3939
pub mod thread;
40-
pub mod thread_local_dtor;
40+
pub mod thread_local_guard;
4141
pub mod thread_local_key;
4242
pub mod thread_parking;
4343
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
@@ -22,9 +24,10 @@
2224
// FIXME: The Rust compiler currently omits weakly function definitions (i.e.,
2325
// __cxa_thread_atexit_impl) and its metadata from LLVM IR.
2426
#[no_sanitize(cfi, kcfi)]
25-
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
27+
pub fn activate() {
28+
use crate::cell::Cell;
2629
use crate::mem;
27-
use crate::sys_common::thread_local_dtor::register_dtor_fallback;
30+
use crate::sys_common::thread_local_key::StaticKey;
2831

2932
/// This is necessary because the __cxa_thread_atexit_impl implementation
3033
/// std links to by default may be a C or C++ implementation that was not
@@ -49,64 +52,47 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
4952
>;
5053
}
5154

52-
if let Some(f) = __cxa_thread_atexit_impl {
53-
unsafe {
54-
f(
55-
mem::transmute::<
56-
unsafe extern "C" fn(*mut u8),
57-
unsafe extern "C" fn(*mut libc::c_void),
58-
>(dtor),
59-
t.cast(),
60-
&__dso_handle as *const _ as *mut _,
61-
);
55+
unsafe {
56+
if let Some(atexit) = __cxa_thread_atexit_impl {
57+
#[thread_local]
58+
static REGISTERED: Cell<bool> = Cell::new(false);
59+
if !REGISTERED.get() {
60+
atexit(
61+
mem::transmute::<
62+
unsafe extern "C" fn(*mut u8),
63+
unsafe extern "C" fn(*mut libc::c_void),
64+
>(run_dtors),
65+
ptr::null_mut(),
66+
&__dso_handle as *const _ as *mut _,
67+
);
68+
REGISTERED.set(true);
69+
}
70+
} else {
71+
static KEY: StaticKey = StaticKey::new(Some(run_dtors));
72+
73+
KEY.set(ptr::invalid_mut(1));
6274
}
63-
return;
6475
}
65-
register_dtor_fallback(t, dtor);
6676
}
6777

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

9485
extern "C" {
9586
fn _tlv_atexit(dtor: unsafe extern "C" fn(*mut u8), arg: *mut u8);
9687
}
9788

98-
match DTORS.try_borrow_mut() {
99-
Ok(mut dtors) => dtors.push((t, dtor)),
100-
Err(_) => rtabort!("global allocator may not use TLS"),
101-
}
89+
#[thread_local]
90+
static REGISTERED: Cell<bool> = Cell::new(false);
10291

103-
unsafe extern "C" fn run_dtors(_: *mut u8) {
104-
let mut list = DTORS.take();
105-
while !list.is_empty() {
106-
for (ptr, dtor) in list {
107-
dtor(ptr);
108-
}
109-
list = DTORS.take();
92+
if !REGISTERED.get() {
93+
unsafe {
94+
_tlv_atexit(run_dtors, ptr::null_mut());
95+
REGISTERED.set(true);
11096
}
11197
}
11298
}
@@ -118,7 +104,12 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
118104
target_os = "aix"
119105
))]
120106
#[cfg_attr(target_family = "wasm", allow(unused))] // might remain unused depending on target details (e.g. wasm32-unknown-emscripten)
121-
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
122-
use crate::sys_common::thread_local_dtor::register_dtor_fallback;
123-
register_dtor_fallback(t, dtor);
107+
pub fn activate() {
108+
use crate::sys_common::thread_local_key::StaticKey;
109+
110+
static KEY: StaticKey = StaticKey::new(Some(run_dtors));
111+
112+
unsafe {
113+
KEY.set(ptr::invalid_mut(1));
114+
}
124115
}

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)