Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit ceb1945

Browse files
committed
Use System allocator for thread-local storage
1 parent 8365fcb commit ceb1945

File tree

5 files changed

+92
-19
lines changed

5 files changed

+92
-19
lines changed

‎library/std/src/sys/thread_local/destructors/list.rs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,14 @@
1+
use crate::alloc::System;
12
use crate::cell::RefCell;
23
use crate::sys::thread_local::guard;
34

45
#[thread_local]
5-
static DTORS: RefCell<Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>> = RefCell::new(Vec::new());
6+
static DTORS: RefCell<Vec<(*mut u8, unsafe extern "C" fn(*mut u8)), System>> =
7+
RefCell::new(Vec::new_in(System));
68

79
pub unsafe fn register(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
8-
let Ok(mut dtors) = DTORS.try_borrow_mut() else {
9-
// This point can only be reached if the global allocator calls this
10-
// function again.
11-
// FIXME: maybe use the system allocator instead?
12-
rtabort!("the global allocator may not use TLS with destructors");
13-
};
14-
10+
let Ok(mut dtors) = DTORS.try_borrow_mut() else { rtabort!("unreachable") };
1511
guard::enable();
16-
1712
dtors.push((t, dtor));
1813
}
1914

@@ -36,7 +31,7 @@ pub unsafe fn run() {
3631
}
3732
None => {
3833
// Free the list memory.
39-
*dtors = Vec::new();
34+
*dtors = Vec::new_in(System);
4035
break;
4136
}
4237
}

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838

3939
use core::arch::asm;
4040

41+
use crate::alloc::System;
4142
use crate::mem::ManuallyDrop;
4243
use crate::os::xous::ffi::{MemoryFlags, map_memory, unmap_memory};
4344
use crate::ptr;
@@ -151,7 +152,10 @@ struct Node {
151152
}
152153

153154
unsafe fn register_dtor(key: Key, dtor: Dtor) {
154-
let mut node = ManuallyDrop::new(Box::new(Node { key, dtor, next: ptr::null_mut() }));
155+
// We use the System allocator here to avoid interfering with a potential
156+
// Global allocator using thread-local storage.
157+
let mut node =
158+
ManuallyDrop::new(Box::new_in(Node { key, dtor, next: ptr::null_mut() }, System));
155159

156160
#[allow(unused_unsafe)]
157161
let mut head = unsafe { DTORS.load(Acquire) };

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use super::key::{Key, LazyKey, get, set};
22
use super::{abort_on_dtor_unwind, guard};
3+
use crate::alloc::System;
34
use crate::cell::Cell;
45
use crate::marker::PhantomData;
56
use crate::ptr;
@@ -95,8 +96,11 @@ impl<T: 'static> Storage<T> {
9596
return ptr::null();
9697
}
9798

98-
let value = Box::new(Value { value: i.and_then(Option::take).unwrap_or_else(f), key });
99-
let ptr = Box::into_raw(value);
99+
// We use the System allocator here to avoid interfering with a potential
100+
// Global allocator using thread-local storage.
101+
let value =
102+
Box::new_in(Value { value: i.and_then(Option::take).unwrap_or_else(f), key }, System);
103+
let ptr = Box::into_raw_with_allocator(value).0;
100104

101105
// SAFETY:
102106
// * key came from a `LazyKey` and is thus correct.
@@ -114,7 +118,7 @@ impl<T: 'static> Storage<T> {
114118
// initializer has already returned and the next scope only starts
115119
// after we return the pointer. Therefore, there can be no references
116120
// to the old value.
117-
drop(unsafe { Box::from_raw(old) });
121+
drop(unsafe { Box::from_raw_in(old,System) });
118122
}
119123

