Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 7dd342e

Browse files
committedJul 18, 2024··
std: make thread::current available in all thread_local! destructors
1 parent 52f3c71 commit 7dd342e

File tree

15 files changed

+383
-102
lines changed

15 files changed

+383
-102
lines changed
 

‎library/std/src/rt.rs

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@
1919
pub use crate::panicking::{begin_panic, panic_count};
2020
pub use core::panicking::{panic_display, panic_fmt};
2121

22+
use crate::any::Any;
2223
use crate::sync::Once;
2324
use crate::sys;
2425
use crate::thread::{self, Thread};
26+
use crate::{mem, panic};
2527

2628
// Prints to the "panic output", depending on the platform this may be:
2729
// - the standard error output
@@ -64,6 +66,11 @@ macro_rules! rtunwrap {
6466
};
6567
}
6668

69+
fn handle_rt_panic(e: Box<dyn Any + Send>) {
70+
mem::forget(e);
71+
rtabort!("initialization or cleanup bug");
72+
}
73+
6774
// One-time runtime initialization.
6875
// Runs before `main`.
6976
// SAFETY: must be called only once during runtime initialization.
@@ -99,6 +106,20 @@ unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
99106
thread::set_current(thread);
100107
}
101108

109+
/// Clean up the thread-local runtime state. This *should* be run after all other
110+
/// code managed by the Rust runtime, but will not cause UB if that condition is
111+
/// not fulfilled. Also note that this function is not guaranteed to be run, but
112+
/// skipping it will cause leaks and therefore is to be avoided.
113+
pub(crate) fn thread_cleanup() {
114+
// This function is run in situations where unwinding leads to an abort
115+
// (think `extern "C"` functions). Abort here instead so that we can
116+
// print a nice message.
117+
panic::catch_unwind(|| {
118+
crate::thread::drop_current();
119+
})
120+
.unwrap_or_else(handle_rt_panic);
121+
}
122+
102123
// One-time runtime cleanup.
103124
// Runs after `main` or at program exit.
104125
// NOTE: this is not guaranteed to run, for example when the program aborts.
@@ -121,11 +142,6 @@ fn lang_start_internal(
121142
argv: *const *const u8,
122143
sigpipe: u8,
123144
) -> Result<isize, !> {
124-
use crate::{mem, panic};
125-
let rt_abort = move |e| {
126-
mem::forget(e);
127-
rtabort!("initialization or cleanup bug");
128-
};
129145
// Guard against the code called by this function from unwinding outside of the Rust-controlled
130146
// code, which is UB. This is a requirement imposed by a combination of how the
131147
// `#[lang="start"]` attribute is implemented as well as by the implementation of the panicking
@@ -137,16 +153,17 @@ fn lang_start_internal(
137153
// prevent std from accidentally introducing a panic to these functions. Another is from
138154
// user code from `main` or, more nefariously, as described in e.g. issue #86030.
139155
// SAFETY: Only called once during runtime initialization.
140-
panic::catch_unwind(move || unsafe { init(argc, argv, sigpipe) }).map_err(rt_abort)?;
156+
panic::catch_unwind(move || unsafe { init(argc, argv, sigpipe) })
157+
.unwrap_or_else(handle_rt_panic);
141158
let ret_code = panic::catch_unwind(move || panic::catch_unwind(main).unwrap_or(101) as isize)
142159
.map_err(move |e| {
143160
mem::forget(e);
144161
rtabort!("drop of the panic payload panicked");
145162
});
146-
panic::catch_unwind(cleanup).map_err(rt_abort)?;
163+
panic::catch_unwind(cleanup).unwrap_or_else(handle_rt_panic);
147164
// Guard against multple threads calling `libc::exit` concurrently.
148165
// See the documentation for `unique_thread_exit` for more information.
149-
panic::catch_unwind(|| crate::sys::exit_guard::unique_thread_exit()).map_err(rt_abort)?;
166+
panic::catch_unwind(crate::sys::exit_guard::unique_thread_exit).unwrap_or_else(handle_rt_panic);
150167
ret_code
151168
}
152169

‎library/std/src/sys/pal/hermit/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ pub unsafe extern "C" fn runtime_entry(
104104
let result = main(argc as isize, argv);
105105

106106
crate::sys::thread_local::destructors::run();
107+
crate::rt::thread_cleanup();
108+
107109
hermit_abi::exit(result);
108110
}
109111

‎library/std/src/sys/pal/hermit/thread.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ impl Thread {
5050

5151
// run all destructors
5252
crate::sys::thread_local::destructors::run();
53+
crate::rt::thread_cleanup();
5354
}
5455
}
5556
}

