Skip to content

Commit 6f46e86

Browse files
committed
std: permute ThreadId values
1 parent 39cf520 commit 6f46e86

File tree

1 file changed

+50
-26
lines changed

1 file changed

+50
-26
lines changed

library/std/src/thread/mod.rs

Lines changed: 50 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,46 +1080,70 @@ pub struct ThreadId(NonZeroU64);
10801080
impl ThreadId {
10811081
// Generate a new unique thread ID.
10821082
fn new() -> ThreadId {
1083+
/// A permutation function that always maps 0 to 0.
1084+
///
1085+
/// Ported from <https://www.gkbrk.com/wiki/avalanche-diagram/>.
1086+
/// This permutation is subject to change. **DO NOT** rely on it.
1087+
/// Always treat thread ids as opaque.
1088+
fn permute(x: u64) -> u64 {
1089+
let mut a = x;
1090+
let mut b = 0;
1091+
let mut c = 0;
1092+
for _ in 0..4 {
1093+
b ^= a.wrapping_add(c).rotate_left(7);
1094+
c ^= b.wrapping_add(a).rotate_left(9);
1095+
a ^= c.wrapping_add(b).rotate_left(13);
1096+
}
1097+
a
1098+
}
1099+
10831100
#[cold]
10841101
fn exhausted() -> ! {
10851102
panic!("failed to generate unique thread ID: bitspace exhausted")
10861103
}
10871104

1088-
cfg_if::cfg_if! {
1089-
if #[cfg(target_has_atomic = "64")] {
1090-
use crate::sync::atomic::{AtomicU64, Ordering::Relaxed};
1105+
fn generate() -> u64 {
1106+
cfg_if::cfg_if! {
1107+
if #[cfg(target_has_atomic = "64")] {
1108+
use crate::sync::atomic::{AtomicU64, Ordering::Relaxed};
10911109

1092-
static COUNTER: AtomicU64 = AtomicU64::new(0);
1110+
static COUNTER: AtomicU64 = AtomicU64::new(0);
10931111

1094-
let mut last = COUNTER.load(Relaxed);
1095-
loop {
1096-
let Some(id) = last.checked_add(1) else {
1097-
exhausted();
1098-
};
1112+
let mut last = COUNTER.load(Relaxed);
1113+
loop {
1114+
let Some(id) = last.checked_add(1) else {
1115+
exhausted();
1116+
};
10991117

1100-
match COUNTER.compare_exchange_weak(last, id, Relaxed, Relaxed) {
1101-
Ok(_) => return ThreadId(NonZeroU64::new(id).unwrap()),
1102-
Err(id) => last = id,
1118+
match COUNTER.compare_exchange_weak(last, id, Relaxed, Relaxed) {
1119+
Ok(_) => return id,
1120+
Err(id) => last = id,
1121+
}
11031122
}
1104-
}
1105-
} else {
1106-
use crate::sync::{Mutex, PoisonError};
1123+
} else {
1124+
use crate::sync::{Mutex, PoisonError};
11071125

1108-
static COUNTER: Mutex<u64> = Mutex::new(0);
1126+
static COUNTER: Mutex<u64> = Mutex::new(0);
11091127

1110-
let mut counter = COUNTER.lock().unwrap_or_else(PoisonError::into_inner);
1111-
let Some(id) = counter.checked_add(1) else {
1112-
// in case the panic handler ends up calling `ThreadId::new()`,
1113-
// avoid reentrant lock acquire.
1114-
drop(counter);
1115-
exhausted();
1116-
};
1128+
let mut counter = COUNTER.lock().unwrap_or_else(PoisonError::into_inner);
1129+
let Some(id) = counter.checked_add(1) else {
1130+
// in case the panic handler ends up calling `ThreadId::new()`,
1131+
// avoid reentrant lock acquire.
1132+
drop(counter);
1133+
exhausted();
1134+
};
11171135

1118-
*counter = id;
1119-
drop(counter);
1120-
ThreadId(NonZeroU64::new(id).unwrap())
1136+
*counter = id;
1137+
drop(counter);
1138+
id
1139+
}
11211140
}
11221141
}
1142+
1143+
// Permute ids to stop users from relying on the exact value of
1144+
// `ThreadId`. Since `generate` never returns zero the id will not
1145+
// be zero either, as `permute` maps zero to itself.
1146+
ThreadId(NonZeroU64::new(permute(generate())).unwrap())
11231147
}
11241148

11251149
/// This returns a numeric identifier for the thread identified by this

0 commit comments

Comments
 (0)