Skip to content

Commit a8c799a

Browse files
authored
Rollup merge of #100022 - joboet:faster_threadid, r=joshtriplett
Optimize thread ID generation By using atomics where available, thread IDs can be generated without locking while still enforcing uniqueness.
2 parents 569788e + 3d21c37 commit a8c799a

File tree

1 file changed

+41
-18
lines changed

1 file changed

+41
-18
lines changed

Diff for: library/std/src/thread/mod.rs

+41-18
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,6 @@ use crate::ptr::addr_of_mut;
170170
use crate::str;
171171
use crate::sync::Arc;
172172
use crate::sys::thread as imp;
173-
use crate::sys_common::mutex;
174173
use crate::sys_common::thread;
175174
use crate::sys_common::thread_info;
176175
use crate::sys_common::thread_parker::Parker;
@@ -1033,24 +1032,48 @@ pub struct ThreadId(NonZeroU64);
10331032
impl ThreadId {
10341033
// Generate a new unique thread ID.
10351034
fn new() -> ThreadId {
1036-
// It is UB to attempt to acquire this mutex reentrantly!
1037-
static GUARD: mutex::StaticMutex = mutex::StaticMutex::new();
1038-
static mut COUNTER: u64 = 1;
1039-
1040-
unsafe {
1041-
let guard = GUARD.lock();
1042-
1043-
// If we somehow use up all our bits, panic so that we're not
1044-
// covering up subtle bugs of IDs being reused.
1045-
if COUNTER == u64::MAX {
1046-
drop(guard); // in case the panic handler ends up calling `ThreadId::new()`, avoid reentrant lock acquire.
1047-
panic!("failed to generate unique thread ID: bitspace exhausted");
1048-
}
1049-
1050-
let id = COUNTER;
1051-
COUNTER += 1;
1035+
#[cold]
1036+
fn exhausted() -> ! {
1037+
panic!("failed to generate unique thread ID: bitspace exhausted")
1038+
}
10521039

1053-
ThreadId(NonZeroU64::new(id).unwrap())
1040+
cfg_if::cfg_if! {
1041+
if #[cfg(target_has_atomic = "64")] {
1042+
use crate::sync::atomic::{AtomicU64, Ordering::Relaxed};
1043+
1044+
static COUNTER: AtomicU64 = AtomicU64::new(0);
1045+
1046+
let mut last = COUNTER.load(Relaxed);
1047+
loop {
1048+
let Some(id) = last.checked_add(1) else {
1049+
exhausted();
1050+
};
1051+
1052+
match COUNTER.compare_exchange_weak(last, id, Relaxed, Relaxed) {
1053+
Ok(_) => return ThreadId(NonZeroU64::new(id).unwrap()),
1054+
Err(id) => last = id,
1055+
}
1056+
}
1057+
} else {
1058+
use crate::sys_common::mutex::StaticMutex;
1059+
1060+
// It is UB to attempt to acquire this mutex reentrantly!
1061+
static GUARD: StaticMutex = StaticMutex::new();
1062+
static mut COUNTER: u64 = 0;
1063+
1064+
unsafe {
1065+
let guard = GUARD.lock();
1066+
1067+
let Some(id) = COUNTER.checked_add(1) else {
1068+
drop(guard); // in case the panic handler ends up calling `ThreadId::new()`, avoid reentrant lock acquire.
1069+
exhausted();
1070+
};
1071+
1072+
COUNTER = id;
1073+
drop(guard);
1074+
ThreadId(NonZeroU64::new(id).unwrap())
1075+
}
1076+
}
10541077
}
10551078
}
10561079

0 commit comments

Comments
 (0)