‎library/std/src/sys/thread_local/guard/apple.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ pub fn enable() {
2626
unsafe extern "C" fn run_dtors(_: *mut u8) {
2727
unsafe {
2828
destructors::run();
29+
crate::rt::thread_cleanup();
2930
}
3031
}
3132
}

‎library/std/src/sys/thread_local/guard/key.rs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
//! that will run all native TLS destructors in the destructor list.
44
55
use crate::ptr;
6-
use crate::sys::thread_local::destructors;
76
use crate::sys::thread_local::key::{set, LazyKey};
87

8+
#[cfg(target_thread_local)]
99
pub fn enable() {
10+
use crate::sys::thread_local::destructors;
11+
1012
static DTORS: LazyKey = LazyKey::new(Some(run));
1113

1214
// Setting the key value to something other than NULL will result in the
@@ -18,6 +20,41 @@ pub fn enable() {
1820
unsafe extern "C" fn run(_: *mut u8) {
1921
unsafe {
2022
destructors::run();
23+
// On platforms with `__cxa_thread_atexit_impl`, `destructors::run`
24+
// does nothing on newer systems as the TLS destructors are
25+
// registered with the system. But because all of those platforms
26+
// call the destructors of TLS keys after the registered ones, this
27+
// function will still be run last (at the time of writing).
28+
crate::rt::thread_cleanup();
29+
}
30+
}
31+
}
32+
33+
/// On platforms with key-based TLS, the system runs the destructors for us.
34+
/// We still have to make sure that [`crate::rt::thread_cleanup`] is called,
35+
/// however. This is done by defering the execution of a TLS destructor to
36+
/// the next round of destruction inside the TLS destructors.
37+
#[cfg(not(target_thread_local))]
38+
pub fn enable() {
39+
const DEFER: *mut u8 = ptr::without_provenance_mut(1);
40+
const RUN: *mut u8 = ptr::without_provenance_mut(2);
41+
42+
static CLEANUP: LazyKey = LazyKey::new(Some(run));
43+
44+
unsafe { set(CLEANUP.force(), DEFER) }
45+
46+
unsafe extern "C" fn run(state: *mut u8) {
47+
if state == DEFER {
48+
// Make sure that this function is run again in the next round of
49+
// TLS destruction. If there is no futher round, there will be leaks,
50+
// but that's okay, `thread_cleanup` is not guaranteed to be called.
51+
unsafe { set(CLEANUP.force(), RUN) }
52+
} else {
53+
debug_assert_eq!(state, RUN);
54+
// If the state is still RUN in the next round of TLS destruction,
55+
// it means that no other TLS destructors defined by this runtime
56+
// have been run, as they would have set the state to DEFER.
57+
crate::rt::thread_cleanup();
2158
}
2259
}
2360
}

‎library/std/src/sys/thread_local/guard/solid.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ pub fn enable() {
1818
}
1919

2020
unsafe extern "C" fn tls_dtor(_unused: *mut u8) {
21-
unsafe { destructors::run() };
21+
unsafe {
22+
destructors::run();
23+
crate::rt::thread_cleanup();
24+
}
2225
}
2326
}

‎library/std/src/sys/thread_local/guard/windows.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,13 @@ unsafe extern "system" fn tls_callback(_h: *mut c_void, dw_reason: u32, _pv: *mu
9292
}
9393

