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 ee6cd82

Browse files
committedNov 5, 2024··
std: lazily allocate the main thread handle
#123550 eliminated the allocation of the main thread handle, but at the cost of greatly increased complexity. This PR proposes another approach: Instead of creating the main thread handle itself, the runtime simply remembers the thread ID of the main thread. The main thread handle is then only allocated when it is used, using the same lazy-initialization mechanism as for non-runtime use of `thread::current`, and the name method uses the thread ID to identify the main thread handle and return the correct name ("main") for it. Thereby, we also allow accessing `thread::current` before main: as the runtime no longer tries to install its own handle, this will no longer trigger an abort. Rather, the name returned from name will only be "main" after the runtime initialization code has run, but I think that is acceptable. I've also moved the `Thread` code into its own module, the size of `thread/mod.rs` is just getting out of hand.
1 parent 3b0cbae commit ee6cd82

File tree

8 files changed

+340
-327
lines changed

8 files changed

+340
-327
lines changed
 

‎library/std/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,7 @@
365365
#![feature(std_internals)]
366366
#![feature(str_internals)]
367367
#![feature(strict_provenance_atomic_ptr)]
368+
#![feature(sync_unsafe_cell)]
368369
#![feature(ub_checks)]
369370
// tidy-alphabetical-end
370371
//

