Skip to content

Commit 00c2df1

Browse files
committed
Remove the Arc rt::init allocation for thread info
1 parent 9618da7 commit 00c2df1

5 files changed

Lines changed: 140 additions & 58 deletions

File tree

library/std/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,7 @@
365365
#![feature(str_internals)]
366366
#![feature(strict_provenance)]
367367
#![feature(strict_provenance_atomic_ptr)]
368+
#![feature(sync_unsafe_cell)]
368369
#![feature(ub_checks)]
369370
// tidy-alphabetical-end
370371
//

library/std/src/rt.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
110110
// handle does not match the current ID, we should attempt to use the
111111
// current thread ID here instead of unconditionally creating a new
112112
// one. Also see #130210.
113-
let thread = Thread::new_main(thread::current_id());
113+
let thread = unsafe { Thread::new_main(thread::current_id()) };
114114
if let Err(_thread) = thread::set_current(thread) {
115115
// `thread::current` will create a new handle if none has been set yet.
116116
// Thus, if someone uses it before main, this call will fail. That's a

library/std/src/thread/mod.rs

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

161+
use core::cell::SyncUnsafeCell;
162+
use core::ffi::CStr;
163+
use core::mem::MaybeUninit;
164+
161165
use crate::any::Any;
162166
use crate::cell::UnsafeCell;
163-
use crate::ffi::CStr;
164167
use crate::marker::PhantomData;
165168
use crate::mem::{self, ManuallyDrop, forget};
166169
use crate::num::NonZero;
@@ -1125,7 +1128,7 @@ pub fn park_timeout(dur: Duration) {
11251128
let guard = PanicGuard;
11261129
// SAFETY: park_timeout is called on the parker owned by this thread.
11271130
unsafe {
1128-
current().inner.as_ref().parker().park_timeout(dur);
1131+
current().0.parker().park_timeout(dur);
11291132
}
11301133
// No panic occurred, do not abort.
11311134
forget(guard);
@@ -1232,65 +1235,132 @@ impl ThreadId {
12321235
// Thread
12331236
////////////////////////////////////////////////////////////////////////////////
12341237

1235-
/// The internal representation of a `Thread`'s name.
1236-
enum ThreadName {
1237-
Main,
1238-
Other(ThreadNameString),
1239-
Unnamed,
1240-
}
1241-
12421238
// This module ensures private fields are kept private, which is necessary to enforce the safety requirements.
12431239
mod thread_name_string {
12441240
use core::str;
12451241

1246-
use super::ThreadName;
12471242
use crate::ffi::{CStr, CString};
12481243

12491244
/// Like a `String` it's guaranteed UTF-8 and like a `CString` it's null terminated.
12501245
pub(crate) struct ThreadNameString {
12511246
inner: CString,
12521247
}
1248+
1249+
impl ThreadNameString {
1250+
pub fn as_str(&self) -> &str {
1251+
// SAFETY: `self.inner` is only initialised via `String`, which upholds the validity invariant of `str`.
1252+
unsafe { str::from_utf8_unchecked(self.inner.to_bytes()) }
1253+
}
1254+
}
1255+
12531256
impl core::ops::Deref for ThreadNameString {
12541257
type Target = CStr;
12551258
fn deref(&self) -> &CStr {
12561259
&self.inner
12571260
}
12581261
}
1262+
12591263
impl From<String> for ThreadNameString {
12601264
fn from(s: String) -> Self {
12611265
Self {
12621266
inner: CString::new(s).expect("thread name may not contain interior null bytes"),
12631267
}
12641268
}
12651269
}
1266-
impl ThreadName {
1267-
pub fn as_cstr(&self) -> Option<&CStr> {
1268-
match self {
1269-
ThreadName::Main => Some(c"main"),
1270-
ThreadName::Other(other) => Some(other),
1271-
ThreadName::Unnamed => None,
1272-
}
1273-
}
1274-
1275-
pub fn as_str(&self) -> Option<&str> {
1276-
// SAFETY: `as_cstr` can only return `Some` for a fixed CStr or a `ThreadNameString`,
1277-
// which is guaranteed to be UTF-8.
1278-
self.as_cstr().map(|s| unsafe { str::from_utf8_unchecked(s.to_bytes()) })
1279-
}
1280-
}
12811270
}
12821271
pub(crate) use thread_name_string::ThreadNameString;
12831272

1284-
/// The internal representation of a `Thread` handle
1285-
struct Inner {
1286-
name: ThreadName, // Guaranteed to be UTF-8
1273+
static MAIN_THREAD_INFO: SyncUnsafeCell<(MaybeUninit<ThreadId>, MaybeUninit<Parker>)> =
1274+
SyncUnsafeCell::new((MaybeUninit::uninit(), MaybeUninit::uninit()));
1275+
1276+
/// # Safety
1277+
///
1278+
/// Must only be called if the main thread has been constructed.
1279+
unsafe fn main_thread_info() -> (ThreadId, &'static Parker) {
1280+
// Safety: MAIN_THREAD_INFO is only ever read in this function, which requires the
1281+
// only write to MAIN_THREAD_INFO (main thread construction) to have been completed.
1282+
let (thread_id, parker) = unsafe { &*MAIN_THREAD_INFO.get() };
1283+
1284+
// Safety: MAIN_THREAD_INFO has been constructed.
1285+
unsafe { (thread_id.assume_init(), parker.assume_init_ref()) }
1286+
}
1287+
1288+
/// The internal representation of a `Thread` that is not the main thread.
1289+
struct OtherInner {
1290+
name: Option<ThreadNameString>,
12871291
id: ThreadId,
12881292
parker: Parker,
12891293
}
12901294

1295+
/// The internal representation of a `Thread` handle.
1296+
#[derive(Clone)]
1297+
enum Inner {
1298+
/// Represents the main thread. May only be constructed by Thread::new_main.
1299+
Main,
1300+
/// Represents any other thread.
1301+
Other(Pin<Arc<OtherInner>>),
1302+
}
1303+
12911304
impl Inner {
1292-
fn parker(self: Pin<&Self>) -> Pin<&Parker> {
1293-
unsafe { Pin::map_unchecked(self, |inner| &inner.parker) }
1305+
fn id(&self) -> ThreadId {
1306+
match self {
1307+
Self::Main => {
1308+
// Safety: Inner::Main is only constructed once the main thread has been constructed.
1309+
let (thread_id, _) = unsafe { main_thread_info() };
1310+
thread_id
1311+
}
1312+
Self::Other(other) => other.id,
1313+
}
1314+
}
1315+
1316+
fn cname(&self) -> Option<&CStr> {
1317+
match self {
1318+
Self::Main => Some(c"main"),
1319+
Self::Other(other) => other.name.as_deref(),
1320+
}
1321+
}
1322+
1323+
fn name(&self) -> Option<&str> {
1324+
match self {
1325+
Self::Main => Some("main"),
1326+
Self::Other(other) => other.name.as_ref().map(ThreadNameString::as_str),
1327+
}
1328+
}
1329+
1330+
fn into_raw(self) -> *const () {
1331+
match self {
1332+
Self::Main => core::ptr::without_provenance(usize::MAX),
1333+
Self::Other(arc) => {
1334+
// Safety: We only expose an opaque pointer, which maintains the `Pin` invariant.
1335+
let inner = unsafe { Pin::into_inner_unchecked(arc) };
1336+
Arc::into_raw(inner) as *const ()
1337+
}
1338+
}
1339+
}
1340+
1341+
/// # Safety
1342+
///
1343+
/// See [`Thread::from_raw`].
1344+
unsafe fn from_raw(ptr: *const ()) -> Self {
1345+
if ptr.addr() == usize::MAX {
1346+
Self::Main
1347+
} else {
1348+
// Safety: Upheld by caller
1349+
Self::Other(unsafe { Pin::new_unchecked(Arc::from_raw(ptr as *const OtherInner)) })
1350+
}
1351+
}
1352+
1353+
fn parker(&self) -> Pin<&Parker> {
1354+
match self {
1355+
Self::Main => {
1356+
// Safety: Inner::Main is only constructed once the main thread has been constructed.
1357+
let (_, parker_ref) = unsafe { main_thread_info() };
1358+
Pin::static_ref(parker_ref)
1359+
}
1360+
Self::Other(inner) => unsafe {
1361+
Pin::map_unchecked(inner.as_ref(), |inner| &inner.parker)
1362+
},
1363+
}
12941364
}
12951365
}
12961366

@@ -1314,41 +1384,53 @@ impl Inner {
13141384
/// docs of [`Builder`] and [`spawn`] for more details.
13151385
///
13161386
/// [`thread::current`]: current::current
1317-
pub struct Thread {
1318-
inner: Pin<Arc<Inner>>,
1319-
}
1387+
pub struct Thread(Inner);
13201388

13211389
impl Thread {
13221390
/// Used only internally to construct a thread object without spawning.
13231391
pub(crate) fn new(id: ThreadId, name: String) -> Thread {
1324-
Self::new_inner(id, ThreadName::Other(name.into()))
1392+
Self::new_inner(id, Some(ThreadNameString::from(name)))
13251393
}
13261394

13271395
pub(crate) fn new_unnamed(id: ThreadId) -> Thread {
1328-
Self::new_inner(id, ThreadName::Unnamed)
1396+
Self::new_inner(id, None)
13291397
}
13301398

1331-
/// Constructs the thread handle for the main thread.
1332-
pub(crate) fn new_main(id: ThreadId) -> Thread {
1333-
Self::new_inner(id, ThreadName::Main)
1399+
/// Used in runtime to construct main thread
1400+
///
1401+
/// # Safety
1402+
///
1403+
/// This must only ever be called once, and must be called on the main thread.
1404+
pub(crate) unsafe fn new_main(thread_id: ThreadId) -> Thread {
1405+
// Safety: As this is only called once and on the main thread, nothing else is accessing MAIN_THREAD_INFO
1406+
// as the only other read occurs in `main_thread_info` *after* the main thread has been constructed,
1407+
// and this function is the only one that constructs the main thread.
1408+
//
1409+
// Pre-main thread spawning cannot hit this either, as the caller promises that this is only called on the main thread.
1410+
let main_thread_info = unsafe { &mut *MAIN_THREAD_INFO.get() };
1411+
1412+
unsafe { Parker::new_in_place((&raw mut main_thread_info.1).cast()) };
1413+
main_thread_info.0.write(thread_id);
1414+
1415+
Self(Inner::Main)
13341416
}
13351417

1336-
fn new_inner(id: ThreadId, name: ThreadName) -> Thread {
1418+
fn new_inner(id: ThreadId, name: Option<ThreadNameString>) -> Thread {
13371419
// We have to use `unsafe` here to construct the `Parker` in-place,
13381420
// which is required for the UNIX implementation.
13391421
//
13401422
// SAFETY: We pin the Arc immediately after creation, so its address never
13411423
// changes.
13421424
let inner = unsafe {
1343-
let mut arc = Arc::<Inner>::new_uninit();
1425+
let mut arc = Arc::<OtherInner>::new_uninit();
13441426
let ptr = Arc::get_mut_unchecked(&mut arc).as_mut_ptr();
13451427
(&raw mut (*ptr).name).write(name);
13461428
(&raw mut (*ptr).id).write(id);
13471429
Parker::new_in_place(&raw mut (*ptr).parker);
13481430
Pin::new_unchecked(arc.assume_init())
13491431
};
13501432

1351-
Thread { inner }
1433+
Self(Inner::Other(inner))
13521434
}
13531435

13541436
/// Like the public [`park`], but callable on any handle. This is used to
@@ -1357,7 +1439,7 @@ impl Thread {
13571439
/// # Safety
13581440
/// May only be called from the thread to which this handle belongs.
13591441
pub(crate) unsafe fn park(&self) {
1360-
unsafe { self.inner.as_ref().parker().park() }
1442+
unsafe { self.0.parker().park() }
13611443
}
13621444

13631445
/// Atomically makes the handle's token available if it is not already.
@@ -1393,7 +1475,7 @@ impl Thread {
13931475
#[stable(feature = "rust1", since = "1.0.0")]
13941476
#[inline]
13951477
pub fn unpark(&self) {
1396-
self.inner.as_ref().parker().unpark();
1478+
self.0.parker().unpark();
13971479
}
13981480

13991481
/// Gets the thread's unique identifier.
@@ -1413,7 +1495,7 @@ impl Thread {
14131495
#[stable(feature = "thread_id", since = "1.19.0")]
14141496
#[must_use]
14151497
pub fn id(&self) -> ThreadId {
1416-
self.inner.id
1498+
self.0.id()
14171499
}
14181500

14191501
/// Gets the thread's name.
@@ -1456,7 +1538,11 @@ impl Thread {
14561538
#[stable(feature = "rust1", since = "1.0.0")]
14571539
#[must_use]
14581540
pub fn name(&self) -> Option<&str> {
1459-
self.inner.name.as_str()
1541+
self.0.name()
1542+
}
1543+
1544+
fn cname(&self) -> Option<&CStr> {
1545+
self.0.cname()
14601546
}
14611547

14621548
/// Consumes the `Thread`, returning a raw pointer.
@@ -1480,9 +1566,7 @@ impl Thread {
14801566
/// ```
14811567
#[unstable(feature = "thread_raw", issue = "97523")]
14821568
pub fn into_raw(self) -> *const () {
1483-
// Safety: We only expose an opaque pointer, which maintains the `Pin` invariant.
1484-
let inner = unsafe { Pin::into_inner_unchecked(self.inner) };
1485-
Arc::into_raw(inner) as *const ()
1569+
self.0.into_raw()
14861570
}
14871571

14881572
/// Constructs a `Thread` from a raw pointer.
@@ -1504,11 +1588,7 @@ impl Thread {
15041588
#[unstable(feature = "thread_raw", issue = "97523")]
15051589
pub unsafe fn from_raw(ptr: *const ()) -> Thread {
15061590
// Safety: Upheld by caller.
1507-
unsafe { Thread { inner: Pin::new_unchecked(Arc::from_raw(ptr as *const Inner)) } }
1508-
}
1509-
1510-
fn cname(&self) -> Option<&CStr> {
1511-
self.inner.name.as_cstr()
1591+
unsafe { Thread(Inner::from_raw(ptr)) }
15121592
}
15131593
}
15141594

tests/debuginfo/thread.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@
1212
// cdb-check:join_handle,d [Type: std::thread::JoinHandle<tuple$<> >]
1313
// cdb-check: [...] __0 [Type: std::thread::JoinInner<tuple$<> >]
1414
//
15-
// cdb-command:dx t,d
15+
// cdb-command:dx -r3 t,d
1616
// cdb-check:t,d : [...] [Type: std::thread::Thread *]
17-
// cdb-check:[...] inner [...][Type: core::pin::Pin<alloc::sync::Arc<std::thread::Inner,alloc::alloc::Global> >]
17+
// cdb-check: [...] __0 : Other [Type: enum2$<std::thread::Inner>]
18+
// cdb-check: [...] __0 [Type: core::pin::Pin<alloc::sync::Arc<std::thread::OtherInner,[...]> >]
1819

1920
use std::thread;
2021

2122
#[allow(unused_variables)]
22-
fn main()
23-
{
23+
fn main() {
2424
let join_handle = thread::spawn(|| {
2525
println!("Initialize a thread");
2626
});

tests/rustdoc/demo-allocator-54478.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
//! }
4141
//!
4242
//! fn main() {
43+
//! drop(String::from("An allocation"));
4344
//! assert!(unsafe { HIT });
4445
//! }
4546
//! ```

0 commit comments

Comments
 (0)