9494
if dw_reason == c::DLL_THREAD_DETACH || dw_reason == c::DLL_PROCESS_DETACH {
95-
#[cfg(target_thread_local)]
9695
unsafe {
96+
#[cfg(target_thread_local)]
9797
super::super::destructors::run();
98-
}
99-
#[cfg(not(target_thread_local))]
100-
unsafe {
98+
#[cfg(not(target_thread_local))]
10199
super::super::key::run_dtors();
100+
101+
crate::rt::thread_cleanup();
102102
}
103103
}
104104
}

‎library/std/src/sys/thread_local/key/xous.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,4 +213,6 @@ unsafe fn run_dtors() {
213213
unsafe { cur = (*cur).next };
214214
}
215215
}
216+
217+
crate::rt::thread_cleanup();
216218
}

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

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,15 @@ cfg_if::cfg_if! {
3131
))] {
3232
mod statik;
3333
pub use statik::{EagerStorage, LazyStorage, thread_local_inner};
34+
pub(crate) use statik::{LocalPointer, local_pointer};
3435
} else if #[cfg(target_thread_local)] {
3536
mod native;
3637
pub use native::{EagerStorage, LazyStorage, thread_local_inner};
38+
pub(crate) use native::{LocalPointer, local_pointer};
3739
} else {
3840
mod os;
3941
pub use os::{Storage, thread_local_inner};
42+
pub(crate) use os::{LocalPointer, local_pointer};
4043
}
4144
}
4245

@@ -72,36 +75,47 @@ pub(crate) mod destructors {
7275
}
7376

7477
/// This module provides a way to schedule the execution of the destructor list
75-
/// on systems without a per-variable destructor system.
76-
mod guard {
78+
/// and the [runtime cleanup](crate::rt::thread_cleanup) function. Calling [enable]
79+
/// should ensure that these functions are called at the right times.
80+
pub(crate) mod guard {
7781
cfg_if::cfg_if! {
7882
if #[cfg(all(target_thread_local, target_vendor = "apple"))] {
7983
mod apple;
80-
pub(super) use apple::enable;
84+
pub(crate) use apple::enable;
8185
} else if #[cfg(target_os = "windows")] {
8286
mod windows;
83-
pub(super) use windows::enable;
87+
pub(crate) use windows::enable;
8488
} else if #[cfg(any(
85-
all(target_family = "wasm", target_feature = "atomics"),
89+
target_family = "wasm",
90+
target_os = "uefi",
91+
target_os = "zkvm",
8692
))] {
87-
pub(super) fn enable() {
88-
// FIXME: Right now there is no concept of "thread exit", but
89-
// this is likely going to show up at some point in the form of
90-
// an exported symbol that the wasm runtime is going to be
91-
// expected to call. For now we just leak everything, but if
92-
// such a function starts to exist it will probably need to
93+
pub(crate) fn enable() {
94+
// FIXME: Right now there is no concept of "thread exit" on
95+
// wasm, but this is likely going to show up at some point in
96+
// the form of an exported symbol that the wasm runtime is going
97+
// to be expected to call. For now we just leak everything, but
98+
// if such a function starts to exist it will probably need to
9399
// iterate the destructor list with this function:
94100
#[allow(unused)]
101+
#[cfg(not(all(target_family = "wasm", not(target_feature = "atomics"))))]
95102
use super::destructors::run;
103+
#[allow(unused)]
104+
use crate::rt::thread_cleanup;
96105
}
97-
} else if #[cfg(target_os = "hermit")] {
98-
pub(super) fn enable() {}
106+
} else if #[cfg(any(
107+
target_os = "hermit",
108+
target_os = "xous",
109+
))] {
110+
// `std` is the only runtime, so it just calls the destructor functions
111+
// itself when the time comes.
112+
pub(crate) fn enable() {}
99113
} else if #[cfg(target_os = "solid_asp3")] {
100114
mod solid;
101-
pub(super) use solid::enable;
102-
} else if #[cfg(all(target_thread_local, not(target_family = "wasm")))] {
115+
pub(crate) use solid::enable;
116+
} else {
103117
mod key;
104-
pub(super) use key::enable;
118+
pub(crate) use key::enable;
105119
}
106120
}
107121
}

‎library/std/src/sys/thread_local/native/mod.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232
mod eager;
3333
mod lazy;
3434