120124
// SAFETY: We just created this value above.
@@ -133,7 +137,7 @@ unsafe extern "C" fn destroy_value<T: 'static>(ptr: *mut u8) {
133137
// Note that to prevent an infinite loop we reset it back to null right
134138
// before we return from the destructor ourselves.
135139
abort_on_dtor_unwind(|| {
136-
let ptr = unsafe { Box::from_raw(ptr as *mut Value<T>) };
140+
let ptr = unsafe { Box::from_raw_in(ptr as *mut Value<T>,System) };
137141
let key = ptr.key;
138142
// SAFETY: `key` is the TLS key `ptr` was stored under.
139143
unsafe { set(key, ptr::without_provenance_mut(1)) };

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@
158158
#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
159159
mod tests;
160160

161+
use crate::alloc::System;
161162
use crate::any::Any;
162163
use crate::cell::UnsafeCell;
163164
use crate::ffi::CStr;
@@ -1439,7 +1440,10 @@ impl Inner {
14391440
///
14401441
/// [`thread::current`]: current::current
14411442
pub struct Thread {
1442-
inner: Pin<Arc<Inner>>,
1443+
// We use the System allocator such that creating or dropping this handle
1444+
// does not interfere with a potential Global allocator using thread-local
1445+
// storage.
1446+
inner: Pin<Arc<Inner, System>>,
14431447
}
14441448

14451449
impl Thread {
@@ -1452,7 +1456,7 @@ impl Thread {
14521456
// SAFETY: We pin the Arc immediately after creation, so its address never
14531457
// changes.
14541458
let inner = unsafe {
1455-
let mut arc = Arc::<Inner>::new_uninit();
1459+
let mut arc = Arc::<Inner,_>::new_uninit_in(System);
14561460
let ptr = Arc::get_mut_unchecked(&mut arc).as_mut_ptr();
14571461
(&raw mut (*ptr).name).write(name);
14581462
(&raw mut (*ptr).id).write(id);
@@ -1610,7 +1614,7 @@ impl Thread {
16101614
pub fn into_raw(self) -> *const () {
16111615
// Safety: We only expose an opaque pointer, which maintains the `Pin` invariant.
16121616
let inner = unsafe { Pin::into_inner_unchecked(self.inner) };
1613-
Arc::into_raw(inner) as *const ()
1617+
Arc::into_raw_with_allocator(inner).0 as *const ()
16141618
}
16151619

16161620
/// Constructs a `Thread` from a raw pointer.
@@ -1632,7 +1636,9 @@ impl Thread {
16321636
#[unstable(feature = "thread_raw", issue = "97523")]
16331637
pub unsafe fn from_raw(ptr: *const ()) -> Thread {
16341638
// Safety: Upheld by caller.
1635-
unsafe { Thread { inner: Pin::new_unchecked(Arc::from_raw(ptr as *const Inner)) } }
1639+
unsafe {
1640+
Thread { inner: Pin::new_unchecked(Arc::from_raw_in(ptr as *const Inner, System)) }
1641+
}
16361642
}
16371643

16381644
fn cname(&self) -> Option<&CStr> {
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
//@ run-pass
2+
//@ needs-threads
3+
4+
use std::alloc::{GlobalAlloc, Layout, System};
5+
use std::thread::Thread;
6+
use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering};
7+
8+
static GLOBAL: AtomicUsize = AtomicUsize::new(0);
9+
10+
struct Local(Thread);
11+
12+
thread_local! {
13+
static LOCAL: Local = {
14+
GLOBAL.fetch_or(1, Ordering::Relaxed);
15+
Local(std::thread::current())
16+
};
17+
}
18+
19+
impl Drop for Local {
20+
fn drop(&mut self) {
21+
GLOBAL.fetch_or(2, Ordering::Relaxed);
22+
}
23+
}
24+
25+
static SHOULD_PANIC_ON_GLOBAL_ALLOC_ACCESS: AtomicBool = AtomicBool::new(false);
26+
27+
#[global_allocator]
28+
static ALLOC: Alloc = Alloc;
29+
struct Alloc;
30+
31+
unsafe impl GlobalAlloc for Alloc {
32+
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
33+
// Make sure we aren't re-entrant.
34+
assert!(!SHOULD_PANIC_ON_GLOBAL_ALLOC_ACCESS.load(Ordering::Relaxed));
35+
SHOULD_PANIC_ON_GLOBAL_ALLOC_ACCESS.store(true, Ordering::Relaxed);
36+
LOCAL.with(|local| {
37+
assert!(local.0.id() == std::thread::current().id());
38+
});
39+
let ret = unsafe { System.alloc(layout) };
40+
SHOULD_PANIC_ON_GLOBAL_ALLOC_ACCESS.store(false, Ordering::Relaxed);
41+
ret
42+
}
43+
44+
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
45+
// Make sure we aren't re-entrant.
46+
assert!(!SHOULD_PANIC_ON_GLOBAL_ALLOC_ACCESS.load(Ordering::Relaxed));
47+
SHOULD_PANIC_ON_GLOBAL_ALLOC_ACCESS.store(true, Ordering::Relaxed);
48+
LOCAL.with(|local| {
49+
assert!(local.0.id() == std::thread::current().id());
50+
});
51+
unsafe { System.dealloc(ptr, layout) }
52+
SHOULD_PANIC_ON_GLOBAL_ALLOC_ACCESS.store(false, Ordering::Relaxed);
53+
}
54+
}
55+
56+
fn main() {
57+
std::thread::spawn(|| {
58+
std::hint::black_box(vec![1, 2]);
59+
assert!(GLOBAL.load(Ordering::Relaxed) == 1);
60+
})
61+
.join()
62+
.unwrap();
63+
assert!(GLOBAL.load(Ordering::Relaxed) == 3);
64+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /