Skip to content

Commit ffa9019

Browse files
committed
Move __thread_local_inner to sys
Move __thread_local_inner macro in crate::thread::local to crate::sys. Currently, the tidy check does not fail for `library/std/src/thread/local.rs` even though it contains platform specific code. This is beacause target_family did not exist at the time the tidy checks were written [1]. [1]: #105861 (comment) Signed-off-by: Ayush Singh <[email protected]>
1 parent 104f430 commit ffa9019

File tree

2 files changed

+194
-194
lines changed

2 files changed

+194
-194
lines changed

library/std/src/sys/mod.rs

+194
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,197 @@ cfg_if::cfg_if! {
7676
pub mod c;
7777
}
7878
}
79+
80+
#[doc(hidden)]
81+
#[unstable(feature = "thread_local_internals", reason = "should not be necessary", issue = "none")]
82+
#[macro_export]
83+
#[allow_internal_unstable(thread_local_internals, cfg_target_thread_local, thread_local)]
84+
#[allow_internal_unsafe]
85+
macro_rules! __thread_local_inner {
86+
// used to generate the `LocalKey` value for const-initialized thread locals
87+
(@key $t:ty, const $init:expr) => {{
88+
#[cfg_attr(not(windows), inline)] // see comments below
89+
#[deny(unsafe_op_in_unsafe_fn)]
90+
unsafe fn __getit(
91+
_init: $crate::option::Option<&mut $crate::option::Option<$t>>,
92+
) -> $crate::option::Option<&'static $t> {
93+
const INIT_EXPR: $t = $init;
94+
95+
// wasm without atomics maps directly to `static mut`, and dtors
96+
// aren't implemented because thread dtors aren't really a thing
97+
// on wasm right now
98+
//
99+
// FIXME(#84224) this should come after the `target_thread_local`
100+
// block.
101+
#[cfg(all(target_family = "wasm", not(target_feature = "atomics")))]
102+
{
103+
static mut VAL: $t = INIT_EXPR;
104+
unsafe { $crate::option::Option::Some(&VAL) }
105+
}
106+
107+
// If the platform has support for `#[thread_local]`, use it.
108+
#[cfg(all(
109+
target_thread_local,
110+
not(all(target_family = "wasm", not(target_feature = "atomics"))),
111+
))]
112+
{
113+
#[thread_local]
114+
static mut VAL: $t = INIT_EXPR;
115+
116+
// If a dtor isn't needed we can do something "very raw" and
117+
// just get going.
118+
if !$crate::mem::needs_drop::<$t>() {
119+
unsafe {
120+
return $crate::option::Option::Some(&VAL)
121+
}
122+
}
123+
124+
// 0 == dtor not registered
125+
// 1 == dtor registered, dtor not run
126+
// 2 == dtor registered and is running or has run
127+
#[thread_local]
128+
static mut STATE: $crate::primitive::u8 = 0;
129+
130+
unsafe extern "C" fn destroy(ptr: *mut $crate::primitive::u8) {
131+
let ptr = ptr as *mut $t;
132+
133+
unsafe {
134+
$crate::debug_assert_eq!(STATE, 1);
135+
STATE = 2;
136+
$crate::ptr::drop_in_place(ptr);
137+
}
138+
}
139+
140+
unsafe {
141+
match STATE {
142+
// 0 == we haven't registered a destructor, so do
143+
// so now.
144+
0 => {
145+
$crate::thread::__FastLocalKeyInner::<$t>::register_dtor(
146+
$crate::ptr::addr_of_mut!(VAL) as *mut $crate::primitive::u8,
147+
destroy,
148+
);
149+
STATE = 1;
150+
$crate::option::Option::Some(&VAL)
151+
}
152+
// 1 == the destructor is registered and the value
153+
// is valid, so return the pointer.
154+
1 => $crate::option::Option::Some(&VAL),
155+
// otherwise the destructor has already run, so we
156+
// can't give access.
157+
_ => $crate::option::Option::None,
158+
}
159+
}
160+
}
161+
162+
// On platforms without `#[thread_local]` we fall back to the
163+
// same implementation as below for os thread locals.
164+
#[cfg(all(
165+
not(target_thread_local),
166+
not(all(target_family = "wasm", not(target_feature = "atomics"))),
167+
))]
168+
{
169+
#[inline]
170+
const fn __init() -> $t { INIT_EXPR }
171+
static __KEY: $crate::thread::__OsLocalKeyInner<$t> =
172+
$crate::thread::__OsLocalKeyInner::new();
173+
#[allow(unused_unsafe)]
174+
unsafe {
175+
__KEY.get(move || {
176+
if let $crate::option::Option::Some(init) = _init {
177+
if let $crate::option::Option::Some(value) = init.take() {
178+
return value;
179+
} else if $crate::cfg!(debug_assertions) {
180+
$crate::unreachable!("missing initial value");
181+
}
182+
}
183+
__init()
184+
})
185+
}
186+
}
187+
}
188+
189+
unsafe {
190+
$crate::thread::LocalKey::new(__getit)
191+
}
192+
}};
193+
194+
// used to generate the `LocalKey` value for `thread_local!`
195+
(@key $t:ty, $init:expr) => {
196+
{
197+
#[inline]
198+
fn __init() -> $t { $init }
199+
200+
// When reading this function you might ask "why is this inlined
201+
// everywhere other than Windows?", and that's a very reasonable
202+
// question to ask. The short story is that it segfaults rustc if
203+
// this function is inlined. The longer story is that Windows looks
204+
// to not support `extern` references to thread locals across DLL
205+
// boundaries. This appears to at least not be supported in the ABI
206+
// that LLVM implements.
207+
//
208+
// Because of this we never inline on Windows, but we do inline on
209+
// other platforms (where external references to thread locals
210+
// across DLLs are supported). A better fix for this would be to
211+
// inline this function on Windows, but only for "statically linked"
212+
// components. For example if two separately compiled rlibs end up
213+
// getting linked into a DLL then it's fine to inline this function
214+
// across that boundary. It's only not fine to inline this function
215+
// across a DLL boundary. Unfortunately rustc doesn't currently
216+
// have this sort of logic available in an attribute, and it's not
217+
// clear that rustc is even equipped to answer this (it's more of a
218+
// Cargo question kinda). This means that, unfortunately, Windows
219+
// gets the pessimistic path for now where it's never inlined.
220+
//
221+
// The issue of "should enable on Windows sometimes" is #84933
222+
#[cfg_attr(not(windows), inline)]
223+
unsafe fn __getit(
224+
init: $crate::option::Option<&mut $crate::option::Option<$t>>,
225+
) -> $crate::option::Option<&'static $t> {
226+
#[cfg(all(target_family = "wasm", not(target_feature = "atomics")))]
227+
static __KEY: $crate::thread::__StaticLocalKeyInner<$t> =
228+
$crate::thread::__StaticLocalKeyInner::new();
229+
230+
#[thread_local]
231+
#[cfg(all(
232+
target_thread_local,
233+
not(all(target_family = "wasm", not(target_feature = "atomics"))),
234+
))]
235+
static __KEY: $crate::thread::__FastLocalKeyInner<$t> =
236+
$crate::thread::__FastLocalKeyInner::new();
237+
238+
#[cfg(all(
239+
not(target_thread_local),
240+
not(all(target_family = "wasm", not(target_feature = "atomics"))),
241+
))]
242+
static __KEY: $crate::thread::__OsLocalKeyInner<$t> =
243+
$crate::thread::__OsLocalKeyInner::new();
244+
245+
// FIXME: remove the #[allow(...)] marker when macros don't
246+
// raise warning for missing/extraneous unsafe blocks anymore.
247+
// See https://github.com/rust-lang/rust/issues/74838.
248+
#[allow(unused_unsafe)]
249+
unsafe {
250+
__KEY.get(move || {
251+
if let $crate::option::Option::Some(init) = init {
252+
if let $crate::option::Option::Some(value) = init.take() {
253+
return value;
254+
} else if $crate::cfg!(debug_assertions) {
255+
$crate::unreachable!("missing default value");
256+
}
257+
}
258+
__init()
259+
})
260+
}
261+
}
262+
263+
unsafe {
264+
$crate::thread::LocalKey::new(__getit)
265+
}
266+
}
267+
};
268+
($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => {
269+
$(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> =
270+
$crate::__thread_local_inner!(@key $t, $($init)*);
271+
}
272+
}

library/std/src/thread/local.rs

-194
Original file line numberDiff line numberDiff line change
@@ -173,200 +173,6 @@ macro_rules! thread_local {
173173
);
174174
}
175175