35+
use crate::cell::Cell;
36+
use crate::ptr;
37+
3538
pub use eager::Storage as EagerStorage;
3639
pub use lazy::Storage as LazyStorage;
3740

@@ -107,3 +110,31 @@ pub macro thread_local_inner {
107110
$crate::thread::local_impl::thread_local_inner!(@key $t, $($init)*);
108111
},
109112
}
113+
114+
#[rustc_macro_transparency = "semitransparent"]
115+
pub(crate) macro local_pointer {
116+
() => {},
117+
($vis:vis static $name:ident; $($rest:tt)*) => {
118+
#[thread_local]
119+
$vis static $name: $crate::sys::thread_local::LocalPointer = $crate::sys::thread_local::LocalPointer::__new();
120+
$crate::sys::thread_local::local_pointer! { $($rest)* }
121+
},
122+
}
123+
124+
pub(crate) struct LocalPointer {
125+
p: Cell<*mut ()>,
126+
}
127+
128+
impl LocalPointer {
129+
pub const fn __new() -> LocalPointer {
130+
LocalPointer { p: Cell::new(ptr::null_mut()) }
131+
}
132+
133+
pub fn get(&self) -> *mut () {
134+
self.p.get()
135+
}
136+
137+
pub fn set(&self, p: *mut ()) {
138+
self.p.set(p)
139+
}
140+
}

‎library/std/src/sys/thread_local/os.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use super::abort_on_dtor_unwind;
2+
use super::guard;
3+
use super::key::{get, set, Key, LazyKey};
24
use crate::cell::Cell;
35
use crate::marker::PhantomData;
46
use crate::ptr;
5-
use crate::sys::thread_local::key::{get, set, Key, LazyKey};
67

78
#[doc(hidden)]
89
#[allow_internal_unstable(thread_local_internals)]
@@ -138,5 +139,35 @@ unsafe extern "C" fn destroy_value<T: 'static>(ptr: *mut u8) {
138139
drop(ptr);
139140
// SAFETY: `key` is the TLS key `ptr` was stored under.
140141
unsafe { set(key, ptr::null_mut()) };
142+
// Make sure that the runtime cleanup will be performed
143+
// after the next round of TLS destruction.
144+
guard::enable();
141145
});
142146
}
147+
148+
#[rustc_macro_transparency = "semitransparent"]
149+
pub(crate) macro local_pointer {
150+
() => {},
151+
($vis:vis static $name:ident; $($rest:tt)*) => {
152+
$vis static $name: $crate::sys::thread_local::LocalPointer = $crate::sys::thread_local::LocalPointer::__new();
153+
$crate::sys::thread_local::local_pointer! { $($rest)* }
154+
},
155+
}
156+
157+
pub(crate) struct LocalPointer {
158+
key: LazyKey,
159+
}
160+
161+
impl LocalPointer {
162+
pub const fn __new() -> LocalPointer {
163+
LocalPointer { key: LazyKey::new(None) }
164+
}
165+
166+
pub fn get(&'static self) -> *mut () {
167+
unsafe { get(self.key.force()) as *mut () }
168+
}
169+
170+
pub fn set(&'static self, p: *mut ()) {
171+
unsafe { set(self.key.force(), p as *mut u8) }
172+
}
173+
}

‎library/std/src/sys/thread_local/statik.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
//! On some targets like wasm there's no threads, so no need to generate
22
//! thread locals and we can instead just use plain statics!
33
4-
use crate::cell::UnsafeCell;
4+
use crate::cell::{Cell, UnsafeCell};
5+
use crate::ptr;
56

