Skip to content

Commit 8481b82

Browse files
committed
Use spinlock for ThreadId if 64-bit atomic unavailable
1 parent 750609c commit 8481b82

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
@@ -1258,21 +1258,45 @@ impl ThreadId {
12581258
}
12591259
}
12601260
_ => {
1261-
use crate::sync::{Mutex, PoisonError};
1262-
1263-
static COUNTER: Mutex<u64> = Mutex::new(0);
1261+
use crate::cell::SyncUnsafeCell;
1262+
use crate::hint::spin_loop;
1263+
use crate::sync::atomic::{Atomic, AtomicBool};
1264+
use crate::thread::yield_now;
1265+
1266+
// If we don't have a 64-bit atomic we use a small spinlock. We don't use Mutex
1267+
// here as we might be trying to get the current thread id in the global allocator,
1268+
// and on some platforms Mutex requires allocation.
1269+
static COUNTER_LOCKED: Atomic<bool> = AtomicBool::new(false);
1270+
static COUNTER: SyncUnsafeCell<u64> = SyncUnsafeCell::new(0);
1271+
1272+
// Acquire lock.
1273+
let mut spin = 0;
1274+
while COUNTER_LOCKED.compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed).is_err() {
1275+
if spin <= 3 {
1276+
for _ in 0..(1 << spin) {
1277+
spin_loop();
1278+
}
1279+
} else {
1280+
yield_now();
1281+
}
1282+
spin += 1;
1283+
}
12641284

1265-
let mut counter = COUNTER.lock().unwrap_or_else(PoisonError::into_inner);
1266-
let Some(id) = counter.checked_add(1) else {
1267-
// in case the panic handler ends up calling `ThreadId::new()`,
1268-
// avoid reentrant lock acquire.
1269-
drop(counter);
1270-
exhausted();
1285+
let id;
1286+
// SAFETY: we have an exclusive lock on the counter.
1287+
unsafe {
1288+
id = (*COUNTER.get()).saturating_add(1);
1289+
(*COUNTER.get()) = id;
12711290
};
12721291

1273-
*counter = id;
1274-
drop(counter);
1275-
ThreadId(NonZero::new(id).unwrap())
1292+
// Release the lock.
1293+
COUNTER_LOCKED.store(false, Ordering::Release);
1294+
1295+
if id == u64::MAX {
1296+
exhausted()
1297+
} else {
1298+
ThreadId(NonZero::new(id).unwrap())
1299+
}
12761300
}
12771301
}
12781302
}

0 commit comments

Comments
 (0)