Skip to content

Commit 815680d

Browse files
committed
Use spinlock for ThreadId if 64-bit atomic unavailable
1 parent 89ff4e2 commit 815680d

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

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

1271-
*counter = id;
1272-
drop(counter);
1273-
ThreadId(NonZero::new(id).unwrap())
1290+
// Release the lock.
1291+
COUNTER_LOCKED.store(false, Ordering::Release);
1292+
1293+
if id == u64::MAX {
1294+
exhausted()
1295+
} else {
1296+
ThreadId(NonZero::new(id).unwrap())
1297+
}
12741298
}
12751299
}
12761300
}

0 commit comments

Comments
 (0)