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