@@ -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