‎library/std/src/panicking.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -247,8 +247,13 @@ fn default_hook(info: &PanicHookInfo<'_>) {
247247
let location = info.location().unwrap();
248248

249249
let msg = payload_as_str(info.payload());
250-
let thread = thread::try_current();
251-
let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>");
250+
let thread;
251+
let name = if thread::is_main() {
252+
"main"
253+
} else {
254+
thread = thread::try_current();
255+
thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>")
256+
};
252257

253258
let write = #[optimize(size)]
254259
|err: &mut dyn crate::io::Write| {

‎library/std/src/rt.rs

+5-18
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ pub use core::panicking::{panic_display, panic_fmt};
2323
#[rustfmt::skip]
2424
use crate::any::Any;
2525
use crate::sync::Once;
26-
use crate::thread::{self, Thread};
26+
use crate::thread::{current_id, set_main_thread};
2727
use crate::{mem, panic, sys};
2828

2929
// Prints to the "panic output", depending on the platform this may be:
@@ -102,23 +102,10 @@ unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
102102
sys::init(argc, argv, sigpipe)
103103
};
104104

105-
// Set up the current thread handle to give it the right name.
106-
//
107-
// When code running before main uses `ReentrantLock` (for example by
108-
// using `println!`), the thread ID can become initialized before we
109-
// create this handle. Since `set_current` fails when the ID of the
110-
// handle does not match the current ID, we should attempt to use the
111-
// current thread ID here instead of unconditionally creating a new
112-
// one. Also see #130210.
113-
let thread = Thread::new_main(thread::current_id());
114-
if let Err(_thread) = thread::set_current(thread) {
115-
// `thread::current` will create a new handle if none has been set yet.
116-
// Thus, if someone uses it before main, this call will fail. That's a
117-
// bad idea though, as we then cannot set the main thread name here.
118-
//
119-
// FIXME: detect the main thread in `thread::current` and use the
120-
// correct name there.
121-
rtabort!("code running before main must not use thread::current");
105+
// Mark the current thread as main thread.
106+
// SAFETY: this is the only place and time where this is called.
107+
unsafe {
108+
set_main_thread(current_id());
122109
}
123110
}
124111

‎library/std/src/sys/sync/rwlock/queue.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ impl Node {
201201
// Fall back to creating an unnamed `Thread` handle to allow locking in
202202
// TLS destructors.
203203
self.thread.get_or_init(|| {
204-
thread::try_current().unwrap_or_else(|| Thread::new_unnamed(ThreadId::new()))
204+
thread::try_current().unwrap_or_else(|| Thread::new(ThreadId::new(), None))
205205
});
206206
self.completed = AtomicBool::new(false);
207207
}

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ fn init_current(current: *mut ()) -> Thread {
204204
CURRENT.set(BUSY);
205205
// If the thread ID was initialized already, use it.
206206
let id = id::get_or_init();
207-
let thread = Thread::new_unnamed(id);
207+
let thread = Thread::new(id, None);
208208

209209
// Make sure that `crate::rt::thread_cleanup` will be run, which will
210210
// call `drop_current`.

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

+10-305
Original file line numberDiff line numberDiff line change
@@ -160,18 +160,15 @@ mod tests;
160160

161161
use crate::any::Any;
162162
use crate::cell::UnsafeCell;
163-
use crate::ffi::CStr;
164163
use crate::marker::PhantomData;
165164
use crate::mem::{self, ManuallyDrop, forget};
166165
use crate::num::NonZero;
167-
use crate::pin::Pin;
168166
use crate::sync::Arc;
169167
use crate::sync::atomic::{AtomicUsize, Ordering};
170-
use crate::sys::sync::Parker;
171168
use crate::sys::thread as imp;
172169
use crate::sys_common::{AsInner, IntoInner};
173170
use crate::time::{Duration, Instant};
174-
use crate::{env, fmt, io, panic, panicking, str};
171+
use crate::{env, fmt, io, panic, panicking};
175172

176173
#[stable(feature = "scoped_threads", since = "1.63.0")]
177174
mod scoped;
@@ -185,6 +182,12 @@ mod current;
185182
pub use current::current;
186183
pub(crate) use current::{current_id, drop_current, set_current, try_current};
187184

185+
mod thread;
186+
187+
#[stable(feature = "rust1", since = "1.0.0")]
188+
pub use thread::Thread;
189+
pub(crate) use thread::{is_main, set_main_thread};
190+
188191
////////////////////////////////////////////////////////////////////////////////
189192
// Thread-local storage
190193
////////////////////////////////////////////////////////////////////////////////
@@ -477,11 +480,7 @@ impl Builder {
477480
amt
478481
});
479482

480-
let id = ThreadId::new();
481-
let my_thread = match name {
482-
Some(name) => Thread::new(id, name.into()),
483-
None => Thread::new_unnamed(id),
484-
};
483+
let my_thread = Thread::new(ThreadId::new(), name);
485484
let their_thread = my_thread.clone();
486485

487486
let my_packet: Arc<Packet<'scope, T>> = Arc::new(Packet {
@@ -1125,7 +1124,7 @@ pub fn park_timeout(dur: Duration) {
11251124
let guard = PanicGuard;
11261125
// SAFETY: park_timeout is called on the parker owned by this thread.
11271126
unsafe {
1128-
current().inner.as_ref().parker().park_timeout(dur);
1127+
current().park_timeout(dur);
11291128
}
11301129
// No panic occurred, do not abort.
11311130
forget(guard);
@@ -1208,7 +1207,7 @@ impl ThreadId {
12081207
}
12091208
}
12101209

1211-
#[cfg(not(target_thread_local))]
1210+
#[allow(unused)]
12121211
fn from_u64(v: u64) -> Option<ThreadId> {
12131212
NonZero::new(v).map(ThreadId)
12141213
}
@@ -1228,300 +1227,6 @@ impl ThreadId {
12281227
}
12291228
}
12301229