67
#[doc(hidden)]
78
#[allow_internal_unstable(thread_local_internals)]
@@ -93,3 +94,33 @@ impl<T> LazyStorage<T> {
9394

9495
// SAFETY: the target doesn't have threads.
9596
unsafe impl<T> Sync for LazyStorage<T> {}
97+
98+
#[rustc_macro_transparency = "semitransparent"]
99+
pub(crate) macro local_pointer {
100+
() => {},
101+
($vis:vis static $name:ident; $($rest:tt)*) => {
102+
$vis static $name: $crate::sys::thread_local::LocalPointer = $crate::sys::thread_local::LocalPointer::__new();
103+
$crate::sys::thread_local::local_pointer! { $($rest)* }
104+
},
105+
}
106+
107+
pub(crate) struct LocalPointer {
108+
p: Cell<*mut ()>,
109+
}
110+
111+
impl LocalPointer {
112+
pub const fn __new() -> LocalPointer {
113+
LocalPointer { p: Cell::new(ptr::null_mut()) }
114+
}
115+
116+
pub fn get(&self) -> *mut () {
117+
self.p.get()
118+
}
119+
120+
pub fn set(&self, p: *mut ()) {
121+
self.p.set(p)
122+
}
123+
}
124+
125+
// SAFETY: the target doesn't have threads.
126+
unsafe impl Sync for LocalPointer {}

‎library/std/src/thread/current.rs

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
use super::Thread;
2+
use crate::mem::ManuallyDrop;
3+
use crate::ptr;
4+
use crate::sys::thread_local::local_pointer;
5+
6+
const NONE: *mut () = ptr::null_mut();
7+
const BUSY: *mut () = ptr::without_provenance_mut(1);
8+
const DESTROYED: *mut () = ptr::without_provenance_mut(2);
9+
10+
local_pointer! {
11+
static CURRENT;
12+
}
13+
14+
/// Sets the thread handle for the current thread.
15+
///
16+
/// Aborts if the handle has been set already to reduce code size.
17+
pub(crate) fn set_current(thread: Thread) {
18+
if CURRENT.get() != NONE {
19+
// Using `panic` here can add ~3kB to the binary size. We have complete
20+
// control over where this is called, so just abort if there is a bug.
21+
rtabort!("thread::set_current should only be called once per thread");
22+
}
23+
24+
// Make sure that `crate::rt::thread_cleanup` will be run, which will
25+
// call `drop_current`.
26+
crate::sys::thread_local::guard::enable();
27+
CURRENT.set(thread.into_raw());
28+
}
29+
30+
/// Gets a handle to the thread that invokes it, if the handle has been initialized.
31+
pub(crate) fn try_current() -> Option<Thread> {
32+
let current = CURRENT.get();
33+
if current > DESTROYED {
34+
unsafe {
35+
let current = ManuallyDrop::new(Thread::from_raw(current));
36+
Some((*current).clone())
37+
}
38+
} else {
39+
None
40+
}
41+
}
42+
43+
/// Gets a handle to the thread that invokes it.
44+
///
45+
/// # Examples
46+
///
47+
/// Getting a handle to the current thread with `thread::current()`:
48+
///
49+
/// ```
50+
/// use std::thread;
51+
///
52+
/// let handler = thread::Builder::new()
53+
/// .name("named thread".into())
54+
/// .spawn(|| {
55+
/// let handle = thread::current();
56+
/// assert_eq!(handle.name(), Some("named thread"));
57+
/// })
58+
/// .unwrap();
59+
///
60+
/// handler.join().unwrap();
61+
/// ```
62+
#[must_use]
63+
#[stable(feature = "rust1", since = "1.0.0")]
64+
pub fn current() -> Thread {
65+
let current = CURRENT.get();
66+
if current > DESTROYED {
67+
unsafe {
68+
let current = ManuallyDrop::new(Thread::from_raw(current));
69+
(*current).clone()
70+
}
71+
} else {
72+
init_current(current)
73+
}
74+
}
75+
76+
#[cold]
77+
fn init_current(current: *mut ()) -> Thread {
78+
if current == NONE {
79+
// Make sure that `crate::rt::thread_cleanup` will be run, which will
80+
// call `drop_current`.
81+
crate::sys::thread_local::guard::enable();
82+
CURRENT.set(BUSY);
83+
let thread = Thread::new_unnamed();
84+
CURRENT.set(thread.clone().into_raw());
85+
thread
86+
} else if current == BUSY {
87+
// BUSY exists solely for this check, but as it is in the slow path, the
88+
// extra TLS write above shouldn't matter. The alternative is nearly always
89+
// a stack overflow.
90+
91+
// If you came across this message, contact the author of your allocator.
92+
// If you are said author: A surprising amount of functions inside the
93+
// standard library (e.g. `Mutex`, `thread_local!`, `File` when using long
94+
// paths, even `panic!` when using unwinding), need memory allocation, so
95+
// you'll get circular dependencies all over the place when using them.
96+
// I (joboet) highly recommend using only APIs from core in your allocator
97+
// and implementing your own system abstractions. Still, if you feel that
98+
// a particular API should be entirely allocation-free, feel free to open
99+
// an issue on the Rust repository, we'll see what we can do.
100+
rtabort!(
101+
"\n
102+
Attempted to access thread-local data while allocating said data.\n
103+
Do not access functions that allocate in the global allocator!\n
104+
This is a bug in the global allocator.\n
105+
"
106+
)
107+
} else {
108+
debug_assert_eq!(current, DESTROYED);
109+
panic!(
110+
"use of std::thread::current() is not possible after the thread's
111+
local data has been destroyed"
112+
)
113+
}
114+
}
115+
116+
/// This should be run in [`crate::rt::thread_cleanup`] to reset the thread
117+
/// handle.
118+
pub(crate) fn drop_current() {
119+
let current = CURRENT.get();
120+
if current > DESTROYED {
121+
unsafe {
122+
CURRENT.set(DESTROYED);
123+
drop(Thread::from_raw(current));
124+
}
125+
}
126+
}

‎library/std/src/thread/local/tests.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::cell::{Cell, UnsafeCell};
22
use crate::sync::atomic::{AtomicU8, Ordering};
33
use crate::sync::{Arc, Condvar, Mutex};
4-
use crate::thread::{self, LocalKey};
4+
use crate::thread::{self, Builder, LocalKey};
55
use crate::thread_local;
66

77
#[derive(Clone, Default)]
@@ -340,3 +340,34 @@ fn join_orders_after_tls_destructors() {
340340
jh2.join().unwrap();
341341
}
342342
}
343+
344+
// Test that thread::current is still available in TLS destructors.
345+
#[test]
346+
fn thread_current_in_dtor() {
347+
// Go through one round of TLS destruction first.
348+
struct Defer;
349+
impl Drop for Defer {
350+
fn drop(&mut self) {
351+
RETRIEVE.with(|_| {});
352+
}
353+
}
354+
355+
struct RetrieveName;
356+
impl Drop for RetrieveName {
357+
fn drop(&mut self) {
358+
*NAME.lock().unwrap() = Some(thread::current().name().unwrap().to_owned());
359+
}
360+
}
361+
362+
static NAME: Mutex<Option<String>> = Mutex::new(None);
363+
364+
thread_local! {
365+
static DEFER: Defer = const { Defer };
366+
static RETRIEVE: RetrieveName = const { RetrieveName };
367+
}
368+
369+
Builder::new().name("test".to_owned()).spawn(|| DEFER.with(|_| {})).unwrap().join().unwrap();
370+
let name = NAME.lock().unwrap();
371+
let name = name.as_ref().unwrap();
372+
assert_eq!(name, "test");
373+
}

