Skip to content

Commit 5703d4d

Browse files
committed
Use spinlock for ThreadId if 64-bit atomic unavailable
1 parent ceb1945 commit 5703d4d

File tree

1 file changed

+36
-12
lines changed

1 file changed

+36
-12
lines changed

library/std/src/thread/mod.rs

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1232,21 +1232,45 @@ impl ThreadId {
12321232
}
12331233
}
12341234
_ => {
1235-
use crate::sync::{Mutex, PoisonError};
1236-
1237-
static COUNTER: Mutex<u64> = Mutex::new(0);
1235+
use crate::cell::SyncUnsafeCell;
1236+
use crate::hint::spin_loop;
1237+
use crate::sync::atomic::{Atomic, AtomicBool};
1238+
use crate::thread::yield_now;
1239+
1240+
// If we don't have a 64-bit atomic we use a small spinlock. We don't use Mutex
1241+
// here as we might be trying to get the current thread id in the global allocator,
1242+
// and on some platforms Mutex requires allocation.
1243+
static COUNTER_LOCKED: Atomic<bool> = AtomicBool::new(false);
1244+
static COUNTER: SyncUnsafeCell<u64> = SyncUnsafeCell::new(0);
1245+
1246+
// Acquire lock.
1247+
let mut spin = 0;
1248+
while COUNTER_LOCKED.compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed).is_err() {
1249+
if spin <= 3 {
1250+
for _ in 0..(1 << spin) {
1251+
spin_loop();
1252+
}
1253+
} else {
1254+
yield_now();
1255+
}
1256+
spin += 1;
1257+
}
12381258

1239-
let mut counter = COUNTER.lock().unwrap_or_else(PoisonError::into_inner);
1240-
let Some(id) = counter.checked_add(1) else {
1241-
// in case the panic handler ends up calling `ThreadId::new()`,
1242-
// avoid reentrant lock acquire.
1243-
drop(counter);
1244-
exhausted();
1259+
let id;
1260+
// SAFETY: we have an exclusive lock on the counter.
1261+
unsafe {
1262+
id = (*COUNTER.get()).saturating_add(1);
1263+
(*COUNTER.get()) = id;
12451264
};
12461265

1247-
*counter = id;
1248-
drop(counter);
1249-
ThreadId(NonZero::new(id).unwrap())
1266+
// Release the lock.
1267+
COUNTER_LOCKED.store(false, Ordering::Release);
1268+
1269+
if id == u64::MAX {
1270+
exhausted()
1271+
} else {
1272+
ThreadId(NonZero::new(id).unwrap())
1273+
}
12501274
}
12511275
}
12521276
}

0 commit comments

Comments
 (0)