1231-
////////////////////////////////////////////////////////////////////////////////
1232-
// Thread
1233-
////////////////////////////////////////////////////////////////////////////////
1234-
1235-
/// The internal representation of a `Thread`'s name.
1236-
enum ThreadName {
1237-
Main,
1238-
Other(ThreadNameString),
1239-
Unnamed,
1240-
}
1241-
1242-
// This module ensures private fields are kept private, which is necessary to enforce the safety requirements.
1243-
mod thread_name_string {
1244-
use core::str;
1245-
1246-
use super::ThreadName;
1247-
use crate::ffi::{CStr, CString};
1248-
1249-
/// Like a `String` it's guaranteed UTF-8 and like a `CString` it's null terminated.
1250-
pub(crate) struct ThreadNameString {
1251-
inner: CString,
1252-
}
1253-
impl core::ops::Deref for ThreadNameString {
1254-
type Target = CStr;
1255-
fn deref(&self) -> &CStr {
1256-
&self.inner
1257-
}
1258-
}
1259-
impl From<String> for ThreadNameString {
1260-
fn from(s: String) -> Self {
1261-
Self {
1262-
inner: CString::new(s).expect("thread name may not contain interior null bytes"),
1263-
}
1264-
}
1265-
}
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-
}
1281-
}
1282-
pub(crate) use thread_name_string::ThreadNameString;
1283-
1284-
/// The internal representation of a `Thread` handle
1285-
struct Inner {
1286-
name: ThreadName, // Guaranteed to be UTF-8
1287-
id: ThreadId,
1288-
parker: Parker,
1289-
}
1290-
1291-
impl Inner {
1292-
fn parker(self: Pin<&Self>) -> Pin<&Parker> {
1293-
unsafe { Pin::map_unchecked(self, |inner| &inner.parker) }
1294-
}
1295-
}
1296-
1297-
#[derive(Clone)]
1298-
#[stable(feature = "rust1", since = "1.0.0")]
1299-
/// A handle to a thread.
1300-
///
1301-
/// Threads are represented via the `Thread` type, which you can get in one of
1302-
/// two ways:
1303-
///
1304-
/// * By spawning a new thread, e.g., using the [`thread::spawn`][`spawn`]
1305-
/// function, and calling [`thread`][`JoinHandle::thread`] on the
1306-
/// [`JoinHandle`].
1307-
/// * By requesting the current thread, using the [`thread::current`] function.
1308-
///
1309-
/// The [`thread::current`] function is available even for threads not spawned
1310-
/// by the APIs of this module.
1311-
///
1312-
/// There is usually no need to create a `Thread` struct yourself, one
1313-
/// should instead use a function like `spawn` to create new threads, see the
1314-
/// docs of [`Builder`] and [`spawn`] for more details.
1315-
///
1316-
/// [`thread::current`]: current::current
1317-
pub struct Thread {
1318-
inner: Pin<Arc<Inner>>,
1319-
}
1320-
1321-
impl Thread {
1322-
/// Used only internally to construct a thread object without spawning.
1323-
pub(crate) fn new(id: ThreadId, name: String) -> Thread {
1324-
Self::new_inner(id, ThreadName::Other(name.into()))
1325-
}
1326-
1327-
pub(crate) fn new_unnamed(id: ThreadId) -> Thread {
1328-
Self::new_inner(id, ThreadName::Unnamed)
1329-
}
1330-
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)
1334-
}
1335-
1336-
fn new_inner(id: ThreadId, name: ThreadName) -> Thread {
1337-
// We have to use `unsafe` here to construct the `Parker` in-place,
1338-
// which is required for the UNIX implementation.
1339-
//
1340-
// SAFETY: We pin the Arc immediately after creation, so its address never
1341-
// changes.
1342-
let inner = unsafe {
1343-
let mut arc = Arc::<Inner>::new_uninit();
1344-
let ptr = Arc::get_mut_unchecked(&mut arc).as_mut_ptr();
1345-
(&raw mut (*ptr).name).write(name);
1346-
(&raw mut (*ptr).id).write(id);
1347-
Parker::new_in_place(&raw mut (*ptr).parker);
1348-
Pin::new_unchecked(arc.assume_init())
1349-
};
1350-
1351-
Thread { inner }
1352-
}
1353-
1354-
/// Like the public [`park`], but callable on any handle. This is used to
1355-
/// allow parking in TLS destructors.
1356-
///
1357-
/// # Safety
1358-
/// May only be called from the thread to which this handle belongs.
1359-
pub(crate) unsafe fn park(&self) {
1360-
unsafe { self.inner.as_ref().parker().park() }
1361-
}
1362-
1363-
/// Atomically makes the handle's token available if it is not already.
1364-
///
1365-
/// Every thread is equipped with some basic low-level blocking support, via
1366-
/// the [`park`][park] function and the `unpark()` method. These can be
1367-
/// used as a more CPU-efficient implementation of a spinlock.
1368-
///
1369-
/// See the [park documentation][park] for more details.
1370-
///
1371-
/// # Examples
1372-
///
1373-
/// ```
1374-
/// use std::thread;
1375-
/// use std::time::Duration;
1376-
///
1377-
/// let parked_thread = thread::Builder::new()
1378-
/// .spawn(|| {
1379-
/// println!("Parking thread");
1380-
/// thread::park();
1381-
/// println!("Thread unparked");
1382-
/// })
1383-
/// .unwrap();
1384-
///
1385-
/// // Let some time pass for the thread to be spawned.
1386-
/// thread::sleep(Duration::from_millis(10));
1387-
///
1388-
/// println!("Unpark the thread");
1389-
/// parked_thread.thread().unpark();
1390-
///
1391-
/// parked_thread.join().unwrap();
1392-
/// ```
1393-
#[stable(feature = "rust1", since = "1.0.0")]
1394-
#[inline]
1395-
pub fn unpark(&self) {
1396-
self.inner.as_ref().parker().unpark();
1397-
}
1398-
1399-
/// Gets the thread's unique identifier.
1400-
///
1401-
/// # Examples
1402-
///
1403-
/// ```
1404-
/// use std::thread;
1405-
///
1406-
/// let other_thread = thread::spawn(|| {
1407-
/// thread::current().id()
1408-
/// });
1409-
///
1410-
/// let other_thread_id = other_thread.join().unwrap();
1411-
/// assert!(thread::current().id() != other_thread_id);
1412-
/// ```
1413-
#[stable(feature = "thread_id", since = "1.19.0")]
1414-
#[must_use]
1415-
pub fn id(&self) -> ThreadId {
1416-
self.inner.id
1417-
}
1418-
1419-
/// Gets the thread's name.
1420-
///
1421-
/// For more information about named threads, see
1422-
/// [this module-level documentation][naming-threads].
1423-
///
1424-
/// # Examples
1425-
///
1426-
/// Threads by default have no name specified:
1427-
///
1428-
/// ```
1429-
/// use std::thread;
1430-
///
1431-
/// let builder = thread::Builder::new();
1432-
///
1433-
/// let handler = builder.spawn(|| {
1434-
/// assert!(thread::current().name().is_none());
1435-
/// }).unwrap();
1436-
///
1437-
/// handler.join().unwrap();
1438-
/// ```
1439-
///
1440-
/// Thread with a specified name:
1441-
///
1442-
/// ```
1443-
/// use std::thread;
1444-
///
1445-
/// let builder = thread::Builder::new()
1446-
/// .name("foo".into());
1447-
///
1448-
/// let handler = builder.spawn(|| {
1449-
/// assert_eq!(thread::current().name(), Some("foo"))
1450-
/// }).unwrap();
1451-
///
1452-
/// handler.join().unwrap();
1453-
/// ```
1454-
///
1455-
/// [naming-threads]: ./index.html#naming-threads
1456-
#[stable(feature = "rust1", since = "1.0.0")]
1457-
#[must_use]
1458-
pub fn name(&self) -> Option<&str> {
1459-
self.inner.name.as_str()
1460-
}
1461-
1462-
/// Consumes the `Thread`, returning a raw pointer.
1463-
///
1464-
/// To avoid a memory leak the pointer must be converted
1465-
/// back into a `Thread` using [`Thread::from_raw`].
1466-
///
1467-
/// # Examples
1468-
///
1469-
/// ```
1470-
/// #![feature(thread_raw)]
1471-
///
1472-
/// use std::thread::{self, Thread};
1473-
///
1474-
/// let thread = thread::current();
1475-
/// let id = thread.id();
1476-
/// let ptr = Thread::into_raw(thread);
1477-
/// unsafe {
1478-
/// assert_eq!(Thread::from_raw(ptr).id(), id);
1479-
/// }
1480-
/// ```
1481-
#[unstable(feature = "thread_raw", issue = "97523")]
1482-
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 ()
1486-
}
1487-
1488-
/// Constructs a `Thread` from a raw pointer.
1489-
///
1490-
/// The raw pointer must have been previously returned
1491-
/// by a call to [`Thread::into_raw`].
1492-
///
1493-
/// # Safety
1494-
///
1495-
/// This function is unsafe because improper use may lead
1496-
/// to memory unsafety, even if the returned `Thread` is never
1497-
/// accessed.
1498-
///
1499-
/// Creating a `Thread` from a pointer other than one returned
1500-
/// from [`Thread::into_raw`] is **undefined behavior**.
1501-
///
1502-
/// Calling this function twice on the same raw pointer can lead
1503-
/// to a double-free if both `Thread` instances are dropped.
1504-
#[unstable(feature = "thread_raw", issue = "97523")]
1505-
pub unsafe fn from_raw(ptr: *const ()) -> Thread {
1506-
// 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()
1512-
}
1513-
}
1514-
1515-
#[stable(feature = "rust1", since = "1.0.0")]
1516-
impl fmt::Debug for Thread {
1517-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1518-
f.debug_struct("Thread")
1519-
.field("id", &self.id())
1520-
.field("name", &self.name())
1521-
.finish_non_exhaustive()
1522-
}
1523-
}
1524-
15251230
////////////////////////////////////////////////////////////////////////////////
15261231
// JoinHandle
15271232
////////////////////////////////////////////////////////////////////////////////

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