‎library/std/src/thread/mod.rs

Lines changed: 23 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@
159159
mod tests;
160160

161161
use crate::any::Any;
162-
use crate::cell::{OnceCell, UnsafeCell};
162+
use crate::cell::UnsafeCell;
163163
use crate::env;
164164
use crate::ffi::{CStr, CString};
165165
use crate::fmt;
@@ -185,29 +185,27 @@ mod scoped;
185185
#[stable(feature = "scoped_threads", since = "1.63.0")]
186186
pub use scoped::{scope, Scope, ScopedJoinHandle};
187187

188+
mod current;
189+
190+
#[stable(feature = "rust1", since = "1.0.0")]
191+
pub use current::current;
192+
pub(crate) use current::{drop_current, set_current, try_current};
193+
188194
////////////////////////////////////////////////////////////////////////////////
189195
// Thread-local storage
190196
////////////////////////////////////////////////////////////////////////////////
191197

192198
#[macro_use]
193199
mod local;
194200

195-
cfg_if::cfg_if! {
196-
if #[cfg(test)] {
197-
// Avoid duplicating the global state associated with thread-locals between this crate and
198-
// realstd. Miri relies on this.
199-
pub use realstd::thread::{local_impl, AccessError, LocalKey};
200-
} else {
201-
#[stable(feature = "rust1", since = "1.0.0")]
202-
pub use self::local::{AccessError, LocalKey};
203-
204-
// Implementation details used by the thread_local!{} macro.
205-
#[doc(hidden)]
206-
#[unstable(feature = "thread_local_internals", issue = "none")]
207-
pub mod local_impl {
208-
pub use crate::sys::thread_local::*;
209-
}
210-
}
201+
#[stable(feature = "rust1", since = "1.0.0")]
202+
pub use self::local::{AccessError, LocalKey};
203+
204+
// Implementation details used by the thread_local!{} macro.
205+
#[doc(hidden)]
206+
#[unstable(feature = "thread_local_internals", issue = "none")]
207+
pub mod local_impl {
208+
pub use crate::sys::thread_local::*;
211209
}
212210