176-
#[doc(hidden)]
177-
#[unstable(feature = "thread_local_internals", reason = "should not be necessary", issue = "none")]
178-
#[macro_export]
179-
#[allow_internal_unstable(thread_local_internals, cfg_target_thread_local, thread_local)]
180-
#[allow_internal_unsafe]
181-
macro_rules! __thread_local_inner {
182-
// used to generate the `LocalKey` value for const-initialized thread locals
183-
(@key $t:ty, const $init:expr) => {{
184-
#[cfg_attr(not(windows), inline)] // see comments below
185-
#[deny(unsafe_op_in_unsafe_fn)]
186-
unsafe fn __getit(
187-
_init: $crate::option::Option<&mut $crate::option::Option<$t>>,
188-
) -> $crate::option::Option<&'static $t> {
189-
const INIT_EXPR: $t = $init;
190-
191-
// wasm without atomics maps directly to `static mut`, and dtors
192-
// aren't implemented because thread dtors aren't really a thing
193-
// on wasm right now
194-
//
195-
// FIXME(#84224) this should come after the `target_thread_local`
196-
// block.
197-
#[cfg(all(target_family = "wasm", not(target_feature = "atomics")))]
198-
{
199-
static mut VAL: $t = INIT_EXPR;
200-
unsafe { $crate::option::Option::Some(&VAL) }
201-
}
202-
203-
// If the platform has support for `#[thread_local]`, use it.
204-
#[cfg(all(
205-
target_thread_local,
206-
not(all(target_family = "wasm", not(target_feature = "atomics"))),
207-
))]
208-
{
209-
#[thread_local]
210-
static mut VAL: $t = INIT_EXPR;
211-
212-
// If a dtor isn't needed we can do something "very raw" and
213-
// just get going.
214-
if !$crate::mem::needs_drop::<$t>() {
215-
unsafe {
216-
return $crate::option::Option::Some(&VAL)
217-
}
218-
}
219-
220-
// 0 == dtor not registered
221-
// 1 == dtor registered, dtor not run
222-
// 2 == dtor registered and is running or has run
223-
#[thread_local]
224-
static mut STATE: $crate::primitive::u8 = 0;
225-
226-
unsafe extern "C" fn destroy(ptr: *mut $crate::primitive::u8) {
227-
let ptr = ptr as *mut $t;
228-
229-
unsafe {
230-
$crate::debug_assert_eq!(STATE, 1);
231-
STATE = 2;
232-
$crate::ptr::drop_in_place(ptr);
233-
}
234-
}
235-
236-
unsafe {
237-
match STATE {
238-
// 0 == we haven't registered a destructor, so do
239-
// so now.
240-
0 => {
241-
$crate::thread::__FastLocalKeyInner::<$t>::register_dtor(
242-
$crate::ptr::addr_of_mut!(VAL) as *mut $crate::primitive::u8,
243-
destroy,
244-
);
245-
STATE = 1;
246-
$crate::option::Option::Some(&VAL)
247-
}
248-
// 1 == the destructor is registered and the value
249-
// is valid, so return the pointer.
250-
1 => $crate::option::Option::Some(&VAL),
251-
// otherwise the destructor has already run, so we
252-
// can't give access.
253-
_ => $crate::option::Option::None,
254-
}
255-
}
256-
}
257-
258-
// On platforms without `#[thread_local]` we fall back to the
259-
// same implementation as below for os thread locals.
260-
#[cfg(all(
261-
not(target_thread_local),
262-
not(all(target_family = "wasm", not(target_feature = "atomics"))),
263-
))]
264-
{
265-
#[inline]
266-
const fn __init() -> $t { INIT_EXPR }
267-
static __KEY: $crate::thread::__OsLocalKeyInner<$t> =
268-
$crate::thread::__OsLocalKeyInner::new();
269-
#[allow(unused_unsafe)]
270-
unsafe {
271-
__KEY.get(move || {
272-
if let $crate::option::Option::Some(init) = _init {
273-
if let $crate::option::Option::Some(value) = init.take() {
274-
return value;
275-
} else if $crate::cfg!(debug_assertions) {
276-
$crate::unreachable!("missing initial value");
277-
}
278-
}
279-
__init()
280-
})
281-
}
282-
}
283-
}
284-
285-
unsafe {
286-
$crate::thread::LocalKey::new(__getit)
287-
}
288-
}};
289-
290-
// used to generate the `LocalKey` value for `thread_local!`
291-
(@key $t:ty, $init:expr) => {
292-
{
293-
#[inline]
294-
fn __init() -> $t { $init }
295-
296-
// When reading this function you might ask "why is this inlined
297-
// everywhere other than Windows?", and that's a very reasonable
298-
// question to ask. The short story is that it segfaults rustc if
299-
// this function is inlined. The longer story is that Windows looks
300-
// to not support `extern` references to thread locals across DLL
301-
// boundaries. This appears to at least not be supported in the ABI
302-
// that LLVM implements.
303-
//
304-
// Because of this we never inline on Windows, but we do inline on
305-
// other platforms (where external references to thread locals
306-
// across DLLs are supported). A better fix for this would be to
307-
// inline this function on Windows, but only for "statically linked"
308-
// components. For example if two separately compiled rlibs end up
309-
// getting linked into a DLL then it's fine to inline this function
310-
// across that boundary. It's only not fine to inline this function
311-
// across a DLL boundary. Unfortunately rustc doesn't currently
312-
// have this sort of logic available in an attribute, and it's not
313-
// clear that rustc is even equipped to answer this (it's more of a
314-
// Cargo question kinda). This means that, unfortunately, Windows
315-
// gets the pessimistic path for now where it's never inlined.
316-
//
317-
// The issue of "should enable on Windows sometimes" is #84933
318-
#[cfg_attr(not(windows), inline)]
319-
unsafe fn __getit(
320-
init: $crate::option::Option<&mut $crate::option::Option<$t>>,
321-
) -> $crate::option::Option<&'static $t> {
322-
#[cfg(all(target_family = "wasm", not(target_feature = "atomics")))]
323-
static __KEY: $crate::thread::__StaticLocalKeyInner<$t> =
324-
$crate::thread::__StaticLocalKeyInner::new();
325-
326-
#[thread_local]
327-
#[cfg(all(
328-
target_thread_local,
329-
not(all(target_family = "wasm", not(target_feature = "atomics"))),
330-
))]
331-
static __KEY: $crate::thread::__FastLocalKeyInner<$t> =
332-
$crate::thread::__FastLocalKeyInner::new();
333-
334-
#[cfg(all(
335-
not(target_thread_local),
336-
not(all(target_family = "wasm", not(target_feature = "atomics"))),
337-
))]
338-
static __KEY: $crate::thread::__OsLocalKeyInner<$t> =
339-
$crate::thread::__OsLocalKeyInner::new();
340-
341-
// FIXME: remove the #[allow(...)] marker when macros don't
342-
// raise warning for missing/extraneous unsafe blocks anymore.
343-
// See https://github.com/rust-lang/rust/issues/74838.
344-
#[allow(unused_unsafe)]
345-
unsafe {
346-
__KEY.get(move || {
347-
if let $crate::option::Option::Some(init) = init {
348-
if let $crate::option::Option::Some(value) = init.take() {
349-
return value;
350-
} else if $crate::cfg!(debug_assertions) {
351-
$crate::unreachable!("missing default value");
352-
}
353-
}
354-
__init()
355-
})
356-
}
357-
}
358-
359-
unsafe {
360-
$crate::thread::LocalKey::new(__getit)
361-
}
362-
}
363-
};
364-
($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => {
365-
$(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> =
366-
$crate::__thread_local_inner!(@key $t, $($init)*);
367-
}
368-
}
369-
370176
/// An error returned by [`LocalKey::try_with`](struct.LocalKey.html#method.try_with).
371177
#[stable(feature = "thread_local_try_with", since = "1.26.0")]
372178
#[non_exhaustive]

0 commit comments

Comments
 (0)