+311
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,311 @@
1+
//! The [`Thread`] handle.
2+
3+
use super::{ThreadId, current_id};
4+
use crate::ffi::{CStr, CString};
5+
use crate::pin::Pin;
6+
use crate::sync::Arc;
7+
use crate::sys::sync::Parker;
8+
use crate::time::Duration;
9+
use crate::{fmt, str};
10+
11+
/// The internal representation of a `Thread` handle
12+
struct Inner {
13+
// INVARIANT: must be valid UTF-8
14+
name: Option<CString>,
15+
id: ThreadId,
16+
parker: Parker,
17+
}
18+
19+
impl Inner {
20+
fn parker(self: Pin<&Self>) -> Pin<&Parker> {
21+
unsafe { Pin::map_unchecked(self, |inner| &inner.parker) }
22+
}
23+
}
24+
25+
/// A handle to a thread.
26+
///
27+
/// Threads are represented via the `Thread` type, which you can get in one of
28+
/// two ways:
29+
///
30+
/// * By spawning a new thread, e.g., using the [`thread::spawn`] function, and
31+
/// calling [`thread`] on the [`JoinHandle`].
32+
/// * By requesting the current thread, using the [`thread::current`] function.
33+
///
34+
/// The [`thread::current`] function is available even for threads not spawned
35+
/// by the APIs of this module.
36+
///
37+
/// There is usually no need to create a `Thread` struct yourself, one should
38+
/// instead use a function like `spawn` to create new threads, see the docs of
39+
/// [`Builder`] and [`spawn`] for more details.
40+
///
41+
/// [`Builder`]: super::Builder
42+
/// [`JoinHandle`]: super::JoinHandle
43+
/// [`spawn`]: super::spawn
44+
/// [`thread`]: super::JoinHandle::thread
45+
/// [`thread::spawn`]: super::spawn
46+
/// [`thread::current`]: super::current::current
47+
#[derive(Clone)]
48+
#[stable(feature = "rust1", since = "1.0.0")]
49+
pub struct Thread {
50+
inner: Pin<Arc<Inner>>,
51+
}
52+
53+
impl Thread {
54+
pub(crate) fn new(id: ThreadId, name: Option<String>) -> Thread {
55+
let name = name.map(|name| {
56+
CString::new(name).expect("thread name may not contain interior null bytes")
57+
});
58+
59+
// We have to use `unsafe` here to construct the `Parker` in-place,
60+
// which is required for the UNIX implementation.
61+
//
62+
// SAFETY: We pin the Arc immediately after creation, so its address never
63+
// changes.
64+
let inner = unsafe {
65+
let mut arc = Arc::<Inner>::new_uninit();
66+
let ptr = Arc::get_mut_unchecked(&mut arc).as_mut_ptr();
67+
Parker::new_in_place(&raw mut (*ptr).parker);
68+
(&raw mut (*ptr).name).write(name);
69+
(&raw mut (*ptr).id).write(id);
70+
Pin::new_unchecked(arc.assume_init())
71+
};
72+
73+
Thread { inner }
74+
}
75+
76+
/// Like the public [`park`](super::park), but callable on any handle. This is used to
77+
/// allow parking in TLS destructors.
78+
///
79+
/// # Safety
80+
/// May only be called from the thread to which this handle belongs.
81+
pub(crate) unsafe fn park(&self) {
82+
unsafe { self.inner.as_ref().parker().park() }
83+
}
84+
85+
/// Like the public [`park_timeout`](super::park_timeout), but callable on any handle.
86+
///
87+
/// # Safety
88+
/// May only be called from the thread to which this handle belongs.
89+
pub(crate) unsafe fn park_timeout(&self, dur: Duration) {
90+
unsafe { self.inner.as_ref().parker().park_timeout(dur) }
91+
}
92+
93+
/// Atomically makes the handle's token available if it is not already.
94+
///
95+
/// Every thread is equipped with some basic low-level blocking support, via
96+
/// the [`park`](super::park) function and the `unpark()` method. These can be
97+
/// used as a more CPU-efficient implementation of a spinlock.
98+
///
99+
/// See the [park documentation](super::park) for more details.
100+
///
101+
/// # Examples
102+
///
103+
/// ```
104+
/// use std::thread;
105+
/// use std::time::Duration;
106+
///
107+
/// let parked_thread = thread::Builder::new()
108+
/// .spawn(|| {
109+
/// println!("Parking thread");
110+
/// thread::park();
111+
/// println!("Thread unparked");
112+
/// })
113+
/// .unwrap();
114+
///
115+
/// // Let some time pass for the thread to be spawned.
116+
/// thread::sleep(Duration::from_millis(10));
117+
///
118+
/// println!("Unpark the thread");
119+
/// parked_thread.thread().unpark();
120+
///
121+
/// parked_thread.join().unwrap();
122+
/// ```
123+
#[stable(feature = "rust1", since = "1.0.0")]
124+
#[inline]
125+
pub fn unpark(&self) {
126+
self.inner.as_ref().parker().unpark();
127+
}
128+
129+
/// Gets the thread's unique identifier.
130+
///
131+
/// # Examples
132+
///
133+
/// ```
134+
/// use std::thread;
135+
///
136+
/// let other_thread = thread::spawn(|| {
137+
/// thread::current().id()
138+
/// });
139+
///
140+
/// let other_thread_id = other_thread.join().unwrap();
141+
/// assert!(thread::current().id() != other_thread_id);
142+
/// ```
143+
#[stable(feature = "thread_id", since = "1.19.0")]
144+
#[must_use]
145+
pub fn id(&self) -> ThreadId {
146+
self.inner.id
147+
}
148+
149+
/// Gets the thread's name.
150+
///
151+
/// For more information about named threads, see
152+
/// [this module-level documentation][naming-threads].
153+
///
154+
/// # Examples
155+
///
156+
/// Threads by default have no name specified:
157+
///
158+
/// ```
159+
/// use std::thread;
160+
///
161+
/// let builder = thread::Builder::new();
162+
///
163+
/// let handler = builder.spawn(|| {
164+
/// assert!(thread::current().name().is_none());
165+
/// }).unwrap();
166+
///
167+
/// handler.join().unwrap();
168+
/// ```
169+
///
170+
/// Thread with a specified name:
171+
///
172+
/// ```
173+
/// use std::thread;
174+
///
175+
/// let builder = thread::Builder::new()
176+
/// .name("foo".into());
177+
///
178+
/// let handler = builder.spawn(|| {
179+
/// assert_eq!(thread::current().name(), Some("foo"))
180+
/// }).unwrap();
181+
///
182+
/// handler.join().unwrap();
183+
/// ```
184+
///
185+
/// [naming-threads]: ./index.html#naming-threads
186+
#[stable(feature = "rust1", since = "1.0.0")]
187+
#[must_use]
188+
pub fn name(&self) -> Option<&str> {
189+
// SAFETY: the thread name is guaranteed to be UTF-8 by invariant.
190+
Some(unsafe { str::from_utf8_unchecked(self.cname()?.to_bytes()) })
191+
}
192+
193+
/// Consumes the `Thread`, returning a raw pointer.
194+
///
195+
/// To avoid a memory leak the pointer must be converted
196+
/// back into a `Thread` using [`Thread::from_raw`].
197+
///
198+
/// # Examples
199+
///
200+
/// ```
201+
/// #![feature(thread_raw)]
202+
///
203+
/// use std::thread::{self, Thread};
204+
///
205+
/// let thread = thread::current();
206+
/// let id = thread.id();
207+
/// let ptr = Thread::into_raw(thread);
208+
/// unsafe {
209+
/// assert_eq!(Thread::from_raw(ptr).id(), id);
210+
/// }
211+
/// ```
212+
#[unstable(feature = "thread_raw", issue = "97523")]
213+
pub fn into_raw(self) -> *const () {
214+
// Safety: We only expose an opaque pointer, which maintains the `Pin` invariant.
215+
let inner = unsafe { Pin::into_inner_unchecked(self.inner) };
216+
Arc::into_raw(inner) as *const ()
217+
}
218+
219+
/// Constructs a `Thread` from a raw pointer.
220+
///
221+
/// The raw pointer must have been previously returned
222+
/// by a call to [`Thread::into_raw`].
223+
///
224+
/// # Safety
225+
///
226+
/// This function is unsafe because improper use may lead
227+
/// to memory unsafety, even if the returned `Thread` is never
228+
/// accessed.
229+
///
230+
/// Creating a `Thread` from a pointer other than one returned
231+
/// from [`Thread::into_raw`] is **undefined behavior**.
232+
///
233+
/// Calling this function twice on the same raw pointer can lead
234+
/// to a double-free if both `Thread` instances are dropped.
235+
#[unstable(feature = "thread_raw", issue = "97523")]
236+
pub unsafe fn from_raw(ptr: *const ()) -> Thread {
237+
// Safety: Upheld by caller.
238+
unsafe { Thread { inner: Pin::new_unchecked(Arc::from_raw(ptr as *const Inner)) } }
239+
}
240+
241+
pub(super) fn cname(&self) -> Option<&CStr> {
242+
if let Some(name) = self.inner.name.as_deref() {
243+
Some(name)
244+
} else if Some(self.id()) == main_thread() {
245+
// We don't give the main thread handle a name explicitly but detect
246+
// it through its ID to support acquiring thread handles before main
247+
// and to enable lazy allocation of the handle.
248+
Some(c"main")
249+
} else {
250+
None
251+
}
252+
}
253+
}
254+
255+
#[stable(feature = "rust1", since = "1.0.0")]
256+
impl fmt::Debug for Thread {
257+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
258+
f.debug_struct("Thread")
259+
.field("id", &self.id())
260+
.field("name", &self.name())
261+
.finish_non_exhaustive()
262+
}
263+
}
264+
265+
cfg_if::cfg_if! {
266+
if #[cfg(target_has_atomic = "64")] {
267+
use crate::sync::atomic::{AtomicU64, Ordering::Relaxed};
268+
269+
static ID: AtomicU64 = AtomicU64::new(0);
270+
271+
/// # Safety
272+
/// May only be called once.
273+
pub(crate) unsafe fn set_main_thread(id: ThreadId) {
274+
ID.store(id.as_u64().get(), Relaxed)
275+
}
276+
277+
fn main_thread() -> Option<ThreadId> {
278+
ThreadId::from_u64(ID.load(Relaxed))
279+
}
280+
} else {
281+
use crate::cell::SyncUnsafeCell;
282+
use crate::sync::atomic::{AtomicBool, Ordering::{Acquire, Release}};
283+
284+
static INIT: AtomicBool = AtomicBool::new(false);
285+
static ID: SyncUnsafeCell<Option<ThreadId>> = SyncUnsafeCell::new(None);
286+
287+
/// # Safety
288+
/// May only be called once.
289+
pub(crate) unsafe fn set_main_thread(id: ThreadId) {
290+
unsafe {
291+
ID.get().write(Some(id));
292+
INIT.store(true, Release);
293+
}
294+
}
295+
296+
fn main_thread() -> Option<ThreadId> {
297+
if INIT.load(Acquire) {
298+
unsafe { ID.get().read() }
299+
} else {
300+
None
301+
}
302+
}
303+
}
304+
}
305+
306+
/// Returns whether this thread is the main thread.
307+
///
308+
/// The result of this call is unreliable for code running outside the Rust runtime.
309+
pub(crate) fn is_main() -> bool {
310+
Some(current_id()) == main_thread()
311+
}

‎tests/ui/runtime/stdout-before-main.rs

+4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ use std::thread;
1313
#[link_section = ".init_array"]
1414
static INIT: extern "C" fn(c_int, *const *const u8, *const *const u8) = {
1515
extern "C" fn init(_argc: c_int, _argv: *const *const u8, _envp: *const *const u8) {
16+
// Try access the thread handle before main. This shouldn't lead to abort
17+
// later on.
18+
drop(thread::current());
19+
1620
print!("Hello from before ");
1721
}
1822

0 commit comments

Comments
 (0)
Please sign in to comment.