213211
////////////////////////////////////////////////////////////////////////////////
@@ -698,58 +696,6 @@ where
698696
Builder::new().spawn(f).expect("failed to spawn thread")
699697
}
700698

701-
thread_local! {
702-
static CURRENT: OnceCell<Thread> = const { OnceCell::new() };
703-
}
704-
705-
/// Sets the thread handle for the current thread.
706-
///
707-
/// Aborts if the handle has been set already to reduce code size.
708-
pub(crate) fn set_current(thread: Thread) {
709-
// Using `unwrap` here can add ~3kB to the binary size. We have complete
710-
// control over where this is called, so just abort if there is a bug.
711-
CURRENT.with(|current| match current.set(thread) {
712-
Ok(()) => {}
713-
Err(_) => rtabort!("thread::set_current should only be called once per thread"),
714-
});
715-
}
716-
717-
/// Gets a handle to the thread that invokes it.
718-
///
719-
/// In contrast to the public `current` function, this will not panic if called
720-
/// from inside a TLS destructor.
721-
pub(crate) fn try_current() -> Option<Thread> {
722-
CURRENT.try_with(|current| current.get_or_init(|| Thread::new_unnamed()).clone()).ok()
723-
}
724-
725-
/// Gets a handle to the thread that invokes it.
726-
///
727-
/// # Examples
728-
///
729-
/// Getting a handle to the current thread with `thread::current()`:
730-
///
731-
/// ```
732-
/// use std::thread;
733-
///
734-
/// let handler = thread::Builder::new()
735-
/// .name("named thread".into())
736-
/// .spawn(|| {
737-
/// let handle = thread::current();
738-
/// assert_eq!(handle.name(), Some("named thread"));
739-
/// })
740-
/// .unwrap();
741-
///
742-
/// handler.join().unwrap();
743-
/// ```
744-
#[must_use]
745-
#[stable(feature = "rust1", since = "1.0.0")]
746-
pub fn current() -> Thread {
747-
try_current().expect(
748-
"use of std::thread::current() is not possible \
749-
after the thread's local data has been destroyed",
750-
)
751-
}
752-
753699
/// Cooperatively gives up a timeslice to the OS scheduler.
754700
///
755701
/// This calls the underlying OS scheduler's yield primitive, signaling
@@ -1352,6 +1298,14 @@ impl Thread {
13521298
Thread { inner }
13531299
}
13541300

1301+
fn into_raw(self) -> *mut () {
1302+
unsafe { Arc::into_raw(Pin::into_inner_unchecked(self.inner)) as *mut () }
1303+
}
1304+
1305+
unsafe fn from_raw(ptr: *mut ()) -> Thread {
1306+
unsafe { Thread { inner: Pin::new_unchecked(Arc::from_raw(ptr as *const Inner)) } }
1307+
}
1308+
13551309
/// Like the public [`park`], but callable on any handle. This is used to
13561310
/// allow parking in TLS destructors.
13571311
///

0 commit comments

Comments
 (0)
Please sign in to comment.